Skip to content

feat: add torrin debrid service#1014

Open
rrevanth wants to merge 2 commits into
Viren070:mainfrom
rrevanth:feat/add-torrin-service
Open

feat: add torrin debrid service#1014
rrevanth wants to merge 2 commits into
Viren070:mainfrom
rrevanth:feat/add-torrin-service

Conversation

@rrevanth

@rrevanth rrevanth commented Jun 11, 2026

Copy link
Copy Markdown

Summary

Adds Torrin as a builtin debrid service. Torrin is an open-source debrid that takes a magnet link and returns signed HTTPS streaming URLs backed by an R2-cached library — POST /api/jobs { magnet } returns either a cached job (200) or a downloading job (202), and Job.stream_urls[].signed_url is the player URL.

This implementation is native (talks directly to api.torrin.app) and torrent-only for this PR — Torrin's usenet/hoster paths require BYOK credentials configured server-side at torrin.app/app/settings and are out of scope here.

Changes

File What
packages/core/src/debrid/torrin.ts New. TorrentDebridService impl: addMagnet, addTorrent (URL or base64 .torrent → magnet via parse-torrent), checkMagnets (batch via POST /api/availability, per-credential cache), getMagnet, listMagnets, removeMagnet, resolve with DistributedLock + playback-link cache + DebridFailureCache + poll-on-cacheAndPlay. Mirrors torbox.ts / stremthru.ts conventions.
packages/core/src/debrid/index.ts Dispatch 'torrin'TorrinDebridService in getDebridService.
packages/core/src/utils/constants.ts New TORRIN_SERVICE id, added to SERVICES + BUILTIN_SUPPORTED_SERVICES, plus SERVICE_DETAILS entry (single apiKey credential, tr_… format).
packages/core/src/config/schema/services.ts Append torrin to the DEFAULT_SERVICE_CREDENTIALS env-var description.
packages/docs/content/docs/configuration/environment-variables.mdx Regenerated via pnpm gen:env-docs.

Verified

  • ✅ `pnpm -F core run build` — clean, zero TS errors
  • ✅ `pnpm -F server run build` — clean
  • ✅ `pnpm gen:env-docs` — regenerated and committed
  • ✅ `pnpm format` — Prettier'd; reverted unrelated pre-existing format drift in untouched files to keep the PR focused

Notes for review

  • addTorrent accepts magnet URIs, .torrent URLs, or base64-encoded .torrent payloads. When a non-magnet input arrives, it's fetched (URL) or decoded (base64) and run through parse-torrent (already a workspace dep) to extract the info hash and trackers, then re-emitted as a magnet URI before being submitted to POST /api/jobs. Mirrors how stremthru.addTorrent handles playbackInfo.downloadUrl.
  • generateTorrentLink is a passthrough. Torrin returns pre-signed URLs in Job.stream_urls[].signed_url; there's no separate "unrestrict" step.
  • Error code mapping: 401 → UNAUTHORIZED, 403 → FORBIDDEN (Torrin returns 403 on free-plan-only paid endpoints), 429 → STORE_LIMIT_EXCEEDED (slot limit reached, Torrin's plan-based concurrency cap), 5xx → INTERNAL_SERVER_ERROR / BAD_GATEWAY.
  • Caches: per-credential availability cache and per-(credential, hash, fileIndex, metadata) playback link cache, both honor appConfig.builtins.debrid.errorCacheTtl and route through the existing Cache abstraction (Redis-aware via appConfig.bootstrap.redisUri).
  • Polling: respects BUILTIN_DOWNLOAD_POLL_INTERVAL / BUILTIN_DOWNLOAD_MAX_WAIT_TIME (the wildcard `*` defaults work fine for Torrin since cache hits return 200 on first call and only new submissions need to poll).

Test plan

  • Add Torrin in the SPA service config with a real `tr_…` API key from torrin.app/app/settings.
  • Trigger a stream search, confirm `checkMagnets` returns cached entries for hashes already in the Torrin shared cache.
  • Click play on a cached result — confirm the `signed_url` resolves and starts playback.
  • Click play on an uncached magnet with `cacheAndPlay` enabled — confirm polling completes and the URL is returned.
  • Disable `cacheAndPlay` and confirm uncached results return `undefined` (no blocking poll).
  • Hit a 429 (slot-limit) deliberately and confirm the error surfaces as `STORE_LIMIT_EXCEEDED`.
  • With an addon that supplies `playbackInfo.downloadUrl` (private trackers, .torrent URL), confirm `addTorrent` fetches → parses → submits as magnet without error.

Summary by CodeRabbit

  • New Features

    • Added Torrin as a supported debrid service, allowing users to add magnets/torrents and resolve playback streams via Torrin.
  • Improvements

    • Faster, more reliable playback resolution with caching, concurrency coalescing and improved handling of torrent inputs and stream selection.
  • Documentation

    • Configuration docs updated to list Torrin among supported services.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bafebb6d-83e6-442f-a87f-886267227d6b

📥 Commits

Reviewing files that changed from the base of the PR and between b829ca4 and 2435ed1.

📒 Files selected for processing (1)
  • packages/core/src/debrid/torrin.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/debrid/torrin.ts

Walkthrough

Adds Torrin debrid service support: registers the service, updates config/docs, wires factory dispatch, and implements TorrinDebridService with HTTP client, magnet lifecycle methods, caching, locking, and playback resolution.

Changes

Torrin Debrid Service Integration

Layer / File(s) Summary
Service registration and constants
packages/core/src/utils/constants.ts
Introduce TORRIN_SERVICE and add torrin to SERVICES and BUILTIN_SUPPORTED_SERVICES; add SERVICE_DETAILS entry requiring an apiKey.
Configuration schema and documentation
packages/core/src/config/schema/services.ts, packages/docs/content/docs/configuration/environment-variables.mdx
Update the DEFAULT_SERVICE_CREDENTIALS env description to include torrin among supported service IDs.
Service factory dispatch
packages/core/src/debrid/index.ts
Import TorrinDebridService and add case 'torrin' to getDebridService, instantiating it with pollInterval and maxWaitTime.
Torrin API types and mapping
packages/core/src/debrid/torrin.ts (lines 1–143)
Define Torrin job/availability/stream/file interfaces and implement mappers from Torrin job status and HTTP codes to internal DebridDownload status and DebridError codes; implement job->download conversion.
Service constructor and options
packages/core/src/debrid/torrin.ts (lines 145–280)
Add TorrinServiceOptions and implement TorrinDebridService constructor, identity/capabilities, token validation, base URL normalisation, and default poll/timeout config.
HTTP client and request handling
packages/core/src/debrid/torrin.ts (lines 145–280)
Implement authenticated JSON request helper that parses responses and throws DebridError with mapped codes and captured response metadata on non-OK responses or upstream failures.
Magnet operations and job lifecycle
packages/core/src/debrid/torrin.ts (lines 282–503)
Implement checkMagnets with availability cache and batch /api/availability calls, addMagnet submitting /api/jobs, addTorrent conversion (magnet, torrent file fetch, base64 .torrent parsing), getMagnet, listMagnets, removeMagnet, and generateTorrentLink passthrough.
Playback resolution with caching and polling
packages/core/src/debrid/torrin.ts (lines 521–733)
Implement resolve using DistributedLock and _resolve: playback-link/failure caching, magnet construction from downloadUrl or BTIH+tr sources, submit/poll job until download or timeout, fetch raw job, select matching stream URL with fallback, optional auto-remove for non-torrent sources, cache resolved signed URL, and getRawJob.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Resolve as TorrinDebridService.resolve()
    participant DistLock as DistributedLock
    participant _Resolve as _resolve()
    participant Cache as Playback/Failure Cache
    participant Torrin as Torrin API
    participant JobDetail as getRawJob()

    Caller->>Resolve: resolve(playbackInfo, filename, cacheAndPlay)
    Resolve->>DistLock: acquire lock for playback key
    DistLock-->>Resolve: lock acquired
    Resolve->>_Resolve: call _resolve()
    _Resolve->>Cache: check playback-link cache
    alt cached URL present
        Cache-->>_Resolve: return cached signed URL
        _Resolve-->>Resolve: return signed URL
    else cache miss
        _Resolve->>Cache: check failure cache
        alt failure cached
            Cache-->>_Resolve: return null (failure)
            _Resolve-->>Resolve: return undefined
        else not failed before
            _Resolve->>_Resolve: build magnet from downloadUrl or BTIH+tr
            _Resolve->>Torrin: POST /api/jobs (submit)
            Torrin-->>_Resolve: job id/status
            loop poll until downloaded or timeout
                _Resolve->>Torrin: GET /api/jobs/{id} (status)
                Torrin-->>_Resolve: job status
            end
            alt job downloaded
                _Resolve->>JobDetail: GET /api/jobs/{id} (full job)
                JobDetail->>Torrin: request job details
                Torrin-->>JobDetail: full job payload with files/streams
                JobDetail-->>_Resolve: parsed job
                _Resolve->>_Resolve: select best matching stream URL
                _Resolve->>Cache: cache signed URL
                Cache-->>_Resolve: cached
                _Resolve-->>Resolve: return signed URL
            else job failed or timeout
                _Resolve->>Cache: cache failure (null)
                _Resolve-->>Resolve: return undefined
            end
        end
    end
    Resolve->>DistLock: release lock
    DistLock-->>Resolve: released
    Resolve-->>Caller: final signed URL or undefined
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Viren070/AIOStreams#605: Related auto-remove-after-resolve cleanup behavior and integration with Torrin resolve autoRemoveDownloads.
  • Viren070/AIOStreams#664: Related addTorrent/downloadUrl pathways used by Torrin resolve and addTorrent implementation.
  • Viren070/AIOStreams#734: Related debrid interface/type refactor that TorrinDebridService implements.

Suggested reviewers

  • Viren070

Poem

🐰 A tiny rabbit taps the key,
Torrin joins the debrid tree,
Locks and caches hum in tune,
Jobs poll under silver moon,
Signed links hop out soon!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: add torrin debrid service' is a clear, concise summary of the main changeset, accurately describing the introduction of Torrin as a new debrid service implementation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Adds Torrin (https://torrin.app) as a builtin debrid service. Torrin is an
open-source debrid that takes magnets and returns signed HTTPS streaming URLs
backed by an R2-cached library.

Implementation is native (talks directly to api.torrin.app) and torrent-only;
usenet/hoster flows are out of scope for this PR because they require BYOK
credentials configured server-side at torrin.app/app/settings.

Files:
- packages/core/src/debrid/torrin.ts: TorrentDebridService impl (addMagnet,
  addTorrent via fetch+parse-torrent->magnet, checkMagnets via batch
  availability, getMagnet, listMagnets, removeMagnet, resolve with
  poll-on-cacheAndPlay). Reuses DistributedLock, DebridFailureCache,
  buildResolveKey, selectFileInTorrentOrNZB to match torbox.ts conventions.
- packages/core/src/debrid/index.ts: dispatch 'torrin' to TorrinDebridService.
- packages/core/src/utils/constants.ts: SERVICE id, BUILTIN_SUPPORTED_SERVICES
  entry, SERVICE_DETAILS metadata (single apiKey credential).
- packages/core/src/config/schema/services.ts: env-var description includes
  the new service id.
- packages/docs/.../environment-variables.mdx: regenerated via gen:env-docs.

Notes:
- addTorrent() accepts a magnet URI, an HTTPS URL to a .torrent file, or a
  base64-encoded .torrent payload. The .torrent path is parsed via
  parse-torrent (already a workspace dep) and converted to a magnet URI before
  submission, since Torrin's POST /api/jobs only accepts magnets.
- generateTorrentLink() is a passthrough -- Torrin returns pre-signed URLs in
  Job.stream_urls[].signed_url, no separate 'unrestrict' step.
@rrevanth rrevanth force-pushed the feat/add-torrin-service branch from c73eb94 to b829ca4 Compare June 11, 2026 18:12
@androidguy28

Copy link
Copy Markdown

The whole website seems like a vibe codded rip off of torbox.. This isn't Dave starting his 3rd service is it?

(Dave being the dude who abandoned Easy debrid and debrider leaving his customer high and dry)

@vctrez

vctrez commented Jun 12, 2026

Copy link
Copy Markdown

The whole website seems like a vibe codded rip off of torbox.. This isn't Dave starting his 3rd service is it?

(Dave being the dude who abandoned Easy debrid and debrider leaving his customer high and dry)

lol appreciate the concern but nah, torrin is OSS AND not a copy of anything. also been building this actively for weeks with features shipping not exactly the "abandon and run" type

but then i guess All Debrid is a copy of Real Debrid

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants