diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f25e42d..e735d724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,26 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Fixed (download regression — 2026-05-29) -- **All downloads no longer rejected with "resolves outside" when the configured download path has a trailing separator.** `PathTraversalGuard.IsDescendant` (Common) compared the child against a canonical root that still carried a trailing directory separator, producing a doubled separator in the prefix check so *every* legitimate child path failed — Lidarr surfaced this as universal download failure. Fixed upstream in Common #552 (the guard now trims the trailing separator off the canonical root before the prefix comparison) and pulled into tidalarr via the `24b43c1` re-pin below. **Confirmed live** in the Lidarr E2E harness: tidalarr downloaded *A Moon Shaped Pool* with zero "resolves outside" rejections. - -### Dependencies -- `ext/Lidarr.Plugin.Common` re-pinned to **`24b43c1`** (2026-05-29) — picks up the PathTraversalGuard trailing-separator fix (#552, see above), the packaging-gates canonical-abstractions opt-in (#549), and the local-ci .NET 8 runtime guardrail (#548). `ext-common-sha.txt` + submodule gitlink advanced together (594a73b → 24b43c1). -- `ext/Lidarr.Plugin.Common` bumped to **v1.17.0** (`639d573`) Wave-23 — picks up the Wave-21 parity helpers (PathTraversalGuard.ContainsTraversalAttempt, AlbumDownloadUri, AlbumReleaseInfoBuilder bracket slots, unified version-bump helper). Tidalarr's own helpers already cover the same ground, but the bump keeps the ecosystem lockstep. -- `ext-common-sha.txt` aligned to `639d573` (was `38eda2c`, then `936556e` after Wave-22). -- `plugin.json` `commonVersion`: 1.16.0 → 1.17.0. - ### Build / cleanup + - `.gitignore` extended with `*.net8.0.zip`, `package-release/`, `release-notes.md` so release-build artifacts no longer pollute the working tree. ### Added + - `AuthFailureGate` singleton registered in `TidalModule` — wraps the bridge-default `IAuthFailureHandler` registered by `AddBridgeDefaults()` so the indexer, download client, and OAuth service share one latch state. Mirrors apple + qobuz adoption (`AppleMusicarrStreamingPlugin.cs:130-134`, `QobuzarrStreamingPlugin.cs:36`). Closes the long-standing comment-only reference at `TidalModule.cs:59` ("independent of AuthFailureGate") that left Lidarr's search loop free to hammer `api.tidal.com` on a dead session — the qobuzarr-incident class where a user got IP-banned after auth expired. - Per-entry-point gate wiring in `TidalLidarrIndexer` + `TidalLidarrDownloadClient` via private static helpers (`IsAuthShortCircuited` + `RecordAuthOutcomeFromException` + `LooksLikeAuthFailure`) that mirror apple's `AppleMusicIndexerAdapter.cs:63-104` pattern. The helpers resolve `AuthFailureGate?` from the runtime's `IServiceProvider` per-call because Lidarr's `HttpIndexerBase` / `DownloadClientBase` ctor signatures are fixed and can't accept additional DI parameters. ### Fixed + - `TidalStreamManifest`: parse failures now emit Warn log entries (was silent swallow) for manifest format drift visibility. ### Changed + - `TidalLidarrIndexer.FetchReleases` short-circuits and returns empty when the gate is latched bad and no probe slot is available — search results are deterministic instead of generating 401-storm log noise. - `TidalLidarrIndexer.Test` short-circuits with an actionable "auth latched bad" validation failure when the gate has no probe slot — the user sees a clear "paste a fresh redirect URL" path instead of a generic timeout. - `TidalLidarrDownloadClient.Download` throws an actionable `InvalidOperationException` when the gate is latched bad — Lidarr surfaces this as a download failure with recovery instructions instead of starting a download that will burn API quota / risk IP-ban. @@ -34,44 +29,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - All four entry-point catch blocks now call `RecordAuthOutcomeFromException` so that 401/403 failures latch the gate for subsequent calls. ### Tests + - `AuthFailureGateAdoptionTests` (8 facts): - 4 DI-registration facts inspect `IServiceCollection` by type `FullName` rather than `GetRequiredService()` because the merged Tidalarr.dll's ILRepack-internalized `Lidarr.Plugin.Common` and `Lidarr.Plugin.Abstractions` copies share an FQN with the standalone references the test project uses but have a different assembly identity — direct `typeof(T)` lookup would miss the registration. - 4 wiring facts use reflection on the merged DLL to verify `TidalLidarrIndexer` + `TidalLidarrDownloadClient` define the private static helpers (`IsAuthShortCircuited`, `RecordAuthOutcomeFromException`) — defense against a future refactor silently removing them. ### Known limitations + - Behavior-level testing (latching the gate and observing indexer short-circuit through real method calls) is blocked by the same cross-ALC issue that breaks the existing `BackendHealthCacheAdoptionTests` (6 pre-existing failures): the test project's standalone `Lidarr.Plugin.Common` / `Lidarr.Plugin.Abstractions` types can't be passed across the merged DLL's internalized boundary. The proper fix is a `bin-tests/` split (qobuzarr-style) where the test project consumes an un-merged Tidalarr.dll — tracked as a separate parity gap. ### Documentation + - CLAUDE.md `## Common helpers in use` section gains `PluginLogContext` (6 confirmed scopes at every canonical entry point: Search, indexer Test, Download, downloadclient Test, OAuthExchange, OAuthRefresh — Tidal has no token-sign path so the apple "auth-token-sign" scope is N/A by design) and `WarnOnce` (documented as not adopted-because-not-needed; repo-wide grep for hand-rolled warn-once patterns returns zero hits). Closes the audit gap of "PluginLogContext partial" and "WarnOnce missing" — both resolve as full coverage / N/A by lack of need. ### Changed (UX — Test() failure messages) + - `TidalLidarrIndexer.Test()` and `TidalLidarrDownloadClient.Test()` catch blocks now route exceptions through `HttpExceptionClassifier` (Common) → categorize as Auth / Network / Timeout / RateLimit / ClientRequest / Server and emit a tailored hint instead of `"Test failed ({CLR-type-name}): {ex.Message}"`. Auth-class failures now surface in the `Authentication` validation field (UI credential section) rather than the generic `Test` bucket. Matches qobuz's adoption pattern at `src/API/AdaptiveQobuzApiClient.cs:54` + `src/Services/AuthTokenManager.cs:376`. ### Changed (parity — class naming) + - `TidalConstants.cs` gains the canonical `PluginName` / `ServiceName` / `PluginVendor` const block matching apple + qobuz convention. Cosmetic parity; no behavior change. - Class `StreamManifest` → `TidalStreamManifest` (file already `TidalStreamManifest.cs`). Brings the class name in line with peer files in `Tidalarr.Domain.Streaming.*` namespace. References updated across 6 source/test/CLI files; 141 affected tests still green. - Class `AudioFormatHandler` → `TidalAudioFormatHandler` (file already `TidalAudioFormatHandler.cs`). Same rationale + pattern as the `StreamManifest` rename. References updated across 5 source/test/CLI files. ### Changed (test infrastructure — `bin-tests/` split) + - Test `` to `Tidalarr.csproj` now passes `OutputPath=bin-tests\;EnablePluginDeployment=false` alongside the existing `PluginPackagingDisable=true`. The test build now writes an un-merged `Lidarr.Plugin.Tidalarr.dll` (plus standalone `Lidarr.Plugin.Common.dll` + `Lidarr.Plugin.Abstractions.dll`) to `src/Tidalarr/bin-tests/` instead of clobbering the production-merged DLL in `src/Tidalarr/bin/`. Matches qobuzarr's pattern at `tests/Qobuzarr.Tests/Qobuzarr.Tests.csproj:55-60`. - `PluginSandboxRuntimeTests.FindPluginDll` and `TidalarrPluginLoadFixture.InitializeAsync` updated to look in `bin-tests/` first, falling back to `bin/` for legacy/manual builds. - `.gitignore` adds `bin-tests/` to the ignore list (matches qobuzarr). - **Net effect**: 11 previously-failing tests are now green — 6 in `BackendHealthCacheAdoptionTests` (cross-ALC type identity), 4 in `PluginSandboxRuntimeTests` (IPlugin discovery), 1 in `TidalarrPluginSmokeTests` (service resolution). Full suite: 1309 passed / 0 failed / 14 skipped. Closes parity-matrix axis #12 (`bin-tests/` split for cross-ALC type identity). ### Changed (CI — Wave-23) + - `.github/workflows/codeql.yml` + `release.yml`: Docker image pin `ghcr.io/hotio/lidarr:pr-plugins` → `pr-plugins-3.1.2.4913` matching apple+brainarr. Floating tag risk was "works today, breaks silently tomorrow" if hotio cuts a `pr-plugins` rebuild for Lidarr 3.1.3. ## [1.2.9] - 2026-05-29 ### Added + - Lyrics enrichment via Common's `LrclibClient` — synced-lyrics (.lrc) fetched alongside audio downloads through LRCLIB public API. - `DownloadPathValidator` adopted in download client `Test()` — syntactic path validation (traversal, relative, invalid chars) before filesystem probe. - `GetAlbumWithTracksAsync` now delegates to API client to load tracks — fixes albums without preloaded track data. - MIT LICENSE file added. ### Fixed + - **Search total failure now surfaces clearly** instead of returning misleading empty result — indexer distinguishes between "no results" and "API failed" states. -- **Search query-bleed bug** — `StreamingApiRequestBuilder` accumulated query parameters across calls, causing all searches to return cached/wrong responses. Fixed upstream in Common v1.12.0 with fail-on-reuse guard. - **Single-flight token refresh TOCTOU race** — `GetValidTokensAsync` now uses proper single-flight pattern to prevent concurrent refresh attempts. - **Empty chunk-URL arrays rejected** in `TidalChunkDownloader` — prevents crashes from malformed manifests (TDD). - **HttpClient leak** — `TidalIndexer` now implements `IDisposable` to properly dispose HTTP client. @@ -82,6 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Async efficiency** — added `ConfigureAwait(false)` to 107 bare awaits across 6 plugin files. ### Changed + - **AuthFailureGate consumer helpers adopted** from Common — `ShouldShortCircuit` and `RecordExceptionOutcome` replace local implementations. - **RateLimitHeaderUtilities** adopted from Common for `Retry-After` header parsing. - **Common submodule bumped** through multiple waves (v1.14.0 → v1.18.0-dev) — brings Wave-22-28 mega-merge, parity matrix, hot-path hardening. @@ -99,6 +103,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Gitignore hardened for credentials. ### Dependencies + - Common submodule re-pinned to `c2aca69` (AuthFailureGate consumer helpers). - FluentAssertions 6.12.2 → 8.10.0 - Microsoft.SourceLink.GitHub 8.0.0 → 10.0.300 @@ -108,6 +113,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - actions/setup-dotnet 4 → 5 ### Build + - Plugin-load-gate disabled for tidalarr (incompatible with internalize). - Canonical-abstractions sidecar opt-out in packaging-gates. - Missing init-common-submodule composite action added. @@ -115,145 +121,132 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.2.8] - 2026-05-24 ### Changed + - Common submodule bumped v1.12.0 → v1.13.1. - Sync plugin.json drift after Common bump. ## [1.2.7] - 2026-05-24 ### Fixed + - **Search query-bleed hotfix** — `StreamingApiRequestBuilder` accumulated query params across calls, causing all searches to return cached/wrong responses. Fixed upstream in Common v1.12.0 with fail-on-reuse guard. ### Changed + - Sync-over-async guard migrated to Common canonical script. - Info-log demotion for reduced noise. ## [1.2.6] - 2026-05-24 ### Fixed + - **PathTraversalGuard trailing-slash hotfix** — all downloads no longer rejected with "resolves outside" when download path has trailing separator. Fixed upstream in Common #552 and pulled via submodule bump. ### Changed + - Sync-over-async lint guard adopted. ## [1.2.5] - 2026-05-24 ### Added + - `HostBridgeRuntimeCache` — credential-change invalidation flushes cached bridge context immediately; 60s graveyard prevents in-flight request failures (Wave 13A). - `PluginLogContext` + `Scrub` observability at 5 entry points — structured per-request correlation and log redaction across Indexer and DownloadClient pipelines (Wave 13C). ### Changed + - Stale credential edge case eliminated — cache no longer returns bridge context built from superseded OAuth tokens after settings save. ## [1.2.4] - 2026-05-24 ### Changed + - `AlbumReleaseInfoBuilder` adopted — unified `ReleaseInfo` string construction replaces two hand-rolled format sites in `TidalLidarrIndexer`. - `HostBridgeDownloadOrchestrator` adopted in `TidalLidarrDownloadClient` — settings-snapshot + tracked-enqueue fixes ProbeOnly race where in-flight snapshot could observe partial settings writes. ### Dependencies + - Common submodule bumped to v1.11.0. ## [1.2.3] - 2026-05-24 ### Fixed + - `DownloadClient.Test()` multi-field failures now surface all errors — `TestValidationBuilder` from Common adopted; fixes latent bug where first failure silently swallowed subsequent field errors. ### Changed + - `BackendHealthCache` adopted via `TidalBackendHealthHandler` (DelegatingHandler, outermost layer of all 4 HTTP pipelines) — replaces hand-rolled per-plugin copy. - `HostGateRegistry.Shutdown` called on module dispose. ### Dependencies + - Common submodule bumped to v1.10.0. ## [1.2.2] - 2026-05-23 ### Fixed + - `invalid_grant` OAuth UX fix — clears consumed/expired authorization code from state and surfaces clear field-level error message instead of generic failure. - `TidalModule.Version` now derived from assembly `InformationalVersionAttribute`; locked by contract test (TDD). - `DownloadClient.Test()` adopted `TestValidationBuilder` — accumulates all field-level failures before returning, fixing latent bug where first error silently swallowed subsequent field failures. ### Changed + - HostBridge primitives adopted (`HostBridgeDownloadTracker`, `PrefixedReleaseGuidParser`, `PlaceholderSearchUri`) — ~120 LOC saved vs hand-rolled equivalents. - Common submodule bumped to v1.9.5. ## [1.2.1] - 2026-05-23 ### Fixed + - Common v1.9.3 — Lidarr-Docker token-protection hotfix + adversarial-review hardening. ## [1.2.0] - 2026-05-23 ### Added + - `AuthFailureGate` adoption — quality-downgrade detector + Lidarr-native `FetchReleases` gate + HttpClient handler-chain trap closure. - CI parity-lint VersionContract step + workflow Pester test. - Documentation: Shared Infrastructure section, CHANGELOG, archived 9 historical plans. - Security hardening backlog document (10 findings, 2 High). - Hardcoded-creds ADR + packaging-gates workflow + regression test. - `HttpExceptionClassifier` adoption in `TidalLidarrDownloadClient.Test()` — categorizes failures with actionable hints. -- TidalRateLimiter wired into every HttpClient — eliminates 429 storms. ### Fixed -- FluentValidation pinned to 9.5.4 (host-coupled AssemblyVersion 9.0.0.0). -- Manifest: dropped deprecated `minimumVersion` (MAN004). -- Non-http(s) redirect URLs rejected (cross-platform parse). -- `MetricsFactoryHttpMessageHandlerFilter` suppressed (ALC trap). -- M.E.Http reverted to 8.0.1 (was 9.0.0 — runtime mismatch). + - Packaging failure made fatal + commonVersion bump. -- Security: enabled `CentralPackageTransitivePinningEnabled`. -- Security: `System.Security.Cryptography.Xml` pinned >= 8.0.3. -- CI smoke-test pinned to specific Common SHA. ### Changed -- Docker E2E harness — tidalarr smoke tests in real Lidarr container. -- Security: PKCEStateStore encrypted at rest via `FileTokenStore`. -- Coverage: coverlet measures Tidalarr modules numerically. -- Settings: migrated FluentValidation `.Errors.First()` → `.ToString()`. -- Common bump to v1.11.0 for wave-16 security fixes — dropped 2 overrides, applied `[ParityAllowedTokenStore]`. -- Token storage migrated to common's encrypted `FileTokenStore`. -- PKCE routed through common's `PKCEGenerator` — collapsed token providers, added log redaction. -- Common's `ChunkedHttpAssembler` adopted — collapsed two near-duplicate chunk paths. -- Common `PluginConfigRoots` adopted; deleted `ConfigPathDefaults`. -### UX improvements -- TidalDownloadClient PreferredQuality describes tiers + subscription requirements (wave 83). -- OAuth token-exchange messages name stale-redirect cause (wave 79). -- Test() ConfigPath + generic-failure messages match wave 68/72 (wave 73). -- TidalLidarrIndexerSettings ConfigPath error names default location (wave 68). - -### Quality improvements -- Quality detection regression coverage for null-tags fix (wave 50). -- TidalQualityDetector null-tags + structured optimizer logging (waves 47, 49). -- CancellationToken propagated through search/album-detail paths (wave 38). -- Optimizer fire-and-forget swallow made explicit (wave 37). +- Common bump to v1.11.0 for wave-16 security fixes — dropped 2 overrides, applied `[ParityAllowedTokenStore]`. ### Infrastructure -- Multi-plugin co-existence support. + - Lidarr.Plugin.*.dll naming contract documented. -- VersionContract parity-lint + workflow Pester test. -- Release packaging failure made fatal. -- CI: Docker E2E job using common composite action. -- CI: consume common's lifted LidarrContainerFixture (wave 22a). ### Dependencies + - Common bumped through multiple versions (v1.5.0 → v1.7.1 → various SHA pins). -- Microsoft.Extensions.{DI,Logging.Abs} bumped to 9.0.0. -- M.E.Http aligned to 9.0 + minimumVersion added. ## [1.1.1] - 2026-05-23 ### Fixed + - Release asset named with `net8.0.zip` suffix — required for Lidarr UI install to recognize plugin. - TidalRateLimiter wired into every HttpClient — eliminates 429 storms. ## [1.1.0] - 2026-05-10 ### Added + - Multi-plugin co-existence support. - Docker E2E coverage cliff fix + sidecar-tolerant scripts in Common. - FluentValidation pinned to 9.5.4 (host-coupled AssemblyVersion 9.0.0.0). - M.E.* 8.0 alignment in Common testkit. ### Changed + - Common bumped to 90da1f6 (Abstractions cross-ALC fix) + aligned M.E.* pins. - Common bumped to 904d5ae. - Manifest: dropped deprecated `minimumVersion` (MAN004). @@ -271,18 +264,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - CI smoke-test pinned to Common SHA. ### UX + - TidalDownloadClient PreferredQuality describes tiers + subscription requirements (wave 83). - OAuth token-exchange messages name stale-redirect cause (wave 79). - Test() ConfigPath + generic-failure messages match wave 68/72 (wave 73). - TidalLidarrIndexerSettings ConfigPath error names default location (wave 68). ### Quality + - Quality regression coverage for null-tags fix (wave 50). - TidalQualityDetector null-tags + structured optimizer logging (waves 47, 49). - CancellationToken propagated through search/album-detail paths (wave 38). - Optimizer fire-and-forget swallow made explicit (wave 37). ### Infrastructure + - Docker E2E job wired using common composite action (wave 23). - Consume common's lifted LidarrContainerFixture (wave 22a). - Docker-based E2E harness — tidalarr smoke tests in real Lidarr container (wave 21). @@ -305,11 +301,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Auto-generated UI screenshots refreshed. ### Documentation + - Multi-Plugin section updated — fixed 2026-05-10. ## [1.0.1-preview-obs-20251011-1534-911d939] - 2025-10-11 ### Added + - CLI hardening: parsing for search/download + gated CLI tests. - TFM_RATIONALE docs (core net6.0, CLI net9.0), linked in README and docs index. - Submodule pinning workflow comparing `ext/Lidarr.Plugin.Common` to `ext-common-sha.txt`. @@ -336,6 +334,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Lidarr.Core/Common references dropped from plugin csproj. ### Infrastructure + - CLI diagnostics + packaging tests (Trait scope=cli). - CLI integration tests for settings/indexer/download validate commands. - Dependency-closure test on packaged zip. @@ -383,6 +382,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - CLI smoke coverage for core commands added. ### CLI + - Cover art embedded after album download. - Artist album folders created for downloads. - README + agent file created. @@ -405,6 +405,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Download commands using shared `SimpleDownloadOrchestrator` + `TidalChunkStreamProvider` added. ### Plugin + - `TidalChunkStreamProvider` DI-registered. - `CreateOrchestrator` factory using shared `SimpleDownloadOrchestrator` added. - `TidalChunkStreamProvider` implementing `IAudioStreamProvider` using `TidalStreamService` + `TidalChunkDownloader` added. @@ -421,6 +422,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Quality mapping preserves Tidal IDs while aligning tiers. ### Core + - DASH manifest parser implementation with TidalSharp patterns completed. - Shared library with merged CLI framework improvements updated. - Production-first CLI framework architecture integrated. diff --git a/README.md b/README.md index a68a410a..8d943842 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ Settings are available in the Lidarr UI under the plugin's Settings panel. Advan | Preferred Quality | Lossless | Low / High / Lossless / HiRes | Audio quality tier. Falls back to the highest your subscription allows; HiFi Plus required for Lossless+. | | Include MQA *(adv)* | on | — | Include Master (MQA) releases. | | Extract FLAC *(adv)* | on | — | Extract FLAC from M4A containers. | +| Re-encode AAC *(adv)* | off | — | Transcode AAC streams to 320 kbps when HiRes/Lossless are unavailable. | | Chunk Delay *(adv)* | 0 ms | 0–60 000 ms | Delay between chunk requests. Increase if rate-limited. | | Max Concurrent Track Downloads *(adv)* | 2 | 1–3 | Parallel tracks per album. | | Max Concurrent Chunk Downloads *(adv)* | 2 | 1–8 | Parallel chunk requests per track. Effective parallelism is capped so that tracks × chunks ≤ 6. Disabled when Chunk Delay > 0. | diff --git a/docs/README.md b/docs/README.md index e90173dc..958888ef 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ The following documents are pre-implementation planning artifacts, completed sta - **Proposals & feedback** (3 files): `ARCHITECT_FEEDBACK_RESPONSE.md`, `SHARED-LIBRARY-PROPOSAL.md`, `SHARED_LIBRARY_ENHANCEMENT_PROPOSAL.md` - **Iteration analyses** (3 files): `ITERATION_1_EDGE_CASES_ANALYSIS.md`, `ITERATION_2_SCALABILITY_ANALYSIS.md`, `ITERATION_3_SHARED_LIBRARY_IMPROVEMENTS.md` - **Test coverage & adoption** (3 files): `COVERAGE_ANALYSIS_SUMMARY.md`, `UNIT_TEST_COVERAGE_PLAN.md`, `UNIT_TEST_SUCCESS_SUMMARY.md`, `TESTING_ADOPTION_PLAN.md` -- **Cross-plugin alignment** (4 files): [alignment/](alignment/) directory +- **Cross-plugin alignment** (4 files): [alignment/](alignment/) directory — [migration-workstreams.md](alignment/migration-workstreams.md) (Tidalarr/Qobuzarr migration workstreams), [qobuzarr-streaming-module-update.md](alignment/qobuzarr-streaming-module-update.md) (Qobuzarr streaming-module adoption updates), [shared-architecture-goals.md](alignment/shared-architecture-goals.md) (shared architecture guiding principles), [tidalarr-qobuzarr-architecture.md](alignment/tidalarr-qobuzarr-architecture.md) (Tidalarr vs Qobuzarr architecture comparison) - **Ecosystem plans** (2 files): `ECOSYSTEM_E2E_PLAN.md`, `ECOSYSTEM_TEST_INFRA_ROADMAP.md` - **Tech debt inventory** (v1.0 snapshot): `TECH-DEBT-INVENTORY.md` diff --git a/docs/TECH_DEBT_BACKLOG.md b/docs/TECH_DEBT_BACKLOG.md index df1e9d13..443f3e97 100644 --- a/docs/TECH_DEBT_BACKLOG.md +++ b/docs/TECH_DEBT_BACKLOG.md @@ -2,7 +2,7 @@ This document tracks actionable tech-debt items with acceptance criteria. -## Hot Fixes (done) +## Done - Remove stray logs (out.txt, err.txt) and ignore entries - [x] Deleted committed files @@ -10,17 +10,13 @@ This document tracks actionable tech-debt items with acceptance criteria. - Conditional CLI test skipping - [x] Introduced `CliFactAttribute` with `RUN_REAL_CLI_TESTS` gate - [x] Replaced hard Skips in CLI tests +- ~~Trim unused Polly packages~~ (resolved) + - [x] Polly no longer referenced in `Tidalarr.csproj`. + - [x] Stale `TidalResiliencePolicy` references cleaned up. + - [x] Build/tests green. ## High Priority (next sprint) -1) ~~Trim unused Polly packages~~ (resolved) - -- Context: `TidalResiliencePolicy` has been removed from source (`src/`). Runtime retries now use Common `ExecuteWithRetryAsync`. Polly is absent from `Tidalarr.csproj`. -- Criteria: - - [x] Verify Polly is no longer referenced in `src/Tidalarr/Tidalarr.csproj`; if still present, remove `Polly` and `Polly.Extensions.Http` PackageReferences. - - [x] Clean up stale `TidalResiliencePolicy` references in docs and scripts. - - [x] Build/tests green. - 1) HostBridge → core mapping tests - Criteria: diff --git a/wiki/Home.md b/wiki/Home.md index cc95f8fe..4d57dce1 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -2,42 +2,11 @@ > **Canonical source:** the root [`README.md`](../README.md) is kept up to date. This wiki page may lag behind; prefer the README for the latest installation steps, configuration table, and feature list. -Tidalarr is a Lidarr plugin that indexes and downloads lossless and hi-res audio from the [Tidal](https://tidal.com) streaming service. It ships as a single merged DLL (`Lidarr.Plugin.Tidalarr.dll`) targeting `net8.0`. +Tidalarr is a Lidarr plugin that indexes and downloads lossless and hi-res audio from [Tidal](https://tidal.com). It ships as a single merged DLL targeting `net8.0`, built on the shared [Lidarr.Plugin.Common](https://github.com/RicherTunes/Lidarr.Plugin.Common) library. -- **Version**: 1.2.9 -- **Repository**: -- **License**: MIT +For full details — features, installation, configuration, CLI usage, and project structure — see the **[README](../README.md)**. -## Built on Lidarr.Plugin.Common - -Tidalarr builds on the shared [Lidarr.Plugin.Common](https://github.com/RicherTunes/Lidarr.Plugin.Common) library (vendored at `ext/Lidarr.Plugin.Common`). Foundation topics — architecture, extension points, shared helpers, and submodule versioning — are documented in **Common's wiki**, not duplicated here: - -| Common wiki page | Why follow it | -|---|---| -| [Home](https://github.com/RicherTunes/Lidarr.Plugin.Common/blob/main/wiki/Home.md) | Overview of the shared library and the four-plugin ecosystem | -| [Architecture Overview](https://github.com/RicherTunes/Lidarr.Plugin.Common/blob/main/wiki/Architecture-Overview.md) | Base classes, DI container, and the plugin lifecycle that Tidalarr inherits | -| [SDK and Extension Points](https://github.com/RicherTunes/Lidarr.Plugin.Common/blob/main/wiki/SDK-and-Extension-Points.md) | How to extend `BaseStreamingIndexer`, `BaseStreamingDownloadClient`, and other service interfaces | -| [Shared Helpers Catalog](https://github.com/RicherTunes/Lidarr.Plugin.Common/blob/main/wiki/Shared-Helpers-Catalog.md) | Ready-made utilities (caching, auth gates, health probes, lyrics enrichment) that Tidalarr consumes | -| [Versioning and Submodule Pinning](https://github.com/RicherTunes/Lidarr.Plugin.Common/blob/main/wiki/Versioning-and-Submodule-Pinning.md) | How `ext-common-sha.txt` and the gitlink stay in sync, and the nightly bump workflow | - -## Installation - -### Prerequisites - -- Lidarr **v3.0.0.4855** or higher on the **plugins branch** (`.NET 8` image, e.g. `pr-plugins-3.1.2.4913`). -- A Tidal subscription (HiFi or HiFi Plus for lossless/hi-res quality). - -### Install via the Lidarr UI - -1. **Settings → Plugins** → paste `https://github.com/RicherTunes/Tidalarr` → **Install** → restart Lidarr. -2. Add **Tidalarr** under **Settings → Indexers** and **Settings → Download Clients**. -3. Complete the Tidal OAuth 2.0 PKCE sign-in from the plugin settings. - -To build from source, see the [Getting Started](#getting-started) section below. - -## Configuration - -### Performance tuning +## Performance tuning Tidal downloads are chunked (many HTTP requests per track), so they will not match single-file providers 1:1. The defaults aim for a safe baseline; raise cautiously if you hit slow downloads. @@ -47,63 +16,4 @@ Tidal downloads are chunked (many HTTP requests per track), so they will not mat | Max Concurrent Track Downloads | 2 | 1–3 | Parallel tracks per album. | | Max Concurrent Chunk Downloads | 2 | 1–8 | Parallel chunk requests per track. When `Chunk Delay > 0`, chunk parallelism is disabled to preserve "delay between requests" semantics. | -Settings are exposed via the Lidarr UI (see the README config table for the full list) and the core classes at `src/Tidalarr/Integration/`. - -## Getting Started - -```bash -# Clone with submodules -git clone --recursive https://github.com/RicherTunes/Tidalarr.git - -# Restore and build -dotnet restore Tidalarr.sln -dotnet build Tidalarr.sln - -# Run tests -pwsh scripts/test.ps1 -``` - -### Host vs. Core - -- **Core plugin** (`src/Tidalarr`): hostless runtime used by CLI and tests; no NzbDrone/Lidarr references. Ships in the plugin zip. -- **Host bridge** (`src/Tidalarr.HostBridge`): host-only wrappers with NzbDrone annotations and pretty enum labels; translates host UI models to core settings via `IHostSettingsMapper`. Not shipped in the plugin zip. -- See [`docs/hostbridge-integration.md`](../docs/hostbridge-integration.md) for wiring details. -- Framework rationale: [`docs/TFM_RATIONALE.md`](../docs/TFM_RATIONALE.md). - -### CLI tool - -`TidalCLI/` provides manual verification helpers and named-argument commands: - -```bash -dotnet run --project TidalCLI -- search "Miles Davis Kind of Blue" -dotnet run --project TidalCLI -- download-album AlbumId= OutputDir= Quality=HiRes -``` - -## Project Structure - -```text -src/Tidalarr/ -├── Application/ # Application-level services -├── Core/ # Constants, exceptions, DTOs -├── Diagnostics/ # Diagnostic helpers -├── Domain/ # API clients, streaming, manifest parsing -├── Infrastructure/ # Caching, resilience, storage -├── Integration/ # Lidarr integration (indexer, download client, DI module) -└── Properties/ # Assembly metadata -``` - -## Documentation - -| Document | Description | -|---|---| -| [`CHANGELOG.md`](../CHANGELOG.md) | Release history (Keep a Changelog format) | -| [`docs/hostbridge-integration.md`](../docs/hostbridge-integration.md) | Host bridge wiring guide | -| [`docs/TFM_RATIONALE.md`](../docs/TFM_RATIONALE.md) | Why `net8.0` core / `net9.0` CLI | -| [`docs/packaging-closure.md`](../docs/packaging-closure.md) | Plugin packaging validation | -| [`docs/ci-gates-verification.md`](../docs/ci-gates-verification.md) | CI gate details | -| [`docs/SETTINGS-MIGRATION.md`](../docs/SETTINGS-MIGRATION.md) | Settings migration notes | -| [`CLAUDE.md`](../CLAUDE.md) | Full development guide for contributors and automation | - -## Support - -Open a [GitHub issue](https://github.com/RicherTunes/Tidalarr/issues) with detailed logs and reproduction steps. +Settings are exposed via the Lidarr UI (see the [README config table](../README.md#configuration) for the full list) and the core classes at `src/Tidalarr/Integration/`.