fixed no result found error

This commit is contained in:
dstark5
2023-11-03 06:05:03 -07:00
parent 3a95d79c4a
commit 51283c3410
8 changed files with 194 additions and 160 deletions

View File

@ -19,13 +19,15 @@
<data android:scheme="https" /> <data android:scheme="https" />
</intent> </intent>
</queries> </queries>
<application <application
android:label="Openlib" android:label="Openlib"
android:name="${applicationName}" android:name="${applicationName}"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:icon="@mipmap/launcher_icon"> android:icon="@mipmap/launcher_icon">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@ -38,6 +40,7 @@
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. --> to determine the Window background behind the Flutter UI. -->
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme"

View File

@ -2,7 +2,6 @@ import 'package:dio/dio.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:html/parser.dart' show parse; import 'package:html/parser.dart' show parse;
import 'package:http/http.dart' as http;
class BookData { class BookData {
final String title; final String title;
@ -52,10 +51,12 @@ class BookInfoData extends BookData {
class AnnasArchieve { class AnnasArchieve {
String baseUrl = "https://annas-archive.org"; String baseUrl = "https://annas-archive.org";
final Dio dio = Dio(BaseOptions(headers: { final Dio dio = Dio();
Map<String, dynamic> defaultDioHeaders = {
"user-agent": "user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36",
})); };
String getMd5(String url) { String getMd5(String url) {
String md5 = url.toString().split('/').last; String md5 = url.toString().split('/').last;
@ -66,7 +67,7 @@ class AnnasArchieve {
var document = var document =
parse(resData.toString().replaceAll(RegExp(r"<!--|-->"), '')); parse(resData.toString().replaceAll(RegExp(r"<!--|-->"), ''));
var books = document.querySelectorAll( var books = document.querySelectorAll(
'a[class="js-vim-focus custom-a flex items-center relative left-[-10px] w-[calc(100%+20px)] px-[10px] py-2 outline-offset-[-2px] outline-2 rounded-[3px] hover:bg-[#00000011] focus:outline "]'); 'a[class="js-vim-focus custom-a flex items-center relative left-[-10px] w-[calc(100%+20px)] px-[10px] outline-offset-[-2px] outline-2 rounded-[3px] hover:bg-[#00000011] focus:outline "]');
List<BookData> bookList = []; List<BookData> bookList = [];
@ -75,16 +76,23 @@ class AnnasArchieve {
'title': element.querySelector('h3')?.text, 'title': element.querySelector('h3')?.text,
'thumbnail': element.querySelector('img')?.attributes['src'], 'thumbnail': element.querySelector('img')?.attributes['src'],
'link': element.attributes['href'], 'link': element.attributes['href'],
'author': element.querySelector('div[class="truncate italic"]')?.text ?? 'author': element
.querySelector(
'div[class="max-lg:line-clamp-[2] lg:truncate leading-[1.2] lg:leading-[1.35] max-lg:text-sm italic"]')
?.text ??
'unknown', 'unknown',
'publisher': 'publisher': element
element.querySelector('div[class="truncate text-sm"]')?.text ?? .querySelector(
"unknown", 'div[class="truncate leading-[1.2] lg:leading-[1.35] max-lg:text-xs"]')
?.text ??
"unknown",
'info': element 'info': element
.querySelector('div[class="truncate text-xs text-gray-500"]') .querySelector(
'div[class="line-clamp-[2] leading-[1.2] text-[10px] lg:text-xs text-gray-500"]')
?.text ?? ?.text ??
'' ''
}; };
if ((data['title'] != null && data['title'] != '') && if ((data['title'] != null && data['title'] != '') &&
(data['link'] != null && data['link'] != '') && (data['link'] != null && data['link'] != '') &&
(data['info'] != null && (data['info'] != null &&
@ -130,19 +138,29 @@ class AnnasArchieve {
Future<String?> _getMirrorLink( Future<String?> _getMirrorLink(
String url, String userAgent, String cookie) async { String url, String userAgent, String cookie) async {
try { try {
final response = await http.get(Uri.parse(url), final response = await dio.get(url,
headers: {"Cookie": cookie, "User-Agent": userAgent}); options: Options(extra: {
if (response.statusCode == 403) { 'withCredentials': true
throw jsonEncode({"code": "403", "url": url}); }, headers: {
} "Host": "annas-archive.org",
var document = parse(response.body.toString()); "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
}));
var document = parse(response.data.toString());
var pTag = document.querySelector('p[class="mb-4"]'); var pTag = document.querySelector('p[class="mb-4"]');
String? link = pTag?.querySelector('a')?.attributes['href']; String? link = pTag?.querySelector('a')?.attributes['href'];
return link; return link;
} catch (e) { } catch (e) {
// print(e); // print('${url} ${e}');
if (e.toString().contains("403")) { if (e.toString().contains("403")) {
rethrow; throw jsonEncode({"code": "403", "url": url});
} }
return null; return null;
} }
@ -238,7 +256,8 @@ class AnnasArchieve {
? '$baseUrl/search?index=&q=$searchQuery&ext=$fileType&sort=$sort' ? '$baseUrl/search?index=&q=$searchQuery&ext=$fileType&sort=$sort'
: '$baseUrl/search?index=&q=$searchQuery&content=$content&ext=$fileType&sort=$sort'; : '$baseUrl/search?index=&q=$searchQuery&content=$content&ext=$fileType&sort=$sort';
final response = await dio.get(encodedURL); final response = await dio.get(encodedURL,
options: Options(headers: defaultDioHeaders));
return _parser(response.data, fileType); return _parser(response.data, fileType);
} on DioException catch (e) { } on DioException catch (e) {
if (e.type == DioExceptionType.unknown) { if (e.type == DioExceptionType.unknown) {
@ -253,7 +272,8 @@ class AnnasArchieve {
required String userAgent, required String userAgent,
required String cookie}) async { required String cookie}) async {
try { try {
final response = await dio.get(url); final response =
await dio.get(url, options: Options(headers: defaultDioHeaders));
BookInfoData? data = BookInfoData? data =
await _bookInfoParser(response.data, url, userAgent, cookie); await _bookInfoParser(response.data, url, userAgent, cookie);
if (data != null) { if (data != null) {

View File

@ -1,5 +1,4 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:http/http.dart' as http;
import 'files.dart'; import 'files.dart';
Future<String> _getFilePath(String fileName) async { Future<String> _getFilePath(String fileName) async {
@ -24,11 +23,11 @@ List<String> _reorderMirrors(List<String> mirrors) {
return [...ipfsMirrors, ...httpsMirrors]; return [...ipfsMirrors, ...httpsMirrors];
} }
Future<String?> _getAliveMirror(List<String> mirrors) async { Future<String?> _getAliveMirror(List<String> mirrors, Dio dio) async {
for (var url in mirrors) { for (var url in mirrors) {
try { try {
final response = final response = await dio.head(url,
await http.head(Uri.parse(url)).timeout(const Duration(seconds: 2)); options: Options(receiveTimeout: const Duration(seconds: 5)));
if (response.statusCode == 200) { if (response.statusCode == 200) {
return url; return url;
} }
@ -48,10 +47,11 @@ Future<void> downloadFile(
required Function mirrorStatus, required Function mirrorStatus,
required Function onDownlaodFailed}) async { required Function onDownlaodFailed}) async {
Dio dio = Dio(); Dio dio = Dio();
String path = await _getFilePath('$md5.$format'); String path = await _getFilePath('$md5.$format');
List<String> orderedMirrors = _reorderMirrors(mirrors); List<String> orderedMirrors = _reorderMirrors(mirrors);
String? workingMirror = await _getAliveMirror(orderedMirrors); String? workingMirror = await _getAliveMirror(orderedMirrors, dio);
// print(workingMirror); // print(workingMirror);
// print(path); // print(path);

View File

@ -1,8 +1,8 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:openlib/services/database.dart'; import 'package:openlib/services/database.dart';
import 'package:openlib/ui/components/error_widget.dart'; import 'package:openlib/ui/components/error_widget.dart';
@ -48,23 +48,21 @@ class BookInfoPage extends ConsumerWidget {
data: data, child: ActionButtonWidget(data: data)); data: data, child: ActionButtonWidget(data: data));
}, },
error: (err, _) { error: (err, _) {
// print(err);
if (err.toString().contains("403")) { if (err.toString().contains("403")) {
var errJson = jsonDecode(err.toString()); var errJson = jsonDecode(err.toString());
if (SchedulerBinding.instance.schedulerPhase == if (SchedulerBinding.instance.schedulerPhase ==
SchedulerPhase.persistentCallbacks) { SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((_) { SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.push(context, Future.delayed(
MaterialPageRoute(builder: (BuildContext context) { const Duration(seconds: 3),
return Webview(url: errJson["url"]); () => Navigator.pushReplacement(context,
})).then((value) { MaterialPageRoute(builder: (BuildContext context) {
// print("got Cf Clearance"); return Webview(url: errJson["url"]);
// ignore: unused_result })));
ref.refresh(bookInfoProvider(url));
// });
});
}); });
} }
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@ -112,7 +110,7 @@ class BookInfoPage extends ConsumerWidget {
child: const Padding( child: const Padding(
padding: EdgeInsets.all(10.0), padding: EdgeInsets.all(10.0),
child: Text( child: Text(
"If you have solved the captcha then you will be automatically redirected to the book page", "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, textAlign: TextAlign.start,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,

View File

@ -17,127 +17,133 @@ class TrendingPage extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final trendingBooks = ref.watch(getTrendingBooks); final trendingBooks = ref.watch(getTrendingBooks);
return trendingBooks.when(data: (data) { return trendingBooks.when(
return Padding( skipLoadingOnRefresh: false,
padding: const EdgeInsets.only(left: 5, right: 5, top: 10), data: (data) {
child: CustomScrollView( return Padding(
physics: const BouncingScrollPhysics(), padding: const EdgeInsets.only(left: 5, right: 5, top: 10),
slivers: [ child: CustomScrollView(
const SliverToBoxAdapter( physics: const BouncingScrollPhysics(),
child: TitleText("Trending"), slivers: [
), const SliverToBoxAdapter(
SliverPadding( child: TitleText("Trending"),
padding: const EdgeInsets.all(5),
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10.0,
crossAxisSpacing: 13.0,
mainAxisExtent: 205,
), ),
delegate: SliverChildBuilderDelegate( SliverPadding(
(BuildContext context, int index) { padding: const EdgeInsets.all(5),
return InkWell( sliver: SliverGrid(
onTap: () { gridDelegate:
Navigator.push(context, const SliverGridDelegateWithFixedCrossAxisCount(
MaterialPageRoute(builder: (BuildContext context) { crossAxisCount: 3,
return ResultPage( mainAxisSpacing: 10.0,
searchQuery: data[index].title!, crossAxisSpacing: 13.0,
); mainAxisExtent: 205,
})); ),
}, delegate: SliverChildBuilderDelegate(
child: SizedBox( (BuildContext context, int index) {
width: double.infinity, return InkWell(
height: double.infinity, onTap: () {
child: Column( Navigator.push(context, MaterialPageRoute(
mainAxisAlignment: MainAxisAlignment.start, builder: (BuildContext context) {
crossAxisAlignment: CrossAxisAlignment.center, return ResultPage(
children: [ searchQuery: data[index].title!,
CachedNetworkImage( );
height: imageHeight, }));
width: imageWidth, },
imageUrl: data[index].thumbnail!, child: SizedBox(
imageBuilder: (context, imageProvider) => width: double.infinity,
Container( height: double.infinity,
decoration: BoxDecoration( child: Column(
boxShadow: const [ mainAxisAlignment: MainAxisAlignment.start,
BoxShadow( crossAxisAlignment: CrossAxisAlignment.center,
color: Colors.grey, children: [
spreadRadius: 0.1, CachedNetworkImage(
blurRadius: 1)
],
borderRadius: const BorderRadius.all(
Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.fill,
),
),
),
placeholder: (context, url) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: "#E3E8E9".toColor(),
),
height: imageHeight,
width: imageWidth,
),
errorWidget: (context, url, error) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey,
),
height: imageHeight, height: imageHeight,
width: imageWidth, width: imageWidth,
child: const Center( imageUrl: data[index].thumbnail!,
child: Icon(Icons.image_rounded), imageBuilder: (context, imageProvider) =>
Container(
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.grey,
spreadRadius: 0.1,
blurRadius: 1)
],
borderRadius: const BorderRadius.all(
Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.fill,
),
),
), ),
); placeholder: (context, url) => Container(
}, decoration: BoxDecoration(
), borderRadius: BorderRadius.circular(5),
Padding( color: "#E3E8E9".toColor(),
padding: const EdgeInsets.only(top: 4), ),
child: SizedBox( height: imageHeight,
width: imageWidth, width: imageWidth,
child: Text( ),
data[index].title!, errorWidget: (context, url, error) {
style: Theme.of(context) return Container(
.textTheme decoration: BoxDecoration(
.displayMedium, borderRadius:
maxLines: 2, BorderRadius.circular(5),
color: Colors.grey,
),
height: imageHeight,
width: imageWidth,
child: const Center(
child: Icon(Icons.image_rounded),
),
);
},
), ),
), Padding(
), padding: const EdgeInsets.only(top: 4),
]), child: SizedBox(
), width: imageWidth,
); child: Text(
}, data[index].title!,
childCount: data.length, style: Theme.of(context)
.textTheme
.displayMedium,
maxLines: 2,
),
),
),
]),
),
);
},
childCount: data.length,
),
),
), ),
), ],
), ),
], );
),
);
}, error: (error, _) {
return CustomErrorWidget(
error: error,
stackTrace: _,
onRefresh: () {
// ignore: unused_result
ref.refresh(getTrendingBooks);
}, },
); error: (error, _) {
}, loading: () { return CustomErrorWidget(
return Center( error: error,
child: SizedBox( stackTrace: _,
width: 25, onRefresh: () {
height: 25, // ignore: unused_result
child: CircularProgressIndicator( ref.refresh(getTrendingBooks);
color: Theme.of(context).colorScheme.secondary, },
), );
)); },
}); loading: () {
return Center(
child: SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(
color: Theme.of(context).colorScheme.secondary,
),
));
});
} }
} }

View File

@ -5,7 +5,7 @@ import 'package:webview_cookie_manager/webview_cookie_manager.dart'
as cookiejar; as cookiejar;
import 'package:openlib/state/state.dart' import 'package:openlib/state/state.dart'
show cookieProvider, userAgentProvider, dbProvider; show cookieProvider, userAgentProvider, dbProvider, bookInfoProvider;
class Webview extends ConsumerStatefulWidget { class Webview extends ConsumerStatefulWidget {
const Webview({Key? key, required this.url}) : super(key: key); const Webview({Key? key, required this.url}) : super(key: key);
@ -38,12 +38,13 @@ class _WebviewState extends ConsumerState<Webview> {
}) })
..setNavigationDelegate(NavigationDelegate( ..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) async { onPageStarted: (url) async {
var x = await controller.runJavaScriptReturningResult( var urlStatusCode = await controller.runJavaScriptReturningResult(
"var xhr = new XMLHttpRequest();xhr.open('GET', window.location.href, false);xhr.send(null);xhr.status;"); "var xhr = new XMLHttpRequest();xhr.open('GET', window.location.href, false);xhr.send(null);xhr.status;");
if (x.toString().contains('200')) { if (urlStatusCode.toString().contains('200')) {
final cookies = await cookieManager final cookies = await cookieManager
.getCookies("https://annas-archive.org"); .getCookies("https://annas-archive.org");
List<String> cookie = []; List<String> cookie = [];
for (var element in cookies) { for (var element in cookies) {
if (element.name == 'cf_clearance' || if (element.name == 'cf_clearance' ||
@ -51,10 +52,17 @@ class _WebviewState extends ConsumerState<Webview> {
cookie.add(element.toString().split(';')[0]); cookie.add(element.toString().split(';')[0]);
} }
} }
ref.read(cookieProvider.notifier).state = cookie.join('; ');
ref String cfClearance = cookie.join('; ');
ref.read(cookieProvider.notifier).state = cfClearance;
await ref
.read(dbProvider) .read(dbProvider)
.setBrowserOptions('cookie', cookie.join('; ')); .setBrowserOptions('cookie', cfClearance);
ref.invalidate(bookInfoProvider);
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
Navigator.pop(context); Navigator.pop(context);
} }

View File

@ -305,7 +305,7 @@ packages:
source: hosted source: hosted
version: "0.15.4" version: "0.15.4"
http: http:
dependency: "direct main" dependency: transitive
description: description:
name: http name: http
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"

View File

@ -47,7 +47,6 @@ dependencies:
path_provider: ^2.0.15 path_provider: ^2.0.15
permission_handler: ^10.4.3 permission_handler: ^10.4.3
open_file: ^3.3.2 open_file: ^3.3.2
http: ^1.1.0
webview_flutter: ^4.4.1 webview_flutter: ^4.4.1
webview_cookie_manager: ^2.0.6 webview_cookie_manager: ^2.0.6