Compare commits
No commits in common. "main" and "v0.1.13" have entirely different histories.
7 changed files with 77 additions and 289 deletions
|
|
@ -12,14 +12,9 @@ permissions:
|
||||||
jobs:
|
jobs:
|
||||||
lint-commits:
|
lint-commits:
|
||||||
name: Lint commits
|
name: Lint commits
|
||||||
runs-on: docker
|
runs-on: ubuntu-latest
|
||||||
container:
|
|
||||||
image: docker.io/library/ubuntu:24.04
|
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
steps:
|
steps:
|
||||||
- name: Install git + grep
|
|
||||||
run: apt-get update && apt-get install -y --no-install-recommends git ca-certificates
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
@ -50,37 +45,9 @@ jobs:
|
||||||
|
|
||||||
lint-scripts:
|
lint-scripts:
|
||||||
name: Lint shell scripts
|
name: Lint shell scripts
|
||||||
runs-on: docker
|
runs-on: ubuntu-latest
|
||||||
container:
|
|
||||||
image: docker.io/library/ubuntu:24.04
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install shellcheck
|
|
||||||
run: apt-get update && apt-get install -y --no-install-recommends shellcheck git ca-certificates
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run ShellCheck
|
- name: Run ShellCheck
|
||||||
run: shellcheck scripts/*.sh
|
run: shellcheck scripts/*.sh
|
||||||
|
|
||||||
security-check:
|
|
||||||
name: Security patterns check
|
|
||||||
runs-on: docker
|
|
||||||
container:
|
|
||||||
image: docker.io/library/ubuntu:24.04
|
|
||||||
steps:
|
|
||||||
- name: Install grep + git
|
|
||||||
run: apt-get update && apt-get install -y --no-install-recommends git grep ca-certificates
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check for unsafe string interpolation in curl payloads
|
|
||||||
run: |
|
|
||||||
# Flag inline JSON in double quotes (allows shell interpolation).
|
|
||||||
# Safe patterns: curl -d '{}' (single quotes) or curl -d "$var" (pre-built payload).
|
|
||||||
if grep -rPn 'curl.*-d\s*"[{]' scripts/*.sh; then
|
|
||||||
echo ""
|
|
||||||
echo "ERROR: Found curl -d with inline JSON in double quotes."
|
|
||||||
echo "Use jq --arg to build JSON safely and pass via variable."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "No unsafe curl patterns found."
|
|
||||||
33
CHANGELOG.md
33
CHANGELOG.md
|
|
@ -2,39 +2,16 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [0.1.17] - 2026-02-16
|
|
||||||
|
|
||||||
### Security
|
|
||||||
|
|
||||||
- Fix shell injection vulnerability in SKILL.md curl search commands
|
|
||||||
- Replace direct URL interpolation with `curl -G --data-urlencode` for all user-supplied query parameters
|
|
||||||
- Add explicit instruction to never interpolate user input directly into URL strings
|
|
||||||
- Update all curl examples (search, episode, common patterns, auth) to use safe parameter encoding
|
|
||||||
|
|
||||||
## [0.1.16] - 2026-02-14
|
|
||||||
|
|
||||||
### Security
|
|
||||||
|
|
||||||
- Fix shell injection vulnerability in aria2 RPC JSON construction (add-torrent.sh)
|
|
||||||
- Add magnet URL format validation before passing to torrent clients
|
|
||||||
- Replace shell string interpolation with `jq --arg` for safe JSON construction
|
|
||||||
- Refactor detect-client.sh JSON output to use `jq` instead of heredoc interpolation
|
|
||||||
- Add CI security pattern check to prevent unsafe curl payload regression
|
|
||||||
|
|
||||||
## [0.1.13] - 2026-02-13
|
## [0.1.13] - 2026-02-13
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Search movies and TV shows across 30+ torrent sources
|
- Search movies and TV shows across 12+ torrent sources
|
||||||
- Filter by quality (480p–2160p), genre, year, rating, language, season/episode
|
- Filter by quality (480p-2160p), genre, year, rating, language, season/episode
|
||||||
- HDR and Dolby Vision filtering (hdr10, dolby_vision, hdr10plus, hlg)
|
- API key authentication with tiered rate limits
|
||||||
- Audio codec filtering (AAC, FLAC, Opus, Atmos)
|
- Quality scoring (0-100) based on resolution, codec, seeders, source trust
|
||||||
- API key authentication with tiered rate limits (anonymous, free, pro)
|
|
||||||
- Quality scoring (0–100) based on resolution, codec, seeders, source trust
|
|
||||||
- Multi-language support (11 languages with accent-insensitive search)
|
- Multi-language support (11 languages with accent-insensitive search)
|
||||||
- TMDB metadata enrichment: posters, backdrops, genres, cast, director credits
|
|
||||||
- Detect installed torrent clients (Transmission, aria2)
|
- Detect installed torrent clients (Transmission, aria2)
|
||||||
- Add magnet links directly to torrent clients
|
- Add magnet links directly to torrent clients
|
||||||
- Download .torrent files or copy magnet links
|
- Download .torrent files or copy magnet links
|
||||||
- OS-specific installation guides for torrent clients (Linux, macOS, Windows/WSL)
|
- OS-specific installation guides for torrent clients
|
||||||
- MCP server alternative for Claude Desktop, Cursor, and Windsurf
|
|
||||||
|
|
|
||||||
23
README.md
23
README.md
|
|
@ -1,27 +1,26 @@
|
||||||
# torrentclaw-skill
|
# torrentclaw-skill
|
||||||
|
|
||||||
**Version:** 0.1.16
|
**Version:** 0.1.13
|
||||||
**License:** MIT
|
**License:** MIT
|
||||||
**Homepage:** https://torrentclaw.com
|
**Homepage:** https://torrentclaw.com
|
||||||
|
|
||||||
Search and download movies and TV shows from 30+ torrent sources directly from your AI agent. TorrentClaw aggregates torrents from YTS, EZTV, Knaben, Prowlarr, Bitmagnet, Torrentio, DonTorrent, Torrents.csv and more — enriched with TMDB metadata, quality scoring, and multi-language support.
|
Agent Skill for searching and downloading torrents via [TorrentClaw](https://torrentclaw.com).
|
||||||
|
|
||||||
Compatible with **Claude Code**, **OpenClaw**, **Codex CLI**, **Cline**, **Roo Code**, and any tool supporting the [Agent Skills](https://agentskills.io) specification.
|
Compatible with Claude Code, OpenClaw, Codex CLI, Cline, Roo Code, and any tool supporting the [Agent Skills](https://agentskills.io) specification.
|
||||||
|
|
||||||
**Alternative:** For Claude Desktop, Cursor, or Windsurf, use the [MCP Server](https://torrentclaw.com/mcp) instead (`npx @torrentclaw/mcp`).
|
**Alternative:** For Claude Desktop, Cursor, or Windsurf, use the [MCP Server](https://torrentclaw.com/mcp) instead (`npx @torrentclaw/mcp`).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Search movies and TV shows across 30+ torrent sources (YTS, EZTV, Knaben, Prowlarr, Bitmagnet, Torrentio, DonTorrent, Torrents.csv, and more)
|
- Search movies and TV shows across 12+ torrent sources (YTS, EZTV, Knaben, Prowlarr, Bitmagnet, Torrentio, DonTorrent, Torrents.csv, and more)
|
||||||
- Filter by quality (480p–2160p), genre, year, rating, language, audio codec, HDR format, season/episode
|
- Filter by quality (480p-2160p), genre, year, rating, language, season/episode (S01E05, 1x05)
|
||||||
- HDR and Dolby Vision filtering (hdr10, dolby_vision) and audio codec filtering (AAC, FLAC, Opus, Atmos)
|
- API key authentication for higher rate limits (120 req/min free, 1K req/min pro)
|
||||||
- Quality scoring (0–100) based on resolution, codec, seeders, source trust
|
- Quality scoring (0-100) based on resolution, codec, seeders, source trust
|
||||||
- Multi-language support (11 languages with accent-insensitive search)
|
- Multi-language support (11 languages with accent-insensitive search)
|
||||||
- TMDB metadata enrichment: posters, backdrops, genres, cast, director credits
|
- Detect installed torrent clients (Transmission, aria2)
|
||||||
- Detect installed torrent clients (Transmission, aria2) and add magnets directly
|
- Add magnet links directly to your torrent client
|
||||||
- Download .torrent files or copy magnet links
|
- Download .torrent files or copy magnet links
|
||||||
- OS-specific installation guides for torrent clients (Linux, macOS, Windows/WSL)
|
- OS-specific installation guides for torrent clients
|
||||||
- API key authentication for higher rate limits (anonymous 30/min, free 120/min, pro 1K/min)
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
@ -65,7 +64,7 @@ Or just ask naturally:
|
||||||
|
|
||||||
The skill will:
|
The skill will:
|
||||||
1. Detect your torrent client (Transmission, aria2)
|
1. Detect your torrent client (Transmission, aria2)
|
||||||
2. Search TorrentClaw across 30+ sources
|
2. Search TorrentClaw across 12+ sources
|
||||||
3. Present results ranked by quality score (0-100)
|
3. Present results ranked by quality score (0-100)
|
||||||
4. Add best torrent to your client or provide magnet link
|
4. Add best torrent to your client or provide magnet link
|
||||||
5. Show install guide if no client detected
|
5. Show install guide if no client detected
|
||||||
|
|
|
||||||
120
SKILL.md
120
SKILL.md
|
|
@ -2,7 +2,7 @@
|
||||||
name: torrentclaw
|
name: torrentclaw
|
||||||
description: Search and download torrents via TorrentClaw. Use when the user asks to find, search, or download movies, TV shows, or torrents. Detects local torrent clients (Transmission, aria2) and adds magnets directly, or offers magnet link copy and .torrent file download. Supports filtering by type (movie/show), genre, year, quality (480p-2160p), rating, language, and season/episode (S01E05, 1x05). Features API key authentication with tiered rate limits, AI-verified matching, and quality scoring (0-100). Returns titles with posters, ratings, and torrents with magnet links and quality scores.
|
description: Search and download torrents via TorrentClaw. Use when the user asks to find, search, or download movies, TV shows, or torrents. Detects local torrent clients (Transmission, aria2) and adds magnets directly, or offers magnet link copy and .torrent file download. Supports filtering by type (movie/show), genre, year, quality (480p-2160p), rating, language, and season/episode (S01E05, 1x05). Features API key authentication with tiered rate limits, AI-verified matching, and quality scoring (0-100). Returns titles with posters, ratings, and torrents with magnet links and quality scores.
|
||||||
license: MIT
|
license: MIT
|
||||||
metadata: {"version": "0.1.17", "repository": "https://github.com/torrentclaw/torrentclaw-skill", "homepage": "https://torrentclaw.com", "openclaw": {"emoji": "🎬", "os": ["darwin", "linux", "win32"], "requires": {"bins": ["curl", "bash", "jq"], "env": ["TORRENTCLAW_API_KEY"]}, "primaryEnv": "TORRENTCLAW_API_KEY"}, "tags": ["torrent", "movies", "tv-shows", "download", "media", "entertainment", "magnet", "transmission", "aria2", "search", "4k", "hdr"]}
|
metadata: {"version": "0.1.13", "repository": "https://github.com/torrentclaw/torrentclaw-skill", "homepage": "https://torrentclaw.com", "openclaw": {"emoji": "🎬", "os": ["darwin", "linux", "win32"]}}
|
||||||
---
|
---
|
||||||
|
|
||||||
# TorrentClaw
|
# TorrentClaw
|
||||||
|
|
@ -31,24 +31,10 @@ The script outputs JSON with detected clients and OS info. Remember the result f
|
||||||
|
|
||||||
### Step 2: Search for content
|
### Step 2: Search for content
|
||||||
|
|
||||||
Query the TorrentClaw API. Always include the `x-search-source: skill` header for analytics. The API key is **optional** — anonymous usage allows 30 req/min, which is enough for casual searches. Only include the `Authorization` header if `$TORRENTCLAW_API_KEY` is set.
|
Query the TorrentClaw API. Always include the `x-search-source: skill` header for analytics:
|
||||||
|
|
||||||
**Important:** Always use `--data-urlencode` for user-supplied values to prevent shell injection. Never interpolate user input directly into the URL string.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s -G -H "x-search-source: skill" \
|
curl -s -H "x-search-source: skill" "https://torrentclaw.com/api/v1/search?q=QUERY&sort=seeders&limit=5"
|
||||||
--data-urlencode "q=QUERY" \
|
|
||||||
-d "sort=seeders" -d "limit=5" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
|
||||||
|
|
||||||
If the user has configured an API key for higher rate limits:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -s -G -H "x-search-source: skill" -H "Authorization: Bearer $TORRENTCLAW_API_KEY" \
|
|
||||||
--data-urlencode "q=QUERY" \
|
|
||||||
-d "sort=seeders" -d "limit=5" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Useful filters** (append as query params):
|
**Useful filters** (append as query params):
|
||||||
|
|
@ -58,8 +44,6 @@ curl -s -G -H "x-search-source: skill" -H "Authorization: Bearer $TORRENTCLAW_AP
|
||||||
- `year_min=2020&year_max=2025`
|
- `year_min=2020&year_max=2025`
|
||||||
- `min_rating=7`
|
- `min_rating=7`
|
||||||
- `lang=es` (ISO 639 language code)
|
- `lang=es` (ISO 639 language code)
|
||||||
- `audio=atmos` (also: aac, flac, opus)
|
|
||||||
- `hdr=dolby_vision` (also: hdr10, hdr10plus, hlg)
|
|
||||||
- `season=1` — Filter by TV show season
|
- `season=1` — Filter by TV show season
|
||||||
- `episode=5` — Filter by episode number
|
- `episode=5` — Filter by episode number
|
||||||
- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar)
|
- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar)
|
||||||
|
|
@ -117,13 +101,13 @@ Recommend **Transmission** for Linux/macOS (lightweight daemon, simple CLI) and
|
||||||
|
|
||||||
Main search endpoint. Required: `q` (query string).
|
Main search endpoint. Required: `q` (query string).
|
||||||
|
|
||||||
**Filters:** `type` (movie/show), `genre`, `year_min`, `year_max`, `min_rating` (0-10), `quality` (480p/720p/1080p/2160p), `lang` (ISO 639), `audio` (aac/flac/opus/atmos), `hdr` (hdr10/dolby_vision/hdr10plus/hlg).
|
**Filters:** `type` (movie/show), `genre`, `year_min`, `year_max`, `min_rating` (0-10), `quality` (480p/720p/1080p/2160p), `lang` (ISO 639), `availability` (all/available/unavailable).
|
||||||
|
|
||||||
**Sorting:** `sort` = relevance | seeders | year | rating | added
|
**Sorting:** `sort` = relevance | seeders | year | rating | added
|
||||||
|
|
||||||
**Pagination:** `page` (1-1000), `limit` (1-50, default 20)
|
**Pagination:** `page` (1-1000), `limit` (1-50, default 20)
|
||||||
|
|
||||||
**Response:** `{ total, page, pageSize, results: [{ id, imdbId, tmdbId, contentType, title, year, overview, posterUrl, backdropUrl, genres, ratingImdb, ratingTmdb, contentUrl, hasTorrents, maxSeeders, torrents: [{ infoHash, magnetUrl, torrentUrl, quality, codec, sourceType, sizeBytes, seeders, leechers, source, qualityScore, scrapedAt, uploadedAt, languages, audioCodec, hdrType, releaseGroup, isProper, isRepack, isRemastered, season, episode }] }] }`
|
**Response:** `{ total, page, pageSize, results: [{ id, imdbId, tmdbId, contentType, title, year, overview, posterUrl, genres, ratingImdb, ratingTmdb, hasTorrents, maxSeeders, torrents: [{ infoHash, magnetUrl, torrentUrl, quality, codec, sourceType, sizeBytes, seeders, leechers, source, qualityScore, scrapedAt, languages, audioCodec, hdrType }] }] }`
|
||||||
|
|
||||||
**New fields:**
|
**New fields:**
|
||||||
- `hasTorrents` (boolean) — Whether content has any associated torrents
|
- `hasTorrents` (boolean) — Whether content has any associated torrents
|
||||||
|
|
@ -136,11 +120,11 @@ Fast typeahead. Param: `q` (min 2 chars). Returns max 8 suggestions.
|
||||||
|
|
||||||
### Popular — `GET /api/v1/popular`
|
### Popular — `GET /api/v1/popular`
|
||||||
|
|
||||||
Trending content by seeders. Params: `limit` (1-24, default 12), `page`.
|
Trending content by seeders. Params: `limit` (1-24), `page`.
|
||||||
|
|
||||||
### Recent — `GET /api/v1/recent`
|
### Recent — `GET /api/v1/recent`
|
||||||
|
|
||||||
Recently added content. Params: `limit` (1-24, default 12), `page`.
|
Recently added content. Params: `limit` (1-24), `page`.
|
||||||
|
|
||||||
### Torrent File — `GET /api/v1/torrent/{infoHash}`
|
### Torrent File — `GET /api/v1/torrent/{infoHash}`
|
||||||
|
|
||||||
|
|
@ -150,34 +134,25 @@ Download .torrent file by 40-char hex info hash. Returns binary `application/x-b
|
||||||
|
|
||||||
Content/torrent counts and recent ingestion history. No params.
|
Content/torrent counts and recent ingestion history. No params.
|
||||||
|
|
||||||
### Credits — `GET /api/v1/content/{id}/credits`
|
### Content Details — `GET /api/v1/content/:id`
|
||||||
|
|
||||||
Director and top 10 cast members with character names.
|
Full metadata for a specific movie or show. Returns complete content object with all torrents, cast, crew, and metadata.
|
||||||
|
|
||||||
**Params:** `id` (path, required — content ID from search)
|
### Track — `GET /api/v1/track`
|
||||||
|
|
||||||
**Response:** `{ contentId, director: "name", cast: [{ name, character, profileUrl }] }`
|
Analytics tracking endpoint. Params: `contentId` (required), `type` (view/click/download).
|
||||||
|
|
||||||
**Usage:** Show cast info when the user asks "who's in this movie?" or wants details about a search result.
|
|
||||||
|
|
||||||
### Track — `POST /api/v1/track`
|
|
||||||
|
|
||||||
Record user interactions for popularity ranking. Call this after the user selects a torrent.
|
|
||||||
|
|
||||||
**Request body (JSON):**
|
|
||||||
```json
|
|
||||||
{"infoHash": "40-char hex", "action": "magnet|torrent_download|copy"}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response:** `{"ok": true}`
|
|
||||||
|
|
||||||
### Search Analytics — `GET /api/v1/search-analytics`
|
### Search Analytics — `GET /api/v1/search-analytics`
|
||||||
|
|
||||||
Search volume, top queries, and zero-result queries by period. **Requires API key with pro tier.**
|
Popular searches and trending queries. **Requires API key with pro tier.**
|
||||||
|
|
||||||
**Params:** `days` (1-90, default 7), `limit` (1-100, default 20)
|
### Cache Stats — `GET /api/v1/cache-stats`
|
||||||
|
|
||||||
**Response:** `{ period, summary, topQueries, zeroResultQueries, dailyVolume }`
|
Search cache metrics and performance stats. No params.
|
||||||
|
|
||||||
|
### Enrichment Stats — `GET /api/v1/enrichment-stats`
|
||||||
|
|
||||||
|
TMDB enrichment progress and coverage statistics. No params.
|
||||||
|
|
||||||
## Season & Episode Search
|
## Season & Episode Search
|
||||||
|
|
||||||
|
|
@ -193,22 +168,19 @@ TorrentClaw supports smart episode filtering with multiple formats:
|
||||||
|
|
||||||
1. **In query text** (automatic parsing):
|
1. **In query text** (automatic parsing):
|
||||||
```bash
|
```bash
|
||||||
curl -s -G --data-urlencode "q=breaking bad S05E14" \
|
curl "https://torrentclaw.com/api/v1/search?q=breaking+bad+S05E14"
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **With explicit parameters**:
|
2. **With explicit parameters**:
|
||||||
```bash
|
```bash
|
||||||
curl -s -G --data-urlencode "q=breaking bad" \
|
curl "https://torrentclaw.com/api/v1/search?q=breaking+bad&season=5&episode=14"
|
||||||
-d "season=5" -d "episode=14" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The API automatically detects episode patterns in queries and filters results accordingly.
|
The API automatically detects episode patterns in queries and filters results accordingly.
|
||||||
|
|
||||||
## API Authentication
|
## API Authentication
|
||||||
|
|
||||||
The API works without authentication (30 req/min anonymous tier). An API key is **only needed** if you require higher rate limits for heavy or automated usage.
|
TorrentClaw supports optional API key authentication for higher rate limits.
|
||||||
|
|
||||||
**Rate Limit Tiers:**
|
**Rate Limit Tiers:**
|
||||||
|
|
||||||
|
|
@ -221,12 +193,13 @@ The API works without authentication (30 req/min anonymous tier). An API key is
|
||||||
|
|
||||||
**Using an API key:**
|
**Using an API key:**
|
||||||
|
|
||||||
Always use the `$TORRENTCLAW_API_KEY` environment variable via the `Authorization` header. Avoid passing the key as a query parameter — query strings may be logged in server access logs and HTTP referrer headers.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s -G -H "Authorization: Bearer $TORRENTCLAW_API_KEY" \
|
# Via header (recommended)
|
||||||
--data-urlencode "q=dune" \
|
curl -H "Authorization: Bearer tc_live_xxxxx" \
|
||||||
"https://torrentclaw.com/api/v1/search"
|
"https://torrentclaw.com/api/v1/search?q=dune"
|
||||||
|
|
||||||
|
# Via query parameter
|
||||||
|
curl "https://torrentclaw.com/api/v1/search?q=dune&api_key=tc_live_xxxxx"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Rate limit headers in response:**
|
**Rate limit headers in response:**
|
||||||
|
|
@ -264,50 +237,23 @@ Use `lang=es` filter.
|
||||||
|
|
||||||
**Search for a specific TV episode:**
|
**Search for a specific TV episode:**
|
||||||
```bash
|
```bash
|
||||||
curl -s -G --data-urlencode "q=entrevias S01E05" \
|
curl "https://torrentclaw.com/api/v1/search?q=entrevias+S01E05&locale=es"
|
||||||
-d "locale=es" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Search with API key for higher rate limits:**
|
**Search with API key for higher rate limits:**
|
||||||
```bash
|
```bash
|
||||||
curl -s -G -H "Authorization: Bearer $TORRENTCLAW_API_KEY" \
|
curl -H "Authorization: Bearer tc_live_xxxxx" \
|
||||||
--data-urlencode "q=dune" \
|
"https://torrentclaw.com/api/v1/search?q=dune&quality=2160p"
|
||||||
-d "quality=2160p" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Find popular sci-fi movies:**
|
**Find popular sci-fi movies:**
|
||||||
```bash
|
```bash
|
||||||
curl -s -G --data-urlencode "genre=Science Fiction" \
|
curl "https://torrentclaw.com/api/v1/search?genre=science-fiction&type=movie&sort=seeders"
|
||||||
-d "type=movie" -d "sort=seeders" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Find Dolby Vision / HDR content:**
|
**Track content view for analytics:**
|
||||||
```bash
|
```bash
|
||||||
curl -s -G --data-urlencode "q=dune" \
|
curl "https://torrentclaw.com/api/v1/track?contentId=123&type=view"
|
||||||
-d "hdr=dolby_vision" -d "quality=2160p" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Find Atmos audio torrents:**
|
|
||||||
```bash
|
|
||||||
curl -s -G --data-urlencode "q=oppenheimer" \
|
|
||||||
-d "audio=atmos" \
|
|
||||||
"https://torrentclaw.com/api/v1/search"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Get cast info for a movie:**
|
|
||||||
```bash
|
|
||||||
curl "https://torrentclaw.com/api/v1/content/42/credits"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Track torrent selection (call after user picks a torrent):**
|
|
||||||
```bash
|
|
||||||
curl -X POST -H "Content-Type: application/json" \
|
|
||||||
-d '{"infoHash":"aaf1e71c...","action":"magnet"}' \
|
|
||||||
"https://torrentclaw.com/api/v1/track"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@
|
||||||
"audioCodec": "AAC",
|
"audioCodec": "AAC",
|
||||||
"hdrType": null,
|
"hdrType": null,
|
||||||
"releaseGroup": "YTS",
|
"releaseGroup": "YTS",
|
||||||
"isProper": false,
|
|
||||||
"isRepack": false,
|
|
||||||
"isRemastered": false,
|
|
||||||
"season": null,
|
"season": null,
|
||||||
"episode": null
|
"episode": null
|
||||||
}
|
}
|
||||||
|
|
@ -84,79 +81,24 @@ X-Api-Key-Id: tc_live_abc1
|
||||||
- **Pro**: 1,000 req/min, 10,000 req/day (with API key)
|
- **Pro**: 1,000 req/min, 10,000 req/day (with API key)
|
||||||
- **Internal**: Unlimited (with API key)
|
- **Internal**: Unlimited (with API key)
|
||||||
|
|
||||||
## Search Query Parameters
|
## New Query Parameters
|
||||||
|
|
||||||
**Season & Episode Filtering:**
|
**Season & Episode Filtering:**
|
||||||
- `season=1` — Filter by TV show season number
|
- `season=1` — Filter by TV show season number
|
||||||
- `episode=5` — Filter by episode number
|
- `episode=5` — Filter by episode number
|
||||||
- Note: Also supports parsing from query text (e.g., `q=breaking+bad+S01E05`)
|
- Note: Also supports parsing from query text (e.g., `q=breaking+bad+S01E05`)
|
||||||
|
|
||||||
**Audio & Video Quality:**
|
|
||||||
- `audio=atmos` — Filter by audio codec (aac, flac, opus, atmos)
|
|
||||||
- `hdr=dolby_vision` — Filter by HDR format (hdr10, dolby_vision, hdr10plus, hlg)
|
|
||||||
- `quality=2160p` — Filter by resolution (480p, 720p, 1080p, 2160p)
|
|
||||||
|
|
||||||
**Localization:**
|
**Localization:**
|
||||||
- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar)
|
- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar)
|
||||||
|
|
||||||
## Response Fields
|
## New Response Fields
|
||||||
|
|
||||||
**Content fields:**
|
**Content fields:**
|
||||||
- `hasTorrents` (boolean) — Whether content has associated torrents
|
- `hasTorrents` (boolean) — Whether content has associated torrents
|
||||||
- `maxSeeders` (number) — Highest seeder count across all torrents for this content
|
- `maxSeeders` (number) — Highest seeder count across all torrents for this content
|
||||||
- `backdropUrl` (string) — TMDB backdrop image URL
|
|
||||||
- `contentUrl` (string) — Relative URL for content detail page
|
|
||||||
|
|
||||||
**Torrent fields:**
|
**Torrent fields:**
|
||||||
- `scrapedAt` (string, ISO 8601) — Timestamp of last tracker scrape for real-time seeder/leecher counts
|
- `scrapedAt` (string, ISO 8601) — Timestamp of last tracker scrape for real-time seeder/leecher counts
|
||||||
- `uploadedAt` (string, ISO 8601) — When the torrent was first uploaded
|
|
||||||
- `releaseGroup` (string) — Release group name (e.g., "YTS", "RARBG")
|
|
||||||
- `isProper` (boolean) — Whether this is a PROPER release (fix for previous release issues)
|
|
||||||
- `isRepack` (boolean) — Whether this is a REPACK (re-packaged due to issues)
|
|
||||||
- `isRemastered` (boolean) — Whether this is a remastered release
|
|
||||||
|
|
||||||
## Credits Response Schema
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"contentId": 1,
|
|
||||||
"director": "Christopher Nolan",
|
|
||||||
"cast": [
|
|
||||||
{
|
|
||||||
"name": "Leonardo DiCaprio",
|
|
||||||
"character": "Cobb",
|
|
||||||
"profileUrl": "https://image.tmdb.org/t/p/w185/..."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Returns `contentId`, director name, and up to 10 cast members. Param: `id` (path, required)
|
|
||||||
|
|
||||||
## Track Request Schema
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"infoHash": "aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
|
||||||
"action": "magnet"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Method: **POST**. Actions: `magnet`, `torrent_download`, `copy`. Response: `{"ok": true}`
|
|
||||||
|
|
||||||
## Search Analytics Response Schema
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"period": { "days": 7, "since": "2026-02-06T00:00:00Z" },
|
|
||||||
"summary": { "totalSearches": 15420, "uniqueQueries": 8730, "avgResults": 12.3, "zeroResultSearches": 120, "webSearches": 10000, "apiSearches": 5420 },
|
|
||||||
"topQueries": [{ "query": "dune", "count": 342, "avgResults": 15.2 }],
|
|
||||||
"zeroResultQueries": [{ "query": "obscure title", "count": 5 }],
|
|
||||||
"dailyVolume": [{ "date": "2026-02-13", "total": 2200, "web": 1500, "api": 700 }]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Params: `days` (1-90, default 7), `limit` (1-100, default 20). **Requires pro tier API key.**
|
|
||||||
|
|
||||||
## Error Responses
|
## Error Responses
|
||||||
|
|
||||||
|
|
@ -173,13 +115,8 @@ Params: `days` (1-90, default 7), `limit` (1-100, default 20). **Requires pro ti
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
| /api/v1/search | 30/min |
|
| /api/v1/search | 30/min |
|
||||||
| /api/v1/autocomplete | 60/min |
|
| /api/v1/autocomplete | 60/min |
|
||||||
| /api/v1/popular | 30/min |
|
|
||||||
| /api/v1/recent | 30/min |
|
|
||||||
| /api/v1/content/{id}/credits | 30/min |
|
|
||||||
| /api/v1/stats | 10/min |
|
| /api/v1/stats | 10/min |
|
||||||
| /api/v1/torrent | 20/min |
|
| /api/v1/torrent | 20/min |
|
||||||
| /api/v1/track | 60/min |
|
|
||||||
| /api/v1/search-analytics | 10/min |
|
|
||||||
|
|
||||||
## Torrent Download Integration
|
## Torrent Download Integration
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,6 @@ if [ -z "$magnet_url" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Validate magnet URL format ---
|
|
||||||
if [[ ! "$magnet_url" =~ ^magnet:\?xt=urn:btih:[a-fA-F0-9]{40} ]] && \
|
|
||||||
[[ ! "$magnet_url" =~ ^magnet:\?xt=urn:btih:[a-zA-Z2-7]{32} ]]; then
|
|
||||||
echo "Error: Invalid magnet URL format. Expected: magnet:?xt=urn:btih:<hash>" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Auto-detect client if not specified ---
|
# --- Auto-detect client if not specified ---
|
||||||
if [ -z "$client" ]; then
|
if [ -z "$client" ]; then
|
||||||
if command -v transmission-remote >/dev/null 2>&1; then
|
if command -v transmission-remote >/dev/null 2>&1; then
|
||||||
|
|
@ -83,14 +76,11 @@ case "$client" in
|
||||||
# Check if aria2 RPC is running
|
# Check if aria2 RPC is running
|
||||||
if curl -sf http://localhost:6800/jsonrpc -d '{"jsonrpc":"2.0","id":"test","method":"aria2.getVersion"}' >/dev/null 2>&1; then
|
if curl -sf http://localhost:6800/jsonrpc -d '{"jsonrpc":"2.0","id":"test","method":"aria2.getVersion"}' >/dev/null 2>&1; then
|
||||||
echo "Adding to aria2 via RPC..."
|
echo "Adding to aria2 via RPC..."
|
||||||
|
dir_param=""
|
||||||
if [ -n "$download_dir" ]; then
|
if [ -n "$download_dir" ]; then
|
||||||
payload=$(jq -n --arg url "$magnet_url" --arg dir "$download_dir" \
|
dir_param=",{\"dir\":\"$download_dir\"}"
|
||||||
'{"jsonrpc":"2.0","id":"add","method":"aria2.addUri","params":[[$url],{"dir":$dir}]}')
|
|
||||||
else
|
|
||||||
payload=$(jq -n --arg url "$magnet_url" \
|
|
||||||
'{"jsonrpc":"2.0","id":"add","method":"aria2.addUri","params":[[$url]]}')
|
|
||||||
fi
|
fi
|
||||||
result=$(curl -sf http://localhost:6800/jsonrpc -d "$payload")
|
result=$(curl -sf http://localhost:6800/jsonrpc -d "{\"jsonrpc\":\"2.0\",\"id\":\"add\",\"method\":\"aria2.addUri\",\"params\":[[\"$magnet_url\"]$dir_param]}")
|
||||||
if echo "$result" | grep -q '"result"'; then
|
if echo "$result" | grep -q '"result"'; then
|
||||||
echo "Torrent added to aria2 successfully."
|
echo "Torrent added to aria2 successfully."
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -27,30 +27,14 @@ esac
|
||||||
# --- Client Detection ---
|
# --- Client Detection ---
|
||||||
|
|
||||||
# Transmission
|
# Transmission
|
||||||
transmission_remote_path=$(command -v transmission-remote 2>/dev/null || true)
|
transmission_path=$(command -v transmission-remote 2>/dev/null || true)
|
||||||
transmission_gtk_path=$(command -v transmission-gtk 2>/dev/null || true)
|
|
||||||
transmission_qt_path=$(command -v transmission-qt 2>/dev/null || true)
|
|
||||||
transmission_daemon_path=$(command -v transmission-daemon 2>/dev/null || true)
|
|
||||||
transmission_path="${transmission_remote_path:-${transmission_gtk_path:-${transmission_qt_path:-${transmission_daemon_path:-}}}}"
|
|
||||||
transmission_installed="false"
|
transmission_installed="false"
|
||||||
transmission_daemon="false"
|
transmission_daemon="false"
|
||||||
transmission_remote_available="false"
|
|
||||||
transmission_variant="none"
|
|
||||||
if [ -n "$transmission_path" ]; then
|
if [ -n "$transmission_path" ]; then
|
||||||
transmission_installed="true"
|
transmission_installed="true"
|
||||||
if [ -n "$transmission_remote_path" ]; then
|
|
||||||
transmission_remote_available="true"
|
|
||||||
transmission_variant="cli"
|
|
||||||
if transmission-remote -l >/dev/null 2>&1; then
|
if transmission-remote -l >/dev/null 2>&1; then
|
||||||
transmission_daemon="true"
|
transmission_daemon="true"
|
||||||
fi
|
fi
|
||||||
elif [ -n "$transmission_gtk_path" ]; then
|
|
||||||
transmission_variant="gtk"
|
|
||||||
elif [ -n "$transmission_qt_path" ]; then
|
|
||||||
transmission_variant="qt"
|
|
||||||
elif [ -n "$transmission_daemon_path" ]; then
|
|
||||||
transmission_variant="daemon"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# aria2
|
# aria2
|
||||||
|
|
@ -73,34 +57,22 @@ elif [ "$aria2_installed" = "true" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- JSON Output ---
|
# --- JSON Output ---
|
||||||
jq -n \
|
cat <<EOF
|
||||||
--arg os "$os_name" \
|
{
|
||||||
--arg distro "$distro" \
|
"os": "$os_name",
|
||||||
--argjson t_installed "$transmission_installed" \
|
"distro": "$distro",
|
||||||
--arg t_path "${transmission_path:-}" \
|
"clients": {
|
||||||
--arg t_variant "$transmission_variant" \
|
"transmission": {
|
||||||
--argjson t_remote "$transmission_remote_available" \
|
"installed": $transmission_installed,
|
||||||
--argjson t_daemon "$transmission_daemon" \
|
"path": $([ -n "$transmission_path" ] && echo "\"$transmission_path\"" || echo "null"),
|
||||||
--argjson a_installed "$aria2_installed" \
|
"daemonRunning": $transmission_daemon
|
||||||
--arg a_path "${aria2_path:-}" \
|
|
||||||
--argjson a_daemon "$aria2_daemon" \
|
|
||||||
--arg preferred "$preferred" \
|
|
||||||
'{
|
|
||||||
os: $os,
|
|
||||||
distro: $distro,
|
|
||||||
clients: {
|
|
||||||
transmission: {
|
|
||||||
installed: $t_installed,
|
|
||||||
path: (if $t_path == "" then null else $t_path end),
|
|
||||||
variant: $t_variant,
|
|
||||||
remoteAvailable: $t_remote,
|
|
||||||
daemonRunning: $t_daemon
|
|
||||||
},
|
},
|
||||||
aria2: {
|
"aria2": {
|
||||||
installed: $a_installed,
|
"installed": $aria2_installed,
|
||||||
path: (if $a_path == "" then null else $a_path end),
|
"path": $([ -n "$aria2_path" ] && echo "\"$aria2_path\"" || echo "null"),
|
||||||
daemonRunning: $a_daemon
|
"daemonRunning": $aria2_daemon
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preferred: $preferred
|
"preferred": "$preferred"
|
||||||
}'
|
}
|
||||||
|
EOF
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue