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.