nzb-search
NZB Search
Search Newznab-compatible Usenet indexers for movies, TV shows, books, and other media. Find quality releases and add them to cart or download NZB files.
Supported Indexers
| Indexer | Prefix | API Key Location | Cart Support |
|---|---|---|---|
| SceneNZBs (default) | @scenenzbs |
pass api/scenenzbs |
✅ API |
| NZBgeek | @nzbgeek |
pass api/nzbgeek |
❌ Web-only |
| NZBFinder | @nzbfinder |
pass api/nzbfinder |
❌ Not supported |
| NZBPlanet | @nzbplanet |
pass api/nzbplanet |
❌ Web-only |
Workflow
- Search - Query for content (movie, TV, book, etc.)
- Filter & Rank - Prioritize by quality indicators
- Present - Show top results with key details
- Action - Download NZB (or add to cart for SceneNZBs)
Quick Start - Most Common Search Pattern
Use this pattern for any search (works reliably across all indexers):
cd ~/.claude/skills/nzb-search && \
./scripts/nzb-api.sh [@indexer] search "QUERY" "&cat=CATEGORY&limit=50&extended=1" | \
jq -r '[.channel.item] | flatten | .[]? | {
title: .title,
guid: .guid,
size: (.size // (.attr[]? | select(."@attributes".name == "size") | ."@attributes".value) // .enclosure."@attributes".length),
grabs: ((.attr[]? | select(."@attributes".name == "grabs") | ."@attributes".value) // "N/A"),
pubDate: .pubDate
} | "\n\(.title)\n Size: \(if .size then ((.size | tonumber) / 1073741824 * 100 | floor / 100 | tostring) + " GB" else "Unknown" end)\n Grabs: \(.grabs)\n Published: \(.pubDate)\n GUID: \(.guid)"'
Common categories: 2000 (Movies), 5000 (TV), 6000 (XXX), 7000 (Books), 7120 (German ebooks)
Search Operations
All searches use scripts/nzb-api.sh. Prefix with @indexer to select indexer (default: scenenzbs).
IMPORTANT - JQ Parsing: The API returns different JSON structures depending on result count:
- Multiple results:
.channel.itemis an array - Single result:
.channel.itemis an object (not an array)
Always use this pattern to handle both cases:
jq '[.channel.item] | flatten | .[]? | ...'
Do NOT use .channel.item[]? directly as it will fail on single results.
Indexer Selection
# Use default indexer (scenenzbs)
./scripts/nzb-api.sh search "inception"
# Use specific indexer
./scripts/nzb-api.sh @nzbgeek search "inception"
./scripts/nzb-api.sh @scenenzbs search "inception"
./scripts/nzb-api.sh @nzbfinder search "inception"
./scripts/nzb-api.sh @nzbplanet search "inception"
# Search ALL indexers at once (results include .indexer field)
./scripts/nzb-api.sh search_all "inception" "&cat=2000"
# List available indexers
./scripts/nzb-api.sh list_indexers
# Get indexer capabilities
./scripts/nzb-api.sh @nzbgeek caps
Reliable jq Parsing Patterns
ALWAYS use these tested patterns instead of improvising:
# 1. SIMPLE LIST - Just show titles and basic info
./scripts/nzb-api.sh search "query" "&cat=6000&limit=50&extended=1" | \
jq -r '[.channel.item] | flatten | .[]? | {
title: .title,
guid: .guid,
size: (.size // (.attr[]? | select(."@attributes".name == "size") | ."@attributes".value) // .enclosure."@attributes".length),
grabs: ((.attr[]? | select(."@attributes".name == "grabs") | ."@attributes".value) // "N/A"),
pubDate: .pubDate
} | "\n\(.title)\n Size: \(if .size then ((.size | tonumber) / 1073741824 * 100 | floor / 100 | tostring) + " GB" else "Unknown" end)\n Grabs: \(.grabs)\n Published: \(.pubDate)\n GUID: \(.guid)"'
# 2. JSON OUTPUT - For further processing/sorting
./scripts/nzb-api.sh search "query" "&cat=6000&limit=50&extended=1" | \
jq '[.channel.item] | flatten | .[]? | {
title: .title,
guid: .guid,
size: (.size // (.attr[]? | select(."@attributes".name == "size") | ."@attributes".value) // .enclosure."@attributes".length | tonumber),
grabs: ((.attr[]? | select(."@attributes".name == "grabs") | ."@attributes".value) // "0" | tonumber),
pubDate: .pubDate
}'
# 3. SORTED BY GRABS (most popular first)
./scripts/nzb-api.sh search "query" "&cat=6000&limit=50&extended=1" | \
jq '[.channel.item] | flatten | .[]? | {
title: .title,
guid: .guid,
size: (.size // (.attr[]? | select(."@attributes".name == "size") | ."@attributes".value) // .enclosure."@attributes".length | tonumber),
grabs: ((.attr[]? | select(."@attributes".name == "grabs") | ."@attributes".value) // "0" | tonumber),
pubDate: .pubDate
}' | jq -s 'sort_by(-.grabs)'
Key points:
- Always use
[.channel.item] | flatten | .[]?to handle single/multiple results - Use
// "default"for fallback values (grabs, size) - Size can be in
.size,.attr[], or.enclosure."@attributes".length- try all three - Convert to GB:
| tonumber / 1073741824 * 100 | floor / 100 - GUID is usually in
.guiddirectly (NZBgeek) or.attr[](SceneNZBs)
Movies
# By title
./scripts/nzb-api.sh movie "inception" "&cat=2000&limit=20&extended=1"
# By IMDb ID
./scripts/nzb-api.sh movie "0468569" "&extended=1"
# With quality filters and extended metadata
./scripts/nzb-api.sh search "inception" "&cat=2000&limit=20&extended=1"
# Search NZBgeek for movies
./scripts/nzb-api.sh @nzbgeek movie "inception"
TV Shows
# Specific episode
./scripts/nzb-api.sh tvsearch "spartacus" 1 3
# Season pack
./scripts/nzb-api.sh tvsearch "breaking bad" 2
# General TV search
./scripts/nzb-api.sh search "the wire" "&cat=5000&limit=15"
Books
# By author or title
./scripts/nzb-api.sh book "author:tolkien" "&limit=10"
# Direct search
./scripts/nzb-api.sh search "fantasy novels" "&cat=7000"
Quality Filtering
Priority indicators:
- Grabs/stats - Higher = more popular/reliable
- Resolution - Prefer 720p or 1080p (avoid 2160p/4K - unnecessarily large)
- Subtitles - Check
subsattribute for "english" when requested - Size - Reasonable for quality level
Finding Quality Releases
# Get extended metadata including grabs, resolution, subs
./scripts/nzb-api.sh search "movie name" "&cat=2000&limit=30&extended=1&sort=stats_desc" | \
jq '[.channel.item] | flatten | .[]? | {
title: .title,
guid: .guid,
size: (.size // (.attr[]? | select(."@attributes".name == "size") | ."@attributes".value) | tonumber),
grabs: ((.attr[]? | select(."@attributes".name == "grabs") | ."@attributes".value) // "0"),
resolution: ((.attr[]? | select(."@attributes".name == "resolution") | ."@attributes".value) // "unknown"),
subs: ((.attr[]? | select(."@attributes".name == "subs") | ."@attributes".value) // "none")
}'
Filter logic:
- Extract resolution from title if not in metadata (look for "720p", "1080p", "2160p")
- Prioritize 1080p, accept 720p
- Exclude 2160p/4K unless specifically requested
- When subtitles requested, filter by
subscontaining "english" or "en" - Sort by grabs (popularity) among quality matches
Size Ranges (approximate)
- Movies 720p: 1-4 GB
- Movies 1080p: 2-8 GB
- TV episode 720p: 500 MB - 1.5 GB
- TV episode 1080p: 1-3 GB
Presenting Results
Show 3-5 top results with:
- Title (include resolution/quality indicators visible in title)
- Size (in GB, formatted)
- Grabs/popularity if available
- Subtitles info if relevant
- Indexer name (when using search_all or comparing across indexers)
Number results clearly for user selection.
Cart & Download Operations
Indexer Support Matrix
| Operation | SceneNZBs | NZBgeek | NZBFinder | NZBPlanet |
|---|---|---|---|---|
| Search | ✅ Newznab API | ✅ Newznab API | ✅ Newznab API | ✅ Newznab API |
| Movie search | ✅ | ✅ | ✅ | ✅ |
| TV search | ✅ | ✅ | ✅ | ✅ |
| Book search | ✅ | ✅ | ❌ Not supported | ✅ |
| Download NZB | ✅ t=get&id=GUID |
✅ t=get&id=GUID |
✅ t=get&id=GUID |
✅ t=get&id=GUID |
| Add to cart | ✅ t=cartadd&id=GUID |
❌ Web-only (session cookie) | ❌ Not supported | ❌ Web-only (session cookie) |
| Remove from cart | ✅ t=cartdel&id=GUID |
❌ Web-only | ❌ Not supported | ❌ Web-only |
| View cart | ❌ Not implemented | ❌ Web-only | ❌ Not supported | ❌ Web-only |
NZBgeek Note: Cart operations require web session authentication with internal release IDs that aren't exposed via the Newznab API. For NZBgeek, use direct download instead of cart.
NZBPlanet Note: Cart operations require web session authentication (POST to /cart?add=ID with PHPSESSID cookie). The Newznab t=cartadd endpoint is documented but non-functional (returns error 300). For NZBPlanet, use direct download instead of cart.
NZBFinder Notes:
- Rate limit: Free tier is limited to 15 API calls per 24 hours. Use sparingly — prefer other indexers for exploratory searches.
- UHD downloads: Require a premium account. Non-UHD downloads work on free tier.
- No book search:
t=bookendpoint is not supported. Use generalsearchwith&cat=7000as fallback. - No cart: Use direct download (
t=get) instead.
Download NZB (Works on All Indexers)
# Download to file (recommended for NZBgeek)
./scripts/nzb-api.sh download "guid-hash-here" "movie-name.nzb"
# From specific indexer
./scripts/nzb-api.sh @nzbgeek download "guid-hash-here" "movie-name.nzb"
# Returns: filename
Add to Cart (SceneNZBs Only)
# Add by GUID (uses default indexer - scenenzbs)
./scripts/nzb-api.sh cartadd "guid-hash-here"
# Response: {"@attributes": {"id": "internal-cart-id"}}
Remove from Cart (SceneNZBs Only)
./scripts/nzb-api.sh cartdel "guid-hash-here"
Examples
"Find Inception with English subtitles"
- Search movies:
./scripts/nzb-api.sh search "inception" "&cat=2000&limit=20&extended=1&sort=stats_desc" - Filter for English subs, 720p/1080p, sort by grabs
- Present top 3-5 results
- Ask user which to add to cart or download
"Find The Hobbit book by Tolkien"
- Search books:
./scripts/nzb-api.sh book "hobbit tolkien" "&limit=15" - Filter by author/title match
- Present top 5 results with size/format
- Add selected to cart
"Find latest episode of show X"
- TV search:
./scripts/nzb-api.sh tvsearch "show x" [season] [ep] - Filter 720p/1080p by grabs
- Present top 3
- Download selected NZB
"Find German J.D. Robb ebooks"
- Search with German category:
./scripts/nzb-api.sh search "j.d. robb" "&cat=7120&limit=50&extended=1" - Parse results and sort by book number or publication date
- Present top results with German titles
- Add selected to cart or download
"Search both indexers for rare content"
- Search all:
./scripts/nzb-api.sh search_all "obscure movie 1985" "&cat=2000&limit=20" - Results include
.indexerfield showing source - Compare availability and quality across indexers
- Use appropriate
@indexerprefix for cart/download
Categories
Note: Categories are standardized by Newznab, but availability varies by indexer. Use caps to check what an indexer supports.
English Content
- 2000 = Movies
- 2060 = 3D
- 2050 = BluRay
- 2040 = HD
- 2030 = SD
- 2045 = UHD
- 5000 = TV
- 5040 = HD
- 5030 = SD
- 5045 = UHD
- 5070 = Anime
- 5080 = Documentary
- 5060 = Sport
- 7000 = Books
- 7020 = Ebook
- 7030 = Comics
- 7010 = Mags
- 3000 = Audio
- 3030 = Audiobook
- 3010 = MP3
- 3040 = Lossless
- 3020 = Video
German Content (DE) - SceneNZBs specific
- 7100 = Books - DE
- 7120 = Ebook (use this for German ebooks!)
- 7130 = Comics
- 7110 = Mags
- 2100 = Movies - DE
- 2140 = HD
- 2150 = BluRay
- 2145 = UHD
- 5100 = TV - DE
- 5140 = HD
- 5145 = UHD
- 5170 = Anime
- 5180 = Documentary
- 5160 = Sport
- 3130 = Audiobook - DE
Spanish Content (ES) - SceneNZBs specific
- 2200 = Movies - ES
- 5200 = TV - ES
- 3230 = Audiobook - ES
Other Categories
- 1000 = Console (PS4, PS5, Xbox, Switch, etc.)
- 4000 = PC (Games, Software, Mobile)
- 6000 = XXX
- 8000 = Other
Important: When searching for German content, always use the DE-specific categories (7120 for ebooks, 2100 for movies, 5100 for TV, etc.) as regular categories (7000, 2000, 5000) contain primarily English content. Check indexer capabilities with caps as not all indexers have localized categories.
Additional Search Parameters
Append to search commands:
&limit=N- max results (default varies, max 100)&maxage=N- posted within N days&minsize=1GB/&maxsize=10GB- size filters&sort=stats_desc- sort by popularity/grabs&extended=1- include all metadata (grabs, resolution, subs, imdb, etc.)
Technical Notes
- URL Encoding: The script automatically URL-encodes all search queries, so spaces and special characters are handled correctly
- Single vs Multiple Results: Always use
[.channel.item] | flatten | .[]?pattern in jq to handle both cases - Newznab Compatibility: Both indexers use the standard Newznab API, so all commands work identically
- API Keys: Stored in
pass- ensure keys exist atapi/scenenzbs,api/nzbgeek,api/nzbfinder, andapi/nzbplanet - Rate Limits: NZBFinder free tier: 15 calls/24h. Other indexers have more generous limits.
Adding New Indexers
To add a new Newznab-compatible indexer, edit the INDEXERS array in scripts/nzb-api.sh:
declare -A INDEXERS=(
["scenenzbs"]="https://scenenzbs.com/api|api/scenenzbs"
["nzbgeek"]="https://api.nzbgeek.info/api|api/nzbgeek"
["nzbfinder"]="https://nzbfinder.ws/api|api/nzbfinder"
["nzbplanet"]="https://api.nzbplanet.net/api|api/nzbplanet"
["newindexer"]="https://newindexer.com/api|api/newindexer"
)
Format: ["name"]="BASE_URL|PASS_PATH"
The script normalizes response differences between indexers automatically (e.g., newznab:attr vs attr, different GUID structures). Non-JSON error responses (XML rate limit errors etc.) are handled gracefully in search_all.
More from markus1189/nixos-config
sourcegraph-search
Search code using Sourcegraph CLI. Use when (re)searching codebases, finding implementation examples, analyzing code patterns
22elfeed
Search the user's Emacs elfeed RSS feed database containing curated feeds from Reddit, blogs, YouTube, GitHub releases, and newsletters. Use when the user asks about articles they've read, mentions RSS feeds or 'something I read', wants to research topics from their curated sources (programming, AI, security, NixOS, Emacs, etc.), or needs to triage unread items.
1telegram
Direct integration with Telegram Bot API for checking inbox messages and sending messages (text, photos, documents) to chats. Triggers when users request 'check Telegram inbox', 'check messages', 'send message to [chat]', or mention Telegram bot interactions. Requires TELEGRAM_BOT_TOKEN environment variable.
1plantuml
Generates diagrams from text using PlantUML. Use when creating sequence diagrams, class diagrams, activity diagrams, C4 architecture diagrams, Gantt charts, mind maps, ER diagrams, or any visual diagram. Triggers on: diagram requests, architecture visualization, UML, flowcharts, system design, data modeling.
1transcribe-audio
Transcribes audio files (mp3, wav, ogg, m4a, flac, webm) using Gemini API via Portkey, saves transcripts as markdown, and supports follow-up analysis. Use when the user asks to transcribe audio, summarize a meeting recording, check a voice note, extract action items from a recording, asks what was discussed in an audio file, or mentions processing audio files in any way.
1humanizing-prose
Guides writing prose that avoids common AI/LLM tells, and reviews existing text for AI tells with concrete reformulation suggestions. Use when the user asks to 'humanize' text, 'de-AI' writing, review text for AI tells, write naturally, avoid sounding like AI, make text sound human, or mentions AI detection concerns.
1