Skip to content

Wzv3#459

Open
prime399 wants to merge 16 commits intoSilentDemonSD:wzv3from
prime399:wzv3
Open

Wzv3#459
prime399 wants to merge 16 commits intoSilentDemonSD:wzv3from
prime399:wzv3

Conversation

@prime399
Copy link

@prime399 prime399 commented Dec 18, 2025

Summary by Sourcery

Extend URL shortening and Mega download handling with additional services and subfolder support.

New Features:

  • Add support for multiple new third-party URL shortener services in the short_url helper.
  • Allow Mega links to specify an optional subfolder path suffix to target a specific folder or file within a shared folder.
  • Support downloading from Mega folder links via the folder API when a sub-path is resolved.

Enhancements:

  • Improve Mega download logic to reuse a parsed Mega link across link-type checks and API calls.
rjriajul and others added 13 commits March 11, 2025 21:24
* perf: restructured code and fixed yt-dlp download issue * feat: added Metadata Feature * chore(release): v1.4.0-x (final end version) Signed-off-by: Riajul <93116400+rjriajul@users.noreply.github.com> Co-authored-by: clyfly <denwahgenshin@gmail.com> Co-authored-by: SilentDemonSD <105407900+SilentDemonSD@users.noreply.github.com>
…ents.com, reel2earn.com, shortner.in, and thalashort.com
This is the final update to the master branch. From now on, the master branch is deprecated — no further updates, pull requests, or pushes will be accepted. The master branch is now officially retired. Signed-off-by: Riajul <93116400+rjriajul@users.noreply.github.com>
@sourcery-ai
Copy link

sourcery-ai bot commented Dec 18, 2025

Reviewer's Guide

Extends URL shortener support for multiple new providers and enhances MEGA download handling to support sub-path selection within folder links and proper folder_api usage for downloads.

Sequence diagram for enhanced MEGA folder download with sub-path selection

sequenceDiagram actor User participant Listener participant add_mega_download participant AsyncMega participant MegaApi_api participant MegaApi_folder participant MegaListener User->>Listener: Provide mega_link (optional sub_path using pipe) Listener->>add_mega_download: add_mega_download(listener, path) add_mega_download->>add_mega_download: Parse listener.link into mega_link and sub_path add_mega_download->>AsyncMega: Create AsyncMega instance add_mega_download->>MegaApi_api: Create api MegaApi instance add_mega_download->>AsyncMega: Assign api to AsyncMega add_mega_download->>MegaListener: Attach MegaListener to api add_mega_download->>AsyncMega: async_api.login(MEGA_EMAIL, MEGA_PASSWORD) alt mega_link is file add_mega_download->>AsyncMega: getPublicNode(mega_link) AsyncMega-->>MegaListener: Set public_node add_mega_download->>add_mega_download: node = mega_listener.public_node else mega_link is folder add_mega_download->>MegaApi_folder: Create folder_api MegaApi instance add_mega_download->>AsyncMega: Assign folder_api to async_api add_mega_download->>MegaApi_folder: folder_api.addListener(mega_listener) add_mega_download->>AsyncMega: run(folder_api.loginToFolder, mega_link) AsyncMega-->>MegaListener: Set node for folder root add_mega_download->>add_mega_download: node = mega_listener.node end opt sub_path provided and link is folder add_mega_download->>add_mega_download: resolve_subnode(api, node, sub_path) add_mega_download-->>add_mega_download: node set to sub_path node or None alt node is None add_mega_download->>Listener: on_download_error(Subfolder not found) add_mega_download->>AsyncMega: logout() add_mega_download-->>Listener: Return else node found add_mega_download->>add_mega_download: Log resolved node name end end alt mega_listener.error is set add_mega_download->>Listener: on_download_error(mega_listener.error) add_mega_download->>AsyncMega: logout() add_mega_download-->>Listener: Return else no listener error add_mega_download->>add_mega_download: Prepare download path and name alt folder_api exists add_mega_download->>AsyncMega: run(folder_api.startDownload, node, path, listener.name, None, False, None) else file or non folder_api add_mega_download->>AsyncMega: startDownload(node, path, listener.name, None, False, None) end AsyncMega-->>Listener: Download completes add_mega_download->>AsyncMega: logout() end 
Loading

Flow diagram for extended short_url provider handling

flowchart TD A[Start short_url with longurl and _shortener] --> B[Is provider modijiurl.com] B -- Yes --> B1[Encode longurl as long_url] B1 --> B2[Call modijiurl api with api and long_url] B2 --> B3[Check result status] B3 -- error --> B4[Log error message and return longurl] B3 -- success --> B5[Return result shortenedUrl] B -- No --> C[Is provider linkshortify.com] C -- Yes --> C1[Encode longurl as long_url] C1 --> C2[Call linkshortify api] C2 --> C3[Check result status] C3 -- error --> C4[Log error message and return longurl] C3 -- success --> C5[Return result shortenedUrl] C -- No --> D[Is provider inshorturl.com] D -- Yes --> D1[Encode longurl as long_url] D1 --> D2[Call inshorturl api] D2 --> D3[Check result status] D3 -- error --> D4[Log error message and return longurl] D3 -- success --> D5[Return result shortenedUrl] D -- No --> E[Is provider vplink.in] E -- Yes --> E1[Encode longurl as long_url] E1 --> E2[Call vplink api with alias CustomAlias] E2 --> E3[Check result status] E3 -- error --> E4[Log error message and return longurl] E3 -- success --> E5[Return result shortenedUrl] E -- No --> F[Is provider papajiurl.com] F -- Yes --> F1[Encode longurl as long_url] F1 --> F2[Call papajiurl api] F2 --> F3[Check result status] F3 -- error --> F4[Log error message and return longurl] F3 -- success --> F5[Return result shortenedUrl] F -- No --> G[Is provider linkcents.com] G -- Yes --> G1[Encode longurl as long_url] G1 --> G2[Call linkcents api] G2 --> G3[Check result status] G3 -- error --> G4[Log error message and return longurl] G3 -- success --> G5[Return result shortenedUrl] G -- No --> H[Is provider reel2earn.com] H -- Yes --> H1[Encode longurl as long_url] H1 --> H2[Call reel2earn api] H2 --> H3[Check result status] H3 -- error --> H4[Log error message and return longurl] H3 -- success --> H5[Return result shortenedUrl] H -- No --> I[Is provider shortner.in] I -- Yes --> I1[Encode longurl as long_url] I1 --> I2[Call shortner api] I2 --> I3[Check result status] I3 -- error --> I4[Log error message and return longurl] I3 -- success --> I5[Return result shortenedUrl] I -- No --> J[Is provider thalashort.com] J -- Yes --> J1[Encode longurl as long_url] J1 --> J2[Call thalashort api] J2 --> J3[Check result status] J3 -- error --> J4[Log error message and return longurl] J3 -- success --> J5[Return result shortenedUrl] J -- No --> K[Fallback to existing shortener handling] K --> L[Return result from fallback branch] 
Loading

File-Level Changes

Change Details Files
Add support for several new URL shortener providers using a common API pattern with error handling fallback to the original URL.
  • Introduce conditional branches for new shortener domains (modijiurl.com, linkshortify.com, inshorturl.com, vplink.in, papajiurl.com, linkcents.com, reel2earn.com, shortner.in, thalashort.com).
  • For each new provider, URL-encode the long URL, call the provider-specific API endpoint with the configured API key, and parse JSON responses.
  • Log errors and return the original long URL when the provider API responds with an error status; otherwise return the shortenedUrl field.
bot/helper/ext_utils/shortener_utils.py
Support MEGA folder sub-path downloads and correctly route downloads via folder_api when working with folders.
  • Parse an optional sub-path from the listener.link string using the '
' delimiter, trimming whitespace and leading/trailing slashes.
  • Use the parsed mega_link instead of the raw listener.link when determining link type, fetching public nodes, and logging into folder links.
  • When a sub-path is provided for folder links, traverse the MEGA folder tree to resolve the corresponding child node; surface a clear error and abort if not found.
  • Switch to folder_api.startDownload via async_api.run when downloading from folder links, while retaining direct async_api.startDownload for file links.

  • Tips and commands

    Interacting with Sourcery

    • Trigger a new review: Comment @sourcery-ai review on the pull request.
    • Continue discussions: Reply directly to Sourcery's review comments.
    • Generate a GitHub issue from a review comment: Ask Sourcery to create an
      issue from a review comment by replying to it. You can also reply to a
      review comment with @sourcery-ai issue to create an issue from it.
    • Generate a pull request title: Write @sourcery-ai anywhere in the pull
      request title to generate a title at any time. You can also comment
      @sourcery-ai title on the pull request to (re-)generate the title at any time.
    • Generate a pull request summary: Write @sourcery-ai summary anywhere in
      the pull request body to generate a PR summary at any time exactly where you
      want it. You can also comment @sourcery-ai summary on the pull request to
      (re-)generate the summary at any time.
    • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
      request to (re-)generate the reviewer's guide at any time.
    • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
      pull request to resolve all Sourcery comments. Useful if you've already
      addressed all the comments and don't want to see them anymore.
    • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
      request to dismiss all existing Sourcery reviews. Especially useful if you
      want to start fresh with a new review - don't forget to comment
      @sourcery-ai review to trigger a new review!

    Customizing Your Experience

    Access your dashboard to:

    • Enable or disable review features such as the Sourcery-generated pull request
      summary, the reviewer's guide, and others.
    • Change the review language.
    • Add, remove or edit custom review instructions.
    • Adjust other review settings.

    Getting Help

    Copy link

    @sourcery-ai sourcery-ai bot left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Hey there - I've reviewed your changes - here's some feedback:

    • The new shortener branches all duplicate the same pattern (quoting the URL, building an API URL, calling cget, checking status, and returning shortenedUrl); consider extracting this into a helper function or data-driven mapping of domain → API base to reduce repetition and ease future additions.
    • For the new shortener responses, using direct result["status"] and result["shortenedUrl"] lookups assumes the API always returns the expected shape; consider using .get() and validating keys or status codes to avoid unexpected KeyError or type issues when the remote service misbehaves.
    • In add_mega_download, you now compute mega_link and call get_mega_link_type(mega_link) multiple times; caching the link type once and reusing it would simplify the branching, and you may also want to normalize sub_path parts (e.g., case sensitivity or trimming extra slashes) to make subfolder resolution more robust.
    Prompt for AI Agents
    Please address the comments from this code review: ## Overall Comments - The new shortener branches all duplicate the same pattern (quoting the URL, building an API URL, calling `cget`, checking `status`, and returning `shortenedUrl`); consider extracting this into a helper function or data-driven mapping of domain → API base to reduce repetition and ease future additions. - For the new shortener responses, using direct `result["status"]` and `result["shortenedUrl"]` lookups assumes the API always returns the expected shape; consider using `.get()` and validating keys or status codes to avoid unexpected `KeyError` or type issues when the remote service misbehaves. - In `add_mega_download`, you now compute `mega_link` and call `get_mega_link_type(mega_link)` multiple times; caching the link type once and reusing it would simplify the branching, and you may also want to normalize `sub_path` parts (e.g., case sensitivity or trimming extra slashes) to make subfolder resolution more robust. ## Individual Comments ### Comment 1 <location> `bot/helper/mirror_leech_utils/download_utils/mega_download.py:65-74` </location> <code_context> child_nodes = [children.get(i) for i in range(children.size())] LOGGER.info(f"Found children: {[child.getName() for child in child_nodes]}") + if sub_path and get_mega_link_type(mega_link) == "folder": +  def resolve_subnode(api_obj, base_node, rel_path): +  current = base_node +  for part in [p for p in rel_path.split("/") if p]: +  kids = api_obj.getChildren(current) +  match = None +  for i in range(kids.size()): +  child = kids.get(i) +  if child.getName() == part: +  match = child +  break +  if not match: +  return None +  current = match +  return current + +  node = await sync_to_async(resolve_subnode, api, node, sub_path) +  if node is None: +  await listener.on_download_error(f"Subfolder not found: {sub_path}") </code_context> <issue_to_address> **issue (bug_risk):** Use the correct MegaApi instance (folder_api vs api) when resolving subfolders for folder links. Here `node` originates from `folder_api` (via `async_api.folder_api`), but `resolve_subnode` is called with the main `api` instance: ```python node = await sync_to_async(resolve_subnode, api, node, sub_path) ``` If the node belongs to the `folder_api` tree, `api.getChildren(node)` may fail or always return no children, breaking subfolder resolution for folder links. Instead, choose the API based on where `node` came from, e.g.: ```python api_obj = folder_api or api node = await sync_to_async(resolve_subnode, api_obj, node, sub_path) ``` so traversal stays within the correct API context. </issue_to_address> ### Comment 2 <location> `bot/helper/mirror_leech_utils/download_utils/mega_download.py:31-35` </location> <code_context> async def add_mega_download(listener, path): + mega_link = listener.link + sub_path = None + if "|" in mega_link: +  mega_link, sub_path = mega_link.split("|", 1) +  mega_link, sub_path = mega_link.strip(), sub_path.strip().strip("/") + async_api = AsyncMega() </code_context> <issue_to_address> **suggestion:** Consider validating or warning when a sub_path is provided for a file link, instead of silently ignoring it. Right now `sub_path` is parsed from `listener.link` but only used when `get_mega_link_type(mega_link) == "folder"`, so a value like `file_link|some/subpath` is silently ignored. Consider explicitly rejecting subpaths for file links, e.g.: ```python link_type = get_mega_link_type(mega_link) if sub_path and link_type == "file": await listener.on_download_error("Subpath is only supported for folder links") return ``` This keeps behavior predictable and avoids silently discarding user input. Suggested implementation: ```python async def add_mega_download(listener, path): mega_link = listener.link sub_path = None if "|" in mega_link: mega_link, sub_path = mega_link.split("|", 1) mega_link, sub_path = mega_link.strip(), sub_path.strip().strip("/") link_type = get_mega_link_type(mega_link) if sub_path and link_type == "file": await listener.on_download_error("Subpath is only supported for folder links") return async_api = AsyncMega() ``` ```python if link_type == "file": ``` </issue_to_address>

    Sourcery is free for open source - if you like our reviews please consider sharing them ✨
    Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
    Comment on lines +65 to +74
    if sub_path and get_mega_link_type(mega_link) == "folder":
    def resolve_subnode(api_obj, base_node, rel_path):
    current = base_node
    for part in [p for p in rel_path.split("/") if p]:
    kids = api_obj.getChildren(current)
    match = None
    for i in range(kids.size()):
    child = kids.get(i)
    if child.getName() == part:
    match = child
    Copy link

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    issue (bug_risk): Use the correct MegaApi instance (folder_api vs api) when resolving subfolders for folder links.

    Here node originates from folder_api (via async_api.folder_api), but resolve_subnode is called with the main api instance:

    node = await sync_to_async(resolve_subnode, api, node, sub_path)

    If the node belongs to the folder_api tree, api.getChildren(node) may fail or always return no children, breaking subfolder resolution for folder links. Instead, choose the API based on where node came from, e.g.:

    api_obj = folder_api or api node = await sync_to_async(resolve_subnode, api_obj, node, sub_path)

    so traversal stays within the correct API context.

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

    Labels

    None yet

    2 participants