From 0a847204026626e03f57b828c4386d964f8ea847 Mon Sep 17 00:00:00 2001 From: 3003h Date: Fri, 3 Nov 2023 01:38:45 +0800 Subject: [PATCH] get image url from api #290 --- jsons/gallery_image.json | 3 +- .../controller/download_controller.dart | 3 +- lib/common/parser/eh_parser.dart | 1 + lib/common/parser/image_page_parser.dart | 9 ++- lib/common/parser/showpage_parser.dart | 74 +++++++++++++++++++ lib/component/exception/error.dart | 2 + lib/models/gallery_image.dart | 19 +++-- lib/network/app_dio/http_transformer.dart | 3 +- lib/network/request.dart | 60 ++++++++++++++- .../controller/gallery_page_controller.dart | 30 ++++++-- lib/pages/image_view/common.dart | 16 ++-- .../controller/view_controller.dart | 3 + .../image_view/view/image_page_view.dart | 2 +- lib/route/navigator_util.dart | 2 +- lib/widget/image/eh_image.dart | 17 +++-- 15 files changed, 212 insertions(+), 32 deletions(-) create mode 100644 lib/common/parser/showpage_parser.dart diff --git a/jsons/gallery_image.json b/jsons/gallery_image.json index 21f7b1161..d101fa758 100644 --- a/jsons/gallery_image.json +++ b/jsons/gallery_image.json @@ -26,5 +26,6 @@ "downloadProcess?": 1.0, "errorInfo?": "", "tempPath?": "", - "filename?": "" + "filename?": "", + "showKey?": "" } \ No newline at end of file diff --git a/lib/common/controller/download_controller.dart b/lib/common/controller/download_controller.dart index f2207ce16..e9a700599 100644 --- a/lib/common/controller/download_controller.dart +++ b/lib/common/controller/download_controller.dart @@ -812,7 +812,7 @@ class DownloadController extends GetxController { }) async { final String? _sourceId = changeSource ? sourceId : ''; - final GalleryImage? _image = await fetchImageInfo( + final GalleryImage? _image = await fetchImageInfoByApi( href, refresh: changeSource, sourceId: _sourceId, @@ -832,6 +832,7 @@ class DownloadController extends GetxController { imageHeight: _image.imageHeight, originImageUrl: _image.originImageUrl, filename: _image.filename, + showKey: _image.showKey, ); return _imageCopyWith; diff --git a/lib/common/parser/eh_parser.dart b/lib/common/parser/eh_parser.dart index f20f5cbb9..1b27180cf 100644 --- a/lib/common/parser/eh_parser.dart +++ b/lib/common/parser/eh_parser.dart @@ -11,5 +11,6 @@ export 'mpv_parser.dart'; export 'mytags_parser.dart'; export 'profile_parser.dart'; export 'search_parser.dart'; +export 'showpage_parser.dart'; export 'torrent_parser.dart'; export 'user_profile_parser.dart'; diff --git a/lib/common/parser/image_page_parser.dart b/lib/common/parser/image_page_parser.dart index 6802d6a63..fa6cbb0dd 100644 --- a/lib/common/parser/image_page_parser.dart +++ b/lib/common/parser/image_page_parser.dart @@ -1,5 +1,6 @@ import 'package:fehviewer/const/const.dart'; import 'package:fehviewer/models/index.dart'; +import 'package:fehviewer/utils/logger.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart' show parse; import 'package:html_unescape/html_unescape.dart'; @@ -57,7 +58,12 @@ GalleryImage paraImage(String htmlText) { originImageUrl = '${htmlUnescape.convert(match!.group(1)!)}fullimg${htmlUnescape.convert(match.group(2)!)}'; } - // print('====================>$originImageUrl'); + logger.t('========>$originImageUrl'); + + // showKey 用于api请求后续图片 script中 + final String showKey = + RegExp(r'showkey="(.*?)"').firstMatch(htmlText)?.group(1) ?? ''; + logger.t('showKey $showKey'); final GalleryImage _reImage = kDefGalleryImage.copyWith( imageUrl: imageUrl, @@ -69,6 +75,7 @@ GalleryImage paraImage(String htmlText) { ser: ser, originImageUrl: originImageUrl, filename: filename, + showKey: showKey, ); return _reImage; diff --git a/lib/common/parser/showpage_parser.dart b/lib/common/parser/showpage_parser.dart new file mode 100644 index 000000000..54e3051f0 --- /dev/null +++ b/lib/common/parser/showpage_parser.dart @@ -0,0 +1,74 @@ +import 'dart:convert'; + +import 'package:fehviewer/component/exception/error.dart'; +import 'package:fehviewer/const/const.dart'; +import 'package:fehviewer/models/index.dart'; +import 'package:fehviewer/utils/logger.dart'; +import 'package:html_unescape/html_unescape.dart'; + +GalleryImage paraShowPage(String jsonString) { + final HtmlUnescape htmlUnescape = HtmlUnescape(); + final jsonMap = jsonDecode(jsonString) as Map; + + final RegExp regImageUrl = RegExp(r']*src="([^"]+)" style'); + final String imageUrl = + regImageUrl.firstMatch('${jsonMap['i3']}')?.group(1) ?? ''; + + // throw EhError(type: EhErrorType.image509); + + if (imageUrl.endsWith('/509.gif') || imageUrl.endsWith('/509s.gif')) { + throw EhError(type: EhErrorType.image509); + } + + logger.d('largeImageUrl $imageUrl'); + + final RegExpMatch? _xy = RegExp(r'(\S+)\s+::\s+(\d+)\s+x\s+(\d+)(\s+::)?') + .firstMatch('${jsonMap['i']}'); + + final String? filename = _xy != null ? _xy.group(1)?.trim() : null; + + // final double? width = _xy != null ? double.parse(_xy.group(2)!) : null; + // final double? height = _xy != null ? double.parse(_xy.group(3)!) : null; + final double? width = double.parse('${jsonMap['x']}'); + final double? height = double.parse('${jsonMap['y']}'); + + if (width == null || height == null) { + throw EhError(type: EhErrorType.parse, error: 'width or height is null'); + } + + final RegExp urlRegExp = + RegExp(r'https?://e[-x]hentai.org/g/([0-9]+)/([0-9a-z]+)/?'); + + final RegExpMatch? urlRult = urlRegExp.firstMatch('${jsonMap['i5']}'); + final gid = urlRult?.group(1) ?? ''; + final token = urlRult?.group(2) ?? ''; + + final int ser = int.parse('${jsonMap['p']}'); + + // 原图链接 + final regExpOriginImageUrl = RegExp(r''); + final match = regExpOriginImageUrl.firstMatch('${jsonMap['i6']}'); + String? originImageUrl; + if (match?.groupCount == 2) { + originImageUrl = + '${htmlUnescape.convert(match!.group(1)!)}fullimg${htmlUnescape.convert(match.group(2)!)}'; + } + logger.d('======>>>> originImageUrl: $originImageUrl'); + + final String _sourceId = + RegExp(r"nl\('(.*?)'\)").firstMatch('${jsonMap['i6']}')?.group(1) ?? ''; + + final GalleryImage _reImage = kDefGalleryImage.copyWith( + imageUrl: imageUrl, + sourceId: _sourceId, + imageWidth: width, + imageHeight: height, + gid: gid, + token: token, + ser: ser, + originImageUrl: originImageUrl, + filename: filename, + ); + + return _reImage; +} diff --git a/lib/component/exception/error.dart b/lib/component/exception/error.dart index cbd5bcc82..3ea245d12 100644 --- a/lib/component/exception/error.dart +++ b/lib/component/exception/error.dart @@ -10,6 +10,8 @@ enum EhErrorType { image509, imageHide, + + parse, } class EhError implements Exception { diff --git a/lib/models/gallery_image.dart b/lib/models/gallery_image.dart index 6218e6ddd..c2b4fe6d3 100644 --- a/lib/models/gallery_image.dart +++ b/lib/models/gallery_image.dart @@ -33,6 +33,7 @@ class GalleryImage { this.errorInfo, this.tempPath, this.filename, + this.showKey, }); final bool? largeThumb; @@ -63,6 +64,7 @@ class GalleryImage { final String? errorInfo; final String? tempPath; final String? filename; + final String? showKey; factory GalleryImage.fromJson(Map json) => GalleryImage( largeThumb: json['largeThumb'] != null ? json['largeThumb'] as bool : null, @@ -92,7 +94,8 @@ class GalleryImage { downloadProcess: json['downloadProcess'] != null ? json['downloadProcess'] as double : null, errorInfo: json['errorInfo'] != null ? json['errorInfo'] as String : null, tempPath: json['tempPath'] != null ? json['tempPath'] as String : null, - filename: json['filename'] != null ? json['filename'] as String : null + filename: json['filename'] != null ? json['filename'] as String : null, + showKey: json['showKey'] != null ? json['showKey'] as String : null ); Map toJson() => { @@ -123,7 +126,8 @@ class GalleryImage { 'downloadProcess': downloadProcess, 'errorInfo': errorInfo, 'tempPath': tempPath, - 'filename': filename + 'filename': filename, + 'showKey': showKey }; GalleryImage clone() => GalleryImage( @@ -154,7 +158,8 @@ class GalleryImage { downloadProcess: downloadProcess, errorInfo: errorInfo, tempPath: tempPath, - filename: filename + filename: filename, + showKey: showKey ); @@ -186,7 +191,8 @@ class GalleryImage { double? downloadProcess, String? errorInfo, String? tempPath, - String? filename + String? filename, + String? showKey }) => GalleryImage( largeThumb: largeThumb ?? this.largeThumb, completeCache: completeCache ?? this.completeCache, @@ -216,12 +222,13 @@ class GalleryImage { errorInfo: errorInfo ?? this.errorInfo, tempPath: tempPath ?? this.tempPath, filename: filename ?? this.filename, + showKey: showKey ?? this.showKey, ); @override bool operator ==(Object other) => identical(this, other) - || other is GalleryImage && largeThumb == other.largeThumb && completeCache == other.completeCache && startPrecache == other.startPrecache && ser == other.ser && href == other.href && imageUrl == other.imageUrl && originImageUrl == other.originImageUrl && thumbUrl == other.thumbUrl && thumbHeight == other.thumbHeight && thumbWidth == other.thumbWidth && imageHeight == other.imageHeight && imageWidth == other.imageWidth && oriHeight == other.oriHeight && oriWidth == other.oriWidth && offSet == other.offSet && sourceId == other.sourceId && completeHeight == other.completeHeight && gid == other.gid && token == other.token && completeDownload == other.completeDownload && filePath == other.filePath && changeSource == other.changeSource && hide == other.hide && checkHide == other.checkHide && downloadProcess == other.downloadProcess && errorInfo == other.errorInfo && tempPath == other.tempPath && filename == other.filename; + || other is GalleryImage && largeThumb == other.largeThumb && completeCache == other.completeCache && startPrecache == other.startPrecache && ser == other.ser && href == other.href && imageUrl == other.imageUrl && originImageUrl == other.originImageUrl && thumbUrl == other.thumbUrl && thumbHeight == other.thumbHeight && thumbWidth == other.thumbWidth && imageHeight == other.imageHeight && imageWidth == other.imageWidth && oriHeight == other.oriHeight && oriWidth == other.oriWidth && offSet == other.offSet && sourceId == other.sourceId && completeHeight == other.completeHeight && gid == other.gid && token == other.token && completeDownload == other.completeDownload && filePath == other.filePath && changeSource == other.changeSource && hide == other.hide && checkHide == other.checkHide && downloadProcess == other.downloadProcess && errorInfo == other.errorInfo && tempPath == other.tempPath && filename == other.filename && showKey == other.showKey; @override - int get hashCode => largeThumb.hashCode ^ completeCache.hashCode ^ startPrecache.hashCode ^ ser.hashCode ^ href.hashCode ^ imageUrl.hashCode ^ originImageUrl.hashCode ^ thumbUrl.hashCode ^ thumbHeight.hashCode ^ thumbWidth.hashCode ^ imageHeight.hashCode ^ imageWidth.hashCode ^ oriHeight.hashCode ^ oriWidth.hashCode ^ offSet.hashCode ^ sourceId.hashCode ^ completeHeight.hashCode ^ gid.hashCode ^ token.hashCode ^ completeDownload.hashCode ^ filePath.hashCode ^ changeSource.hashCode ^ hide.hashCode ^ checkHide.hashCode ^ downloadProcess.hashCode ^ errorInfo.hashCode ^ tempPath.hashCode ^ filename.hashCode; + int get hashCode => largeThumb.hashCode ^ completeCache.hashCode ^ startPrecache.hashCode ^ ser.hashCode ^ href.hashCode ^ imageUrl.hashCode ^ originImageUrl.hashCode ^ thumbUrl.hashCode ^ thumbHeight.hashCode ^ thumbWidth.hashCode ^ imageHeight.hashCode ^ imageWidth.hashCode ^ oriHeight.hashCode ^ oriWidth.hashCode ^ offSet.hashCode ^ sourceId.hashCode ^ completeHeight.hashCode ^ gid.hashCode ^ token.hashCode ^ completeDownload.hashCode ^ filePath.hashCode ^ changeSource.hashCode ^ hide.hashCode ^ checkHide.hashCode ^ downloadProcess.hashCode ^ errorInfo.hashCode ^ tempPath.hashCode ^ filename.hashCode ^ showKey.hashCode; } diff --git a/lib/network/app_dio/http_transformer.dart b/lib/network/app_dio/http_transformer.dart index 2b11108a5..d0960bf49 100644 --- a/lib/network/app_dio/http_transformer.dart +++ b/lib/network/app_dio/http_transformer.dart @@ -185,7 +185,8 @@ class GalleryMpvImageHttpTransformer extends HttpTransformer { FutureOr> parse( Response response) async { final html = response.data as String; - final mpvPage = await compute(parserMpvPage, html); + // final mpvPage = await compute(parserMpvPage, html); + final mpvPage = parserMpvPage(html); if (mpvPage.mpvkey == null || mpvPage.mpvkey!.isEmpty) { return DioHttpResponse.failure( diff --git a/lib/network/request.dart b/lib/network/request.dart index 36287cfbd..9dd4d1c83 100644 --- a/lib/network/request.dart +++ b/lib/network/request.dart @@ -232,7 +232,60 @@ Future getGalleryDetail({ } } -Future fetchImageInfo( +Future fetchImageInfoByApi( + String href, { + String? showKey, + bool refresh = false, + String? sourceId, + CancelToken? cancelToken, +}) async { + // 如果 showKey 为空,直接使用常规请求,解析html + if (showKey == null || showKey.isEmpty) { + logger.d('fetchImageInfoByApi: showKey is null'); + final _image = await _fetchImageInfo( + href, + refresh: refresh, + sourceId: sourceId, + cancelToken: cancelToken, + ); + return _image; + } + + logger.d( + 'fetchImageInfoByApi: href $href, refresh $refresh, sourceId $sourceId'); + + String mpvSer = '1'; + final isMpv = regGalleryMpvPageUrl.hasMatch(href); + if (isMpv) { + mpvSer = regGalleryMpvPageUrl.firstMatch(href)?.group(3) ?? '1'; + } + + final RegExp regExp = + RegExp(r'https://e[-x]hentai.org/s/([0-9a-z]+)/(\d+)-(\d+)'); + final RegExpMatch? regRult = regExp.firstMatch(href); + final int gid = int.parse(regRult?.group(2) ?? '0'); + final String imgkey = regRult?.group(1) ?? ''; + final int page = int.parse(regRult?.group(3) ?? '0'); + + final Map reqMap = { + 'method': 'showpage', + 'gid': gid, + 'page': page, + 'imgkey': imgkey, + 'showkey': showKey, + }; + + // const url = '/api.php'; + // DioHttpClient dioHttpClient = DioHttpClient(dioConfig: globalDioConfig); + final String reqJsonStr = jsonEncode(reqMap); + + // 请求api + final response = await postEhApi(reqJsonStr, forceRefresh: refresh); + + return paraShowPage(response); +} + +Future _fetchImageInfo( String href, { bool refresh = false, String? sourceId, @@ -968,7 +1021,10 @@ Future postEhApi( bool forceRefresh = true, }) async { const String url = '/api.php'; - DioHttpClient dioHttpClient = DioHttpClient(dioConfig: globalDioConfig); + DioHttpClient dioHttpClient = DioHttpClient( + dioConfig: globalDioConfig.copyWith( + contentType: Headers.jsonContentType, + )); DioHttpResponse httpResponse = await dioHttpClient.post( url, data: data, diff --git a/lib/pages/gallery/controller/gallery_page_controller.dart b/lib/pages/gallery/controller/gallery_page_controller.dart index 26c0085af..ac3f93346 100644 --- a/lib/pages/gallery/controller/gallery_page_controller.dart +++ b/lib/pages/gallery/controller/gallery_page_controller.dart @@ -317,7 +317,16 @@ class GalleryPageController extends GetxController gState.images.indexWhere((GalleryImage element) => element.ser == ser); if (_index != null && _index >= 0) { final image = imageCallback(gState.images[_index]); - // logger.d('${image.toJson()}'); + + // update showKey + if (image.showKey != null && + image.showKey != gState.galleryProvider?.showKey) { + logger.d('update showKey ${image.showKey}'); + gState.galleryProvider = gState.galleryProvider?.copyWith( + showKey: image.showKey, + ); + } + gState.images[_index] = image; return image; } @@ -537,6 +546,7 @@ class GalleryPageController extends GetxController bool changeSource = false, bool refresh = false, }) async { + logger.d('fetchAndParserImageInfo $itemSer'); try { /// 当前缩略图对象 final GalleryImage? _curImages = gState.imageMap[itemSer]; @@ -557,6 +567,8 @@ class GalleryPageController extends GetxController final String? _sourceId = changeSource ? gState.imageMap[itemSer]?.sourceId : ''; + final _showKey = gState.galleryProvider?.showKey; + logger.t( 'ser:$itemSer ,href: ${gState.imageMap[itemSer]?.href} , _sourceId: $_sourceId'); @@ -568,15 +580,22 @@ class GalleryPageController extends GetxController path: gState.imageMap[itemSer]?.href ?? ''); } - // 加载当前页信息 - final GalleryImage? _image = await fetchImageInfo( + // 请求当前页信息 + final GalleryImage? _image = await fetchImageInfoByApi( gState.imageMap[itemSer]?.href ?? '', sourceId: _sourceId, refresh: changeSource || refresh, - debugLabel: 'fetchAndParserImageInfo 加载当前页信息', + showKey: _showKey, ); - logger.t('fetch _image ${_image?.toJson()}'); + logger.d('fetch _image ${_image?.toJson()}'); + + if (_image?.showKey != null && _image?.showKey != _showKey) { + logger.d('update showKey ${_image?.showKey}'); + gState.galleryProvider = gState.galleryProvider?.copyWith( + showKey: _image?.showKey, + ); + } // 换源加载 if (changeSource) { @@ -598,6 +617,7 @@ class GalleryPageController extends GetxController errorInfo: '', tempPath: '', completeCache: false, + showKey: _image.showKey, ); return uptImageBySer(ser: itemSer, imageCallback: (image) => __image); diff --git a/lib/pages/image_view/common.dart b/lib/pages/image_view/common.dart index c6ccc3482..3d2446155 100644 --- a/lib/pages/image_view/common.dart +++ b/lib/pages/image_view/common.dart @@ -57,6 +57,7 @@ class GalleryPara { required Map? imageMap, required int itemSer, required int max, + String? showKey, }) async* { if (imageMap == null) { return; @@ -95,16 +96,19 @@ class GalleryPara { final String _href = imageMap[_ser]?.href ?? ''; // paraImageLageInfoFromHtml - final GalleryImage? _imageFromPage = await fetchImageInfo(_href); + // final GalleryImage? _imageFetch = await fetchImageInfo(_href); + final GalleryImage? _imageFetch = + await fetchImageInfoByApi(_href, showKey: showKey); - _url = _imageFromPage?.imageUrl ?? ''; + _url = _imageFetch?.imageUrl ?? ''; _image = _image.copyWith( imageUrl: _url, - imageWidth: _imageFromPage?.imageWidth, - imageHeight: _imageFromPage?.imageHeight, - originImageUrl: _imageFromPage?.originImageUrl, - filename: _imageFromPage?.filename, + imageWidth: _imageFetch?.imageWidth, + imageHeight: _imageFetch?.imageHeight, + originImageUrl: _imageFetch?.originImageUrl, + filename: _imageFetch?.filename, + showKey: _imageFetch?.showKey, ); _processingSerSet.remove(_ser); diff --git a/lib/pages/image_view/controller/view_controller.dart b/lib/pages/image_view/controller/view_controller.dart index 12208553a..e933b294d 100644 --- a/lib/pages/image_view/controller/view_controller.dart +++ b/lib/pages/image_view/controller/view_controller.dart @@ -235,6 +235,7 @@ class ViewExtController extends GetxController { imageMap: vState.imageMap, itemSer: vState.currentItemIndex, max: _ehSettingService.preloadImage.value, + showKey: vState.pageState?.galleryProvider?.showKey, ) .listen((GalleryImage? event) { if (event != null) { @@ -376,6 +377,7 @@ class ViewExtController extends GetxController { imageMap: _galleryPageStat?.imageMap, itemSer: vState.currentItemIndex, max: _ehSettingService.preloadImage.value, + showKey: vState.pageState?.galleryProvider?.showKey, ) .listen((GalleryImage? event) { if (event != null) { @@ -559,6 +561,7 @@ class ViewExtController extends GetxController { imageMap: _galleryPageStat?.imageMap, itemSer: itemSer, max: _ehSettingService.preloadImage.value, + showKey: vState.pageState?.galleryProvider?.showKey, ) .listen((GalleryImage? event) { if (event != null) { diff --git a/lib/pages/image_view/view/image_page_view.dart b/lib/pages/image_view/view/image_page_view.dart index a1a888f5a..a2c38862e 100644 --- a/lib/pages/image_view/view/image_page_view.dart +++ b/lib/pages/image_view/view/image_page_view.dart @@ -24,7 +24,7 @@ class ImagePageView extends GetView { final imageView = GetBuilder( id: idSlidePage, builder: (logic) { - logger.d('logic.pageViewType ${logic.pageViewType}'); + logger.t('logic.pageViewType ${logic.pageViewType}'); if (logic.vState.columnMode != ViewColumnMode.single) { return _buildDoubleView(logic, context); diff --git a/lib/route/navigator_util.dart b/lib/route/navigator_util.dart index bb37eb686..388afc4a3 100644 --- a/lib/route/navigator_util.dart +++ b/lib/route/navigator_util.dart @@ -143,7 +143,7 @@ class NavigatorUtil { _gid = matcher?[1]; } else if (regGalleryPageUrl.hasMatch(url)) { // url为画廊某一页的链接 - final _image = await fetchImageInfo(url.linkRedirect); + final _image = await fetchImageInfoByApi(url.linkRedirect); if (_image == null) { return; diff --git a/lib/widget/image/eh_image.dart b/lib/widget/image/eh_image.dart index 932550fe9..c68999a74 100644 --- a/lib/widget/image/eh_image.dart +++ b/lib/widget/image/eh_image.dart @@ -169,15 +169,17 @@ class EhImageProvider extends ImageProvider { cumulativeBytesLoaded: count, expectedTotalBytes: total)); }); - } on DioError catch (e) { + } on DioException catch (e) { if (e.response?.statusCode == 403) { logger .d('403 ${key.pageInfo.gid}.${key.pageInfo.ser}下载链接已经失效 需要更新'); - final imageFetched = await _fetchImageInfo(galleryImage.href!, - itemSer: key.pageInfo.ser, - image: galleryImage, - gid: key.pageInfo.gid, - changeSource: true); + final imageFetched = await _fetchImageInfo( + galleryImage.href!, + itemSer: key.pageInfo.ser, + image: galleryImage, + gid: key.pageInfo.gid, + changeSource: true, + ); logger.d('imageFetched... ${imageFetched.toJson()}'); final imageUrl = downloadOrigImage ? imageFetched.originImageUrl @@ -234,7 +236,7 @@ Future _fetchImageInfo( }) async { final String? _sourceId = changeSource ? sourceId : ''; - final GalleryImage? _image = await fetchImageInfo( + final GalleryImage? _image = await fetchImageInfoByApi( href, refresh: changeSource, sourceId: _sourceId, @@ -254,6 +256,7 @@ Future _fetchImageInfo( imageHeight: _image.imageHeight, originImageUrl: _image.originImageUrl, filename: _image.filename, + showKey: _image.showKey, ); return _imageCopyWith;