Two related bugs left anime downloads stuck at 0% with no error visible to
the user. Manga downloads from clean HTTPS sources were unaffected.
1) lib/utils/extensions/string_extensions.dart
isMediaVideo() did a plain endsWith on the full URL string, so URLs
shaped like https://host/play/{id}/video.mp4?for={token} (used by
AnimeGG and several other sources) failed the filter because of the
trailing `?for=...` query string. With both m3u8Urls and nonM3u8Urls
empty in downloadChapter, the surrounding
Future.doWhile(() => isOk == true) poll never sets isOk and waits
forever -- MDownloader is never constructed.
Fix: match against Uri.tryParse(this)?.path instead of the full
string, and use a leading "." in the suffix so e.g. "flashmp4" cannot
accidentally match.
2) lib/services/download_manager/download_isolate_pool.dart
Once the URL passes the filter, _downloadFile (anime branch) opens a
streaming request. When the source extension sets Range: bytes=0-,
the server correctly responds with HTTP 206 Partial Content. The
previous "if (response.statusCode != 200)" check rejected that,
retried 3x, and threw. The throw was masked by an outer catch(_) in
downloadChapter, so the user only saw a forever-spinner.
Fix: accept any 2xx (>= 200 && < 300). Same fix applied to
_downloadSegment for HLS segment fetches.
Repro
- Source: AnimeGG (en) -- install via Mangayomi extensions
- Pick any episode (tested with Toriko Ep 147, Gintama Ep 39, Grand Blue
Ep 12)
- Tap the download icon
Before: an empty
".../AnimeGG (EN)/<series>/<episode>.mp4"-named folder is created, the
download icon stays in the spinner state, no error toast.
After: the .mp4 is written to disk at the size declared in Content-Length
(65,026,283 bytes for Toriko Ep 147), plays in the system video player.
Tested on macOS 26.3 / Apple Silicon with AnimeGG (multiple episodes,
multiple series, including a 180 MB 720p) and a manga control
(Asura Scans, 9 pages) on the same build to confirm no regression on the
manga path.
Changes:
- Add season-keyword regex (staffel, season, saison, temporada) and
episode-keyword regex (folge, episode, ep.) to reliably extract
the correct number regardless of name format
- parseChapterNumber() now encodes season context into the sort key
(season * 100000 + episode) so multi-season anime sort correctly
across seasons without mixing episode numbers
- Add parseEpisodeNumber() which strips season context and returns
only the episode number within a season; use this for tracker
updates (MAL/AniList/Kitsu) and AniSkip lookups, where the tracker
entry is already season-specific
- Switch updateTrackChapterRead and getAniSkipResults to
parseEpisodeNumber to fix incorrect episode reporting for
multi-season anime
- Compile all RegExp objects as static finals instead of per-call
instantiation
- Refactor duplicated parse logic into a single private _parse()
method with an applySeason flag
- remove the reverse parameter because false is already the model default, so passing it is redundant.
- flip the reverse bool, to keep the chapter sorting of already added manga the same.
Otherwise the user would have to change the sorting orientation for the chapters in the library.
- Add ChapterRecognition for numeric chapter parsing
- Replace old comparators with chapter‑number–aware sorting
- Unify sort modes and simplify list handling
- Rewrite updateMangaDetail with URL‑based dedupe
- Preserve read state across scanlators
- Update existing chapters instead of recreating
- Only create Update entries for new unread chapters
- Recompute smartUpdateDays using combined chapter list
- Remove outdated reversed/index‑based logic
- Added UpcomingUIModel for managing upcoming manga list items with headers and items.
- Introduced CalendarDay widget to display individual days with event indicators.
- Created CalendarHeader widget for navigating between months.
- Developed CalendarIndicator for visualizing events on specific days.
- Implemented UpcomingCalendar to manage the calendar view and event loading.
- Added UpcomingItem widget for displaying individual upcoming manga with cover images.
- Introduced FetchInterval utility to calculate fetch intervals based on chapter upload dates.
- Refactored updateMangaDetail to utilize FetchInterval for smart update days.
- Enhanced MedianExtension to ensure correct median calculation.
- Removed unused imports and commented-out code for cleaner implementation.
- Using round() will push values up too early.
Example: log(999) / log(1024) = 0.999
.round() = 1.
Result: 0.98 kB instead of 999 B
- Use correct units, as base1024 = KiB, MiB, etc. and base1000 = kB, MB, GB, ...
- Move the cacheDir creation to storage_provider from `others.dart`, `custom_extended_image_provider.dart` and `storage_usage.dart`.
- Use the correct directory, `getApplicationCacheDirectory()` instead of the `getTemporaryDirectory()` (which is being deleted by the OS regularly) for cache files.
- remove the `_cacheDownloadPath` from `storage_usage.dart` as the path is never being created in the first place, so using that path in `clearCache()` and `_getTotalDiskSpace()` is unnecessary.
- allow multiple local folders
- added support for scanning .epub novels
- added metadata,json support
- scanned entries now appear in browse screen instead of the default library category (can be added to library)
- Introduced `TransitionViewPaged` and `TransitionViewVertical` widgets to handle chapter transitions.
- Created `ChapterTransitionPage` widget to display transition information between chapters.
- Updated reader view logic to incorporate transition pages when navigating chapters.
- Enhanced `UChapDataPreload` model to support transition states and next chapter information.
feat(localization): add chapter transition messages in multiple languages
fix(dependencies): update Dart SDK and dependencies
- Updated Dart SDK constraint to ^3.8.0.
- Changed `epubx` dependency to use the latest version from GitHub.