mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-03-11 17:25:32 +00:00
feat: can now download m3u8 videos
This commit is contained in:
parent
3bf1d08e0e
commit
8ed6b21125
14 changed files with 271 additions and 70 deletions
|
|
@ -41,11 +41,13 @@ class AnimePlayerView extends riv.ConsumerStatefulWidget {
|
|||
|
||||
class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
|
||||
String? _infoHash;
|
||||
HttpServer? _httpServer;
|
||||
@override
|
||||
void dispose() {
|
||||
if (_infoHash != null) {
|
||||
MTorrentServer().removeTorrent(_infoHash);
|
||||
}
|
||||
_httpServer?.close();
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
overlays: SystemUiOverlay.values);
|
||||
super.dispose();
|
||||
|
|
@ -58,8 +60,9 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
|
|||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
return serversData.when(
|
||||
data: (data) {
|
||||
final (videos, isLocal, infoHash) = data;
|
||||
final (videos, isLocal, infoHash, httpServer) = data;
|
||||
_infoHash = infoHash;
|
||||
_httpServer = httpServer;
|
||||
if (videos.isEmpty &&
|
||||
!(widget.episode.manga.value!.isLocalArchive ?? false)) {
|
||||
return Scaffold(
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import 'package:mangayomi/providers/storage_provider.dart';
|
|||
import 'package:mangayomi/services/get_video_list.dart';
|
||||
import 'package:mangayomi/services/get_chapter_pages.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:mangayomi/services/m3u8/m3u8_downloader.dart';
|
||||
import 'package:mangayomi/utils/extensions/string_extensions.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
|
|
@ -47,7 +48,9 @@ Future<List<PageUrl>> downloadChapter(
|
|||
"downloads/${isManga ? "Manga" : "Anime"}/${manga.source} (${manga.lang!.toUpperCase()})/${manga.name!.replaceForbiddenCharacters('_')}${isManga ? "/$scanlator${chapter.name!.replaceForbiddenCharacters('_')}" : ""}";
|
||||
path = Directory("${path1!.path}$finalPath/");
|
||||
Map<String, String> videoHeader = {};
|
||||
|
||||
bool hasM3U8File = false;
|
||||
bool nonM3U8File = false;
|
||||
M3u8Downloader? m3u8Downloader;
|
||||
void savePageUrls() {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
List<ChapterPageurls>? chapterPageUrls = [];
|
||||
|
|
@ -82,15 +85,36 @@ Future<List<PageUrl>> downloadChapter(
|
|||
});
|
||||
} else {
|
||||
ref
|
||||
.read(getVideoListProvider(
|
||||
episode: chapter,
|
||||
).future)
|
||||
.then((value) {
|
||||
final videosUrls = value.$1
|
||||
.read(
|
||||
getVideoListProvider(episode: chapter, ignoreM3u8File: true).future)
|
||||
.then((value) async {
|
||||
final m3u8Urls = value.$1
|
||||
.where((element) =>
|
||||
element.originalUrl.endsWith(".m3u8") ||
|
||||
element.originalUrl.endsWith(".m3u"))
|
||||
.toList();
|
||||
final nonM3u8Urls = value.$1
|
||||
.where((element) => element.originalUrl.isMediaVideo())
|
||||
.toList();
|
||||
nonM3U8File = nonM3u8Urls.isNotEmpty && !Platform.isIOS;
|
||||
hasM3U8File = nonM3U8File ? false : m3u8Urls.isNotEmpty;
|
||||
final videosUrls = nonM3U8File
|
||||
? nonM3u8Urls
|
||||
: (hasM3U8File || Platform.isIOS)
|
||||
? m3u8Urls
|
||||
: nonM3u8Urls;
|
||||
if (videosUrls.isNotEmpty) {
|
||||
pageUrls = [PageUrl(videosUrls.first.url)];
|
||||
List<TsInfo> tsList = [];
|
||||
if (hasM3U8File) {
|
||||
m3u8Downloader = M3u8Downloader(
|
||||
m3u8Url: videosUrls.first.url,
|
||||
downloadDir: "${path!.path}$chapterName",
|
||||
headers: videosUrls.first.headers ?? {});
|
||||
tsList = await m3u8Downloader!.getTsList();
|
||||
}
|
||||
pageUrls = hasM3U8File
|
||||
? [...tsList.map((e) => PageUrl(e.url))]
|
||||
: [PageUrl(videosUrls.first.url)];
|
||||
videoHeader.addAll(videosUrls.first.headers ?? {});
|
||||
isOk = true;
|
||||
}
|
||||
|
|
@ -202,6 +226,28 @@ Future<List<PageUrl>> downloadChapter(
|
|||
if (file.existsSync()) {
|
||||
await file.copy("${path.path}$chapterName.mp4");
|
||||
await file.delete();
|
||||
} else if (hasM3U8File) {
|
||||
final tempFile = File(
|
||||
"${tempDir.path}/Mangayomi/$finalPath/$chapterName/TS_${index + 1}.ts");
|
||||
final file = File("${path.path}$chapterName/TS_${index + 1}.ts");
|
||||
if (tempFile.existsSync()) {
|
||||
await tempFile
|
||||
.copy("${path.path}$chapterName/TS_${index + 1}.ts");
|
||||
await tempFile.delete();
|
||||
} else if (file.existsSync()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: page.url,
|
||||
headers: pageHeaders,
|
||||
url: page.url.trim().trimLeft().trimRight(),
|
||||
filename: "TS_${index + 1}.ts",
|
||||
baseDirectory: BaseDirectory.temporary,
|
||||
directory: 'Mangayomi/$finalPath/$chapterName/',
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
retries: 3,
|
||||
requiresWiFi: onlyOnWifi));
|
||||
}
|
||||
} else {
|
||||
if ((await path.exists())) {
|
||||
if (await File("${path.path}$chapterName.mp4").exists()) {
|
||||
|
|
@ -259,15 +305,21 @@ Future<List<PageUrl>> downloadChapter(
|
|||
await FileDownloader().downloadBatch(
|
||||
tasks,
|
||||
batchProgressCallback: (succeeded, failed) async {
|
||||
if (isManga) {
|
||||
if (isManga || hasM3U8File) {
|
||||
if (succeeded == tasks.length) {
|
||||
if (hasM3U8File) {
|
||||
} else {
|
||||
savePageUrls();
|
||||
if (ref.watch(saveAsCBZArchiveStateProvider)) {
|
||||
await ref.watch(convertToCBZProvider(path!.path, mangaDir.path,
|
||||
chapter.name!, pageUrls.map((e) => e.url).toList())
|
||||
await ref.watch(convertToCBZProvider(
|
||||
path!.path,
|
||||
mangaDir.path,
|
||||
chapter.name!,
|
||||
pageUrls.map((e) => e.url).toList())
|
||||
.future);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool isEmpty = isar.downloads
|
||||
.filter()
|
||||
.chapterIdEqualTo(chapter.id!)
|
||||
|
|
@ -301,7 +353,7 @@ Future<List<PageUrl>> downloadChapter(
|
|||
},
|
||||
taskProgressCallback: (taskProgress) async {
|
||||
final progress = taskProgress.progress;
|
||||
if (!isManga) {
|
||||
if (!isManga && !hasM3U8File) {
|
||||
bool isEmpty = isar.downloads
|
||||
.filter()
|
||||
.chapterIdEqualTo(chapter.id!)
|
||||
|
|
@ -335,7 +387,8 @@ Future<List<PageUrl>> downloadChapter(
|
|||
if (progress == 1.0) {
|
||||
final file = File(
|
||||
"${tempDir.path}/${taskProgress.task.directory}/${taskProgress.task.filename}");
|
||||
await file.copy("${path!.path}${taskProgress.task.filename}");
|
||||
await file.copy(
|
||||
"${path!.path}${hasM3U8File ? "$chapterName/" : ""}${taskProgress.task.filename}");
|
||||
await file.delete();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'eca8ccbe5f93f07c3471af81355fe9b3a8ec11e8';
|
||||
String _$downloadChapterHash() => r'ceb6f5d311f5da585b0272a0af598532ab511adc';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'aniskip.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$aniSkipHash() => r'04cf38b827f60d846b1d8fe87e994e9876d106ff';
|
||||
String _$aniSkipHash() => r'2e5d19b025a2207ff64da7bf7908450ea9e5ff8c';
|
||||
|
||||
/// See also [AniSkip].
|
||||
@ProviderFor(AniSkip)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/m3u8/m3u8_server.dart';
|
||||
import 'package:mangayomi/services/torrent_server.dart';
|
||||
import 'package:mangayomi/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/extensions/string_extensions.dart';
|
||||
|
|
@ -13,20 +14,27 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|||
part 'get_video_list.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<(List<Video>, bool, String?)> getVideoList(
|
||||
GetVideoListRef ref, {
|
||||
required Chapter episode,
|
||||
}) async {
|
||||
Future<(List<Video>, bool, String?, HttpServer?)> getVideoList(
|
||||
GetVideoListRef ref,
|
||||
{required Chapter episode,
|
||||
bool ignoreM3u8File = false}) async {
|
||||
final storageProvider = StorageProvider();
|
||||
final mangaDirectory = await storageProvider.getMangaMainDirectory(episode);
|
||||
final isLocalArchive = episode.manga.value!.isLocalArchive! &&
|
||||
episode.manga.value!.source != "torrent";
|
||||
final mp4animePath =
|
||||
"${mangaDirectory!.path}${episode.name!.replaceForbiddenCharacters(' ')}.mp4";
|
||||
final episodeFolderPath =
|
||||
"${mangaDirectory.path}${episode.name!.replaceForbiddenCharacters(' ')}";
|
||||
|
||||
if (await File(mp4animePath).exists() || isLocalArchive) {
|
||||
final path = isLocalArchive ? episode.archivePath : mp4animePath;
|
||||
return ([Video(path!, episode.name!, path, subtitles: [])], true, null);
|
||||
return (
|
||||
[Video(path!, episode.name!, path, subtitles: [])],
|
||||
true,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
final source =
|
||||
getSource(episode.manga.value!.lang!, episode.manga.value!.source!);
|
||||
|
|
@ -34,7 +42,19 @@ Future<(List<Video>, bool, String?)> getVideoList(
|
|||
if (source?.isTorrent ?? false || episode.manga.value!.source == "torrent") {
|
||||
final (videos, infohash) = await MTorrentServer()
|
||||
.getTorrentPlaylist(episode.url, episode.archivePath);
|
||||
return (videos, false, infohash);
|
||||
return (videos, false, infohash, null);
|
||||
}
|
||||
if (File("$episodeFolderPath/index.m3u8").existsSync() && !ignoreM3u8File) {
|
||||
const indexUrl = "http://localhost:3000/index.m3u8";
|
||||
final httpServer = await m3u8Server(
|
||||
m3u8Content: File("$episodeFolderPath/index.m3u8").readAsStringSync(),
|
||||
episodeFolderPath: episodeFolderPath);
|
||||
return (
|
||||
[Video(indexUrl, episode.name!, indexUrl)],
|
||||
false,
|
||||
null,
|
||||
httpServer
|
||||
);
|
||||
}
|
||||
List<Video> list = [];
|
||||
if (source?.sourceCodeLanguage == SourceCodeLanguage.dart) {
|
||||
|
|
@ -48,5 +68,5 @@ Future<(List<Video>, bool, String?)> getVideoList(
|
|||
videos.add(video);
|
||||
}
|
||||
}
|
||||
return (videos, false, null);
|
||||
return (videos, false, null, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_video_list.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getVideoListHash() => r'46918505b5cf3401ea9f41a5c287f8746b93b1b8';
|
||||
String _$getVideoListHash() => r'2002f381edbe8c3c5e8a00826b3d9aaf49410e57';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -35,16 +35,18 @@ const getVideoListProvider = GetVideoListFamily();
|
|||
|
||||
/// See also [getVideoList].
|
||||
class GetVideoListFamily
|
||||
extends Family<AsyncValue<(List<Video>, bool, String?)>> {
|
||||
extends Family<AsyncValue<(List<Video>, bool, String?, HttpServer?)>> {
|
||||
/// See also [getVideoList].
|
||||
const GetVideoListFamily();
|
||||
|
||||
/// See also [getVideoList].
|
||||
GetVideoListProvider call({
|
||||
required Chapter episode,
|
||||
bool ignoreM3u8File = false,
|
||||
}) {
|
||||
return GetVideoListProvider(
|
||||
episode: episode,
|
||||
ignoreM3u8File: ignoreM3u8File,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +56,7 @@ class GetVideoListFamily
|
|||
) {
|
||||
return call(
|
||||
episode: provider.episode,
|
||||
ignoreM3u8File: provider.ignoreM3u8File,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -73,15 +76,17 @@ class GetVideoListFamily
|
|||
}
|
||||
|
||||
/// See also [getVideoList].
|
||||
class GetVideoListProvider
|
||||
extends AutoDisposeFutureProvider<(List<Video>, bool, String?)> {
|
||||
class GetVideoListProvider extends AutoDisposeFutureProvider<
|
||||
(List<Video>, bool, String?, HttpServer?)> {
|
||||
/// See also [getVideoList].
|
||||
GetVideoListProvider({
|
||||
required Chapter episode,
|
||||
bool ignoreM3u8File = false,
|
||||
}) : this._internal(
|
||||
(ref) => getVideoList(
|
||||
ref as GetVideoListRef,
|
||||
episode: episode,
|
||||
ignoreM3u8File: ignoreM3u8File,
|
||||
),
|
||||
from: getVideoListProvider,
|
||||
name: r'getVideoListProvider',
|
||||
|
|
@ -93,6 +98,7 @@ class GetVideoListProvider
|
|||
allTransitiveDependencies:
|
||||
GetVideoListFamily._allTransitiveDependencies,
|
||||
episode: episode,
|
||||
ignoreM3u8File: ignoreM3u8File,
|
||||
);
|
||||
|
||||
GetVideoListProvider._internal(
|
||||
|
|
@ -103,13 +109,16 @@ class GetVideoListProvider
|
|||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.episode,
|
||||
required this.ignoreM3u8File,
|
||||
}) : super.internal();
|
||||
|
||||
final Chapter episode;
|
||||
final bool ignoreM3u8File;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<(List<Video>, bool, String?)> Function(GetVideoListRef provider)
|
||||
FutureOr<(List<Video>, bool, String?, HttpServer?)> Function(
|
||||
GetVideoListRef provider)
|
||||
create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
|
|
@ -122,43 +131,51 @@ class GetVideoListProvider
|
|||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
episode: episode,
|
||||
ignoreM3u8File: ignoreM3u8File,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<(List<Video>, bool, String?)>
|
||||
AutoDisposeFutureProviderElement<(List<Video>, bool, String?, HttpServer?)>
|
||||
createElement() {
|
||||
return _GetVideoListProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetVideoListProvider && other.episode == episode;
|
||||
return other is GetVideoListProvider &&
|
||||
other.episode == episode &&
|
||||
other.ignoreM3u8File == ignoreM3u8File;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, episode.hashCode);
|
||||
hash = _SystemHash.combine(hash, ignoreM3u8File.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin GetVideoListRef
|
||||
on AutoDisposeFutureProviderRef<(List<Video>, bool, String?)> {
|
||||
on AutoDisposeFutureProviderRef<(List<Video>, bool, String?, HttpServer?)> {
|
||||
/// The parameter `episode` of this provider.
|
||||
Chapter get episode;
|
||||
|
||||
/// The parameter `ignoreM3u8File` of this provider.
|
||||
bool get ignoreM3u8File;
|
||||
}
|
||||
|
||||
class _GetVideoListProviderElement
|
||||
extends AutoDisposeFutureProviderElement<(List<Video>, bool, String?)>
|
||||
with GetVideoListRef {
|
||||
class _GetVideoListProviderElement extends AutoDisposeFutureProviderElement<
|
||||
(List<Video>, bool, String?, HttpServer?)> with GetVideoListRef {
|
||||
_GetVideoListProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
Chapter get episode => (origin as GetVideoListProvider).episode;
|
||||
@override
|
||||
bool get ignoreM3u8File => (origin as GetVideoListProvider).ignoreM3u8File;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
|
|||
64
lib/services/m3u8/m3u8_downloader.dart
Normal file
64
lib/services/m3u8/m3u8_downloader.dart
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import 'dart:io';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class TsInfo {
|
||||
final String name;
|
||||
final String url;
|
||||
TsInfo(this.name, this.url);
|
||||
}
|
||||
|
||||
class M3u8Downloader {
|
||||
final String m3u8Url;
|
||||
final String downloadDir;
|
||||
final Map<String, String>? headers;
|
||||
M3u8Downloader(
|
||||
{required this.m3u8Url,
|
||||
required this.downloadDir,
|
||||
required this.headers});
|
||||
|
||||
Future<List<TsInfo>> getTsList() async {
|
||||
final uri = Uri.parse(m3u8Url);
|
||||
final m3u8Host = "${uri.scheme}://${uri.host}${path.dirname(uri.path)}";
|
||||
final m3u8Body = await _getM3u8Body(m3u8Url, headers);
|
||||
final tsList = _parseTsList(m3u8Host, m3u8Body);
|
||||
if (kDebugMode) {
|
||||
print("Total TS files to download: ${tsList.length}");
|
||||
}
|
||||
return tsList;
|
||||
}
|
||||
|
||||
Future<String> _getM3u8Body(String url, Map<String, String>? headers) async {
|
||||
final response =
|
||||
await MClient.httpClient().get(Uri.parse(url), headers: headers);
|
||||
if (response.statusCode == 200) {
|
||||
return response.body;
|
||||
} else {
|
||||
throw Exception("Failed to load m3u8 body");
|
||||
}
|
||||
}
|
||||
|
||||
List<TsInfo> _parseTsList(String host, String body) {
|
||||
final lines = body.split("\n");
|
||||
final tsList = <TsInfo>[];
|
||||
int index = 0;
|
||||
String allText = "";
|
||||
for (final line in lines) {
|
||||
if (!line.startsWith("#") && line.isNotEmpty) {
|
||||
index++;
|
||||
final tsUrl = line.startsWith("http")
|
||||
? line
|
||||
: "$host/${line.replaceFirst("/", "")}";
|
||||
allText += "http://localhost:3000/TS_$index.ts\n";
|
||||
tsList.add(TsInfo("TS_$index", tsUrl));
|
||||
} else {
|
||||
allText += "$line\n";
|
||||
}
|
||||
}
|
||||
Directory(downloadDir).createSync(recursive: true);
|
||||
File("$downloadDir/index.m3u8").writeAsStringSync(allText);
|
||||
return tsList;
|
||||
}
|
||||
}
|
||||
41
lib/services/m3u8/m3u8_server.dart
Normal file
41
lib/services/m3u8/m3u8_server.dart
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart' as io;
|
||||
|
||||
Future<HttpServer> m3u8Server(
|
||||
{required String m3u8Content, required String episodeFolderPath}) async {
|
||||
final handler =
|
||||
const Pipeline().addMiddleware(logRequests()).addHandler((request) {
|
||||
return _handleRequest(request, m3u8Content, episodeFolderPath);
|
||||
});
|
||||
final server = await io.serve(handler, 'localhost', 3000);
|
||||
if (kDebugMode) {
|
||||
print(
|
||||
'[INFO-M3U8_SERVER] Listening on running on http://${server.address.host}:${server.port}');
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
Response _handleRequest(
|
||||
Request request, String m3u8Content, String episodeFolderPath) {
|
||||
if (request.url.path == 'index.m3u8') {
|
||||
return Response.ok(m3u8Content,
|
||||
headers: {'Content-Type': 'application/vnd.apple.mpegurl'});
|
||||
}
|
||||
if (request.url.path.endsWith('.ts')) {
|
||||
final tsFilePath = '$episodeFolderPath/${request.url.pathSegments.last}';
|
||||
final file = File(tsFilePath);
|
||||
|
||||
if (file.existsSync()) {
|
||||
return Response.ok(file.openRead(), headers: {
|
||||
'Content-Type': 'video/MP2T',
|
||||
});
|
||||
} else {
|
||||
return Response.notFound('File not found');
|
||||
}
|
||||
}
|
||||
|
||||
return Response.notFound('Not exist');
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ part of 'anilist.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$anilistHash() => r'4d54bf86bb2f1133e77609c94b22f4ad17837f20';
|
||||
String _$anilistHash() => r'd3a8852d689b13c3bde46ec05b464e7779149e58';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'kitsu.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$kitsuHash() => r'b9e7867b0c059c8983189d8b94bc6d6a1c1bd3c5';
|
||||
String _$kitsuHash() => r'6953b7520cc144f42992bbecc0d5306841c2382f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'myanimelist.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$myAnimeListHash() => r'90ac28c6fb5ea17c085e8ffa77eddbe48ea1948d';
|
||||
String _$myAnimeListHash() => r'd69a03e6f385688047c13771528c086542e03218';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
26
pubspec.lock
26
pubspec.lock
|
|
@ -5,10 +5,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
version: "73.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
|
|
@ -18,10 +18,10 @@ packages:
|
|||
dependency: "direct overridden"
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
version: "6.8.0"
|
||||
analyzer_plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -215,13 +215,13 @@ packages:
|
|||
source: hosted
|
||||
version: "4.10.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
version: "1.19.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -697,10 +697,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
version: "4.1.0"
|
||||
http_profile:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1033,7 +1033,7 @@ packages:
|
|||
source: hosted
|
||||
version: "3.0.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
|
|
@ -1377,13 +1377,13 @@ packages:
|
|||
source: hosted
|
||||
version: "4.0.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
version: "1.4.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ dependencies:
|
|||
path: rhttp
|
||||
ref: main
|
||||
cupertino_http: ^1.5.1
|
||||
shelf: ^1.4.2
|
||||
path: ^1.9.0
|
||||
|
||||
dependency_overrides:
|
||||
http: ^1.2.1
|
||||
|
|
@ -104,6 +106,7 @@ dependency_overrides:
|
|||
path: media_kit_video
|
||||
ref: 50c510d018cc5286eb6730f3ea165290f19dc5f6
|
||||
meta: ^1.15.0
|
||||
collection: ^1.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
36
rust/Cargo.lock
generated
36
rust/Cargo.lock
generated
|
|
@ -697,9 +697,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
|
|
@ -709,9 +709,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
|
|
@ -1096,9 +1096,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -1108,9 +1108,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
|
@ -1154,18 +1154,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1222,9 +1222,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1252,18 +1252,18 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
Loading…
Reference in a new issue