Skip to content

en/Donghuastream: Fix video loading and improve extractors#66

Merged
cuong-tran merged 25 commits intomasterfrom
donghuastream
Mar 12, 2026
Merged

en/Donghuastream: Fix video loading and improve extractors#66
cuong-tran merged 25 commits intomasterfrom
donghuastream

Conversation

@cuong-tran
Copy link
Contributor

@cuong-tran cuong-tran commented Mar 12, 2026

Summary by Sourcery

Update DonghuaStream extension to improve video host extraction, add host selection preferences, and refine episode and quality handling.

New Features:

  • Add support for Ok.ru and Rumble video hosts in DonghuaStream with dedicated extractors.
  • Introduce user preferences to enable or disable specific video hosts and to skip preview episodes.
  • Allow custom quality preference ordering for video selection.

Enhancements:

  • Adjust search and pagination behavior to match DonghuaStream's current site structure.
  • Refine video sorting logic by reusing a compiled quality regex and improving tie-breaking by quality label.
  • Modernize StreamPlay extractor to use the new API flow with unpacked script handling, better HLS handling, and support for non-HLS sources.

Build:

  • Bump DonghuaStream extension overrideVersionCode to 16 and add dependencies for Okru and JS unpacker libraries.

Copilot AI review requested due to automatic review settings March 12, 2026 17:45
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 12, 2026

Reviewer's Guide

Updates the DonghuaStream extension to support additional video hosts, configurable host/preview behavior, and a more robust StreamPlay extraction flow using async utilities and new extractors, while adjusting search/pagination and quality sorting.

Sequence diagram for updated getVideoList host selection and extraction

sequenceDiagram
    participant DS as DonghuaStream
    participant Pref as SharedPreferences
    participant DME as DailymotionExtractor
    participant SPE as StreamPlayExtractor
    participant OKE as OkruExtractor
    participant RE as RumbleExtractor

    DS->>Pref: read getHosters
    DS->>DS: runBlocking { getVideoList(url, name) }
    alt Dailymotion enabled and url contains dailymotion
        DS->>DME: videosFromUrl(url, prefix)
        DME-->>DS: List Video
    else Streamplay enabled and url contains streamplay
        DS->>SPE: videosFromUrl(url, prefix)
        SPE-->>DS: List Video
    else Okru enabled and url contains ok.ru
        DS->>DS: UrlUtils.fixUrl(url)
        alt url fixed
            DS->>OKE: videosFromUrl(fixedUrl, prefix)
            OKE-->>DS: List Video
        else invalid url
            DS-->>DS: emptyList
        end
    else Rumble enabled and url contains rumble
        DS->>RE: videosFromUrl(url, prefix)
        RE-->>DS: List Video
    else No matching enabled host
        DS-->>DS: emptyList
    end
Loading

Sequence diagram for new StreamPlayExtractor async extraction flow

sequenceDiagram
    participant DS as DonghuaStream
    participant SPE as StreamPlayExtractor
    participant C as OkHttpClient
    participant SP as streamplay_page
    participant API as streamplay_api
    participant PU as PlaylistUtils

    DS->>SPE: videosFromUrl(url, prefix)
    SPE->>C: GET url with headers
    C-->>SPE: Response
    SPE->>SPE: useAsJsoup() parse document

    loop for each server link
        SPE->>SPE: extractAndDecodeFromDocument(serverUrl, serverPrefix)
        SPE->>C: GET serverUrl
        C-->>SPE: Response
        SPE->>SPE: useAsJsoup() parse server document
        alt packed script present
            SPE->>SPE: JsUnpacker.unpackAndCombine(script)
            SPE->>SPE: extract kaken via kakenRegex
        else mobile non packed script
            SPE->>SPE: extract kaken from window.kaken
        end
        SPE->>C: POST https://play.streamplay.co.in/api/ with kaken
        C-->>SPE: API JSON
        SPE->>SPE: parseAs APIResponse
        SPE->>SPE: build subtitleList from tracks
        par for each source in sources
            alt type is hls and videoUrl endsWith master.m3u8
                SPE->>PU: extractFromHls(videoUrl, referer, subtitleList, nameGen)
                PU-->>SPE: List Video
            else non HLS or non master
                SPE-->>SPE: create single Video with Original label
            end
        end
    end
    SPE-->>DS: aggregated List Video
Loading

Class diagram for updated DonghuaStream extension and extractors

classDiagram
    class AnimeStream

    class DonghuaStream {
        +String name
        +String baseUrl
        +String lang
        +boolean fetchFilters
        +String[] prefQualityValues
        +String[] prefQualityEntries
        +fun popularAnimeNextPageSelector() String
        +fun latestUpdatesNextPageSelector() String
        +fun searchAnimeRequest(page~Int~, query~String~, filters~AnimeFilterList~) Request
        +fun setupPreferenceScreen(screen~PreferenceScreen~) void
        +fun episodeListParse(response~Response~) List~SEpisode~
        +fun getVideoList(url~String~, name~String~) List~Video~
        +fun List~Video~.sort() List~Video~
        -SharedPreferences.ignorePreview : Boolean
        -SharedPreferences.getHosters : Set~String~
        -const PREF_HOSTER_KEY : String
        -const INTERNAL_HOSTER_NAMES : List~String~
        -const PREF_HOSTER_ENTRY_VALUES : List~String~
        -const PREF_HOSTER_DEFAULT : Set~String~
        -const IGNORE_PREVIEW_KEY : String
        -const IGNORE_PREVIEW_DEFAULT : Boolean
        -DailymotionExtractor dailymotionExtractor
        -StreamPlayExtractor streamPlayExtractor
        -OkruExtractor okruExtractor
        -RumbleExtractor rumbleExtractor
        -Regex qualityRegex
    }

    class StreamPlayExtractor {
        -OkHttpClient client
        -Headers headers
        -PlaylistUtils playlistUtils
        -Regex kakenRegex
        +suspend fun videosFromUrl(url~String~, prefix~String~=) List~Video~
        -suspend fun extractAndDecodeFromDocument(url~String~, prefix~String~) List~Video~
    }

    class RumbleExtractor {
        -OkHttpClient client
        -Headers headers
        -PlaylistUtils playlistUtils
        -Regex regex
        +fun videosFromUrl(url~String~, prefix~String~=) List~Video~
        -fun extractRumbleId(url~String~) String?
    }

    class APIResponse {
        +List~SourceObject~ sources
        +List~TrackObject~ tracks?
    }

    class SourceObject {
        +String file
        +String label
        +String type
        +String videoUrl
    }

    class TrackObject {
        +String file
        +String label
        +String kind
    }

    class DailymotionExtractor
    class OkruExtractor
    class PlaylistUtils {
        +fun extractFromHls(playlistUrl~String~, referer~String~, subtitleList~List~Track~~, videoNameGen~Function1~String,String~~) List~Video~
    }

    class RumbleExtractor_DependencyNote

    DonghuaStream --|> AnimeStream
    DonghuaStream --> DailymotionExtractor : uses
    DonghuaStream --> StreamPlayExtractor : uses
    DonghuaStream --> OkruExtractor : uses
    DonghuaStream --> RumbleExtractor : uses
    DonghuaStream --> SharedPreferences : stores_prefs
    DonghuaStream --> Regex : uses_qualityRegex

    StreamPlayExtractor --> PlaylistUtils : uses
    StreamPlayExtractor --> APIResponse : parses
    StreamPlayExtractor --> SourceObject : contains
    StreamPlayExtractor --> TrackObject : contains

    RumbleExtractor --> PlaylistUtils : uses

    APIResponse o-- SourceObject : has_many
    APIResponse o-- TrackObject : has_many

    SourceObject --> String : file_label_type
    TrackObject --> String : file_label_kind
Loading

File-Level Changes

Change Details Files
Add user-configurable host and preview controls plus improved search/pagination behavior in DonghuaStream source
  • Override popular/latest next-page selectors and implement a custom searchAnimeRequest that builds paginated search URLs via HttpUrl
  • Introduce SharedPreferences-backed properties for enabled hosters and preview-episode skipping, with associated preference keys/defaults
  • Implement setupPreferenceScreen to expose a set preference for enabling/disabling Dailymotion/Streamplay/Rumble/Ok.ru and a switch to skip preview episodes
  • Wire episodeListParse to filter out preview episodes based on the skip-preview preference
  • Define explicit preferred quality values/entries and update video list sort to reuse a cached quality regex and secondary sort by quality string
src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/DonghuaStream.kt
Extend video extraction to new hosts (Rumble, Ok.ru) and gate extraction by user-selected hosters
  • Add OkruExtractor and custom RumbleExtractor for additional hosts
  • Initialize new extractors (OkruExtractor, RumbleExtractor) alongside existing Dailymotion and StreamPlay extractors
  • Update getVideoList to run in a runBlocking block and conditionally call each extractor only if the corresponding host is enabled and matches the URL, including URL fixing for Ok.ru
src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/DonghuaStream.kt
src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/extractors/RumbleExtractor.kt
Refactor StreamPlay extractor to use POST-based API with packed script decoding, async utilities, and richer source handling
  • Change videosFromUrl to be suspend, fetch pages with awaitSuccess/useAsJsoup, and iterate #servers links in parallel using parallelCatchingFlatMap
  • Add JsUnpacker-based unpacking logic and regex to extract the kaken token either from packed or non-packed script variants
  • Switch API calls from GET with timestamp param to a POST to https://play.streamplay.co.in/api/ sending kaken as text/plain and appropriate headers (Origin/Referer/X-Requested-With)
  • Parse APIResponse using awaitSuccess().parseAs, extend SourceObject to include label/type and derive videoUrl by replacing master.txt with master.m3u8
  • Handle both HLS master playlists via PlaylistUtils.extractFromHls and non-HLS sources by constructing Video objects with proper Referer/headers and subtitle tracks
src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/extractors/StreamPlayExtractor.kt
Update module metadata and dependencies for new extractors
  • Bump overrideVersionCode from 15 to 16
  • Add dependencies on okruextractor and unpacker libraries alongside existing dailymotionextractor and playlistutils
src/en/donghuastream/build.gradle

Possibly linked issues

  • #(no explicit number provided): PR repairs Donghuastream video loading via updated StreamPlay logic and added Okru/Rumble extractors, resolving unavailable videos.

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

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on improving the robustness and functionality of the DonghuaStream anime extension. It addresses video loading issues by integrating new video hoster extractors and enhancing an existing one, ensuring a wider range of content is playable. Additionally, it introduces user-configurable preferences for hoster selection and episode filtering, alongside refinements to navigation and search mechanisms, providing a more stable and customizable user experience.

Highlights

  • Enhanced Video Extraction: Implemented new video extractors for Ok.ru and Rumble, and significantly refactored the StreamPlay extractor to improve reliability and support multiple servers, including handling JavaScript unpacking for video source retrieval.
  • User Preferences for Hosters and Content Filtering: Added new user preferences allowing users to enable or disable specific video hosters and to automatically skip 'Preview' episodes, providing more control over content playback.
  • Improved Navigation and Search: Overrode methods for popular anime, latest updates, and search requests to ensure correct pagination and search functionality within the DonghuaStream source.
  • Dependency Updates: Included new dependencies for okruextractor and unpacker to support the expanded video extraction capabilities.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/en/donghuastream/build.gradle
    • Updated overrideVersionCode from 15 to 16.
    • Added okruextractor and unpacker dependencies.
  • src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/DonghuaStream.kt
    • Imported necessary libraries for preferences, new extractors, and utility functions.
    • Implemented custom pagination selectors for popular anime and latest updates.
    • Overrode searchAnimeRequest to construct search URLs correctly.
    • Introduced SharedPreferences properties for ignorePreview and getHosters.
    • Added setupPreferenceScreen to allow users to enable/disable hosters (Dailymotion, Streamplay, Rumble, Ok.ru) and skip preview episodes.
    • Initialized OkruExtractor and RumbleExtractor instances.
    • Modified getVideoList to conditionally call extractors based on user preferences and URL content, wrapped in runBlocking.
    • Updated episodeListParse to filter out preview episodes based on user preference.
    • Refined video sorting logic to use a pre-compiled regex and thenByDescending for more accurate quality sorting.
  • src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/extractors/RumbleExtractor.kt
    • Added a new extractor class, RumbleExtractor, to handle video extraction from Rumble.
    • Implemented videosFromUrl to parse Rumble embed URLs, extract video IDs, and generate HLS playlist URLs.
    • Utilized PlaylistUtils for HLS stream extraction.
  • src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/extractors/StreamPlayExtractor.kt
    • Imported JsUnpacker, UrlUtils, parallelCatchingFlatMap, awaitSuccess, useAsJsoup, POST, toMediaType, and toRequestBody.
    • Converted videosFromUrl to a suspend function and refactored to process multiple server links concurrently.
    • Introduced extractAndDecodeFromDocument to handle individual server URLs, including JavaScript unpacking to retrieve the kaken token.
    • Changed the API request method from GET to POST, sending the kaken token in the request body.
    • Updated the APIResponse.SourceObject data class to include label and type fields, and added a videoUrl getter.
    • Modified video extraction to support both HLS playlists and direct video links, using parallelCatchingFlatMap for efficient processing.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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 - I've found 1 issue, and left some high level feedback:

  • The host handling logic duplicates host identifiers between INTERNAL_HOSTER_NAMES and the string checks in getVideoList; consider centralizing these values (e.g., constants or an enum) so host keys and URL checks can't drift out of sync.
  • In StreamPlayExtractor.SourceObject.videoUrl, the master.txtmaster.m3u8 replacement assumes a specific filename pattern; if the API ever returns direct .m3u8 or another variant, this could produce invalid URLs—consider making this transformation conditional or more defensive based on type or the existing extension.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The host handling logic duplicates host identifiers between `INTERNAL_HOSTER_NAMES` and the string checks in `getVideoList`; consider centralizing these values (e.g., constants or an enum) so host keys and URL checks can't drift out of sync.
- In `StreamPlayExtractor.SourceObject.videoUrl`, the `master.txt``master.m3u8` replacement assumes a specific filename pattern; if the API ever returns direct `.m3u8` or another variant, this could produce invalid URLs—consider making this transformation conditional or more defensive based on `type` or the existing extension.

## Individual Comments

### Comment 1
<location path="src/en/donghuastream/src/eu/kanade/tachiyomi/animeextension/en/donghuastream/DonghuaStream.kt" line_range="40-43" />
<code_context>
+    override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()
+
+    override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
+        val url = baseUrl.toHttpUrl().newBuilder().apply {
+            addPathSegment("pagg")
+            addPathSegment(page.toString())
+            addPathSegment("")
+            addQueryParameter("s", query)
+        }.build()
</code_context>
<issue_to_address>
**issue (bug_risk):** Empty path segment in searchAnimeRequest is likely invalid for HttpUrl and can throw at runtime.

OkHttp’s `addPathSegment` rejects empty strings and throws `IllegalArgumentException`, so this call will always fail. If you just need a trailing slash, remove this line, or construct the path explicitly with non-empty segments (e.g. `addPathSegment("pagg").addPathSegment(page.toString())`) and let the builder handle separators.
</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.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly enhances the DonghuaStream extension by adding support for Ok.ru and Rumble video hosts, introducing user preferences for host selection and skipping previews, and overhauling the StreamPlay extractor to align with recent site changes. The implementation is solid, and the new features are valuable. I've included a couple of minor suggestions to improve code clarity and maintainability.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the DonghuaStream extension to restore/expand video extraction across multiple hosters and to improve playback reliability (notably for StreamPlay), while adding a couple of user-facing preferences to control hoster usage and episode filtering.

Changes:

  • Reworked StreamPlay extraction to decode kaken, call the StreamPlay API via POST, and generate videos from HLS or direct sources.
  • Added a Rumble extractor and integrated Ok.ru support into video extraction routing.
  • Added extension preferences for hoster enable/disable and skipping preview episodes, plus adjusted pagination/search and refined video sorting.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/en/donghuastream/.../extractors/StreamPlayExtractor.kt Major StreamPlay extractor rewrite (unpacking + POST API flow, parallel server/source extraction).
src/en/donghuastream/.../extractors/RumbleExtractor.kt New extractor to build an HLS playlist URL from a Rumble embed URL.
src/en/donghuastream/.../DonghuaStream.kt Adds hoster selection + preview-skip preferences; routes Ok.ru/Rumble/StreamPlay/Dailymotion; tweaks paging/search and sorting.
src/en/donghuastream/build.gradle Bumps extension version and adds okruextractor + unpacker dependencies needed by the new extractors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@cuong-tran cuong-tran merged commit 03cda2f into master Mar 12, 2026
4 checks passed
@github-actions github-actions bot deleted the donghuastream branch March 12, 2026 18:02
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants