New Source Animetoki#587
Conversation
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
Reviewer's GuideAdds 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 resolutionsequenceDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- There are two CloudExtractor implementations (in
en.animetokianden.animetoki.extractors) with nearly identical code; consider removing one and updating imports to avoid confusion and duplication. - The
naturalComparefunction is duplicated in bothAnimeTokiandCloudExtractor; 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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
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.
- improved CloudExtractor parsing - added natural sorting - fix thumbnail URL resolution
…etter maintanence
These have been resolved in the recent commits
|
|
Thank you for the update, @limeskat. It's great to see those issues addressed. The cleanup of redundant files, proper resource management with |
Checklist:
extVersionCodevalue inbuild.gradlefor individual extensionsoverrideVersionCodeorbaseVersionCodeas needed for all multisrc extensionsisNsfw = trueflag inbuild.gradlewhen appropriateidif a source's name or language were changedweb_hi_res_512.pngwhen adding a new extensionAdd 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:
Enhancements:
Build: