mirror of
https://github.com/dstark5/Openlib.git
synced 2025-05-20 16:06:23 +08:00
Fixed "no mirror found" and "always redirected to captcha" issues
This commit is contained in:
@ -25,7 +25,8 @@
|
||||
android:name="${applicationName}"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
|
@ -25,6 +25,7 @@ import 'package:openlib/state/state.dart'
|
||||
selectedIndexProvider,
|
||||
themeModeProvider,
|
||||
openPdfWithExternalAppProvider,
|
||||
openEpubWithExternalAppProvider,
|
||||
userAgentProvider,
|
||||
cookieProvider;
|
||||
|
||||
@ -46,6 +47,13 @@ void main() async {
|
||||
? false
|
||||
: true;
|
||||
|
||||
bool openEpubwithExternalapp = await dataBase
|
||||
.getPreference('openEpubwithExternalApp')
|
||||
.catchError((e) => print(e)) ==
|
||||
0
|
||||
? false
|
||||
: true;
|
||||
|
||||
String browserUserAgent = await dataBase.getBrowserOptions('userAgent');
|
||||
String browserCookie = await dataBase.getBrowserOptions('cookie');
|
||||
|
||||
@ -64,6 +72,8 @@ void main() async {
|
||||
(ref) => isDarkMode ? ThemeMode.dark : ThemeMode.light),
|
||||
openPdfWithExternalAppProvider
|
||||
.overrideWith((ref) => openPdfwithExternalapp),
|
||||
openEpubWithExternalAppProvider
|
||||
.overrideWith((ref) => openEpubwithExternalapp),
|
||||
userAgentProvider.overrideWith((ref) => browserUserAgent),
|
||||
cookieProvider.overrideWith((ref) => browserCookie),
|
||||
],
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Dart imports:
|
||||
import 'dart:convert';
|
||||
// import 'dart:convert';
|
||||
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart';
|
||||
@ -28,7 +28,7 @@ class BookData {
|
||||
}
|
||||
|
||||
class BookInfoData extends BookData {
|
||||
final List<String>? mirrors;
|
||||
String? mirror;
|
||||
final String? description;
|
||||
final String? format;
|
||||
|
||||
@ -40,13 +40,13 @@ class BookInfoData extends BookData {
|
||||
required super.info,
|
||||
required super.link,
|
||||
required super.md5,
|
||||
required this.mirrors,
|
||||
required this.format,
|
||||
required this.mirror,
|
||||
required this.description});
|
||||
}
|
||||
|
||||
class AnnasArchieve {
|
||||
String baseUrl = "https://annas-archive.org";
|
||||
static const String baseUrl = "https://annas-archive.org";
|
||||
|
||||
final Dio dio = Dio();
|
||||
|
||||
@ -131,65 +131,82 @@ class AnnasArchieve {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> _getMirrorLink(
|
||||
String url, String userAgent, String cookie) async {
|
||||
try {
|
||||
final response = await dio.get(url,
|
||||
options: Options(extra: {
|
||||
'withCredentials': true
|
||||
}, headers: {
|
||||
"Host": "annas-archive.org",
|
||||
"Origin": "https://annas-archive.org",
|
||||
"Upgrade-Insecure-Requests": "1",
|
||||
"Sec-Fetch-Dest": "secure",
|
||||
"Sec-Fetch-Mode": "navigate",
|
||||
"Sec-Fetch-Site": "same-site",
|
||||
"Cookie": cookie,
|
||||
"User-Agent": userAgent
|
||||
}));
|
||||
// Future<String?> _getMirrorLink(
|
||||
// String url, String userAgent, String cookie) async {
|
||||
// try {
|
||||
// final response = await dio.get(url,
|
||||
// options: Options(extra: {
|
||||
// 'withCredentials': true
|
||||
// }, headers: {
|
||||
// "Host": "annas-archive.org",
|
||||
// "Origin": baseUrl,
|
||||
// "Upgrade-Insecure-Requests": "1",
|
||||
// "Sec-Fetch-Dest": "secure",
|
||||
// "Sec-Fetch-Mode": "navigate",
|
||||
// "Sec-Fetch-Site": "same-site",
|
||||
// "Cookie": cookie,
|
||||
// "User-Agent": userAgent
|
||||
// }));
|
||||
|
||||
var document = parse(response.data.toString());
|
||||
// var document = parse(response.data.toString());
|
||||
|
||||
var pTag = document.querySelectorAll('p[class="mb-4"]');
|
||||
String? link = pTag[1].querySelector('a')?.attributes['href'];
|
||||
return link;
|
||||
} catch (e) {
|
||||
// print('${url} ${e}');
|
||||
if (e.toString().contains("403")) {
|
||||
throw jsonEncode({"code": "403", "url": url});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// var pTag = document.querySelectorAll('p[class="mb-4"]');
|
||||
// String? link = pTag[1].querySelector('a')?.attributes['href'];
|
||||
// return link;
|
||||
// } catch (e) {
|
||||
// // print('${url} ${e}');
|
||||
// if (e.toString().contains("403")) {
|
||||
// throw jsonEncode({"code": "403", "url": url});
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<BookInfoData?> _bookInfoParser(resData, url, userAgent, cookie) async {
|
||||
Future<BookInfoData?> _bookInfoParser(resData, url) async {
|
||||
var document = parse(resData.toString());
|
||||
var main = document.querySelector('main[class="main"]');
|
||||
var ul = main?.querySelectorAll('ul[class="list-inside mb-4 ml-1"]');
|
||||
|
||||
List<String> mirrors = [];
|
||||
// List<String> mirrors = [];
|
||||
|
||||
// if (ul != null) {
|
||||
// var anchorTags = [];
|
||||
|
||||
// for (var e in ul) {
|
||||
// anchorTags.insertAll(0, e.querySelectorAll('a'));
|
||||
// }
|
||||
|
||||
// for (var element in anchorTags) {
|
||||
// if (element.attributes['href'] != null &&
|
||||
// element.attributes['href']!.startsWith('/slow_download') &&
|
||||
// element.attributes['href']!.endsWith('/2')) {
|
||||
// String? url =
|
||||
// await _getMirrorLink('$baseUrl${element.attributes['href']!}');
|
||||
// if (url != null && url.isNotEmpty) {
|
||||
// mirrors.add(url);
|
||||
// }
|
||||
// } else if (element.attributes['href']!.startsWith('https://')) {
|
||||
// if (element.attributes['href'] != null &&
|
||||
// element.attributes['href'].contains('ipfs') == true) {
|
||||
// mirrors.add(element.attributes['href']!);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
String? mirror;
|
||||
var anchorTags = [];
|
||||
|
||||
if (ul != null) {
|
||||
var anchorTags = [];
|
||||
|
||||
for (var e in ul) {
|
||||
anchorTags.insertAll(0, e.querySelectorAll('a'));
|
||||
}
|
||||
}
|
||||
|
||||
for (var element in anchorTags) {
|
||||
if (element.attributes['href'] != null &&
|
||||
element.attributes['href']!.startsWith('/slow_download')) {
|
||||
String? url = await _getMirrorLink(
|
||||
'$baseUrl${element.attributes['href']!}', userAgent, cookie);
|
||||
if (url != null && url.isNotEmpty) {
|
||||
mirrors.add(url);
|
||||
}
|
||||
} else if (element.attributes['href']!.startsWith('https://')) {
|
||||
if (element.attributes['href'] != null &&
|
||||
element.attributes['href'].contains('ipfs') == true) {
|
||||
mirrors.add(element.attributes['href']!);
|
||||
}
|
||||
}
|
||||
for (var element in anchorTags) {
|
||||
if (element.attributes['href'] != null &&
|
||||
element.attributes['href']!.startsWith('/slow_download') &&
|
||||
element.attributes['href']!.endsWith('/2')) {
|
||||
mirror = '$baseUrl${element.attributes['href']}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,8 +223,9 @@ class AnnasArchieve {
|
||||
main?.querySelector('div[class="text-sm text-gray-500"]')?.text ?? '',
|
||||
'description': main
|
||||
?.querySelector(
|
||||
'div[class="mt-4 line-clamp-[5] js-md5-top-box-description"]')
|
||||
?.text ??
|
||||
'div[class="mt-4 line-clamp-[8] js-md5-top-box-description"]')
|
||||
?.text
|
||||
.replaceFirst("description", '') ??
|
||||
" "
|
||||
};
|
||||
|
||||
@ -232,7 +250,7 @@ class AnnasArchieve {
|
||||
link: data['link'],
|
||||
md5: getMd5(data['link'].toString()),
|
||||
format: getFormat(data['info']),
|
||||
mirrors: mirrors,
|
||||
mirror: mirror,
|
||||
description: data['description'],
|
||||
);
|
||||
} else {
|
||||
@ -282,15 +300,11 @@ class AnnasArchieve {
|
||||
}
|
||||
}
|
||||
|
||||
Future<BookInfoData> bookInfo(
|
||||
{required String url,
|
||||
required String userAgent,
|
||||
required String cookie}) async {
|
||||
Future<BookInfoData> bookInfo({required String url}) async {
|
||||
try {
|
||||
final response =
|
||||
await dio.get(url, options: Options(headers: defaultDioHeaders));
|
||||
BookInfoData? data =
|
||||
await _bookInfoParser(response.data, url, userAgent, cookie);
|
||||
BookInfoData? data = await _bookInfoParser(response.data, url);
|
||||
if (data != null) {
|
||||
return data;
|
||||
} else {
|
||||
|
@ -105,14 +105,13 @@ final searchProvider = FutureProvider.family
|
||||
final cookieProvider = StateProvider<String>((ref) => "");
|
||||
final userAgentProvider = StateProvider<String>((ref) => "");
|
||||
|
||||
final webViewLoadingState = StateProvider.autoDispose<bool>((ref) => true);
|
||||
|
||||
//Provider for Book Info
|
||||
final bookInfoProvider =
|
||||
FutureProvider.family<BookInfoData, String>((ref, url) async {
|
||||
AnnasArchieve annasArchieve = AnnasArchieve();
|
||||
BookInfoData data = await annasArchieve.bookInfo(
|
||||
url: url,
|
||||
userAgent: ref.read(userAgentProvider),
|
||||
cookie: ref.read(cookieProvider));
|
||||
BookInfoData data = await annasArchieve.bookInfo(url: url);
|
||||
return data;
|
||||
});
|
||||
|
||||
@ -194,6 +193,7 @@ final getBookPosition =
|
||||
});
|
||||
|
||||
final openPdfWithExternalAppProvider = StateProvider<bool>((ref) => false);
|
||||
final openEpubWithExternalAppProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
final filePathProvider =
|
||||
FutureProvider.family<String, String>((ref, fileName) async {
|
||||
|
@ -47,7 +47,7 @@ class AboutPage extends StatelessWidget {
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 7, right: 7, top: 5),
|
||||
child: Text(
|
||||
"1.0.6",
|
||||
"1.0.7",
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -1,14 +1,14 @@
|
||||
// Dart imports:
|
||||
import 'dart:convert';
|
||||
// import 'dart:convert';
|
||||
|
||||
// Flutter imports:
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
// import 'package:flutter/scheduler.dart';
|
||||
|
||||
// Package imports:
|
||||
import 'package:dio/dio.dart' show CancelToken;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
// import 'package:flutter_svg/svg.dart';
|
||||
|
||||
// Project imports:
|
||||
import 'package:openlib/services/annas_archieve.dart' show BookInfoData;
|
||||
@ -58,91 +58,91 @@ class BookInfoPage extends ConsumerWidget {
|
||||
data: data, child: ActionButtonWidget(data: data));
|
||||
},
|
||||
error: (err, _) {
|
||||
if (err.toString().contains("403")) {
|
||||
var errJson = jsonDecode(err.toString());
|
||||
// if (err.toString().contains("403")) {
|
||||
// var errJson = jsonDecode(err.toString());
|
||||
|
||||
if (SchedulerBinding.instance.schedulerPhase ==
|
||||
SchedulerPhase.persistentCallbacks) {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
Future.delayed(
|
||||
const Duration(seconds: 3),
|
||||
() => Navigator.pushReplacement(context,
|
||||
MaterialPageRoute(builder: (BuildContext context) {
|
||||
return Webview(url: errJson["url"]);
|
||||
})));
|
||||
});
|
||||
}
|
||||
// if (SchedulerBinding.instance.schedulerPhase ==
|
||||
// SchedulerPhase.persistentCallbacks) {
|
||||
// SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
// Future.delayed(
|
||||
// const Duration(seconds: 3),
|
||||
// () => Navigator.pushReplacement(context,
|
||||
// MaterialPageRoute(builder: (BuildContext context) {
|
||||
// return Webview(url: errJson["url"]);
|
||||
// })));
|
||||
// });
|
||||
// }
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 210,
|
||||
child: SvgPicture.asset(
|
||||
'assets/captcha.svg',
|
||||
width: 210,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
Text(
|
||||
"Captcha required",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).textTheme.headlineMedium?.color,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
"you will be redirected to solve captcha",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(30, 15, 30, 10),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color.fromARGB(255, 255, 186, 186),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text(
|
||||
"If you have solved the captcha then you will be automatically redirected to the results page . In case you seeing this page even after completing try using a VPN .",
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return CustomErrorWidget(
|
||||
error: err,
|
||||
stackTrace: _,
|
||||
onRefresh: () {
|
||||
// ignore: unused_result
|
||||
ref.refresh(bookInfoProvider(url));
|
||||
},
|
||||
);
|
||||
}
|
||||
// return Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
// children: [
|
||||
// SizedBox(
|
||||
// width: 210,
|
||||
// child: SvgPicture.asset(
|
||||
// 'assets/captcha.svg',
|
||||
// width: 210,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 30,
|
||||
// ),
|
||||
// Text(
|
||||
// "Captcha required",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontSize: 18,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Theme.of(context).textTheme.headlineMedium?.color,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Text(
|
||||
// "you will be redirected to solve captcha",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontSize: 13,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Theme.of(context).textTheme.headlineSmall?.color,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.fromLTRB(30, 15, 30, 10),
|
||||
// child: Container(
|
||||
// width: double.infinity,
|
||||
// decoration: BoxDecoration(
|
||||
// color: const Color.fromARGB(255, 255, 186, 186),
|
||||
// borderRadius: BorderRadius.circular(5)),
|
||||
// child: const Padding(
|
||||
// padding: EdgeInsets.all(10.0),
|
||||
// child: Text(
|
||||
// "If you have solved the captcha then you will be automatically redirected to the results page . In case you seeing this page even after completing try using a VPN .",
|
||||
// textAlign: TextAlign.start,
|
||||
// style: TextStyle(
|
||||
// fontSize: 13,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// );
|
||||
// } else {
|
||||
return CustomErrorWidget(
|
||||
error: err,
|
||||
stackTrace: _,
|
||||
onRefresh: () {
|
||||
// ignore: unused_result
|
||||
ref.refresh(bookInfoProvider(url));
|
||||
},
|
||||
);
|
||||
// }
|
||||
},
|
||||
loading: () {
|
||||
return Center(
|
||||
@ -198,7 +198,17 @@ class _ActionButtonWidgetState extends ConsumerState<ActionButtonWidget> {
|
||||
color: Colors.white,
|
||||
)),
|
||||
onPressed: () async {
|
||||
await downloadFileWidget(ref, context, widget.data);
|
||||
final result = await Navigator.push(context,
|
||||
MaterialPageRoute(builder: (BuildContext context) {
|
||||
return Webview(url: widget.data.mirror ?? '');
|
||||
}));
|
||||
|
||||
if (result != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
widget.data.mirror = result;
|
||||
// ignore: use_build_context_synchronously
|
||||
await downloadFileWidget(ref, context, widget.data);
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
@ -222,7 +232,7 @@ class _ActionButtonWidgetState extends ConsumerState<ActionButtonWidget> {
|
||||
}
|
||||
|
||||
Future<void> downloadFileWidget(
|
||||
WidgetRef ref, BuildContext context, dynamic data) async {
|
||||
WidgetRef ref, BuildContext context, BookInfoData data) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
@ -230,8 +240,10 @@ Future<void> downloadFileWidget(
|
||||
return _ShowDialog(title: data.title);
|
||||
});
|
||||
|
||||
List<String> mirrors = [data.mirror!];
|
||||
print(mirrors);
|
||||
downloadFile(
|
||||
mirrors: data.mirrors!,
|
||||
mirrors: mirrors,
|
||||
md5: data.md5,
|
||||
format: data.format!,
|
||||
onStart: () {
|
||||
@ -263,7 +275,7 @@ Future<void> downloadFileWidget(
|
||||
|
||||
try {
|
||||
final checkSum = await verifyFileCheckSum(
|
||||
md5Hash: data.md5, format: data.format);
|
||||
md5Hash: data.md5, format: data.format!);
|
||||
if (checkSum == true) {
|
||||
ref.read(checkSumState.notifier).state =
|
||||
CheckSumProcessState.success;
|
||||
|
@ -102,11 +102,11 @@ Future<void> openCbrAndCbz(
|
||||
{required String fileName, required BuildContext context}) async {
|
||||
try {
|
||||
String path = await getFilePath(fileName);
|
||||
await OpenFile.open(path);
|
||||
await OpenFile.open(path, linuxByProcess: true);
|
||||
} catch (e) {
|
||||
// ignore: avoid_print
|
||||
// print(e);
|
||||
// ignore: use_build_context_synchronously
|
||||
showSnackBar(context: context, message: 'Unable to open pdf!');
|
||||
showSnackBar(context: context, message: 'Unable to open file!');
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
// Dart imports:
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
// Flutter imports:
|
||||
@ -11,12 +10,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:open_file/open_file.dart';
|
||||
|
||||
// Project imports:
|
||||
import 'package:openlib/services/database.dart';
|
||||
import 'package:openlib/services/files.dart' show getFilePath;
|
||||
import 'package:openlib/ui/components/snack_bar_widget.dart';
|
||||
|
||||
import 'package:openlib/state/state.dart'
|
||||
show filePathProvider, saveEpubState, getBookPosition;
|
||||
show
|
||||
filePathProvider,
|
||||
saveEpubState,
|
||||
getBookPosition,
|
||||
openEpubWithExternalAppProvider;
|
||||
|
||||
Future<void> launchEpubViewer(
|
||||
{required String fileName,
|
||||
@ -24,10 +25,24 @@ Future<void> launchEpubViewer(
|
||||
required WidgetRef ref}) async {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
String path = await getFilePath(fileName);
|
||||
MyLibraryDb dataBase = MyLibraryDb.instance;
|
||||
bool openWithExternalApp = ref.watch(openEpubWithExternalAppProvider);
|
||||
|
||||
String? epubConfig = await dataBase.getBookState(fileName);
|
||||
await OpenFile.open(path);
|
||||
if (openWithExternalApp) {
|
||||
await OpenFile.open(path, linuxByProcess: true);
|
||||
} else {
|
||||
try {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.push(context,
|
||||
MaterialPageRoute(builder: (BuildContext context) {
|
||||
return EpubViewerWidget(
|
||||
fileName: fileName,
|
||||
);
|
||||
}));
|
||||
} catch (e) {
|
||||
// ignore: use_build_context_synchronously
|
||||
showSnackBar(context: context, message: 'Unable to open pdf!');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
|
||||
return EpubViewerWidget(
|
||||
|
@ -22,7 +22,6 @@ import 'package:openlib/state/state.dart'
|
||||
openPdfWithExternalAppProvider,
|
||||
getBookPosition;
|
||||
|
||||
|
||||
Future<void> launchPdfViewer(
|
||||
{required String fileName,
|
||||
required BuildContext context,
|
||||
@ -30,7 +29,7 @@ Future<void> launchPdfViewer(
|
||||
bool openWithExternalApp = ref.watch(openPdfWithExternalAppProvider);
|
||||
if (openWithExternalApp) {
|
||||
String path = await getFilePath(fileName);
|
||||
await OpenFile.open(path);
|
||||
await OpenFile.open(path, linuxByProcess: true);
|
||||
} else {
|
||||
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
|
||||
return PdfView(
|
||||
|
@ -18,7 +18,10 @@ import 'package:openlib/ui/about_page.dart';
|
||||
import 'package:openlib/ui/components/page_title_widget.dart';
|
||||
|
||||
import 'package:openlib/state/state.dart'
|
||||
show themeModeProvider, openPdfWithExternalAppProvider;
|
||||
show
|
||||
themeModeProvider,
|
||||
openPdfWithExternalAppProvider,
|
||||
openEpubWithExternalAppProvider;
|
||||
|
||||
Future<void> requestStoragePermission() async {
|
||||
bool permissionGranted = false;
|
||||
@ -112,6 +115,30 @@ class SettingsPage extends ConsumerWidget {
|
||||
)
|
||||
],
|
||||
),
|
||||
_PaddedContainer(
|
||||
children: [
|
||||
Text(
|
||||
"Open Epub with External Reader",
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.tertiary,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
// This bool value toggles the switch.
|
||||
value: ref.watch(
|
||||
openEpubWithExternalAppProvider,
|
||||
),
|
||||
activeColor: Colors.red,
|
||||
onChanged: (bool value) {
|
||||
ref.read(openEpubWithExternalAppProvider.notifier).state =
|
||||
value;
|
||||
dataBase.savePreference('openEpubwithExternalApp', value);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
_PaddedContainer(
|
||||
onClick: () async {
|
||||
final currentDirectory =
|
||||
|
@ -3,16 +3,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
// Package imports:
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
// Project imports:
|
||||
import 'package:openlib/services/database.dart';
|
||||
|
||||
import 'package:webview_cookie_manager/webview_cookie_manager.dart'
|
||||
as cookiejar;
|
||||
|
||||
import 'package:openlib/state/state.dart'
|
||||
show cookieProvider, userAgentProvider, bookInfoProvider;
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
|
||||
class Webview extends ConsumerStatefulWidget {
|
||||
const Webview({super.key, required this.url});
|
||||
@ -23,58 +14,67 @@ class Webview extends ConsumerStatefulWidget {
|
||||
}
|
||||
|
||||
class _WebviewState extends ConsumerState<Webview> {
|
||||
WebViewController controller = WebViewController();
|
||||
final GlobalKey webViewKey = GlobalKey();
|
||||
|
||||
InAppWebViewController? webViewController;
|
||||
|
||||
final urlController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
final cookieManager = cookiejar.WebviewCookieManager();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
MyLibraryDb dataBase = MyLibraryDb.instance;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: const Text("Solve Captcha"),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: WebViewWidget(
|
||||
controller: controller
|
||||
..setJavaScriptMode(JavaScriptMode.unrestricted)
|
||||
// ..setBackgroundColor(const Color(
|
||||
// 0x00000000)) // TODO: Crashes macOS app. https://github.com/flutter/flutter/issues/153773
|
||||
..loadRequest(Uri.parse(widget.url))
|
||||
..getUserAgent().then((value) {
|
||||
ref.read(userAgentProvider.notifier).state = value!;
|
||||
dataBase.setBrowserOptions('userAgent', value);
|
||||
})
|
||||
..setNavigationDelegate(NavigationDelegate(
|
||||
onPageStarted: (url) async {
|
||||
var urlStatusCode = await controller.runJavaScriptReturningResult(
|
||||
"var xhr = new XMLHttpRequest();xhr.open('GET', window.location.href, false);xhr.send(null);xhr.status;");
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
InAppWebView(
|
||||
key: webViewKey,
|
||||
initialUrlRequest: URLRequest(url: WebUri(widget.url)),
|
||||
onWebViewCreated: (controller) {
|
||||
webViewController = controller;
|
||||
},
|
||||
onLoadStart: (controller, url) {},
|
||||
onLoadStop: (controller, url) async {
|
||||
String query =
|
||||
"""document.querySelector('a[class="font-bold"]').href""";
|
||||
String? mirrorLink = await webViewController
|
||||
?.evaluateJavascript(source: query);
|
||||
// final ipfsUrl = widget.url
|
||||
// .replaceAll("slow_download", "ipfs_downloads")
|
||||
// .replaceAll("/0/2", "");
|
||||
|
||||
if (urlStatusCode.toString().contains('200')) {
|
||||
final cookies = await cookieManager
|
||||
.getCookies("https://annas-archive.org");
|
||||
// await webViewController?.loadUrl(
|
||||
// urlRequest: URLRequest(
|
||||
// url: WebUri('https://example.com/new-page')));
|
||||
|
||||
List<String> cookie = [];
|
||||
for (var element in cookies) {
|
||||
if (element.name == 'cf_clearance' ||
|
||||
element.name == 'cf_chl_2') {
|
||||
cookie.add(element.toString().split(';')[0]);
|
||||
}
|
||||
}
|
||||
|
||||
String cfClearance = cookie.join('; ');
|
||||
|
||||
ref.read(cookieProvider.notifier).state = cfClearance;
|
||||
|
||||
await dataBase.setBrowserOptions('cookie', cfClearance);
|
||||
|
||||
ref.invalidate(bookInfoProvider);
|
||||
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
)),
|
||||
if (mirrorLink != null) {
|
||||
Future.delayed(const Duration(milliseconds: 70), () {
|
||||
// ignore: use_build_context_synchronously
|
||||
Navigator.pop(context, mirrorLink);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -6,9 +6,13 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <open_file_linux/open_file_linux_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
|
||||
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
open_file_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
|
@ -6,15 +6,17 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import device_info_plus
|
||||
import flutter_inappwebview_macos
|
||||
import open_file_mac
|
||||
import path_provider_foundation
|
||||
import sqflite
|
||||
import url_launcher_macos
|
||||
import webview_flutter_wkwebview
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
|
||||
}
|
||||
|
180
pubspec.lock
180
pubspec.lock
@ -254,6 +254,62 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0-beta.2"
|
||||
flutter_inappwebview:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_inappwebview
|
||||
sha256: "3e9a443a18ecef966fb930c3a76ca5ab6a7aafc0c7b5e14a4a850cf107b09959"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_inappwebview_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_android
|
||||
sha256: d247f6ed417f1f8c364612fa05a2ecba7f775c8d0c044c1d3b9ee33a6515c421
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.13"
|
||||
flutter_inappwebview_internal_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_internal_annotations
|
||||
sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter_inappwebview_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_ios
|
||||
sha256: f363577208b97b10b319cd0c428555cd8493e88b468019a8c5635a0e4312bd0f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.13"
|
||||
flutter_inappwebview_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_macos
|
||||
sha256: b55b9e506c549ce88e26580351d2c71d54f4825901666bd6cfa4be9415bb2636
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.11"
|
||||
flutter_inappwebview_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_platform_interface
|
||||
sha256: "545fd4c25a07d2775f7d5af05a979b2cac4fbf79393b0a7f5d33ba39ba4f6187"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.10"
|
||||
flutter_inappwebview_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_inappwebview_web
|
||||
sha256: d8c680abfb6fec71609a700199635d38a744df0febd5544c5a020bd73de8ee07
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -282,10 +338,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de"
|
||||
sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.21"
|
||||
version: "2.0.22"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -376,6 +432,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.6.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -460,10 +524,66 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: open_file
|
||||
sha256: a5a32d44acb7c899987d0999e1e3cbb0a0f1adebbf41ac813ec6d2d8faa0af20
|
||||
sha256: de371f549b1320a48980952473fae1903d4927975506534c8ea4643642eb5f98
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.2"
|
||||
version: "3.5.3"
|
||||
open_file_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_android
|
||||
sha256: b5e1a2e9c5ea8e256b015403e94299039627c7205c2a5e6bb426c33235b6ca9a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
open_file_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_ios
|
||||
sha256: "8d9c03495cf14ca70bdbf191894b822ba3b2629cc0046ee311cbbe504db66c44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
open_file_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_linux
|
||||
sha256: cd2088722048b9c40f8615c6d83005fe0726e0e447e9cdfb40c2b65477291f7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
open_file_mac:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_mac
|
||||
sha256: "9d809f528cccc6dc9390caf50893eae9a6944e0f3b8a2558c7ad19e91c9244a1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
open_file_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_platform_interface
|
||||
sha256: "14c50efb1a9667cb96e4fa68d601e6ad348fe337b02789834029b37ae3631498"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
open_file_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_web
|
||||
sha256: ba35c6f38c21c2bb4268a80927bb828353dda0edfce92e274e0b9639e4f31360
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
open_file_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: open_file_windows
|
||||
sha256: "2f4318d2d3958ec8d63b6dd4430c15b1fcb2fe7a2113e83c734584501a5c6d81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -604,10 +724,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
|
||||
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "3.2.2"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -833,10 +953,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
||||
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.2"
|
||||
version: "4.5.0"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -873,10 +993,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.4"
|
||||
version: "14.2.5"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -885,46 +1005,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
webview_cookie_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_cookie_manager
|
||||
sha256: "425a9feac5cd2cb62a71da3dda5ac2eaf9ece5481ee8d79f3868dc5ba8223ad3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.6"
|
||||
webview_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: ec81f57aa1611f8ebecf1d2259da4ef052281cb5ad624131c93546c79ccc7736
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: "6e64fcb1c19d92024da8f33503aaeeda35825d77142c01d0ea2aa32edc79fdc8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.16.7"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_platform_interface
|
||||
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: "1942a12224ab31e9508cf00c0c6347b931b023b8a4f0811e5dec3b06f94f117d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.15.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
10
pubspec.yaml
10
pubspec.yaml
@ -16,10 +16,10 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.6+9
|
||||
version: 1.0.7+1
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.5 <4.0.0"
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
@ -46,8 +46,9 @@ dependencies:
|
||||
path_provider: ^2.0.15
|
||||
permission_handler: ^11.2.0
|
||||
open_file: ^3.3.2
|
||||
webview_flutter: ^4.4.1
|
||||
webview_cookie_manager: ^2.0.6
|
||||
# webview_flutter: ^4.9.0
|
||||
# webview_cookie_manager: ^2.0.6
|
||||
# vocsy_epub_viewer: ^2.0.0
|
||||
|
||||
flutter_svg: ^2.0.7
|
||||
google_fonts: ^6.1.0
|
||||
@ -63,6 +64,7 @@ dependencies:
|
||||
crypto: ^3.0.3
|
||||
file_picker: ^8.1.2
|
||||
device_info_plus: ^10.1.2
|
||||
flutter_inappwebview: ^6.0.0
|
||||
|
||||
dev_dependencies:
|
||||
import_sorter: ^4.6.0
|
||||
|
Reference in New Issue
Block a user