String mangaSlugFromUrl(String pageUrl) { try { final parts = Uri.parse(pageUrl).pathSegments.where((s) => s.isNotEmpty).toList(); final mi = parts.indexOf('manga'); if (mi != -1 && mi + 1 < parts.length) { return parts[mi + 1]; } } catch (_) {} return 'comic'; } String mangaBaseUrlFromListingUrl(String pageUrl) { final u = Uri.parse(pageUrl); final parts = u.pathSegments.where((s) => s.isNotEmpty).toList(); final mi = parts.indexOf('manga'); if (mi == -1 || mi + 1 >= parts.length) { throw StateError( 'Could not find /manga/{slug}/ in URL; use a manga or chapter link from MangaRead.', ); } final slug = parts[mi + 1]; return Uri(scheme: u.scheme, host: u.host, path: '/manga/$slug/').toString(); } String listingUrlForSlug(String slug, {String origin = 'https://www.mangaread.org'}) { final base = origin.replaceAll(RegExp(r'/+$'), ''); return '$base/manga/$slug/'; } String chapterKeyFromUrl(String chapterUrl) { try { final segs = Uri.parse(chapterUrl).pathSegments.where((s) => s.isNotEmpty).toList(); return segs.isEmpty ? 'chapter' : segs.last; } catch (_) { return 'chapter'; } } String? chapterNumberFromTitle(String title) { final m = RegExp(r'(?:Chapter|Ch\.?)\s*([\d.]+)', caseSensitive: false) .firstMatch(title.trim().replaceAll(RegExp(r'\s+'), ' ')); return m?.group(1); } String absoluteUrl(String href, String baseHref) { return Uri.parse(baseHref).resolve(href.trim()).toString(); }