mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 15:02:07 +00:00
torrent server integration
This commit is contained in:
parent
3f108e1c43
commit
7e245e3bc2
5 changed files with 115 additions and 37 deletions
|
|
@ -133,6 +133,8 @@ class Source {
|
|||
'additionalParams': additionalParams,
|
||||
};
|
||||
|
||||
bool get isTorrent => (typeSource?.toLowerCase() ?? "") == "torrent";
|
||||
|
||||
MSource toMSource() {
|
||||
return MSource(
|
||||
id: id,
|
||||
|
|
|
|||
|
|
@ -92,43 +92,48 @@ const SourceSchema = CollectionSchema(
|
|||
name: r'isPinned',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
r'isTorrent': PropertySchema(
|
||||
id: 15,
|
||||
name: r'isTorrent',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'lang': PropertySchema(
|
||||
id: 16,
|
||||
name: r'lang',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'lastUsed': PropertySchema(
|
||||
id: 16,
|
||||
id: 17,
|
||||
name: r'lastUsed',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'name': PropertySchema(
|
||||
id: 17,
|
||||
id: 18,
|
||||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCode': PropertySchema(
|
||||
id: 18,
|
||||
id: 19,
|
||||
name: r'sourceCode',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCodeUrl': PropertySchema(
|
||||
id: 19,
|
||||
id: 20,
|
||||
name: r'sourceCodeUrl',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'typeSource': PropertySchema(
|
||||
id: 20,
|
||||
id: 21,
|
||||
name: r'typeSource',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'version': PropertySchema(
|
||||
id: 21,
|
||||
id: 22,
|
||||
name: r'version',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'versionLast': PropertySchema(
|
||||
id: 22,
|
||||
id: 23,
|
||||
name: r'versionLast',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -267,14 +272,15 @@ void _sourceSerialize(
|
|||
writer.writeBool(offsets[12], object.isManga);
|
||||
writer.writeBool(offsets[13], object.isNsfw);
|
||||
writer.writeBool(offsets[14], object.isPinned);
|
||||
writer.writeString(offsets[15], object.lang);
|
||||
writer.writeBool(offsets[16], object.lastUsed);
|
||||
writer.writeString(offsets[17], object.name);
|
||||
writer.writeString(offsets[18], object.sourceCode);
|
||||
writer.writeString(offsets[19], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[20], object.typeSource);
|
||||
writer.writeString(offsets[21], object.version);
|
||||
writer.writeString(offsets[22], object.versionLast);
|
||||
writer.writeBool(offsets[15], object.isTorrent);
|
||||
writer.writeString(offsets[16], object.lang);
|
||||
writer.writeBool(offsets[17], object.lastUsed);
|
||||
writer.writeString(offsets[18], object.name);
|
||||
writer.writeString(offsets[19], object.sourceCode);
|
||||
writer.writeString(offsets[20], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[21], object.typeSource);
|
||||
writer.writeString(offsets[22], object.version);
|
||||
writer.writeString(offsets[23], object.versionLast);
|
||||
}
|
||||
|
||||
Source _sourceDeserialize(
|
||||
|
|
@ -300,14 +306,14 @@ Source _sourceDeserialize(
|
|||
isManga: reader.readBoolOrNull(offsets[12]),
|
||||
isNsfw: reader.readBoolOrNull(offsets[13]),
|
||||
isPinned: reader.readBoolOrNull(offsets[14]),
|
||||
lang: reader.readStringOrNull(offsets[15]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[16]),
|
||||
name: reader.readStringOrNull(offsets[17]),
|
||||
sourceCode: reader.readStringOrNull(offsets[18]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[19]),
|
||||
typeSource: reader.readStringOrNull(offsets[20]),
|
||||
version: reader.readStringOrNull(offsets[21]),
|
||||
versionLast: reader.readStringOrNull(offsets[22]),
|
||||
lang: reader.readStringOrNull(offsets[16]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[17]),
|
||||
name: reader.readStringOrNull(offsets[18]),
|
||||
sourceCode: reader.readStringOrNull(offsets[19]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[20]),
|
||||
typeSource: reader.readStringOrNull(offsets[21]),
|
||||
version: reader.readStringOrNull(offsets[22]),
|
||||
versionLast: reader.readStringOrNull(offsets[23]),
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
|
@ -350,11 +356,11 @@ P _sourceDeserializeProp<P>(
|
|||
case 14:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 15:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 16:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 17:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 17:
|
||||
return (reader.readBoolOrNull(offset)) as P;
|
||||
case 18:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 19:
|
||||
|
|
@ -365,6 +371,8 @@ P _sourceDeserializeProp<P>(
|
|||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 22:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 23:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
|
@ -1886,6 +1894,16 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> isTorrentEqualTo(
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isTorrent',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> langIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -3119,6 +3137,18 @@ extension SourceQuerySortBy on QueryBuilder<Source, Source, QSortBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByIsTorrent() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isTorrent', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByIsTorrentDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isTorrent', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> sortByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -3409,6 +3439,18 @@ extension SourceQuerySortThenBy on QueryBuilder<Source, Source, QSortThenBy> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByIsTorrent() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isTorrent', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByIsTorrentDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isTorrent', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterSortBy> thenByLang() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'lang', Sort.asc);
|
||||
|
|
@ -3607,6 +3649,12 @@ extension SourceQueryWhereDistinct on QueryBuilder<Source, Source, QDistinct> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QDistinct> distinctByIsTorrent() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isTorrent');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QDistinct> distinctByLang(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
|
@ -3761,6 +3809,12 @@ extension SourceQueryProperty on QueryBuilder<Source, Source, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, bool, QQueryOperations> isTorrentProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isTorrent');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, String?, QQueryOperations> langProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'lang');
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import 'package:mangayomi/modules/widgets/progress_center.dart';
|
|||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/services/aniskip.dart';
|
||||
import 'package:mangayomi/services/get_video_list.dart';
|
||||
import 'package:mangayomi/services/torrent_server.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
|
|
@ -33,6 +34,13 @@ class AnimePlayerView extends riv.ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
|
||||
String? _infoHash;
|
||||
@override
|
||||
void dispose() {
|
||||
MTorrentServer().removeTorrent(_infoHash);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversData = ref.watch(getVideoListProvider(
|
||||
|
|
@ -41,6 +49,7 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
|
|||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
return serversData.when(
|
||||
data: (data) {
|
||||
_infoHash = data.$3;
|
||||
if (data.$1.isEmpty &&
|
||||
!(widget.episode.manga.value!.isLocalArchive ?? false)) {
|
||||
return Scaffold(
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/eval/runtime/runtime.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/torrent_server.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/sources/source_test.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'get_video_list.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<(List<Video>, bool)> getVideoList(
|
||||
Future<(List<Video>, bool, String?)> getVideoList(
|
||||
GetVideoListRef ref, {
|
||||
required Chapter episode,
|
||||
}) async {
|
||||
|
|
@ -20,13 +21,21 @@ Future<(List<Video>, bool)> getVideoList(
|
|||
final mangaDirectory = await storageProvider.getMangaMainDirectory(episode);
|
||||
final isLocalArchive = episode.manga.value!.isLocalArchive!;
|
||||
final mp4animePath = "${mangaDirectory!.path}${episode.name}.mp4";
|
||||
|
||||
if (await File(mp4animePath).exists() || isLocalArchive) {
|
||||
final path = isLocalArchive ? episode.archivePath : mp4animePath;
|
||||
return ([Video(path!, episode.name!, path, subtitles: [])], true);
|
||||
return ([Video(path!, episode.name!, path, subtitles: [])], true, null);
|
||||
}
|
||||
|
||||
final source =
|
||||
getSource(episode.manga.value!.lang!, episode.manga.value!.source!)!;
|
||||
|
||||
if (source.isTorrent) {
|
||||
final (videos, infohash) =
|
||||
await MTorrentServer().getTorrentPlaylist(episode.url!);
|
||||
return (videos, false, infohash);
|
||||
}
|
||||
|
||||
final bytecode =
|
||||
compilerEval(useTestSourceCode ? testSourceCode : source.sourceCode!);
|
||||
|
||||
|
|
@ -35,5 +44,5 @@ Future<(List<Video>, bool)> getVideoList(
|
|||
var res = runtime.executeLib('package:mangayomi/main.dart', 'main');
|
||||
final dd =
|
||||
(await (res as MProvider).getVideoList(source.toMSource(), episode.url!));
|
||||
return (dd, false);
|
||||
return (dd, false, null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_video_list.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getVideoListHash() => r'924c2961d148f9ebb0952239c0528d5269a4526a';
|
||||
String _$getVideoListHash() => r'd1e21cd01a2d2eda2050c199f255eb0502d67fad';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -34,7 +34,8 @@ class _SystemHash {
|
|||
const getVideoListProvider = GetVideoListFamily();
|
||||
|
||||
/// See also [getVideoList].
|
||||
class GetVideoListFamily extends Family<AsyncValue<(List<Video>, bool)>> {
|
||||
class GetVideoListFamily
|
||||
extends Family<AsyncValue<(List<Video>, bool, String?)>> {
|
||||
/// See also [getVideoList].
|
||||
const GetVideoListFamily();
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ class GetVideoListFamily extends Family<AsyncValue<(List<Video>, bool)>> {
|
|||
|
||||
/// See also [getVideoList].
|
||||
class GetVideoListProvider
|
||||
extends AutoDisposeFutureProvider<(List<Video>, bool)> {
|
||||
extends AutoDisposeFutureProvider<(List<Video>, bool, String?)> {
|
||||
/// See also [getVideoList].
|
||||
GetVideoListProvider({
|
||||
required Chapter episode,
|
||||
|
|
@ -108,7 +109,8 @@ class GetVideoListProvider
|
|||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<(List<Video>, bool)> Function(GetVideoListRef provider) create,
|
||||
FutureOr<(List<Video>, bool, String?)> Function(GetVideoListRef provider)
|
||||
create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
|
|
@ -125,7 +127,8 @@ class GetVideoListProvider
|
|||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<(List<Video>, bool)> createElement() {
|
||||
AutoDisposeFutureProviderElement<(List<Video>, bool, String?)>
|
||||
createElement() {
|
||||
return _GetVideoListProviderElement(this);
|
||||
}
|
||||
|
||||
|
|
@ -143,13 +146,14 @@ class GetVideoListProvider
|
|||
}
|
||||
}
|
||||
|
||||
mixin GetVideoListRef on AutoDisposeFutureProviderRef<(List<Video>, bool)> {
|
||||
mixin GetVideoListRef
|
||||
on AutoDisposeFutureProviderRef<(List<Video>, bool, String?)> {
|
||||
/// The parameter `episode` of this provider.
|
||||
Chapter get episode;
|
||||
}
|
||||
|
||||
class _GetVideoListProviderElement
|
||||
extends AutoDisposeFutureProviderElement<(List<Video>, bool)>
|
||||
extends AutoDisposeFutureProviderElement<(List<Video>, bool, String?)>
|
||||
with GetVideoListRef {
|
||||
_GetVideoListProviderElement(super.provider);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue