diff --git a/violet/lib/component/hentai.dart b/violet/lib/component/hentai.dart index 35705cee0..a72e16864 100644 --- a/violet/lib/component/hentai.dart +++ b/violet/lib/component/hentai.dart @@ -560,9 +560,13 @@ class HentaiManager { case 'Hitomi': { - var urls = await HitomiManager.getImageList(qr.id().toString()); - if (urls.$1.isEmpty || urls.$2.isEmpty) break; - return HitomiImageProvider(urls, qr.id().toString()); + final imgList = + await HitomiManager.getImageList(qr.id().toString()); + if (imgList.bigThumbnails.isEmpty || + imgList.bigThumbnails.isEmpty) { + break; + } + return HitomiImageProvider(imgList, qr.id().toString()); } case 'Hisoki': diff --git a/violet/lib/component/hitomi/hitomi.dart b/violet/lib/component/hitomi/hitomi.dart index 3eecd1e57..b53640757 100644 --- a/violet/lib/component/hitomi/hitomi.dart +++ b/violet/lib/component/hitomi/hitomi.dart @@ -13,13 +13,24 @@ import 'package:violet/script/script_manager.dart'; import 'package:violet/settings/settings.dart'; import 'package:violet/variables.dart'; +class ImageList { + final List urls; + final List bigThumbnails; + final List? smallThumbnails; + + const ImageList({ + required this.urls, + required this.bigThumbnails, + this.smallThumbnails, + }); +} + class HitomiManager { // [Image List], [Big Thumbnail List (Perhaps only two are valid.)], [Small Thubmnail List] - static Future<(List, List, List)> getImageList( - String id) async { + static Future getImageList(String id) async { final result = await ScriptManager.runHitomiGetImageList(int.parse(id)); if (result != null) return result; - return const ([], [], []); + return const ImageList(urls: [], bigThumbnails: []); } static int? getArticleCount(String classification, String name) { diff --git a/violet/lib/component/hitomi/hitomi_provider.dart b/violet/lib/component/hitomi/hitomi_provider.dart index 209b1d39c..70472108e 100644 --- a/violet/lib/component/hitomi/hitomi_provider.dart +++ b/violet/lib/component/hitomi/hitomi_provider.dart @@ -10,22 +10,22 @@ import 'package:violet/network/wrapper.dart' as http; import 'package:violet/script/script_manager.dart'; class HitomiImageProvider extends VioletImageProvider { - (List, List, List?) urls; + ImageList imageList; String id; - HitomiImageProvider(this.urls, this.id); + HitomiImageProvider(this.imageList, this.id); @override Future init() async {} @override Future> getSmallImagesUrl() async { - return urls.$3 ?? []; + return imageList.smallThumbnails ?? []; } @override Future getThumbnailUrl() async { - return urls.$2[0]; + return imageList.bigThumbnails[0]; } @override @@ -41,18 +41,18 @@ class HitomiImageProvider extends VioletImageProvider { @override Future getImageUrl(int page) async { - return urls.$1[page]; + return imageList.urls[page]; } @override bool canGetImageUrlSync() => true; @override - String getImageUrlSync(int page) => urls.$1[page]; + String getImageUrlSync(int page) => imageList.urls[page]; @override int length() { - return urls.$1.length; + return imageList.urls.length; } List? _heightCache; @@ -60,16 +60,22 @@ class HitomiImageProvider extends VioletImageProvider { @override Future getEstimatedImageHeight(int page, double baseWidth) async { - if (urls.$3 == null || urls.$3!.length <= page) return -1; + if (imageList.smallThumbnails == null || + imageList.smallThumbnails!.length <= page) { + return -1; + } if (_estimatedCache == null) { - _estimatedCache = List.filled(urls.$3!.length, 0); + _estimatedCache = + List.filled(imageList.smallThumbnails!.length, 0); } else if (_estimatedCache![page] != 0) { return _estimatedCache![page]; } final header = await getHeader(page); - final image = (await http.get(urls.$3![page], headers: header)).bodyBytes; + final image = + (await http.get(imageList.smallThumbnails![page], headers: header)) + .bodyBytes; final thumbSize = ImageSizeGetter.getSize(MemoryInput(image)); // w1:h1=w2:h2 @@ -91,34 +97,34 @@ class HitomiImageProvider extends VioletImageProvider { @override Future refresh() async { - urls = await HitomiManager.getImageList(id); + imageList = await HitomiManager.getImageList(id); } @override Future refreshPartial(List target) async { - if (urls.$1.length != target.length) { + if (imageList.urls.length != target.length) { await refresh(); return; } final turls = await HitomiManager.getImageList(id); - for (var i = 0; i < turls.$1.length; i++) { - if (target[i]) urls.$1[i] = turls.$1[i]; + for (var i = 0; i < turls.urls.length; i++) { + if (target[i]) imageList.urls[i] = turls.urls[i]; } } @override Future getOriginalImageHeight(int page) async { if (_heightCache == null) { - _heightCache = List.filled(urls.$3!.length, 0); + _heightCache = List.filled(imageList.smallThumbnails!.length, 0); } else if (_heightCache![page] != 0) { return _heightCache![page]; } final info = await ScriptManager.getGalleryInfo(id); if (info == null) { - _heightCache = List.filled(urls.$3!.length, -1); + _heightCache = List.filled(imageList.smallThumbnails!.length, -1); return -1; } diff --git a/violet/lib/pages/download/download_item_widget.dart b/violet/lib/pages/download/download_item_widget.dart index d2fd42655..d9ef620b4 100644 --- a/violet/lib/pages/download/download_item_widget.dart +++ b/violet/lib/pages/download/download_item_widget.dart @@ -722,7 +722,7 @@ class _ThumbnailWidget extends StatelessWidget { future: HitomiManager.getImageList(id.toString()).then((value) async { var header = await ScriptManager.runHitomiGetHeaderContent(id.toString()); - return (value.$1[0], header); + return (value.urls[0], header); }), builder: (context, AsyncSnapshot<(String, Map)> snapshot) { diff --git a/violet/lib/pages/viewer/overlay/viewer_thumbnails.dart b/violet/lib/pages/viewer/overlay/viewer_thumbnails.dart index 486f09d15..17218b2cd 100644 --- a/violet/lib/pages/viewer/overlay/viewer_thumbnails.dart +++ b/violet/lib/pages/viewer/overlay/viewer_thumbnails.dart @@ -146,10 +146,11 @@ class _ViewerThumbnailState extends State { ProviderManager.insert(_pageInfo.id * 1000000, prov); } else { try { - var urls = + var imgList = await HitomiManager.getImageList(_pageInfo.id.toString()); - if (urls.$1.isNotEmpty && urls.$2.isNotEmpty) { - prov = HitomiImageProvider(urls, _pageInfo.id.toString()); + if (imgList.urls.isNotEmpty && + imgList.bigThumbnails.isNotEmpty) { + prov = HitomiImageProvider(imgList, _pageInfo.id.toString()); ProviderManager.insert(_pageInfo.id * 1000000, prov); } } catch (_) {} diff --git a/violet/lib/script/freezed/script_model.dart b/violet/lib/script/freezed/script_model.dart new file mode 100644 index 000000000..180d3206c --- /dev/null +++ b/violet/lib/script/freezed/script_model.dart @@ -0,0 +1,20 @@ +// This source code is a part of Project Violet. +// Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License. + +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:flutter/foundation.dart'; + +part 'script_model.freezed.dart'; +part 'script_model.g.dart'; + +@freezed +class ScriptImageList with _$ScriptImageList { + const factory ScriptImageList({ + required List result, + required List btresult, + required List stresult, + }) = _ScriptImageList; + + factory ScriptImageList.fromJson(Map json) => + _$ScriptImageListFromJson(json); +} diff --git a/violet/lib/script/freezed/script_model.freezed.dart b/violet/lib/script/freezed/script_model.freezed.dart new file mode 100644 index 000000000..d7cc19c71 --- /dev/null +++ b/violet/lib/script/freezed/script_model.freezed.dart @@ -0,0 +1,228 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'script_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ScriptImageList _$ScriptImageListFromJson(Map json) { + return _ScriptImageList.fromJson(json); +} + +/// @nodoc +mixin _$ScriptImageList { + List get result => throw _privateConstructorUsedError; + List get btresult => throw _privateConstructorUsedError; + List get stresult => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ScriptImageListCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ScriptImageListCopyWith<$Res> { + factory $ScriptImageListCopyWith( + ScriptImageList value, $Res Function(ScriptImageList) then) = + _$ScriptImageListCopyWithImpl<$Res, ScriptImageList>; + @useResult + $Res call( + {List result, List btresult, List stresult}); +} + +/// @nodoc +class _$ScriptImageListCopyWithImpl<$Res, $Val extends ScriptImageList> + implements $ScriptImageListCopyWith<$Res> { + _$ScriptImageListCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? result = null, + Object? btresult = null, + Object? stresult = null, + }) { + return _then(_value.copyWith( + result: null == result + ? _value.result + : result // ignore: cast_nullable_to_non_nullable + as List, + btresult: null == btresult + ? _value.btresult + : btresult // ignore: cast_nullable_to_non_nullable + as List, + stresult: null == stresult + ? _value.stresult + : stresult // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ScriptImageListImplCopyWith<$Res> + implements $ScriptImageListCopyWith<$Res> { + factory _$$ScriptImageListImplCopyWith(_$ScriptImageListImpl value, + $Res Function(_$ScriptImageListImpl) then) = + __$$ScriptImageListImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {List result, List btresult, List stresult}); +} + +/// @nodoc +class __$$ScriptImageListImplCopyWithImpl<$Res> + extends _$ScriptImageListCopyWithImpl<$Res, _$ScriptImageListImpl> + implements _$$ScriptImageListImplCopyWith<$Res> { + __$$ScriptImageListImplCopyWithImpl( + _$ScriptImageListImpl _value, $Res Function(_$ScriptImageListImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? result = null, + Object? btresult = null, + Object? stresult = null, + }) { + return _then(_$ScriptImageListImpl( + result: null == result + ? _value._result + : result // ignore: cast_nullable_to_non_nullable + as List, + btresult: null == btresult + ? _value._btresult + : btresult // ignore: cast_nullable_to_non_nullable + as List, + stresult: null == stresult + ? _value._stresult + : stresult // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ScriptImageListImpl + with DiagnosticableTreeMixin + implements _ScriptImageList { + const _$ScriptImageListImpl( + {required final List result, + required final List btresult, + required final List stresult}) + : _result = result, + _btresult = btresult, + _stresult = stresult; + + factory _$ScriptImageListImpl.fromJson(Map json) => + _$$ScriptImageListImplFromJson(json); + + final List _result; + @override + List get result { + if (_result is EqualUnmodifiableListView) return _result; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_result); + } + + final List _btresult; + @override + List get btresult { + if (_btresult is EqualUnmodifiableListView) return _btresult; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_btresult); + } + + final List _stresult; + @override + List get stresult { + if (_stresult is EqualUnmodifiableListView) return _stresult; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_stresult); + } + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'ScriptImageList(result: $result, btresult: $btresult, stresult: $stresult)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'ScriptImageList')) + ..add(DiagnosticsProperty('result', result)) + ..add(DiagnosticsProperty('btresult', btresult)) + ..add(DiagnosticsProperty('stresult', stresult)); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ScriptImageListImpl && + const DeepCollectionEquality().equals(other._result, _result) && + const DeepCollectionEquality().equals(other._btresult, _btresult) && + const DeepCollectionEquality().equals(other._stresult, _stresult)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_result), + const DeepCollectionEquality().hash(_btresult), + const DeepCollectionEquality().hash(_stresult)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ScriptImageListImplCopyWith<_$ScriptImageListImpl> get copyWith => + __$$ScriptImageListImplCopyWithImpl<_$ScriptImageListImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ScriptImageListImplToJson( + this, + ); + } +} + +abstract class _ScriptImageList implements ScriptImageList { + const factory _ScriptImageList( + {required final List result, + required final List btresult, + required final List stresult}) = _$ScriptImageListImpl; + + factory _ScriptImageList.fromJson(Map json) = + _$ScriptImageListImpl.fromJson; + + @override + List get result; + @override + List get btresult; + @override + List get stresult; + @override + @JsonKey(ignore: true) + _$$ScriptImageListImplCopyWith<_$ScriptImageListImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/violet/lib/script/freezed/script_model.g.dart b/violet/lib/script/freezed/script_model.g.dart new file mode 100644 index 000000000..4e03dffa1 --- /dev/null +++ b/violet/lib/script/freezed/script_model.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'script_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ScriptImageListImpl _$$ScriptImageListImplFromJson( + Map json) => + _$ScriptImageListImpl( + result: + (json['result'] as List).map((e) => e as String).toList(), + btresult: + (json['btresult'] as List).map((e) => e as String).toList(), + stresult: + (json['stresult'] as List).map((e) => e as String).toList(), + ); + +Map _$$ScriptImageListImplToJson( + _$ScriptImageListImpl instance) => + { + 'result': instance.result, + 'btresult': instance.btresult, + 'stresult': instance.stresult, + }; diff --git a/violet/lib/script/script_manager.dart b/violet/lib/script/script_manager.dart index 920cc9e15..8500986e0 100644 --- a/violet/lib/script/script_manager.dart +++ b/violet/lib/script/script_manager.dart @@ -6,9 +6,11 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter_js/flutter_js.dart'; import 'package:html/parser.dart'; +import 'package:violet/component/hitomi/hitomi.dart'; import 'package:violet/context/viewer_context.dart'; import 'package:violet/log/log.dart'; import 'package:violet/network/wrapper.dart' as http; +import 'package:violet/script/freezed/script_model.dart'; import 'package:violet/script/script_webview.dart'; import 'package:violet/widgets/article_item/image_provider_manager.dart'; @@ -121,8 +123,7 @@ class ScriptManager { return galleryInfo.body; } - static Future<(List, List, List)?> - runHitomiGetImageList(int id) async { + static Future runHitomiGetImageList(int id) async { if (_scriptCache == null) return null; try { @@ -134,26 +135,13 @@ class ScriptManager { if (galleryInfo.statusCode != 200) return null; _runtime.evaluate(galleryInfo.body); final jResult = _runtime.evaluate('hitomi_get_image_list()').stringResult; - final jResultObject = jsonDecode(jResult); + final jResultImageList = ScriptImageList.fromJson(jsonDecode(jResult)); - if (jResultObject is Map) { - return ( - (jResultObject['result'] as List) - .map((e) => e as String) - .toList(), - (jResultObject['btresult'] as List) - .map((e) => e as String) - .toList(), - (jResultObject['stresult'] as List) - .map((e) => e as String) - .toList() - ); - } else { - Logger.error('[script-HitomiGetImageList] E: JSError\n' - 'Id: $id\n' - 'Message: $jResult'); - return null; - } + return ImageList( + urls: jResultImageList.result, + bigThumbnails: jResultImageList.btresult, + smallThumbnails: jResultImageList.stresult, + ); } catch (e, st) { Logger.error('[script-HitomiGetImageList] E: $e\n' 'Id: $id\n' diff --git a/violet/pubspec.lock b/violet/pubspec.lock index 88055a420..389df5a2f 100644 --- a/violet/pubspec.lock +++ b/violet/pubspec.lock @@ -182,10 +182,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.11" build_runner_core: dependency: transitive description: @@ -867,18 +867,18 @@ packages: dependency: "direct dev" description: name: freezed - sha256: b2a49420e37993b14de4e2096ff37545154e3f0bdc3c6b217e10bbba400aaad8 + sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1 url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.5.2" freezed_annotation: dependency: "direct main" description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.4" frontend_server_client: dependency: transitive description: @@ -1035,21 +1035,21 @@ packages: source: hosted version: "0.6.7" json_annotation: - dependency: transitive + dependency: "direct main" description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b url: "https://pub.dev" source: hosted - version: "6.7.1" + version: "6.8.0" kdtree: dependency: "direct main" description: @@ -1960,5 +1960,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.4.0 <4.0.0" flutter: ">=3.19.6" diff --git a/violet/pubspec.yaml b/violet/pubspec.yaml index de8faab2b..188ea0f41 100644 --- a/violet/pubspec.yaml +++ b/violet/pubspec.yaml @@ -100,7 +100,7 @@ dependencies: flutter_js: ^0.8.0 flutter_windowmanager: ^0.2.0 fluttertoast: ^8.2.4 - freezed_annotation: + freezed_annotation: ^2.4.4 get: ^4.6.6 gradient_widgets: ^0.6.0 html: ^0.15.0 @@ -144,13 +144,14 @@ dependencies: rust_lib_violet: path: rust_builder flutter_rust_bridge: 2.0.0-dev.24 + json_annotation: ^4.9.0 dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.4.4 - json_serializable: ^6.7.0 - freezed: ^2.3.5 + json_serializable: ^6.8.0 + freezed: ^2.5.2 drift_sqflite: ^2.0.0 sqflite_common_ffi: flutter_lints: ^3.0.0