-
-
Couldn't load subscription status.
- Fork 79
feat: debrid-link downloader support #1236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughA new Debrid-Link downloader service is integrated into the application. The changes include a new API client (DebridLinkAPI), a downloader implementation (DebridLinkDownloader) with torrent and file management, configuration models, and updates to data models and router endpoints to support the new service. Changes
Sequence DiagramsequenceDiagram
participant Client
participant DebridLinkDownloader
participant DebridLinkAPI
participant DebridLink_Service as Debrid-Link<br/>API
Client->>DebridLinkDownloader: validate()
DebridLinkDownloader->>DebridLinkDownloader: _validate_settings()
DebridLinkDownloader->>DebridLink_Service: get_user_info()
DebridLink_Service-->>DebridLinkDownloader: user info
DebridLinkDownloader->>DebridLinkDownloader: _validate_premium()
DebridLinkDownloader-->>Client: validation result
Client->>DebridLinkDownloader: add_torrent(infohash)
DebridLinkDownloader->>DebridLink_Service: POST /torrents/add
DebridLink_Service-->>DebridLinkDownloader: torrent_id
DebridLinkDownloader-->>Client: torrent_id
Client->>DebridLinkDownloader: get_instant_availability(infohash)
DebridLinkDownloader->>DebridLinkDownloader: _process_torrent()
DebridLinkDownloader->>DebridLink_Service: add & check availability
DebridLink_Service-->>DebridLinkDownloader: availability data
DebridLinkDownloader->>DebridLink_Service: delete_torrent()
DebridLinkDownloader-->>Client: TorrentContainer or None
Client->>DebridLinkDownloader: resolve_link(link)
DebridLinkDownloader->>DebridLink_Service: GET /links/check
DebridLink_Service-->>DebridLinkDownloader: resolved link info
DebridLinkDownloader-->>Client: link details
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
src/program/services/downloaders/__init__.py(2 hunks)src/program/services/downloaders/debridlink.py(1 hunks)src/program/services/downloaders/models.py(1 hunks)src/program/settings/models.py(2 hunks)src/routers/secure/default.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/program/services/downloaders/debridlink.py (3)
src/program/services/downloaders/models.py (8)
DebridFile(70-130)InvalidDebridFileException(66-67)TorrentContainer(133-156)TorrentInfo(159-190)UserInfo(202-216)create(79-121)file_ids(147-149)file_ids(188-190)src/program/utils/request.py (6)
CircuitBreakerOpen(90-95)SmartResponse(161-227)SmartSession(272-704)data(172-205)post(585-586)delete(591-592)src/program/services/downloaders/shared.py (2)
DownloaderBase(17-99)premium_days_left(107-122)
src/program/services/downloaders/__init__.py (1)
src/program/services/downloaders/debridlink.py (1)
DebridLinkDownloader(56-450)
🪛 Ruff (0.14.2)
src/program/services/downloaders/debridlink.py
113-113: Consider moving this statement to an else block
(TRY300)
114-114: Do not catch blind exception: Exception
(BLE001)
170-170: Do not catch blind exception: Exception
(BLE001)
181-181: Consider moving this statement to an else block
(TRY300)
188-189: try-except-pass detected, consider logging the exception
(S110)
188-188: Do not catch blind exception: Exception
(BLE001)
196-197: try-except-pass detected, consider logging the exception
(S110)
196-196: Do not catch blind exception: Exception
(BLE001)
206-207: try-except-pass detected, consider logging the exception
(S110)
206-206: Do not catch blind exception: Exception
(BLE001)
209-209: Do not catch blind exception: Exception
(BLE001)
214-215: try-except-pass detected, consider logging the exception
(S110)
214-214: Do not catch blind exception: Exception
(BLE001)
299-299: Avoid specifying long messages outside the exception class
(TRY003)
325-325: f-string without any placeholders
Remove extraneous f prefix
(F541)
344-344: Avoid specifying long messages outside the exception class
(TRY003)
448-448: Do not catch blind exception: Exception
(BLE001)
| resp: SmartResponse = self.api.session.get("account/infos") | ||
| self._maybe_backoff(resp) | ||
| if not resp.ok: | ||
| logger.error(f"Failed to get user info: {self._handle_error(resp)}") | ||
| return None | ||
|
|
||
| # Debrid-Link API v2 returns data in 'value' field | ||
| data = resp.data | ||
| if hasattr(data, "value"): | ||
| data = data.value | ||
|
|
||
| # Parse premium expiration | ||
| premium_expires_at = None | ||
| premium_days_left_val = None | ||
| account_type = getattr(data, "accountType", 0) | ||
|
|
||
| if account_type > 0: # Premium account | ||
| premium_until = getattr(data, "premiumLeft", 0) | ||
| if premium_until > 0: | ||
| premium_expires_at = datetime.fromtimestamp(premium_until) | ||
| premium_days_left_val = max( | ||
| 0, (premium_expires_at - datetime.now()).days | ||
| ) | ||
|
|
||
| return UserInfo( | ||
| service="debridlink", | ||
| username=getattr(data, "username", None), | ||
| email=getattr(data, "email", None), | ||
| user_id=getattr(data, "id", 0), | ||
| premium_status="premium" if account_type > 0 else "free", | ||
| premium_expires_at=premium_expires_at, | ||
| premium_days_left=premium_days_left_val, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Debrid-Link premium expiry math.
premiumLeft from Debrid-Link’s API is the number of seconds remaining, not a Unix timestamp. Calling datetime.fromtimestamp(premium_until) therefore generates an expiry date in January 1970 and makes every premium account look expired (premium_days_left collapses to 0), which flows into _validate_premium() logging and the /downloader_user_info response. Please convert the duration to an absolute expiry (e.g. datetime.now(tz=UTC) + timedelta(seconds=premium_until)) before storing it. (pkg.go.dev)
🤖 Prompt for AI Agents
In src/program/services/downloaders/debridlink.py around lines 414 to 446, the
code treats data.premiumLeft as a Unix timestamp but the API returns a duration
in seconds; replace the timestamp conversion with an expiry computed from now:
set premium_expires_at = datetime.now(tz=timezone.utc) +
timedelta(seconds=premium_until) (or use the project's UTC helper) and compute
premium_days_left as max(0, (premium_expires_at -
datetime.now(tz=timezone.utc)).days); ensure the stored datetime is
timezone-aware and update any imports if needed (datetime, timezone, timedelta).
Pull Request Check List
Resolves: #issue-number-here
Description:
Summary by CodeRabbit
Release Notes