一键导入
media-source-debug
Debug why Sonarr/Radarr can't find sources — check indexer backoffs, search results, Prowlarr health
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Debug why Sonarr/Radarr can't find sources — check indexer backoffs, search results, Prowlarr health
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Add or remove movies/shows from a named Plex collection — search library by title, resolve ratingKey, PUT into collection by name
Find a good torrent for a specific movie and add it to Radarr — search releases, evaluate seeds/quality, confirm with user, grab
Find a good torrent for a specific TV series/season and add it to Sonarr — search Prowlarr, evaluate seeds/quality, confirm with user, enable monitoring, grab
Upload a Coder template via API — pack tar, upload file, create version with variable overrides, publish or create workspace
Debug a failing Coder workspace build — check HelmRelease, pod state, and build logs via API
Add a new Helm-based application to prod-gen2 (or non-prod-gen2) via Flux — namespace, HelmRepository, HelmRelease, HTTPRoute, kustomization overlay
| name | media-source-debug |
| description | Debug why Sonarr/Radarr can't find sources — check indexer backoffs, search results, Prowlarr health |
User says a movie or show has no sources, or search returns no results. Load .env for API keys. Follow these steps.
source /workspaces/home-kubernetes/.env
RADARR_BASE=https://radarr.local.abbottland.io
SONARR_BASE=https://sonarr.local.abbottland.io
PROWLARR_BASE=https://prowlarr.local.abbottland.io
Radarr URLs use TMDB ID (e.g. /movie/324857 → TMDB 324857):
# Find by TMDB ID
curl -s "$RADARR_BASE/api/v3/movie" -H "X-Api-Key: $RADARR_API_KEY" | \
python3 -c "import sys,json; [print(m['id'],m['title']) for m in json.load(sys.stdin) if m['tmdbId']==324857 or m['id']==324857]"
# Sonarr
curl -s "$SONARR_BASE/api/v3/series" -H "X-Api-Key: $SONARR_API_KEY" | \
python3 -c "import sys,json; [print(s['id'],s['title']) for s in json.load(sys.stdin)]"
# Radarr (internal ID from step 1, NOT the TMDB ID)
curl -s "$RADARR_BASE/api/v3/release?movieId=<ID>" -H "X-Api-Key: $RADARR_API_KEY" | \
python3 -c "
import sys,json
d=json.load(sys.stdin)
print('Results:', len(d) if isinstance(d,list) else d)
for r in d[:5]:
print(r.get('indexer','?'), '|', r.get('title','?')[:60], '| seeds:', r.get('seeders',0))
"
# Sonarr
curl -s "$SONARR_BASE/api/v3/release?seriesId=<ID>&seasonNumber=<N>" -H "X-Api-Key: $SONARR_API_KEY" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print('Results:', len(d) if isinstance(d,list) else d)"
curl -s "$RADARR_BASE/api/v3/log?level=Info&pageSize=5" -H "X-Api-Key: $RADARR_API_KEY" | \
python3 -c "import sys,json; [print(r['time'],r['message']) for r in json.load(sys.stdin)['records']]"
Look for Searching indexers for [...]. N active indexers. If N is less than the number of configured indexers, some are backed off or disabled.
Prowlarr uses PostgreSQL at nas.local.abbottland.io:5432 (databases: prowlarrdb, prowlarrlogdb). No SQLite file — /config only has definitions and logs.
# Check current backoffs via API
curl -s "$PROWLARR_BASE/api/v1/indexerstatus" -H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "import sys,json; [print('Indexer',s['indexerId'],'backed off until',s['disabledTill']) for s in json.load(sys.stdin)]"
# List indexers to map ID → name
curl -s "$PROWLARR_BASE/api/v1/indexer" -H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "import sys,json; [print(i['id'],i['name'],i.get('enable')) for i in json.load(sys.stdin)]"
Note: the torznab endpoint returns the backoff directly if hit — test it:
# Port-forward and test torznab for a specific Prowlarr indexer (replace 1 with indexer ID)
kubectl port-forward -n media svc/prowlarr 19696:9696 &
sleep 3
curl -s "http://localhost:19696/1/api?apikey=$PROWLARR_API_KEY&t=movie&q=test&cat=2000"
kill %1
If the response is <error code="429" description="Indexer is disabled till ...">, the backoff is active in-memory even if the DB shows clear.
The backoff lives in both Postgres AND in-memory. Must clear both.
PG_PASS=$(kubectl get secret -n media postgres-credentials -o jsonpath='{.data.password}' | base64 -d)
kubectl run -n media pg-client --rm -it --image=postgres:alpine --restart=Never \
--env="PGPASSWORD=$PG_PASS" -- \
psql -h nas.local.abbottland.io -U postgres -d prowlarrdb \
-c 'DELETE FROM "IndexerStatus" WHERE "ProviderId"=<ID>;'
Collation version mismatch warning is safe to ignore.
kubectl rollout restart deployment/prowlarr -n media
kubectl rollout status deployment/prowlarr -n media
All config (indexers, app connections) is in Postgres — restart is safe. However: Prowlarr will re-test the indexer on startup. If the indexer is truly down (e.g. apibay.org returning 522), the backoff will immediately regenerate. Check whether the indexer is actually reachable before restarting.
# Test the indexer directly via Prowlarr search (bypasses backoff)
curl -s "$PROWLARR_BASE/api/v1/search?query=test&indexerIds[]=<ID>" \
-H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print('Count:', len(d))"
If this returns 0, the indexer is actually down. Clearing the backoff won't help until it recovers.
curl -s "$RADARR_BASE/api/v3/indexer" -H "X-Api-Key: $RADARR_API_KEY" | \
python3 -c "
import sys,json
for ix in json.load(sys.stdin):
cats = next((f['value'] for f in ix['fields'] if f['name']=='categories'), [])
seeds = next((f['value'] for f in ix['fields'] if f['name']=='minimumSeeders'), '?')
print(ix['name'], '→ categories:', cats, '| minSeeders:', seeds)
"
Movie categories: 2000–2090. TV categories: 5000–5090.
# Search all indexers for a movie
curl -s "$PROWLARR_BASE/api/v1/search?query=Incredibles+2&categories[]=2000&type=movie" \
-H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "
import sys,json
d=json.load(sys.stdin)
print('Total:', len(d))
for r in d[:5]:
print(r.get('indexer','?'), '|', r.get('title','?')[:60], '| cats:', [c['id'] for c in r.get('categories',[])])
"
# Bypass backoff and search single indexer directly
curl -s "$PROWLARR_BASE/api/v1/search?query=<title>&indexerIds[]=<ID>" \
-H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print('Count:', len(d))"
Note: direct Prowlarr search ignores the backoff; Radarr/Sonarr respect it.
# Force Prowlarr to sync all indexers to connected apps
curl -s -X POST "$PROWLARR_BASE/api/v1/command" \
-H "X-Api-Key: $PROWLARR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "ApplicationIndexerSync"}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('Status:', d.get('status'))"
# Add a new indexer (example: YTS)
curl -s -X POST "$PROWLARR_BASE/api/v1/indexer" \
-H "X-Api-Key: $PROWLARR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "YTS",
"implementationName": "Cardigann",
"implementation": "Cardigann",
"configContract": "CardigannSettings",
"enable": true,
"appProfileId": 1,
"priority": 1,
"protocol": "torrent",
"privacy": "public",
"fields": [
{"name": "definitionFile", "value": "yts"},
{"name": "baseUrl", "value": "https://yts.bz/"},
{"name": "apiurl", "value": "movies-api.accel.li"}
],
"tags": []
}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('ID:', d.get('id'), d.get('name'))"
YTS auto-syncs to Radarr (movie-only, cats 2000/2040/2045/2060). Wait ~10s then verify in Radarr.
Usually caused by minimumSeeders filtering out results with 0 seeders.
# Lower YTS minimum seeders to show all results (Radarr indexer ID 18 for YTS)
YTS_CONFIG=$(curl -s "$RADARR_BASE/api/v3/indexer/18" -H "X-Api-Key: $RADARR_API_KEY")
echo "$YTS_CONFIG" | python3 -c "
import sys,json
d=json.load(sys.stdin)
for f in d.get('fields',[]):
if f['name'] == 'minimumSeeders':
f['value'] = 0
print(json.dumps(d))
" | curl -s -X PUT "$RADARR_BASE/api/v3/indexer/18" \
-H "X-Api-Key: $RADARR_API_KEY" \
-H "Content-Type: application/json" \
-d @- | python3 -c "import sys,json; d=json.load(sys.stdin); print('Updated:', d.get('name'))"
Some indexers (e.g. LimeTorrents) sync to Sonarr but not Radarr because keyword searches return results with no movie category. The cardigann definition scrapes category from page HTML that only appears on browse/RSS pages, not keyword search result pages. Prowlarr's sync test uses a keyword-less browse, but if that also fails to categorize, Radarr rejects it.
Diagnose: check Prowlarr warn logs after ApplicationIndexerSync:
curl -s "$PROWLARR_BASE/api/v1/log?level=Warn&pageSize=20" -H "X-Api-Key: $PROWLARR_API_KEY" | \
python3 -c "
import sys,json
for r in json.load(sys.stdin).get('records',[]):
if 'sync' in r.get('message','').lower() or 'category' in r.get('message','').lower():
print(r['time'][:19], r['message'][:300])
"
If you see No Results in configured categories, the definition is failing to extract categories.
Fix: patch the cardigann YAML to hardcode category fallback to "Movies" instead of "Other":
# For LimeTorrents
kubectl exec -n media deployment/prowlarr --context prod-gen2 -- sh -c "
sed -i 's/default: \"{{ if .Result.category_is_tv_show }}TV shows{{ else }}Other{{ end }}\"/default: \"{{ if .Result.category_is_tv_show }}TV shows{{ else }}Movies{{ end }}\"/' /config/Definitions/limetorrents.yml
chmod 444 /config/Definitions/limetorrents.yml
grep -n 'Movies' /config/Definitions/limetorrents.yml | grep -v '^27:\|^31:\|^72:'
"
The chmod 444 prevents Prowlarr's daily IndexerDefinitionUpdate task from overwriting the patch. If Prowlarr ever updates to a version that fixes the definition upstream, reset with chmod 644 and let the update run.
Then re-sync to apps:
curl -s -X POST "$PROWLARR_BASE/api/v1/command" \
-H "X-Api-Key: $PROWLARR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "ApplicationIndexerSync"}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('Status:', d.get('status'))"
| Symptom | Cause | Fix |
|---|---|---|
N active indexers < configured count | Indexer in backoff | Steps 4–5 |
| Backoff clears but immediately regenerates after restart | Underlying indexer is down (e.g. apibay.org 522) | Fix the indexer or add a replacement |
| 0 results but Prowlarr direct search finds content | Radarr category filter or seeders filter | Steps 6, 9 |
| Only 3D / low quality results visible | Other versions have 0 seeders | Lower minimumSeeders (Step 9) |
| Indexer in Prowlarr/Sonarr but not syncing to Radarr | Cardigann definition extracts wrong category on keyword search | Patch definition default from Other to Movies, chmod 444 (Step 10) |
| Indexer add fails with "CloudFlare Protection" | Site uses Cloudflare | Need FlareSolverr; not currently deployed |
ApplicationIndexerSync returns no status | Wrong command name | Use ApplicationIndexerSync (not SyncApplications) |
| Collation version mismatch on psql | Postgres upgrade | Safe to ignore; or ALTER DATABASE prowlarrdb REFRESH COLLATION VERSION; |
nas.local.abbottland.io:5432, database prowlarrdbpostgres-credentials secret in media namespace (user postgres)/config PVC only has definitions, logs, backupsapiurl setting is configurable but no known working alternative to apibay.org/config PVC (/config/Definitions/). Prowlarr updates them daily via IndexerDefinitionUpdate task. chmod 444 on a patched file blocks the overwrite.| Prowlarr ID | Name | Good for | Notes |
|---|---|---|---|
| 1 | The Pirate Bay | General | Uses apibay.org; goes down periodically |
| 8 | Nyaa.si | Anime TV | Synced to Radarr but anime-only results |
| 9 | AnimeTosho | Anime TV | Same — anime only despite movie cats |
| 10 | LimeTorrents | General | Radarr ID 19; cardigann patched (chmod 444) to return Movies cat; good seeded results |
| 11 | YTS | Movies | Radarr ID 18; best Radarr source; set minSeeders=0 to see all |