From 98c550feb0509d910c3ddc73d67c4344f688d441 Mon Sep 17 00:00:00 2001 From: Deivid Soto Date: Fri, 13 Feb 2026 18:40:25 +0100 Subject: [PATCH] feat: initial open-source project structure Agent Skill for searching and downloading torrents via TorrentClaw. Includes SKILL.md with OpenClaw metadata, bash scripts for torrent client detection, CONTRIBUTING.md, CHANGELOG.md, CI/CD with GitHub Actions (shellcheck + conventional commits), lefthook git hooks, Makefile, and .editorconfig. --- .editorconfig | 19 +++ .github/workflows/ci.yml | 53 +++++++ .gitignore | 23 +++ .lefthookrc | 1 + CHANGELOG.md | 17 +++ CONTRIBUTING.md | 65 ++++++++ Makefile | 23 +++ README.md | 106 +++++++++++++ SKILL.md | 290 ++++++++++++++++++++++++++++++++++++ lefthook.yml | 29 ++++ references/api-reference.md | 165 ++++++++++++++++++++ scripts/add-torrent.sh | 105 +++++++++++++ scripts/detect-client.sh | 78 ++++++++++ scripts/install-guide.sh | 122 +++++++++++++++ 14 files changed, 1096 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .lefthookrc create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 SKILL.md create mode 100644 lefthook.yml create mode 100644 references/api-reference.md create mode 100755 scripts/add-torrent.sh create mode 100755 scripts/detect-client.sh create mode 100755 scripts/install-guide.sh diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..bedeff6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.sh] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0c4e9e1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + +permissions: + contents: read + +jobs: + lint-commits: + name: Lint commits + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate conventional commits + run: | + base="${{ github.event.pull_request.base.sha }}" + head="${{ github.event.pull_request.head.sha }}" + pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,}$' + + failed=0 + while IFS= read -r msg; do + first_line=$(echo "$msg" | head -1) + if ! echo "$first_line" | grep -qE "$pattern"; then + echo "FAIL: $first_line" + failed=1 + fi + done < <(git log --format="%s" "$base".."$head") + + if [ "$failed" -eq 1 ]; then + echo "" + echo "Some commits do not follow Conventional Commits format." + echo "Expected: [scope][!]: " + echo "See: https://www.conventionalcommits.org/" + exit 1 + fi + echo "All commits follow Conventional Commits format." + + lint-scripts: + name: Lint shell scripts + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run ShellCheck + run: shellcheck scripts/*.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..150b715 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +desktop.ini + +# Temp +/tmp/ +*.tmp + +# Lefthook +lefthook-local.yml +.lefthookrc.local + +# Environment +.env +.env.local diff --git a/.lefthookrc b/.lefthookrc new file mode 100644 index 0000000..93aecfc --- /dev/null +++ b/.lefthookrc @@ -0,0 +1 @@ +command -v shellcheck >/dev/null 2>&1 || export PATH="/usr/local/bin:$HOME/.local/bin:$PATH" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d9ff5b7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.1.13] - 2026-02-13 + +### Features + +- Search movies and TV shows across 12+ torrent sources +- Filter by quality (480p-2160p), genre, year, rating, language, season/episode +- API key authentication with tiered rate limits +- Quality scoring (0-100) based on resolution, codec, seeders, source trust +- Multi-language support (11 languages with accent-insensitive search) +- Detect installed torrent clients (Transmission, aria2) +- Add magnet links directly to torrent clients +- Download .torrent files or copy magnet links +- OS-specific installation guides for torrent clients diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..42ed669 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,65 @@ +# Contributing to torrentclaw-skill + +Thanks for your interest in contributing! Here's how you can help. + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com//torrentclaw-skill.git` +3. Install dev tools and git hooks: + ```bash + make install-tools + make hooks + ``` +4. Create a branch: `git checkout -b feat/my-feature` +5. Make your changes +6. Lint locally: `make lint` +7. Commit with a clear message (see below) — the commit-msg hook will validate the format +8. Push and open a Pull Request + +## Requirements + +- Bash 4+ +- [shellcheck](https://github.com/koalaman/shellcheck) (installed via your package manager) +- [lefthook](https://github.com/evilmartians/lefthook) (installed via your package manager) + +## Commit Messages + +Commits are validated automatically by a git hook. We follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +[optional scope][!]: +``` + +Valid types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` + +Examples: + +``` +feat: add qBittorrent client detection +fix(detect): correct aria2 daemon check on macOS +docs: update API reference with new endpoints +chore: update shellcheck to latest version +feat!: redesign install guide output format +``` + +## Code Style + +- All shell scripts must pass `shellcheck` +- Use `#!/usr/bin/env bash` as the shebang +- Use `set -euo pipefail` at the top of every script +- Keep functions focused and small +- Add comments only where the logic isn't self-evident + +## Reporting Bugs + +Open an issue with: + +- What you expected to happen +- What actually happened +- Steps to reproduce +- Your OS and bash version + +## License + +By contributing, you agree that your contributions will be licensed under the project's [MIT License](LICENSE). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..54dfc7e --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +.PHONY: lint shellcheck version install-tools hooks + +# Lint shell scripts +shellcheck: + shellcheck scripts/*.sh + +# Lint everything +lint: shellcheck + +# Version management +version: + @grep '^metadata:' SKILL.md | grep -oP '"version":\s*"\K[^"]+' + +# Developer setup +install-tools: + @echo "Checking lefthook..." + @command -v lefthook >/dev/null 2>&1 || (echo "Install lefthook: https://github.com/evilmartians/lefthook#install" && exit 1) + @echo "Checking shellcheck..." + @command -v shellcheck >/dev/null 2>&1 || (echo "Install shellcheck: https://github.com/koalaman/shellcheck#installing" && exit 1) + @echo "All tools installed." + +hooks: + lefthook install diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec8845a --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# torrentclaw-skill + +**Version:** 0.1.13 +**License:** MIT +**Homepage:** https://torrentclaw.com + +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. + +**Alternative:** For Claude Desktop, Cursor, or Windsurf, use the [MCP Server](https://torrentclaw.com/mcp) instead (`npx @torrentclaw/mcp`). + +## Features + +- 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, season/episode (S01E05, 1x05) +- 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 +- Multi-language support (11 languages with accent-insensitive search) +- Detect installed torrent clients (Transmission, aria2) +- Add magnet links directly to your torrent client +- Download .torrent files or copy magnet links +- OS-specific installation guides for torrent clients + +## Install + +### Claude Code + +```bash +# Personal (all projects) +ln -s /path/to/torrentclaw-skill ~/.claude/skills/torrentclaw + +# Or project-specific +ln -s /path/to/torrentclaw-skill .claude/skills/torrentclaw +``` + +### OpenClaw + +```bash +claw skill install torrentclaw +# or from local +ln -s /path/to/torrentclaw-skill ~/.openclaw/skills/torrentclaw +``` + +### ClawHub + +```bash +clawhub install torrentclaw +``` + +## Usage + +``` +/torrentclaw "Inception 1080p" +/torrentclaw "Breaking Bad S05E14" +/torrentclaw "best 4K movies 2024" +``` + +Or just ask naturally: + +> "Find me Inception in the best quality" +> "I need Breaking Bad season 5 episode 14" +> "Search for sci-fi movies from 2023 in 4K" + +The skill will: +1. Detect your torrent client (Transmission, aria2) +2. Search TorrentClaw across 12+ sources +3. Present results ranked by quality score (0-100) +4. Add best torrent to your client or provide magnet link +5. Show install guide if no client detected + +## Scripts + +| Script | Purpose | +|--------|---------| +| `scripts/detect-client.sh` | Detect Transmission/aria2 and output JSON | +| `scripts/add-torrent.sh` | Add magnet to detected client | +| `scripts/install-guide.sh` | Show OS-specific install instructions | + +## API + +Public API at `https://torrentclaw.com/api/v1/`. + +**Authentication:** Optional. Anonymous usage allows 30 req/min. API keys provide higher limits: +- **Free tier**: 120 req/min, 1,000 req/day +- **Pro tier**: 1,000 req/min, 10,000 req/day + +See [references/api-reference.md](references/api-reference.md) for full documentation and [SKILL.md](SKILL.md) for workflow examples. + +## Links + +- **Website**: https://torrentclaw.com +- **Skill Documentation**: https://torrentclaw.com/skill +- **MCP Server**: https://torrentclaw.com/mcp +- **API Reference**: https://torrentclaw.com/api/docs +- **OpenAPI Spec**: https://torrentclaw.com/api/openapi.json +- **Changelog**: [CHANGELOG.md](CHANGELOG.md) +- **GitHub**: https://github.com/torrentclaw/torrentclaw-skill + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. + +## License + +MIT — See [LICENSE](LICENSE) for details. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..e105cdf --- /dev/null +++ b/SKILL.md @@ -0,0 +1,290 @@ +--- +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. +license: MIT +metadata: {"version": "0.1.13", "repository": "https://github.com/torrentclaw/torrentclaw-skill", "homepage": "https://torrentclaw.com", "openclaw": {"emoji": "🎬", "os": ["darwin", "linux", "win32"]}} +--- + +# TorrentClaw + +Search movies and TV shows across multiple torrent sources with TMDB metadata enrichment. Detect local torrent clients and start downloads automatically. + +## Base URL + +``` +https://torrentclaw.com +``` + +## Workflow + +Follow these steps when the user asks to find or download a torrent: + +### Step 1: Detect torrent clients + +Run the detection script to check what's available on the user's system: + +```bash +bash "$(dirname "$0")/scripts/detect-client.sh" +``` + +The script outputs JSON with detected clients and OS info. Remember the result for Step 4. + +### Step 2: Search for content + +Query the TorrentClaw API. Always include the `x-search-source: skill` header for analytics: + +```bash +curl -s -H "x-search-source: skill" "https://torrentclaw.com/api/v1/search?q=QUERY&sort=seeders&limit=5" +``` + +**Useful filters** (append as query params): +- `type=movie` or `type=show` +- `quality=1080p` (also: 720p, 2160p, 480p) +- `genre=Action` (see references/api-reference.md for full list) +- `year_min=2020&year_max=2025` +- `min_rating=7` +- `lang=es` (ISO 639 language code) +- `season=1` — Filter by TV show season +- `episode=5` — Filter by episode number +- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar) +- `sort=seeders` (also: relevance, year, rating, added) + +### Step 3: Present results + +Display results in a clear table format. For each content item show: +- Title, year, content type +- IMDb rating (or TMDB rating as fallback) +- For each torrent: quality, codec, size (human-readable), seeders + +Example format: +``` +1. Inception (2010) - Movie - IMDb: 8.8 + a) 1080p BluRay x265 - 2.1 GB - 847 seeders + b) 2160p WEB-DL x265 HDR - 8.3 GB - 234 seeders + c) 720p BluRay x264 - 1.0 GB - 156 seeders +``` + +Ask the user which torrent they want. + +### Step 4: Handle download + +Based on the detection from Step 1: + +**If a torrent client was detected:** +Offer to add the magnet link directly: + +```bash +bash "$(dirname "$0")/scripts/add-torrent.sh" "MAGNET_URL" +``` + +Or with a specific client and download directory: + +```bash +bash "$(dirname "$0")/scripts/add-torrent.sh" "MAGNET_URL" --client transmission --download-dir ~/Downloads +``` + +**If NO torrent client was detected:** +Offer these options: +1. **Copy magnet link** — Give the user the full `magnetUrl` from the API response to copy +2. **Download .torrent file** — `curl -o "filename.torrent" "https://torrentclaw.com/api/v1/torrent/INFO_HASH"` +3. **Install a client** — Run the install guide script: + +```bash +bash "$(dirname "$0")/scripts/install-guide.sh" transmission +``` + +Recommend **Transmission** for Linux/macOS (lightweight daemon, simple CLI) and **aria2** as alternative (multi-protocol, no daemon needed). + +## Endpoints + +### Search — `GET /api/v1/search` + +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), `availability` (all/available/unavailable). + +**Sorting:** `sort` = relevance | seeders | year | rating | added + +**Pagination:** `page` (1-1000), `limit` (1-50, default 20) + +**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:** +- `hasTorrents` (boolean) — Whether content has any associated torrents +- `maxSeeders` (number) — Highest seeder count across all torrents for this content +- `scrapedAt` (string) — ISO timestamp of last tracker scrape for real-time seeder/leecher counts + +### Autocomplete — `GET /api/v1/autocomplete` + +Fast typeahead. Param: `q` (min 2 chars). Returns max 8 suggestions. + +### Popular — `GET /api/v1/popular` + +Trending content by seeders. Params: `limit` (1-24), `page`. + +### Recent — `GET /api/v1/recent` + +Recently added content. Params: `limit` (1-24), `page`. + +### Torrent File — `GET /api/v1/torrent/{infoHash}` + +Download .torrent file by 40-char hex info hash. Returns binary `application/x-bittorrent`. + +### Stats — `GET /api/v1/stats` + +Content/torrent counts and recent ingestion history. No params. + +### Content Details — `GET /api/v1/content/:id` + +Full metadata for a specific movie or show. Returns complete content object with all torrents, cast, crew, and metadata. + +### Track — `GET /api/v1/track` + +Analytics tracking endpoint. Params: `contentId` (required), `type` (view/click/download). + +### Search Analytics — `GET /api/v1/search-analytics` + +Popular searches and trending queries. **Requires API key with pro tier.** + +### Cache Stats — `GET /api/v1/cache-stats` + +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 + +TorrentClaw supports smart episode filtering with multiple formats: + +**Supported formats:** +- `S01E05` (standard format) +- `1x05` (alternative format) +- `1x05-1x08` (episode ranges) +- `Season 1 Episode 5` (natural language) + +**Usage:** + +1. **In query text** (automatic parsing): +```bash +curl "https://torrentclaw.com/api/v1/search?q=breaking+bad+S05E14" +``` + +2. **With explicit parameters**: +```bash +curl "https://torrentclaw.com/api/v1/search?q=breaking+bad&season=5&episode=14" +``` + +The API automatically detects episode patterns in queries and filters results accordingly. + +## API Authentication + +TorrentClaw supports optional API key authentication for higher rate limits. + +**Rate Limit Tiers:** + +| Tier | Requests/min | Requests/day | Authentication | +|------|--------------|--------------|----------------| +| Anonymous | 30 | Unlimited | None | +| Free | 120 | 1,000 | API key required | +| Pro | 1,000 | 10,000 | API key required | +| Internal | Unlimited | Unlimited | API key required | + +**Using an API key:** + +```bash +# Via header (recommended) +curl -H "Authorization: Bearer tc_live_xxxxx" \ + "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:** +- `X-RateLimit-Tier` - Your current tier (anonymous/free/pro/internal) +- `X-RateLimit-Remaining` - Requests remaining in current window + +**Getting an API key:** +Contact via https://torrentclaw.com/contact or https://torrentclaw.com/api/v1/contact + +## MCP Server Integration + +For users of **Claude Desktop**, **Cursor**, or **Windsurf**, TorrentClaw is also available as an MCP (Model Context Protocol) server: + +```bash +npx @torrentclaw/mcp +``` + +**MCP vs Skill:** +- **Skill (this file)**: For OpenClaw, Claude Code, Cline, Roo Code — natural language interface +- **MCP Server**: For Claude Desktop, Cursor, Windsurf — structured tools interface +- **Both** use the same TorrentClaw API backend + +See https://torrentclaw.com/mcp for MCP installation and usage. + +## Common Patterns + +**Find best quality torrent for a movie:** +Search with `sort=seeders`, pick the torrent with highest `qualityScore`. + +**Find 4K content:** +Use `quality=2160p` filter. + +**Browse Spanish-language torrents:** +Use `lang=es` filter. + +**Search for a specific TV episode:** +```bash +curl "https://torrentclaw.com/api/v1/search?q=entrevias+S01E05&locale=es" +``` + +**Search with API key for higher rate limits:** +```bash +curl -H "Authorization: Bearer tc_live_xxxxx" \ + "https://torrentclaw.com/api/v1/search?q=dune&quality=2160p" +``` + +**Find popular sci-fi movies:** +```bash +curl "https://torrentclaw.com/api/v1/search?genre=science-fiction&type=movie&sort=seeders" +``` + +**Track content view for analytics:** +```bash +curl "https://torrentclaw.com/api/v1/track?contentId=123&type=view" +``` + +## Troubleshooting + +**Scripts not executable:** Run `chmod +x scripts/*.sh` in the skill directory. + +**Transmission not detected but installed:** Ensure `transmission-remote` is in PATH. On some systems the package is `transmission-cli`. + +**aria2 starts but exits immediately:** aria2c in direct mode downloads to current directory. Use `--download-dir` flag or `--daemon` mode. + +**No torrent client detected:** Run `bash scripts/install-guide.sh transmission` to see installation instructions for your OS (Linux, macOS, Windows/WSL). + +**API key not working:** +- Verify the key format: `tc_live_` followed by 32 hex characters +- Check the `Authorization: Bearer ` header is correct +- Ensure the key hasn't expired (contact support if needed) +- Check `X-RateLimit-Tier` header in responses to confirm tier + +**Rate limits:** +- Anonymous: 30 req/min (no auth) +- Free tier: 120 req/min, 1K/day (with API key) +- Pro tier: 1K req/min, 10K/day (with API key) +- If you get 429, wait a moment or use an API key for higher limits + +**Windows users:** Scripts require bash. Use WSL (Windows Subsystem for Linux) or Git Bash. + +## Links + +- **Website**: https://torrentclaw.com +- **GitHub**: https://github.com/torrentclaw/torrentclaw-skill +- **OpenAPI Spec**: https://torrentclaw.com/api/openapi.json +- **Swagger UI**: https://torrentclaw.com/api/docs +- **MCP Server**: https://torrentclaw.com/mcp +- **llms.txt**: https://torrentclaw.com/llms.txt diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..5b5e818 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,29 @@ +rc: ./.lefthookrc + +commit-msg: + commands: + validate: + run: | + msg=$(head -1 {1}) + if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,}$'; then + echo "" + echo "ERROR: Invalid commit message format." + echo "" + echo " Got: $msg" + echo "" + echo " Expected: [optional scope][!]: " + echo "" + echo " Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert" + echo " Examples:" + echo " feat: add qBittorrent client detection" + echo " fix(detect): correct aria2 daemon check" + echo " docs: update API reference" + echo "" + exit 1 + fi + +pre-commit: + commands: + shellcheck: + glob: "*.sh" + run: shellcheck {staged_files} diff --git a/references/api-reference.md b/references/api-reference.md new file mode 100644 index 0000000..47dfcee --- /dev/null +++ b/references/api-reference.md @@ -0,0 +1,165 @@ +# TorrentClaw API Reference + +## Search Response Schema + +```json +{ + "total": 42, + "page": 1, + "pageSize": 20, + "results": [ + { + "id": 1, + "imdbId": "tt1375666", + "tmdbId": "27205", + "contentType": "movie", + "title": "Inception", + "titleOriginal": "Inception", + "year": 2010, + "overview": "A thief who steals corporate secrets...", + "posterUrl": "https://image.tmdb.org/t/p/w500/oYuLEt3zVCKq57qu2F8dT7NIa6f.jpg", + "genres": ["Action", "Science Fiction", "Adventure"], + "ratingImdb": "8.8", + "ratingTmdb": "8.4", + "contentUrl": "/movies/inception-2010-1", + "hasTorrents": true, + "maxSeeders": 847, + "torrents": [ + { + "infoHash": "aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e", + "magnetUrl": "magnet:?xt=urn:btih:aaf1e71c...&dn=Inception+2010+1080p&tr=udp://tracker.opentrackr.org:1337/announce&tr=...", + "torrentUrl": "/api/v1/torrent/aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e", + "quality": "1080p", + "codec": "x265", + "sourceType": "BluRay", + "sizeBytes": "2147483648", + "seeders": 847, + "leechers": 23, + "source": "yts", + "qualityScore": 85, + "scrapedAt": "2026-02-13T10:30:00Z", + "uploadedAt": "2024-03-15T12:00:00Z", + "languages": ["en"], + "audioCodec": "AAC", + "hdrType": null, + "releaseGroup": "YTS", + "season": null, + "episode": null + } + ] + } + ] +} +``` + +## Allowed Genres + +Action, Adventure, Animation, Comedy, Crime, Documentary, Drama, Family, Fantasy, History, Horror, Music, Mystery, Romance, Science Fiction, Thriller, War, Western, Reality, Talk, News, Soap, Kids, TV Movie, Action & Adventure, Sci-Fi & Fantasy, War & Politics + +## API Key Authentication + +**Request Headers:** +``` +Authorization: Bearer tc_live_xxxxx +``` + +Or via query parameter: +``` +?api_key=tc_live_xxxxx +``` + +**Response Headers:** +``` +X-RateLimit-Tier: free +X-RateLimit-Remaining: 115 +X-Api-Key-Id: tc_live_abc1 +``` + +**Rate Limit Tiers:** +- **Anonymous**: 30 req/min (no key) +- **Free**: 120 req/min, 1,000 req/day (with API key) +- **Pro**: 1,000 req/min, 10,000 req/day (with API key) +- **Internal**: Unlimited (with API key) + +## New Query Parameters + +**Season & Episode Filtering:** +- `season=1` — Filter by TV show season number +- `episode=5` — Filter by episode number +- Note: Also supports parsing from query text (e.g., `q=breaking+bad+S01E05`) + +**Localization:** +- `locale=es` — Get titles in Spanish (also: fr, de, pt, it, ja, ko, zh, ru, ar) + +## New Response Fields + +**Content fields:** +- `hasTorrents` (boolean) — Whether content has associated torrents +- `maxSeeders` (number) — Highest seeder count across all torrents for this content + +**Torrent fields:** +- `scrapedAt` (string, ISO 8601) — Timestamp of last tracker scrape for real-time seeder/leecher counts + +## Error Responses + +| Status | Meaning | +|--------|---------| +| 400 | Invalid parameters (missing q, bad genre, etc.) | +| 404 | Torrent file not found (torrent endpoint only) | +| 429 | Rate limited | +| 500 | Internal server error | + +## Rate Limits + +| Endpoint | Limit | +|----------|-------| +| /api/v1/search | 30/min | +| /api/v1/autocomplete | 60/min | +| /api/v1/stats | 10/min | +| /api/v1/torrent | 20/min | + +## Torrent Download Integration + +### Using magnetUrl with Transmission + +```bash +# Search and add best torrent to Transmission +RESULT=$(curl -s -H "x-search-source: skill" "https://torrentclaw.com/api/v1/search?q=inception&type=movie&sort=seeders&limit=1") +MAGNET=$(echo "$RESULT" | jq -r '.results[0].torrents[0].magnetUrl') +transmission-remote -a "$MAGNET" +``` + +### Using magnetUrl with aria2 + +```bash +RESULT=$(curl -s -H "x-search-source: skill" "https://torrentclaw.com/api/v1/search?q=inception&sort=seeders&limit=1") +MAGNET=$(echo "$RESULT" | jq -r '.results[0].torrents[0].magnetUrl') +aria2c "$MAGNET" --dir=~/Downloads +``` + +### Downloading .torrent files + +```bash +# Get info hash from search result +INFO_HASH=$(echo "$RESULT" | jq -r '.results[0].torrents[0].infoHash') + +# Download .torrent file +curl -o "movie.torrent" "https://torrentclaw.com/api/v1/torrent/$INFO_HASH" + +# The file includes a descriptive filename in Content-Disposition header: +# TorrentClaw.com-Inception-1080p-EN.torrent +``` + +## Data Sources + +| Source | Content | Notes | +|--------|---------|-------| +| YTS | Movies | High quality, IMDb IDs | +| EZTV | TV Shows | Episode torrents, IMDb IDs | +| Knaben | Mixed | Meta-search aggregator | +| Prowlarr | Mixed | Indexer aggregator | +| Bitmagnet | Mixed | DHT discovery | +| Torrentio | Mixed | Stremio ecosystem | +| DonTorrent | Mixed | Spanish content | +| Torrents.csv | Mixed | Open dataset | +| TMDB | Metadata | Posters, genres, translations | diff --git a/scripts/add-torrent.sh b/scripts/add-torrent.sh new file mode 100755 index 0000000..3d45764 --- /dev/null +++ b/scripts/add-torrent.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# Adds a magnet link to a detected torrent client. +# Usage: ./add-torrent.sh "" [--client transmission|aria2] [--download-dir /path] +# +# Exit codes: +# 0 - Success +# 1 - Invalid parameters +# 2 - No torrent client found +# 3 - Client error (failed to add) + +set -euo pipefail + +# --- Parse Arguments --- +magnet_url="" +client="" +download_dir="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --client) + client="$2" + shift 2 + ;; + --download-dir) + download_dir="$2" + shift 2 + ;; + -*) + echo "Error: Unknown option $1" >&2 + exit 1 + ;; + *) + if [ -z "$magnet_url" ]; then + magnet_url="$1" + fi + shift + ;; + esac +done + +if [ -z "$magnet_url" ]; then + echo "Error: Magnet URL is required" >&2 + echo "Usage: $0 \"\" [--client transmission|aria2] [--download-dir /path]" >&2 + exit 1 +fi + +# --- Auto-detect client if not specified --- +if [ -z "$client" ]; then + if command -v transmission-remote >/dev/null 2>&1; then + client="transmission" + elif command -v aria2c >/dev/null 2>&1; then + client="aria2" + else + echo "Error: No torrent client detected. Install transmission-cli or aria2." >&2 + exit 2 + fi +fi + +# --- Add torrent --- +case "$client" in + transmission) + args=(-a "$magnet_url") + if [ -n "$download_dir" ]; then + args+=(-w "$download_dir") + fi + echo "Adding to Transmission..." + if transmission-remote "${args[@]}"; then + echo "Torrent added to Transmission successfully." + else + echo "Error: Failed to add torrent to Transmission. Is the daemon running?" >&2 + echo "Start it with: transmission-daemon" >&2 + exit 3 + fi + ;; + aria2) + # 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 + echo "Adding to aria2 via RPC..." + dir_param="" + if [ -n "$download_dir" ]; then + dir_param=",{\"dir\":\"$download_dir\"}" + fi + 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 + echo "Torrent added to aria2 successfully." + else + echo "Error: aria2 RPC rejected the request." >&2 + exit 3 + fi + else + # Direct download mode + echo "Adding to aria2 (direct mode)..." + args=("$magnet_url") + if [ -n "$download_dir" ]; then + args+=(--dir="$download_dir") + fi + aria2c "${args[@]}" & + echo "aria2 download started in background (PID: $!)." + fi + ;; + *) + echo "Error: Unknown client '$client'. Supported: transmission, aria2" >&2 + exit 1 + ;; +esac diff --git a/scripts/detect-client.sh b/scripts/detect-client.sh new file mode 100755 index 0000000..4bbf664 --- /dev/null +++ b/scripts/detect-client.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Detects installed torrent clients and outputs JSON. +# Usage: ./detect-client.sh + +set -euo pipefail + +# --- OS Detection --- +os_name=$(uname -s) +distro="unknown" + +case "$os_name" in + Linux) + if [ -f /etc/os-release ]; then + # shellcheck source=/dev/null + distro=$(. /etc/os-release && echo "${ID:-unknown}") + fi + ;; + Darwin) + distro="macos" + ;; + MINGW*|MSYS*|CYGWIN*) + os_name="Windows" + distro="windows" + ;; +esac + +# --- Client Detection --- + +# Transmission +transmission_path=$(command -v transmission-remote 2>/dev/null || true) +transmission_installed="false" +transmission_daemon="false" +if [ -n "$transmission_path" ]; then + transmission_installed="true" + if transmission-remote -l >/dev/null 2>&1; then + transmission_daemon="true" + fi +fi + +# aria2 +aria2_path=$(command -v aria2c 2>/dev/null || true) +aria2_installed="false" +aria2_daemon="false" +if [ -n "$aria2_path" ]; then + aria2_installed="true" + if curl -sf http://localhost:6800/jsonrpc -d '{"jsonrpc":"2.0","id":"test","method":"aria2.getVersion"}' >/dev/null 2>&1; then + aria2_daemon="true" + fi +fi + +# --- Preferred Client --- +preferred="none" +if [ "$transmission_installed" = "true" ]; then + preferred="transmission" +elif [ "$aria2_installed" = "true" ]; then + preferred="aria2" +fi + +# --- JSON Output --- +cat <