Skip to content

Commit b0faeb4

Browse files
authored
feat: permanent artist blacklist + rejection reasons (#148)
* feat(web): add Digarr signature theme + refresh ROADMAP shipped section * feat(core): add REJECTION_REASONS constant + type guard * feat(db): add artist_blocks table and rejection_reason columns * feat(db): add artist-blocks query module (CRUD + getBlockedMbids) * feat(pipeline): expose getBlockedMbids on StoreDb * feat(pipeline): add blockedMbids layer to filter, orchestrator, subscriptions, and quick-discover * feat(server): add rejectStatusSchema with refine rules * feat(server): extend reject route with structured reason + permanent block dual-write * feat(server): add /api/v1/artist-blocks GET/DELETE/POST routes * feat(web): add artist-blocks API client helpers * feat(web): add RejectionPicker bottom-sheet/modal + en i18n keys * feat(web): open RejectionPicker on card-stack reject; thread reason+permanent through handleReject * feat(web): add Settings > Blocked tab with search + unblock-with-undo * feat(i18n): translate rejection picker + blocked-artists keys to 14 locales * feat(backup): include artist_blocks in backup envelope and restore order * test(e2e): rejection picker + permanent block + unblock spec (fixme until seed harness lands)
1 parent 36c780c commit b0faeb4

81 files changed

Lines changed: 5049 additions & 28 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/ROADMAP.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Roadmap
22

3-
> Updated: 2026-04-19 | Current: v0.39.4
3+
> Updated: 2026-04-25 | Current: v0.43.0
44
>
55
> Priorities change with feedback. This is current intent, not a promise.
66
@@ -102,8 +102,10 @@ Release reminder: after publishing a new app image, update the pinned digests in
102102
- Multilingual support is fully shipped across 15 locales, including locale-aware AI output and stricter translation-quality checks
103103
- Library operations now cover Lidarr, Plex, Jellyfin, Emby, and `slskd`, with artist and album sync, reconciliation review, persistent Library Health snapshots, and better sync visibility
104104
- Operations and safety now include backup/restore, pre-flight migration checks, auto-backups, job history, stuck-task detection, and browser-test release gates
105-
- Recent integration work added Deezer OAuth feeds, Emby support, linked `slskd` targets, and broader playlist export coverage
106-
- Deep-audit remediation across 13 phases landed on v0.27.x through v0.39.x: auth-surface hardening and first-admin guards, full SSRF sweep and outbound IP pinning, pipeline isolation with atomic writes, DB index and upsert fixes, key rotation support, Kubernetes PSS / SA / PDB, cosign keyless signing plus SLSA v1.0 provenance, Zod validation on every write route, AI-provider reliability, i18n completeness at 15 locales, and an E2E browser-test gate in CI
105+
- Integration work added Deezer OAuth feeds, Emby support, linked `slskd` targets, and broader playlist export coverage
106+
- TheAudioDB is now the primary artist-image source ahead of the Lidarr/SkyHook + fanart.tv + musicinfo.pro chain, with a token-bucket rate limiter and an optional SSRF-guarded image proxy. Recommendation cards expose a Wikidata-sourced artist description and external-link pills (Wikipedia, official site, Discogs, MusicBrainz), cached per locale
107+
- API surface migrated to `/api/v1/*` with mutation routes returning `204 No Content`, probe failures expressed as HTTP status plus `application/problem+json`, and cursor pagination on six list endpoints. Old `/api/*` paths 308-redirect with `Deprecation` and `Sunset` headers through 2026-07-19
108+
- Deep-audit remediation closed across 13 phases (v0.27.x through v0.40.x): auth-surface hardening and first-admin guards, full SSRF sweep including NAT64/Teredo and outbound IP pinning, pipeline isolation with atomic writes, DB index and upsert fixes, dual-key encryption rotation, Kubernetes PSS-restricted with dedicated SA and PDB, Docker hardening with BuildKit cache, cosign keyless signing plus SLSA v1.0 provenance via Sigstore OIDC, Zod validation on every write route, AI provider reliability (Anthropic prompt caching, retry/backoff, Zod-validated outputs, promptfoo eval gate), i18n completeness at 15 locales, component-test plus E2E plus a11y coverage hitting WCAG AA contrast, and a docs/architecture sweep with release-surface consolidation
107109

108110
Release-level detail lives in [CHANGELOG.md](../CHANGELOG.md); this doc keeps
109111
the feature-level summary and the upcoming milestones only.

drizzle/0031_brief_katie_power.sql

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
CREATE TABLE IF NOT EXISTS "artist_blocks" (
2+
"id" serial PRIMARY KEY NOT NULL,
3+
"user_id" integer NOT NULL,
4+
"artist_id" integer NOT NULL,
5+
"reason" text,
6+
"reason_text" text,
7+
"source" text DEFAULT 'rejection' NOT NULL,
8+
"blocked_at" timestamp with time zone DEFAULT now() NOT NULL
9+
);
10+
--> statement-breakpoint
11+
ALTER TABLE "recommendations" ADD COLUMN IF NOT EXISTS "rejection_reason" text;--> statement-breakpoint
12+
ALTER TABLE "recommendations" ADD COLUMN IF NOT EXISTS "rejection_reason_text" text;--> statement-breakpoint
13+
DO $$ BEGIN
14+
IF NOT EXISTS (
15+
SELECT 1
16+
FROM pg_constraint
17+
WHERE conname = 'artist_blocks_user_id_users_id_fk'
18+
) THEN
19+
ALTER TABLE "artist_blocks" ADD CONSTRAINT "artist_blocks_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
20+
END IF;
21+
END $$;
22+
--> statement-breakpoint
23+
DO $$ BEGIN
24+
IF NOT EXISTS (
25+
SELECT 1
26+
FROM pg_constraint
27+
WHERE conname = 'artist_blocks_artist_id_artists_id_fk'
28+
) THEN
29+
ALTER TABLE "artist_blocks" ADD CONSTRAINT "artist_blocks_artist_id_artists_id_fk" FOREIGN KEY ("artist_id") REFERENCES "public"."artists"("id") ON DELETE cascade ON UPDATE no action;
30+
END IF;
31+
END $$;
32+
--> statement-breakpoint
33+
CREATE UNIQUE INDEX IF NOT EXISTS "artist_blocks_user_artist_idx" ON "artist_blocks" USING btree ("user_id","artist_id");--> statement-breakpoint
34+
CREATE INDEX IF NOT EXISTS "artist_blocks_user_idx" ON "artist_blocks" USING btree ("user_id");

0 commit comments

Comments
 (0)