MyGo 云音乐
用 Go 与 MyGo 写成的第三方网易云音乐桌面客户端。原生界面,没有 WebView;边下边播,无损与 Hi-Res,逐字歌词与「律动」,刘海播放器。
Translation pending
Family music library audit
Translation pending
MediaTypeScript · CSSGitHub @patricktrOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Audits a family's Spotify libraries for AI-generated kids-music slop. Heuristic classifier enriched via MusicBrainz, optionally adjudicated by Claude. Auto-unlikes high-confidence brain rot with a reversible audit log; routes borderline tracks to a per-account thumbs-up/down review UI.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A self-hosted Next.js app that audits a family's Spotify libraries and quietly removes AI-generated brain-rot tracks before they fill up a kid's Liked Songs.Read the full README ↗A self-hosted Next.js app that audits a family's Spotify libraries and quietly removes AI-generated brain-rot tracks before they fill up a kid's Liked Songs.
If you have a kid with a Spotify account on your Family Plan, you've probably noticed that searches for real songs increasingly return algorithmically optimized garbage from artists named things like "Poopers the Penguin" — anonymous projects with a few hundred monthly listeners, freshly uploaded, engineered to hijack autoplay queues. The Spotify product team does not appear to care, and parental controls don't touch it. This is a personal frustration project: a thing that watches one kid's library every night and pulls out the slop, with an audit trail so anything wrongly removed can be put back.
cleanup_enabled = true get auto-unliked. The app itself has no account limit — Spotify's Development Mode cap of 25 OAuth-allowed users is the ceiling unless you apply for Extended Quota Mode.actions row for every removal./review. Lists every classified track across all accounts (filterable by account and verdict, sortable by confidence) with the actual signals each verdict was based on. Thumbs-up / thumbs-down buttons record your override into the reviews table — used both as a safety net (the cleaner respects keep/protect decisions) and as ground-truth feedback for tuning heuristic weights.ADMIN_PASSWORD), enforced by edge middleware. Cron endpoints and the Spotify OAuth callback are allowlisted so they keep working.The classifier in lib/classifier.ts is heuristics-first, LLM-on-the-edge. Most tracks never hit Claude. Each scanned artist is enriched from two data sources before classification:
preview_url, and the entire /audio-features endpoint are stripped from dev-mode apps as of November 2024, so we don't rely on them. The /artists/{id} lookup gives us follower count, popularity, and genre tags when we can reach it (Spotify rate-limits this hard in dev mode).id, name, type (Person / Group / Other), country, life-span (begin and end years), and folksonomy tags. MusicBrainz is human-curated, so "is this artist in MB at all, with a matching name and a non-trivial cataloging footprint" is a strong proxy for "is this a real artist."Hard heuristics, in priority order:
| Heuristic | Verdict | Confidence | Requires |
|---|---|---|---|
Toilet-humor regex in track name (poop / fart / butt / pee-pee / booger / tinkle / toot / stinky / tushy) | brain_rot | 0.95 | track name only |
Brain-rot tag from Spotify (phonk, sigma, skibidi, gachi, brainrot, rage rap, tiktok rap) | brain_rot | 0.9 | Spotify artist genres |
| Brain-rot tag from MusicBrainz (same list) | brain_rot | 0.88 | MB tags |
| Mega-artist on Spotify (followers > 5M) | authentic | 0.92 | Spotify follower count |
Established artist in MB: normalized name match + cataloged begin_year + 5+ years active. Confidence 0.9 with 5+ tags, 0.8 otherwise. | authentic | 0.8–0.9 | MB name match + life-span |
| AI-slop strong: Spotify followers < 5k, released in last 12 months, MB has no name match | brain_rot | 0.9 | Spotify followers + release date + MB result |
| AI-slop partial: Spotify followers < 5k, released in last 12 months (MB inconclusive) | brain_rot | 0.75 | Spotify followers + release date |
Cataloged artist in MB: name match + Person/Group + ≥1 tag (but no life-span) | authentic | 0.65 | MB name match + tags |
| Obscure + no MB match: Spotify followers < 50k AND MB name mismatch | brain_rot | 0.7 | Spotify followers + MB result |
| Weak MB match: name match but no tags, no life-span | falls through | — | — |
Everything that falls through goes to Claude opus-4-7 (when ANTHROPIC_API_KEY is set) with a cached system prompt that bakes in:
fuck in a Pink song is not brain rot.musicbrainz_name_matches_spotify boolean computed from a normalized comparison (strips diacritics, lowercase, drops common punctuation including both straight and curly quote marks).The system prompt is sent with cache_control: ephemeral, so per-request cost stays low once the cache warms.
Heuristics-only mode is a supported configuration: leave ANTHROPIC_API_KEY unset (or set LLM_CLASSIFIER_ENABLED=false) and the heuristic layer runs as usual, with anything it can't resolve queued as borderline (confidence 0.5) for manual review at /review.
score is decorativeThe classifier stores mb_score for diagnostics but does not gate on it. Lucene normalizes the top result of any search to 100, even for terrible matches — searching artist:"Poopers the Magic Penguin" returns "Rie Sinclair" at score 100. The real match-quality signal is a normalized comparison of the MB-returned name against the artist name we searched for. Only a name match counts as an MB hit.
You will need: a GitHub account, a Vercel account, a Spotify Developer app, and — optionally — an Anthropic API key.
Fork and clone.
git clone https://github.com/<you>/spotify-cleaner.git
cd spotify-cleaner
pnpm install
Create a Vercel project and link it.
vercel link
Provision Neon Postgres via the Vercel Marketplace. This auto-injects POSTGRES_URL and POSTGRES_URL_NON_POOLING into your Vercel project env.
vercel integration add neon
vercel env pull .env.local
Create a Spotify Developer app at https://developer.spotify.com/dashboard. Grab the Client ID and Client Secret. Under "Redirect URIs" add both:
http://localhost:3000/api/spotify/callbackhttps://<your-prod-domain>/api/spotify/callbackThen add every family member to the app's User Management allowlist — this is the step that bites everyone the first time, with a misleading 403 user is not registered for this application error during OAuth. New Spotify dev apps start in Development Mode, which restricts API access to up to 25 explicitly-listed Spotify accounts. You (the app creator) are on the list automatically; nobody else is. From your dev app's dashboard, click User Management, then add a row for each family member whose account you'll connect:
Save. No invitation or acceptance flow — once a Spotify account is on the list, its next OAuth attempt against your app succeeds. If you skip this step, OAuth will work for you (since you're auto-allowed) but fail for everyone else with the 403 above.
Get an Anthropic API key at https://console.anthropic.com. Optional — if you skip this, the heuristic layer still runs and anything it can't resolve will sit in the review queue (verdict borderline, confidence 0.5) for you to handle by hand. You can also leave the key set but force heuristics-only mode with LLM_CLASSIFIER_ENABLED=false.
Schedules are defined in vercel.json:
| Path | Schedule | What it does |
|---|---|---|
/api/cron/poll-plays | */30 * * * * | Every 30 minutes. Pulls the last 50 plays for every connected account into the plays table. |
/api/cron/scan-library | 0 4 * * * | Daily at 04:00 UTC. For every account with a stored refresh token: reconciles Liked Songs, enriches new artists via Spotify + MusicBrainz, classifies anything lacking a current-version row. Auto-unlikes brain rot only for accounts with cleanup_enabled = true. |
Both endpoints reject any request whose Authorization header isn't Bearer $CRON_SECRET. To trigger manually for a single account (useful when iterating on the classifier, since MusicBrainz rate-limiting means a full scan of an uncached library takes about 1.1 seconds per unique artist):
# All accounts
curl -H "Authorization: Bearer $CRON_SECRET" https://<your-prod-domain>/api/cron/scan-library
# Just one account
curl -H "Authorization: Bearer $CRON_SECRET" "https://<your-prod-domain>/api/cron/scan-library?account_id=<uuid>"
/api/cron/ping is a diagnostic endpoint that runs a single SELECT 1 against the database and reports the round-trip latency.
The auto-unlike behavior is controlled by AUTO_UNLIKE_THRESHOLD (default 0.7). Any classification with verdict = brain_rot and confidence >= AUTO_UNLIKE_THRESHOLD gets unliked on the next scan. Set it higher (e.g., 0.85) to be more conservative, or lower to be more aggressive.
Nothing is destructive:
actions row recording the track, the classification that triggered it, and the prior_liked_at timestamp.actions row with action = 'relike' and reverted_action_id pointing back at the original. The original row's reverted_at is filled in.actions where reverted_at IS NULL, call PUT /v1/me/tracks on Spotify with each track ID, and write the matching relike rows.The reviews table also acts as a safety net: a protect or keep decision on a track prevents the cleaner from ever unliking it for that account, even if the classifier later flips its verdict.
popularity and preview_url are not returned from /me/tracks for apps in Development Mode. /audio-features returns 403. /artists?ids= (batched) returns 403; we work around it by calling /artists/{id} per-ID with parallel chunks and tolerating per-request failures. To get any of that back, you'd need to apply for Extended Quota Mode with Spotify (multi-week review).Retry-After: 80000+ for hours. The fetch wrapper caps retries at 30s and gives up after that rather than burning the function budget.keep at /review and the cleaner will leave them alone going forward.actions table for a few days before trusting it./review as borderline (confidence 0.5). With MusicBrainz enrichment doing most of the heavy lifting, a typical small kid's library produces a manageable borderline list — but on larger libraries (parent accounts with hundreds of songs) expect noticeably more borderlines without LLM adjudication.keep at /review, treat all of X's other tracks as authentic-leaning. The reviews table already supports a nullable account_id for global overrides, which is the natural home for this.plays, brain-rot ingress rate over time, "tracks classified brain rot before vs. after we tightened the AI-slop rule."keep / protect. The reviews table supports always_unlike; the scan logic doesn't honor it yet.actions row from the last 24 hours in one call.AGPL-3.0-or-later. If you host a modified version as a network service, you must make your modified source available to users of that service.
Set env vars in Vercel (see .env.example):
SPOTIFY_CLIENT_ID
SPOTIFY_CLIENT_SECRET
SPOTIFY_REDIRECT_URI # https://<your-prod-domain>/api/spotify/callback
TOKEN_ENCRYPTION_KEY # 32 random bytes, base64url-encoded
ANTHROPIC_API_KEY # optional; omit for heuristics-only mode
LLM_CLASSIFIER_ENABLED # optional; set to `false` to force heuristics-only even when the key is set
CRON_SECRET # 32 random bytes you generate; Vercel cron requests include it as the Authorization Bearer token
ADMIN_PASSWORD # the shared password for the app-level login gate at /login
# POSTGRES_URL, POSTGRES_URL_NON_POOLING come from the Neon integration
Generate the encryption key with:
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64url'))"
Apply the schema.
pnpm db:push
Deploy.
vercel deploy --prod
Connect accounts. Visit your production domain, use the connect form on the admin home, and walk through Spotify OAuth once per family member. Flip cleanup_enabled to true only on the account whose library you want pruned.