mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-01-11 22:40:36 +00:00
Add webview for desktop
This commit is contained in:
parent
33eb2458a4
commit
6c67cecf4b
13 changed files with 464 additions and 257 deletions
|
|
@ -1,5 +1,6 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
import 'dart:io';
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
|
@ -22,7 +23,10 @@ import 'package:path_provider/path_provider.dart';
|
|||
import 'package:path/path.dart' as path;
|
||||
|
||||
late Isar isar;
|
||||
void main() async {
|
||||
void main(List<String> args) async {
|
||||
if (runWebViewTitleBarWidget(args)) {
|
||||
return;
|
||||
}
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await _initDB();
|
||||
runApp(const ProviderScope(child: MyApp()));
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class _MangaDetailsViewState extends ConsumerState<MangaDetailsView> {
|
|||
),
|
||||
)
|
||||
: SizedBox(
|
||||
width: mediaWidth(context, 0.4),
|
||||
width: isTablet(context) ? null : mediaWidth(context, 0.4),
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
Map<String, String> data = {
|
||||
'url': getMangaBaseUrl(widget.mangaType.source!),
|
||||
'source': widget.mangaType.source!,
|
||||
'title': ''
|
||||
};
|
||||
context.push("/mangawebview", extra: data);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class MangaWebView extends ConsumerStatefulWidget {
|
||||
final String url;
|
||||
|
|
@ -26,166 +35,233 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
|
|||
final GlobalKey webViewKey = GlobalKey();
|
||||
|
||||
double progress = 0;
|
||||
@override
|
||||
void initState() {
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
_runWebViewDesktop();
|
||||
} else {
|
||||
setState(() {
|
||||
isNotDesktop = true;
|
||||
});
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Webview? webview;
|
||||
_runWebViewDesktop() async {
|
||||
webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
userDataFolderWindows: await getWebViewPath(),
|
||||
),
|
||||
);
|
||||
webview!
|
||||
..setBrightness(Brightness.dark)
|
||||
..setApplicationNameForUserAgent(defaultUserAgent)
|
||||
..launch(widget.url)
|
||||
..onClose.whenComplete(() {
|
||||
Navigator.pop(context);
|
||||
});
|
||||
}
|
||||
|
||||
bool isNotDesktop = false;
|
||||
InAppWebViewController? _webViewController;
|
||||
late String _url = widget.url;
|
||||
late String _title = widget.title;
|
||||
bool _canGoback = false;
|
||||
bool _canGoForward = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
child: WillPopScope(
|
||||
onWillPop: () async {
|
||||
_webViewController?.goBack();
|
||||
return false;
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: AppBar().preferredSize.height,
|
||||
child: Row(
|
||||
return !isNotDesktop
|
||||
? Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
_title,
|
||||
style: const TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
webview!.close();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
),
|
||||
)
|
||||
: SafeArea(
|
||||
child: WillPopScope(
|
||||
onWillPop: () async {
|
||||
_webViewController?.goBack();
|
||||
return false;
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
subtitle: Text(
|
||||
_url,
|
||||
style: const TextStyle(
|
||||
fontSize: 10, overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
title: Text(
|
||||
_title,
|
||||
style: const TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
SizedBox(
|
||||
height: AppBar().preferredSize.height,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
subtitle: Text(
|
||||
_url,
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
overflow: TextOverflow.ellipsis),
|
||||
),
|
||||
title: Text(
|
||||
_title,
|
||||
style: const TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_back,
|
||||
color: _canGoback ? null : Colors.grey),
|
||||
onPressed: _canGoback
|
||||
? () {
|
||||
_webViewController?.goBack();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_forward,
|
||||
color: _canGoForward ? null : Colors.grey),
|
||||
onPressed: _canGoForward
|
||||
? () {
|
||||
_webViewController?.goForward();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
PopupMenuButton(itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Refresh")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 1, child: Text("Share")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 2, child: Text("Open in browser")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 3, child: Text("Clear cookie")),
|
||||
];
|
||||
}, onSelected: (value) async {
|
||||
if (value == 0) {
|
||||
_webViewController?.reload();
|
||||
} else if (value == 1) {
|
||||
Share.share(_url);
|
||||
} else if (value == 2) {
|
||||
await InAppBrowser.openWithSystemBrowser(
|
||||
url: WebUri.uri(Uri.parse(_url)));
|
||||
} else if (value == 3) {
|
||||
CookieManager.instance().getAllCookies();
|
||||
}
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_back,
|
||||
color: _canGoback ? null : Colors.grey),
|
||||
onPressed: _canGoback
|
||||
? () {
|
||||
_webViewController?.goBack();
|
||||
progress < 1.0
|
||||
? LinearProgressIndicator(value: progress)
|
||||
: Container(),
|
||||
Expanded(
|
||||
child: InAppWebView(
|
||||
key: webViewKey,
|
||||
onWebViewCreated: (controller) async {
|
||||
_webViewController = controller;
|
||||
},
|
||||
onLoadStart: (controller, url) async {
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
});
|
||||
},
|
||||
onPermissionRequest: (controller, request) async {
|
||||
return PermissionResponse(
|
||||
resources: request.resources,
|
||||
action: PermissionResponseAction.GRANT);
|
||||
},
|
||||
shouldOverrideUrlLoading:
|
||||
(controller, navigationAction) async {
|
||||
var uri = navigationAction.request.url!;
|
||||
|
||||
if (![
|
||||
"http",
|
||||
"https",
|
||||
"file",
|
||||
"chrome",
|
||||
"data",
|
||||
"javascript",
|
||||
"about"
|
||||
].contains(uri.scheme)) {
|
||||
if (await canLaunchUrl(uri)) {
|
||||
// Launch the App
|
||||
await launchUrl(
|
||||
uri,
|
||||
);
|
||||
// and cancel the request
|
||||
return NavigationActionPolicy.CANCEL;
|
||||
}
|
||||
: null,
|
||||
}
|
||||
|
||||
return NavigationActionPolicy.ALLOW;
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
});
|
||||
},
|
||||
onReceivedError: (controller, request, error) {},
|
||||
onProgressChanged: (controller, progress) async {
|
||||
setState(() {
|
||||
this.progress = progress / 100;
|
||||
});
|
||||
},
|
||||
onUpdateVisitedHistory:
|
||||
(controller, url, isReload) async {
|
||||
await ref.watch(
|
||||
setCookieProvider(widget.source, url.toString())
|
||||
.future);
|
||||
final canGoback = await controller.canGoBack();
|
||||
final canGoForward = await controller.canGoForward();
|
||||
final title = await controller.getTitle();
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
_title = title!;
|
||||
_canGoback = canGoback;
|
||||
_canGoForward = canGoForward;
|
||||
});
|
||||
},
|
||||
initialSettings: InAppWebViewSettings(
|
||||
userAgent: isar.settings.getSync(227)!.userAgent!),
|
||||
initialUrlRequest:
|
||||
URLRequest(url: WebUri.uri(Uri.parse(widget.url))),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_forward,
|
||||
color: _canGoForward ? null : Colors.grey),
|
||||
onPressed: _canGoForward
|
||||
? () {
|
||||
_webViewController?.goForward();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
PopupMenuButton(itemBuilder: (context) {
|
||||
return [
|
||||
const PopupMenuItem<int>(
|
||||
value: 0, child: Text("Refresh")),
|
||||
const PopupMenuItem<int>(value: 1, child: Text("Share")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 2, child: Text("Open in browser")),
|
||||
const PopupMenuItem<int>(
|
||||
value: 3, child: Text("Clear cookie")),
|
||||
];
|
||||
}, onSelected: (value) async {
|
||||
if (value == 0) {
|
||||
_webViewController?.reload();
|
||||
} else if (value == 1) {
|
||||
Share.share(_url);
|
||||
} else if (value == 2) {
|
||||
await InAppBrowser.openWithSystemBrowser(
|
||||
url: WebUri.uri(Uri.parse(_url)));
|
||||
} else if (value == 3) {
|
||||
CookieManager.instance().getAllCookies();
|
||||
}
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
progress < 1.0
|
||||
? LinearProgressIndicator(value: progress)
|
||||
: Container(),
|
||||
Expanded(
|
||||
child: InAppWebView(
|
||||
key: webViewKey,
|
||||
onWebViewCreated: (controller) async {
|
||||
_webViewController = controller;
|
||||
},
|
||||
onLoadStart: (controller, url) async {
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
});
|
||||
},
|
||||
onPermissionRequest: (controller, request) async {
|
||||
return PermissionResponse(
|
||||
resources: request.resources,
|
||||
action: PermissionResponseAction.GRANT);
|
||||
},
|
||||
shouldOverrideUrlLoading: (controller, navigationAction) async {
|
||||
var uri = navigationAction.request.url!;
|
||||
|
||||
if (![
|
||||
"http",
|
||||
"https",
|
||||
"file",
|
||||
"chrome",
|
||||
"data",
|
||||
"javascript",
|
||||
"about"
|
||||
].contains(uri.scheme)) {
|
||||
if (await canLaunchUrl(uri)) {
|
||||
// Launch the App
|
||||
await launchUrl(
|
||||
uri,
|
||||
);
|
||||
// and cancel the request
|
||||
return NavigationActionPolicy.CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
return NavigationActionPolicy.ALLOW;
|
||||
},
|
||||
onLoadStop: (controller, url) async {
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
});
|
||||
},
|
||||
onReceivedError: (controller, request, error) {},
|
||||
onProgressChanged: (controller, progress) async {
|
||||
setState(() {
|
||||
this.progress = progress / 100;
|
||||
});
|
||||
},
|
||||
onUpdateVisitedHistory: (controller, url, isReload) async {
|
||||
await ref.watch(
|
||||
setCookieProvider(widget.source, url.toString()).future);
|
||||
final canGoback = await controller.canGoBack();
|
||||
final canGoForward = await controller.canGoForward();
|
||||
final title = await controller.getTitle();
|
||||
setState(() {
|
||||
_url = url.toString();
|
||||
_title = title!;
|
||||
_canGoback = canGoback;
|
||||
_canGoForward = canGoForward;
|
||||
});
|
||||
},
|
||||
initialSettings: InAppWebViewSettings(
|
||||
userAgent: isar.settings.getSync(227)!.userAgent!),
|
||||
initialUrlRequest:
|
||||
URLRequest(url: WebUri.uri(Uri.parse(widget.url))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getWebViewPath() async {
|
||||
final document = await getApplicationDocumentsDirectory();
|
||||
return p.join(
|
||||
document.path,
|
||||
'desktop_webview_window',
|
||||
);
|
||||
}
|
||||
|
||||
decodeHtml(Webview webview) async {
|
||||
final html = await webview
|
||||
.evaluateJavaScript("window.document.documentElement.outerHTML;");
|
||||
// final cookie = await webview.evaluateJavaScript("window.document.cookie;");
|
||||
// log(cookie!);
|
||||
return jsonDecode(html!) as String;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/webview/webview.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cookie.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'cloudflare_bypass.g.dart';
|
||||
|
|
@ -12,49 +18,88 @@ Future<dom.Document?> cloudflareBypassDom(CloudflareBypassDomRef ref,
|
|||
{required String url,
|
||||
required String source,
|
||||
required bool useUserAgent}) async {
|
||||
// log(source);
|
||||
final ua = isar.settings.getSync(227)!.userAgent!;
|
||||
bool isOk = false;
|
||||
dom.Document? htmll;
|
||||
final ua = isar.settings.getSync(227)!.userAgent!;
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
String? html;
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("https://challenges.cloudflare.com")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
String? html;
|
||||
final webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
windowHeight: 500,
|
||||
windowWidth: 500,
|
||||
userDataFolderWindows: await getWebViewPath(),
|
||||
),
|
||||
);
|
||||
webview
|
||||
..setBrightness(Brightness.dark)
|
||||
..setApplicationNameForUserAgent(useUserAgent ? ua : '')
|
||||
..launch(url);
|
||||
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
html = await decodeHtml(webview);
|
||||
isOk = true;
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
htmll = dom.Document.html(html!);
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
html = await decodeHtml(webview);
|
||||
htmll = dom.Document.html(html!);
|
||||
isOk = true;
|
||||
webview.close();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
String? html;
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("https://challenges.cloudflare.com")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
htmll = dom.Document.html(html!);
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings:
|
||||
useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
headlessWebViewJapScan.run();
|
||||
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await ref.watch(setCookieProvider(source, url).future);
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await ref.watch(setCookieProvider(source, url).future);
|
||||
}
|
||||
return htmll;
|
||||
}
|
||||
|
||||
|
|
@ -66,42 +111,71 @@ Future<String> cloudflareBypassHtml(CloudflareBypassHtmlRef ref,
|
|||
final ua = isar.settings.getSync(227)!.userAgent!;
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("Un instant…")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
await Future.delayed(Duration(seconds: 10));
|
||||
html = await controller.evaluateJavascript(
|
||||
source: "window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings: useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
final webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
windowHeight: 500,
|
||||
windowWidth: 500,
|
||||
userDataFolderWindows: await getWebViewPath(),
|
||||
),
|
||||
);
|
||||
webview
|
||||
..setBrightness(Brightness.dark)
|
||||
..setApplicationNameForUserAgent(useUserAgent ? ua : '')
|
||||
..launch(url);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
if (html == null) {
|
||||
html = await decodeHtml(webview);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await ref.watch(setCookieProvider(source, url).future);
|
||||
});
|
||||
|
||||
isOk = true;
|
||||
webview.close();
|
||||
} else {
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (html == null ||
|
||||
html!.contains("Just a moment") ||
|
||||
html!.contains("Un instant…")) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
await Future.delayed(Duration(seconds: 10));
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialSettings:
|
||||
useUserAgent ? InAppWebViewSettings(userAgent: ua) : null,
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(url)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await ref.watch(setCookieProvider(source, url).future);
|
||||
}
|
||||
return html!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/modules/webview/webview.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
|
||||
|
|
@ -91,47 +94,76 @@ class Madara extends MangaYomiServices {
|
|||
.toList();
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
await Future.doWhile(() async {
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
final webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
windowHeight: 500,
|
||||
windowWidth: 500,
|
||||
userDataFolderWindows: await getWebViewPath(),
|
||||
),
|
||||
);
|
||||
webview
|
||||
..setBrightness(Brightness.dark)
|
||||
..setApplicationNameForUserAgent(defaultUserAgent)
|
||||
..launch(manga.url!);
|
||||
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 10));
|
||||
html = await decodeHtml(webview);
|
||||
if (xpathSelector(html!)
|
||||
.query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
|
||||
.attrs
|
||||
.isEmpty) {
|
||||
html = await decodeHtml(webview);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await decodeHtml(webview);
|
||||
isOk = true;
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
html = await decodeHtml(webview);
|
||||
webview.close();
|
||||
} else {
|
||||
HeadlessInAppWebView? headlessWebViewJapScan;
|
||||
headlessWebViewJapScan = HeadlessInAppWebView(
|
||||
onLoadStop: (controller, u) async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
if (xpathSelector(html!)
|
||||
.query(
|
||||
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
|
||||
.attrs
|
||||
.isEmpty) {
|
||||
await Future.doWhile(() async {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(manga.url!)),
|
||||
),
|
||||
);
|
||||
|
||||
headlessWebViewJapScan.run();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (xpathSelector(html!)
|
||||
.query(
|
||||
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
|
||||
.attrs
|
||||
.isEmpty) {
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
html = await controller.evaluateJavascript(
|
||||
source:
|
||||
"window.document.getElementsByTagName('html')[0].outerHTML;");
|
||||
isOk = true;
|
||||
headlessWebViewJapScan!.dispose();
|
||||
},
|
||||
initialUrlRequest: URLRequest(
|
||||
url: WebUri.uri(Uri.parse(manga.url!)),
|
||||
),
|
||||
);
|
||||
}
|
||||
final xpath = xpathSelector(html!);
|
||||
for (var url in xpath
|
||||
.query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href")
|
||||
|
|
|
|||
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <flutter_js/flutter_js_plugin.h>
|
||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
flutter_js
|
||||
isar_flutter_libs
|
||||
url_launcher_linux
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import desktop_webview_window
|
||||
import flutter_inappwebview
|
||||
import flutter_js
|
||||
import isar_flutter_libs
|
||||
|
|
@ -15,6 +16,7 @@ import sqflite
|
|||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
FlutterJsPlugin.register(with: registry.registrar(forPlugin: "FlutterJsPlugin"))
|
||||
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
|
||||
|
|
|
|||
|
|
@ -282,6 +282,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
desktop_webview_window:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: desktop_webview_window
|
||||
sha256: da2fc164b46257c7a8b88649d3f2b34b4d98e7b7c403fb9e4183ebe8ff008004
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
draggable_menu:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ dependencies:
|
|||
isar_flutter_libs: 3.1.0+1
|
||||
share_plus: ^7.0.0
|
||||
xpath_selector_html_parser: ^3.0.1
|
||||
desktop_webview_window: ^0.2.0
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <desktop_webview_window/desktop_webview_window_plugin.h>
|
||||
#include <flutter_js/flutter_js_plugin.h>
|
||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
|
|
@ -13,6 +14,8 @@
|
|||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
DesktopWebviewWindowPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin"));
|
||||
FlutterJsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterJsPlugin"));
|
||||
IsarFlutterLibsPluginRegisterWithRegistrar(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
desktop_webview_window
|
||||
flutter_js
|
||||
isar_flutter_libs
|
||||
permission_handler_windows
|
||||
|
|
|
|||
Loading…
Reference in a new issue