diff --git a/assets/i18n/en.json b/assets/i18n/en.json index db222fcb..623c1106 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -102,6 +102,8 @@ "theme-black": "Black", "nsfw": "NSFW", "nsfw-subtitle": "Show NSFW content", + "webview-ua": "Webview User-Agent", + "webview-ua-subtitle": "Modify the User-Agent in the request header for Webviews and extensions.", "external-player": "Preferred video player", "external-player-subtitle": "Currently, the preferred player is {player}", "external-player-builtin": "Built-in", diff --git a/assets/i18n/zh.json b/assets/i18n/zh.json index 8d8fbc2b..5b4c6fd6 100644 --- a/assets/i18n/zh.json +++ b/assets/i18n/zh.json @@ -90,6 +90,8 @@ "theme-black": "黑色", "nsfw": "NSFW", "nsfw-subtitle": "显示 NSFW 内容", + "webview-ua": "Webview User-Agent", + "webview-ua-subtitle": "修改 Webview 和扩展的请求头的 User-Agent", "external-player": "优先使用的视频播放器", "external-player-subtitle": "当前优先使用的是 {player}", "external-player-builtin": "内置播放器", diff --git a/lib/controllers/detail_controller.dart b/lib/controllers/detail_controller.dart index aa09c806..47ba0691 100644 --- a/lib/controllers/detail_controller.dart +++ b/lib/controllers/detail_controller.dart @@ -3,10 +3,10 @@ import 'dart:convert'; import 'dart:io'; -import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:fluent_ui/fluent_ui.dart' as fluent; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:flutter_windows_webview/flutter_windows_webview.dart'; import 'package:get/get.dart'; import 'package:miru_app/data/providers/tmdb_provider.dart'; import 'package:miru_app/models/index.dart'; @@ -20,7 +20,6 @@ import 'package:miru_app/utils/extension.dart'; import 'package:miru_app/data/services/extension_service.dart'; import 'package:miru_app/utils/external_player.dart'; import 'package:miru_app/utils/i18n.dart'; -import 'package:miru_app/utils/miru_directory.dart'; import 'package:miru_app/utils/miru_storage.dart'; import 'package:miru_app/views/widgets/messenger.dart'; @@ -78,23 +77,31 @@ class DetailPageController extends GetxController { fluent.IconButton( icon: const Icon(fluent.FluentIcons.pop_expand), onPressed: () async { - final webview = await WebviewWindow.create( - configuration: CreateConfiguration( - userDataFolderWindows: await MiruDirectory.getDirectory, - title: detail!.title, + final webview = FlutterWindowsWebview(); + await webview.setUA(MiruStorage.getUASetting()); + webview.launchWebview( + extension!.webSite + url, + WebviewOptions( + onNavigation: (url) { + if (Uri.parse(url).host != Uri.parse(extension!.webSite).host) { + return false; + } + webview.getCookies(url).then((value) async { + if (value.containsKey("cf_clearance")) { + debugPrint("验证通过"); + } + runtime.value!.setCookie( + value.entries + .map((e) => '${e.key}=${e.value}') + .toList() + .join(';'), + ); + }); + + return false; + }, ), ); - webview - ..addOnUrlRequestCallback((url) async { - if (Uri.parse(url).host != Uri.parse(extension!.webSite).host) { - return; - } - final cookies = await webview.evaluateJavaScript( - 'document.cookie', - ); - runtime.value?.setCookie(cookies!.split("\"")[1]); - }) - ..launch(extension!.webSite + url); }, ), fluent.FlyoutTarget( diff --git a/lib/data/services/extension_service.dart b/lib/data/services/extension_service.dart index c1fd87af..26d4128d 100644 --- a/lib/data/services/extension_service.dart +++ b/lib/data/services/extension_service.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; +import 'package:miru_app/utils/miru_storage.dart'; import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart'; import 'dart:io'; @@ -58,12 +59,16 @@ class ExtensionService { "Request: ${args[0]} , ${args[1]}", ); _cuurentRequestUrl = args[0]; + final headers = args[1]['headers'] ?? {}; + if (headers['User-Agent'] == null) { + headers['User-Agent'] = MiruStorage.getUASetting(); + } return (await _dio.request( args[0], data: args[1]['data'], queryParameters: args[1]['queryParameters'] ?? {}, options: Options( - headers: args[1]['headers'] ?? {}, + headers: headers, method: args[1]['method'] ?? 'get', ), )) @@ -386,11 +391,11 @@ class ExtensionService { } // 列出所有的 cookie - // Future listCookie() async { - // final cookies = - // await _cookieJar.loadForRequest(Uri.parse(extension.webSite)); - // return cookies.map((e) => e.toString()).join(';'); - // } + Future listCookie() async { + final cookies = + await _cookieJar.loadForRequest(Uri.parse(extension.webSite)); + return cookies.map((e) => e.toString()).join(';'); + } Future _runExtension(Future Function() fun) async { try { @@ -405,6 +410,14 @@ class ExtensionService { } } + Future> get _defaultHeaders async { + return { + "Referer": _cuurentRequestUrl, + "User-Agent": MiruStorage.getUASetting(), + "Cookie": await listCookie(), + }; + } + Future> latest(int page) async { return _runExtension(() async { final jsResult = await runtime.handlePromise( @@ -415,9 +428,7 @@ class ExtensionService { return ExtensionListItem.fromJson(e); }).toList(); for (var element in result) { - element.headers ??= { - "Referer": _cuurentRequestUrl, - }; + element.headers ??= await _defaultHeaders; } return result; }); @@ -438,9 +449,7 @@ class ExtensionService { return ExtensionListItem.fromJson(e); }).toList(); for (var element in result) { - element.headers ??= { - "Referer": _cuurentRequestUrl, - }; + element.headers ??= await _defaultHeaders; } return result; }); @@ -477,9 +486,7 @@ class ExtensionService { ); final result = ExtensionDetail.fromJson(jsonDecode(jsResult.stringResult)); - result.headers ??= { - "Referer": _cuurentRequestUrl, - }; + result.headers ??= await _defaultHeaders; return result; }); } @@ -494,15 +501,11 @@ class ExtensionService { switch (extension.type) { case ExtensionType.bangumi: final result = ExtensionBangumiWatch.fromJson(data); - result.headers ??= { - "Referer": _cuurentRequestUrl, - }; + result.headers ??= await _defaultHeaders; return result; case ExtensionType.manga: final result = ExtensionMangaWatch.fromJson(data); - result.headers ??= { - "Referer": _cuurentRequestUrl, - }; + result.headers ??= await _defaultHeaders; return result; default: return ExtensionFikushonWatch.fromJson(data); diff --git a/lib/main.dart b/lib/main.dart index a07d6b12..257242a6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,9 @@ import 'dart:convert'; import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; -import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:fluent_ui/fluent_ui.dart' as fluent; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:media_kit/media_kit.dart'; import 'package:miru_app/controllers/application_controller.dart'; @@ -22,10 +20,6 @@ import 'package:window_manager/window_manager.dart'; void main(List args) async { WidgetsFlutterBinding.ensureInitialized(); - if (runWebViewTitleBarWidget(args)) { - return; - } - // 多窗口 if (args.firstOrNull == 'multi_window') { final windowId = int.parse(args[1]); @@ -82,7 +76,6 @@ void main(List args) async { statusBarIconBrightness: Brightness.dark, ); SystemChrome.setSystemUIOverlayStyle(style); - await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); } runApp(const MainApp()); } diff --git a/lib/utils/miru_storage.dart b/lib/utils/miru_storage.dart index 10cecba3..d06ca0e6 100644 --- a/lib/utils/miru_storage.dart +++ b/lib/utils/miru_storage.dart @@ -119,6 +119,10 @@ class MiruStorage { await _initSetting(SettingKey.arrowRight, 2.0); await _initSetting(SettingKey.readingMode, "standard"); await _initSetting(SettingKey.windowSize, "1280,720"); + await _initSetting(SettingKey.androidWebviewUA, + "Mozilla/5.0 (Linux; Android 13; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.43 Mobile Safari/537.36"); + await _initSetting(SettingKey.windowsWebviewUA, + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"); } static _initSetting(String key, dynamic value) async { @@ -134,6 +138,21 @@ class MiruStorage { static getSetting(String key) { return settings.get(key); } + + static getUASetting() { + if (Platform.isAndroid) { + return settings.get(SettingKey.androidWebviewUA); + } + return settings.get(SettingKey.windowsWebviewUA); + } + + static setUASetting(String value) async { + if (Platform.isAndroid) { + setSetting(SettingKey.androidWebviewUA, value); + } else { + setSetting(SettingKey.windowsWebviewUA, value); + } + } } class SettingKey { @@ -154,4 +173,6 @@ class SettingKey { static String readingMode = 'ReadingMode'; static String windowSize = 'WindowsSize'; static String windowPosition = 'WindowsPosition'; + static String androidWebviewUA = "AndroidWebviewUA"; + static String windowsWebviewUA = "WindowsWebviewUA"; } diff --git a/lib/views/pages/detail_page.dart b/lib/views/pages/detail_page.dart index 5ead46b1..50e45efd 100644 --- a/lib/views/pages/detail_page.dart +++ b/lib/views/pages/detail_page.dart @@ -255,6 +255,7 @@ class _DetailPageState extends State { alt: c.detail?.title ?? '', url: c.backgorund, noText: true, + headers: c.detail?.headers, ), ).blur( begin: const Offset(10, 10), diff --git a/lib/views/pages/search/extension_searcher_page.dart b/lib/views/pages/search/extension_searcher_page.dart index f1020e88..fd415e0e 100644 --- a/lib/views/pages/search/extension_searcher_page.dart +++ b/lib/views/pages/search/extension_searcher_page.dart @@ -237,6 +237,7 @@ class _ExtensionSearcherPageState extends fluent.State { package: widget.package, cover: item.cover, update: item.update, + headers: item.headers, ); }, ), @@ -316,6 +317,7 @@ class _ExtensionSearcherPageState extends fluent.State { package: widget.package, cover: item.cover, update: item.update, + headers: item.headers, ); }, )), diff --git a/lib/views/pages/settings/settings_page.dart b/lib/views/pages/settings/settings_page.dart index 71da5420..ccb1d2d0 100644 --- a/lib/views/pages/settings/settings_page.dart +++ b/lib/views/pages/settings/settings_page.dart @@ -147,6 +147,20 @@ class _SettingsPageState extends State { MiruStorage.setSetting(SettingKey.enableNSFW, value); }, ), + // UA + SettingsIntpuTile( + title: 'settings.webview-ua'.i18n, + buildSubtitle: () { + if (!Platform.isAndroid) { + return 'settings.webview-ua-subtitle'.i18n; + } + return MiruStorage.getUASetting(); + }, + onChanged: (value) { + MiruStorage.setUASetting(value); + }, + text: MiruStorage.getUASetting(), + ), ], ), ), diff --git a/lib/views/pages/webview_page.dart b/lib/views/pages/webview_page.dart index da385831..2cbdc180 100644 --- a/lib/views/pages/webview_page.dart +++ b/lib/views/pages/webview_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:miru_app/data/services/extension_service.dart'; +import 'package:miru_app/utils/miru_storage.dart'; +import 'package:webview_cookie_manager/webview_cookie_manager.dart'; class WebViewPage extends StatefulWidget { const WebViewPage({ @@ -17,26 +19,47 @@ class WebViewPage extends StatefulWidget { class _WebViewPageState extends State { late String url = widget.extensionRuntime.extension.webSite + widget.url; + final cookieManager = WebviewCookieManager(); + late Uri loadUrl = Uri.parse(url); + + _setCookie() async { + if (loadUrl.host != Uri.parse(url).host) { + return; + } + final cookies = await cookieManager.getCookies(loadUrl.toString()); + final cookieString = + cookies.map((e) => '${e.name}=${e.value}').toList().join(';'); + debugPrint('$url $cookieString'); + widget.extensionRuntime.setCookie( + cookieString, + ); + } + + @override + void dispose() { + _setCookie(); + super.dispose(); + } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(url), + title: Text(loadUrl.toString()), ), body: InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse(url), ), - onLoadStop: (controller, url) async { - if (url!.host != - Uri.parse(widget.extensionRuntime.extension.webSite).host) { - return; - } - final cookies = await controller.evaluateJavascript( - source: 'document.cookie', - ); - widget.extensionRuntime.setCookie(cookies); + initialOptions: InAppWebViewGroupOptions( + crossPlatform: InAppWebViewOptions( + userAgent: MiruStorage.getUASetting(), + ), + ), + onLoadStart: (controller, url) { + setState(() { + loadUrl = url!; + }); }, ), ); diff --git a/lib/views/widgets/cover.dart b/lib/views/widgets/cover.dart index 3c405abb..20ea2f7f 100644 --- a/lib/views/widgets/cover.dart +++ b/lib/views/widgets/cover.dart @@ -8,10 +8,12 @@ class Cover extends StatelessWidget { required this.alt, this.url, this.noText = false, + required this.headers, }); final String? url; final String alt; final bool noText; + final Map? headers; @override Widget build(BuildContext context) { @@ -20,6 +22,7 @@ class Cover extends StatelessWidget { url!, width: double.infinity, height: double.infinity, + headers: headers, ); } diff --git a/lib/views/widgets/detail/detail_appbar_flexible_space.dart b/lib/views/widgets/detail/detail_appbar_flexible_space.dart index 84ba6daa..a4067aae 100644 --- a/lib/views/widgets/detail/detail_appbar_flexible_space.dart +++ b/lib/views/widgets/detail/detail_appbar_flexible_space.dart @@ -71,6 +71,7 @@ class _DetailAppbarflexibleSpaceState extends State { alt: c.data.value?.title ?? '', url: c.backgorund, noText: true, + headers: c.detail?.headers, ), ), Positioned.fill( diff --git a/lib/views/widgets/extension_item_card.dart b/lib/views/widgets/extension_item_card.dart index 919bf6ee..c28bd4fa 100644 --- a/lib/views/widgets/extension_item_card.dart +++ b/lib/views/widgets/extension_item_card.dart @@ -13,12 +13,14 @@ class ExtensionItemCard extends StatefulWidget { required this.package, this.cover, this.update, + this.headers, }); final String title; final String? cover; final String? update; final String url; final String package; + final Map? headers; @override State createState() => _ExtensionItemCardState(); @@ -32,6 +34,7 @@ class _ExtensionItemCardState extends State { title: widget.title, cover: widget.cover, subtitle: widget.update, + headers: widget.headers, onTap: () { Get.to(DetailPage( url: widget.url, @@ -48,6 +51,7 @@ class _ExtensionItemCardState extends State { title: widget.title, cover: widget.cover, subtitle: widget.update, + headers: widget.headers, onTap: () { router.push( Uri( diff --git a/lib/views/widgets/grid_item_tile.dart b/lib/views/widgets/grid_item_tile.dart index 13202d5b..9092a46f 100644 --- a/lib/views/widgets/grid_item_tile.dart +++ b/lib/views/widgets/grid_item_tile.dart @@ -9,11 +9,13 @@ class GridItemTile extends StatefulWidget { this.cover, this.subtitle, this.onTap, + this.headers, }); final String title; final String? cover; final String? subtitle; final Function()? onTap; + final Map? headers; @override State createState() => _GridItemTileState(); @@ -33,6 +35,7 @@ class _GridItemTileState extends State { child: Cover( alt: widget.title, url: widget.cover, + headers: widget.headers, ), ), Positioned( @@ -134,6 +137,7 @@ class _GridItemTileState extends State { child: Cover( alt: widget.title, url: widget.cover, + headers: widget.headers, ), )), ), diff --git a/lib/views/widgets/search/search_all_tile.dart b/lib/views/widgets/search/search_all_tile.dart index 89daaf67..6ba9c709 100644 --- a/lib/views/widgets/search/search_all_tile.dart +++ b/lib/views/widgets/search/search_all_tile.dart @@ -55,6 +55,7 @@ class _SearchAllTileState extends State { width: Platform.isAndroid ? 110 : 170, margin: const EdgeInsets.only(right: 16), child: ExtensionItemCard( + headers: data[index].headers, key: ValueKey(data[index].url), title: data[index].title, url: data[index].url, diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d3934e30..df5c810e 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -20,9 +19,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) desktop_multi_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopMultiWindowPlugin"); desktop_multi_window_plugin_register_with_registrar(desktop_multi_window_registrar); - g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin"); - desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar); g_autoptr(FlPluginRegistrar) flutter_js_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterJsPlugin"); flutter_js_plugin_register_with_registrar(flutter_js_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 75cf1b6d..d67a10b7 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_multi_window - desktop_webview_window flutter_js isar_flutter_libs media_kit_libs_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f71d65fb..ffb24ca7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,6 @@ import FlutterMacOS import Foundation import desktop_multi_window -import desktop_webview_window import device_info_plus import flutter_js import isar_flutter_libs @@ -23,7 +22,6 @@ import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterMultiWindowPlugin.register(with: registry.registrar(forPlugin: "FlutterMultiWindowPlugin")) - DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterJsPlugin.register(with: registry.registrar(forPlugin: "FlutterJsPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 9905a1da..cb03d0aa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -273,14 +273,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" - desktop_webview_window: - dependency: "direct main" - description: - name: desktop_webview_window - sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0" - url: "https://pub.dev" - source: hosted - version: "0.2.3" device_info_plus: dependency: "direct main" description: @@ -509,6 +501,15 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_windows_webview: + dependency: "direct main" + description: + path: "." + ref: master + resolved-ref: "2ea8dd630da4530b632fc41aca50decef360e29a" + url: "https://github.com/MiaoMint/flutter_windows_webview" + source: git + version: "0.0.1" frontend_server_client: dependency: transitive description: @@ -1434,6 +1435,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + webview_cookie_manager: + dependency: "direct main" + description: + name: webview_cookie_manager + sha256: "425a9feac5cd2cb62a71da3dda5ac2eaf9ece5481ee8d79f3868dc5ba8223ad3" + url: "https://pub.dev" + source: hosted + version: "2.0.6" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4325b793..33b1ec62 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,7 +48,11 @@ dependencies: window_manager: ^0.3.7 cookie_jar: ^4.0.8 flutter_inappwebview: ^5.7.2+3 - desktop_webview_window: ^0.2.1 + flutter_windows_webview: + git: + url: https://github.com/MiaoMint/flutter_windows_webview + ref: master + webview_cookie_manager: ^2.0.6 http_parser: ^4.0.2 html: ^0.15.4 xpath_selector_html_parser: ^3.0.1 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index c697e2b2..9a844ed8 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,8 +7,8 @@ #include "generated_plugin_registrant.h" #include -#include #include +#include #include #include #include @@ -20,10 +20,10 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { DesktopMultiWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopMultiWindowPlugin")); - DesktopWebviewWindowPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin")); FlutterJsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterJsPlugin")); + FlutterWindowsWebviewPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterWindowsWebviewPluginCApi")); IsarFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 7fbaee51..b09fc824 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,8 +4,8 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_multi_window - desktop_webview_window flutter_js + flutter_windows_webview isar_flutter_libs media_kit_libs_windows_video media_kit_video