Skip to content

New Source Animetoki#587

Open
limeskat wants to merge 8 commits into
yuzono:masterfrom
limeskat:en/anitoki
Open

New Source Animetoki#587
limeskat wants to merge 8 commits into
yuzono:masterfrom
limeskat:en/anitoki

Conversation

@limeskat

@limeskat limeskat commented Jul 4, 2026

Copy link
Copy Markdown

Checklist:

  • Updated extVersionCode value in build.gradle for individual extensions
  • Updated overrideVersionCode or baseVersionCode as needed for all multisrc extensions
  • Referenced all related issues in the PR body (e.g. "Closes #xyz")
  • Added the isNsfw = true flag in build.gradle when appropriate
  • Have not changed source names
  • Have explicitly kept the id if a source's name or language were changed
  • Have tested the modifications by compiling and running the extension through Android Studio
  • Have removed web_hi_res_512.png when adding a new extension
  • This PR is AI-assisted, I have reviewed the changes manually and confirmed they are not slop
  • Have made sure all the icons are in png format

Add a 👍 reaction to pull requests you find important.

Summary by Sourcery

Add a new AnimeToki English anime streaming extension with support for popular/latest listings, search, details, episodes, and video playback.

New Features:

  • Introduce AnimeToki source implementation for Tachiyomi anime with Cloudflare-compatible client and episode/video handling.
  • Add filter support for genres and sub-pages to refine AnimeToki search results.

Enhancements:

  • Implement cloud storage and worker resolver utilities to extract episodes and playable URLs from AnimeToki-hosted files.
  • Add a session warm-up interceptor and WebView-based resolver to improve reliability when navigating AnimeToki and its cloud endpoints.

Build:

  • Add build.gradle configuration for the AnimeToki extension, including metadata and version code.

limeskat added 3 commits July 4, 2026 18:01
Closes #1026

- [x] Updated `extVersionCode` value in `build.gradle` for individual extensions
- [x] Referenced all related issues in the PR body (e.g. "Closes #xyz")
- [x] Have not changed source names
- [x] Have tested the modifications by compiling and running the extension through Android Studio
- [x] Have removed `web_hi_res_512.png` when adding a new extension
- [x] Have made sure all the icons are in png format
- [x] This PR is AI-assisted, I have reviewed the changes manually and confirmed they are not slop
@sourcery-ai

sourcery-ai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a new Tachiyomi anime extension for the AnimeToki site, including source implementation, Cloud/Worker file extractors, filters, session warm-up, DTOs, and Gradle configuration.

Sequence diagram for AnimeToki episode and video resolution

sequenceDiagram
    actor User
    participant AnimeToki
    participant CloudExtractor
    participant CloudAPI as cloud.animetoki.com
    participant WorkerAPI as workers.dev

    User->>AnimeToki: episodeListParse(response)
    AnimeToki->>AnimeToki: select cloud and CDN links

    alt cloud/drive links
        AnimeToki->>CloudExtractor: getEpisodesFromCloudUrl(cloudUrl)
        CloudExtractor->>CloudExtractor: splitUrl(url)
        CloudExtractor->>CloudExtractor: urlToBase64(baseUrl, segments)
        loop traverse folders
            CloudExtractor->>CloudAPI: POST folderUrl
            CloudAPI-->>CloudExtractor: CloudFileResponse
            CloudExtractor->>CloudExtractor: traverseFolder(...)
        end
        CloudExtractor-->>AnimeToki: List<SEpisode>
    else workers.dev links
        AnimeToki->>AnimeToki: fetchWorkerEpisodes(folderUrl)
        loop recurse folders
            AnimeToki->>WorkerAPI: GET folderUrl
            WorkerAPI-->>AnimeToki: HTML listing
            AnimeToki->>AnimeToki: add SEpisode for files
        end
    end

    User->>AnimeToki: fetchVideoList(episode)
    alt cloud/drive URL
        AnimeToki-->>User: List<Video>(direct URL)
    else workers.dev URL
        AnimeToki->>AnimeToki: resolveWorkerUrl(url)
        AnimeToki->>WorkerAPI: POST parentUrl
        WorkerAPI-->>AnimeToki: JSON files
        AnimeToki-->>User: List<Video>(download URL)
    else direct file URL
        AnimeToki-->>User: List<Video>(clean URL)
    end
Loading

File-Level Changes

Change Details Files
Implement AnimeToki ParsedAnimeHttpSource with popular/latest/search, details parsing, custom episode discovery, and video URL resolution including Cloud/Worker handling.
  • Configure AnimeToki source metadata (name, baseUrl, language, Cloudflare-aware OkHttp client).
  • Implement popular and latest lists with custom first-page popular widget handling and a shared item parser.
  • Implement search with query, genre, and sub-page filters, mapping filters to category URLs.
  • Parse anime details including title, thumbnail, genres, description, status, and studio via HTML and regex with Unicode normalization.
  • Implement custom episode list parsing that aggregates episodes from cloud.animetoki.com / drive.animetoki.com via extractor, plus direct CDN and Cloudflare Worker directory links, including recursive folder traversal and final list reversal.
  • Resolve video URLs differently for direct cloud/drive links, workers.dev links (via JSON API resolution), and generic CDN URLs with query cleanup.
  • Provide an AnimeFilterList via AnimeTokiFilters implementation.
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt
Add CloudExtractor and related DTOs to traverse AnimeToki cloud storage folders and build episode lists from API responses.
  • Implement CloudExtractor helper inside the animetoki package and a duplicate under an extractors subpackage, which POSTs to encoded folder URLs, retries on failure, and logs errors.
  • Convert cloud URLs into base64-encoded path segments compatible with AnimeToki cloud API and recursively traverse folders to collect video files as SEpisode instances, using a natural sort on filenames and incremental episode numbers.
  • Introduce serializable DTOs (CloudFileResponse, CloudFile, WorkerFileResponse, WorkerFile) to parse cloud/worker JSON APIs and expose an actualMimeType helper for mimeType/mime_type variants.
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/CloudExtractor.kt
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/extractors/CloudExtractor.kt
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/Dto.kt
Introduce utilities for session warm-up, Cloudflare/WebView cookie resolution, and filter configuration for the AnimeToki extension.
  • Add SessionWarmUpInterceptor to eagerly hit animetoki.com and cloud.animetoki.com once per client to pre-establish Cloudflare session before regular requests.
  • Add WebViewResolver helper that spins up an Android WebView on the main thread, waits for Cloudflare challenge completion or clearance cookie, and injects cookies back into the OkHttp client cookie jar.
  • Define AnimeTokiFilters with Genre and Sub-page UriPartFilter implementations to expose basic category-based filtering in search.
  • Add Gradle module configuration for the new AnimeToki extension including extName, extClass, extVersionCode, and isNsfw flag, and apply the legacy extension plugin.
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/SessionWarmUpInterceptor.kt
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/WebViewResolver.kt
src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeTokiFilters.kt
src/en/animetoki/build.gradle

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • There are two CloudExtractor implementations (in en.animetoki and en.animetoki.extractors) with nearly identical code; consider removing one and updating imports to avoid confusion and duplication.
  • The naturalCompare function is duplicated in both AnimeToki and CloudExtractor; extracting this into a shared utility would simplify maintenance.
  • WebViewResolver is currently not referenced by the extension; if it’s not needed for this source, consider removing it to keep the extension lean, or wire it into the client/session setup if it’s required for Cloudflare bypass.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There are two CloudExtractor implementations (in `en.animetoki` and `en.animetoki.extractors`) with nearly identical code; consider removing one and updating imports to avoid confusion and duplication.
- The `naturalCompare` function is duplicated in both `AnimeToki` and `CloudExtractor`; extracting this into a shared utility would simplify maintenance.
- WebViewResolver is currently not referenced by the extension; if it’s not needed for this source, consider removing it to keep the extension lean, or wire it into the client/session setup if it’s required for Cloudflare bypass.

## Individual Comments

### Comment 1
<location path="src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt" line_range="243-246" />
<code_context>
+            }
+        }
+
+        episodes.forEachIndexed { index, episode ->
+            episode.episode_number = (index + 1).toFloat()
+        }
+        return episodes.reversed()
+    }
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Episode ordering and episode_number are inconsistent due to numbering before reversing.

`episode_number` is assigned based on the original list order, but you then return `episodes.reversed()`, so the first returned episode has the highest `episode_number`. Since Tachiyomi typically expects list order and `episode_number` to match, this is likely to cause incorrect or confusing behaviour. Either reverse first and then assign `episode_number` on the reversed list, or remove the final `reversed()` and keep the original order if that’s the intended sequence.
</issue_to_address>

### Comment 2
<location path="src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/CloudExtractor.kt" line_range="14" />
<code_context>
+import okhttp3.OkHttpClient
+import java.net.URLDecoder
+
+class CloudExtractor(private val client: OkHttpClient, private val headers: Headers) {
+
+    private val json = Json { ignoreUnknownKeys = true }
</code_context>
<issue_to_address>
**issue:** CloudExtractor is implemented twice with near-identical code, which is error-prone.

There are two `CloudExtractor` classes (`animetoki.extractors.CloudExtractor` and `animetoki.CloudExtractor`) with duplicated logic, which complicates maintenance and risks subtle behavioral differences over time. Please consolidate to a single implementation (preferably the one in `extractors`) and have the other either removed or delegate to it, updating all call sites accordingly.
</issue_to_address>

### Comment 3
<location path="src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt" line_range="353-362" />
<code_context>
+    private fun naturalCompare(a: String, b: String): Int {
</code_context>
<issue_to_address>
**suggestion:** naturalCompare is duplicated across classes and appears unused here.

This implementation closely matches `extractors.CloudExtractor.naturalCompare` and is not used in this class. Please either remove it if unnecessary, or refactor to reuse a shared helper/the `CloudExtractor` version so there’s a single source of truth for natural sorting.

Suggested implementation:

```
    private fun naturalCompare(a: String, b: String): Int =
        CloudExtractor.naturalCompare(a, b)

```

- Remove the remainder of the old `naturalCompare` implementation (everything after the `while (ib < b.length && b[ib].isDigit()) ib++` line up to the closing `}` of the function), so that only the single-expression delegating function remains.
- Add an import for the shared helper if it’s not already present, e.g.:
  `import eu.kanade.tachiyomi.animeextension.en.extractors.CloudExtractor`
  (adjust the package to match where `CloudExtractor.naturalCompare` is actually defined).
- If `CloudExtractor.naturalCompare` is a member function rather than `@JvmStatic`/top-level, refactor to a shared top-level/util helper instead, or call it via an appropriate instance, and update this method to delegate to that shared implementation.
</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 thread src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt Outdated

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

Copy link
Copy Markdown
Contributor

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 introduces a new AnimeToki extension, implementing the main source class, custom filters, a cloud extractor, and session warm-up utilities. The review feedback highlights critical improvements, including properly closing OkHttp responses to prevent resource leaks, avoiding unsafe double-bang (!!) operators to prevent crashes, removing redundant files and unused helper functions, and making URL selectors more robust against absolute URLs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt Outdated
Comment thread src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt Outdated
Comment thread src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt Outdated
Comment thread src/en/animetoki/src/eu/kanade/tachiyomi/animeextension/en/animetoki/AnimeToki.kt Outdated
@limeskat limeskat closed this Jul 4, 2026
- improved CloudExtractor parsing
- added natural sorting
- fix thumbnail URL resolution
@limeskat limeskat reopened this Jul 4, 2026
@limeskat

limeskat commented Jul 4, 2026

Copy link
Copy Markdown
Author

@sourcery-ai

Hey - I've found 3 issues, and left some high level feedback:

  • There are two CloudExtractor implementations (in en.animetoki and en.animetoki.extractors) with nearly identical code; consider removing one and updating imports to avoid confusion and duplication.
  • The naturalCompare function is duplicated in both AnimeToki and CloudExtractor; extracting this into a shared utility would simplify maintenance.
  • WebViewResolver is currently not referenced by the extension; if it’s not needed for this source, consider removing it to keep the extension lean, or wire it into the client/session setup if it’s required for Cloudflare bypass.

@gemini-code-assist

The review feedback highlights critical improvements, including properly closing OkHttp responses to prevent resource leaks, avoiding unsafe double-bang (!!) operators to prevent crashes, removing redundant files and unused helper functions, and making URL selectors more robust against absolute URLs.

These have been resolved in the recent commits

  • The duplicate CloudExtractor was removed.

  • The duplicate functions naturalCompare was moved to a standalone file(AnimeTokiUtils.kt).

  • The unused WebViewResolver.kt was removed.

  • OkHttp connections are now properly closed within .use { ... } blocks to prevent resource leaks.

  • Unsafe double-bang (!!) operators were replaced with safe calls (?.) to prevent crashes.

  • Robust wildcard matchers (href*=) have been implemented for URL filtering.

  • Unused helper functions and redundant files were cleaned up.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Thank you for the update, @limeskat. It's great to see those issues addressed. The cleanup of redundant files, proper resource management with .use { ... }, and the shift to safer null handling are all excellent improvements that will make the extension more stable and maintainable. The consolidation of utility functions into AnimeTokiUtils.kt is also a good practice. Everything looks solid now.

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.

1 participant