mirror of
https://github.com/dstark5/Openlib.git
synced 2025-08-06 15:18:54 +08:00
276 lines
8.6 KiB
Dart
276 lines
8.6 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:html/parser.dart' show parse;
|
|
import 'package:http/http.dart' as http;
|
|
|
|
class BookData {
|
|
final String title;
|
|
final String? author;
|
|
final String? thumbnail;
|
|
final String link;
|
|
final String md5;
|
|
final String? publisher;
|
|
final String? info;
|
|
|
|
BookData(
|
|
{required this.title,
|
|
this.author,
|
|
this.thumbnail,
|
|
required this.link,
|
|
required this.md5,
|
|
this.publisher,
|
|
this.info});
|
|
}
|
|
|
|
class BookInfoData extends BookData {
|
|
final List<String>? mirrors;
|
|
final String? description;
|
|
final String? format;
|
|
|
|
BookInfoData(
|
|
{required String title,
|
|
required String? author,
|
|
required String? thumbnail,
|
|
required String? publisher,
|
|
required String? info,
|
|
required String link,
|
|
required String md5,
|
|
required this.mirrors,
|
|
required this.format,
|
|
required this.description})
|
|
: super(
|
|
title: title,
|
|
author: author,
|
|
thumbnail: thumbnail,
|
|
publisher: publisher,
|
|
info: info,
|
|
link: link,
|
|
md5: md5);
|
|
}
|
|
|
|
class AnnasArchieve {
|
|
String baseUrl = "https://annas-archive.org";
|
|
|
|
final Dio dio = Dio(BaseOptions(headers: {
|
|
"user-agent":
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0",
|
|
}));
|
|
|
|
String getMd5(String url) {
|
|
String md5 = url.toString().split('/').last;
|
|
return md5;
|
|
}
|
|
|
|
List<BookData> _parser(resData, String fileType) {
|
|
var document =
|
|
parse(resData.toString().replaceAll(RegExp(r"<!--|-->"), ''));
|
|
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 "]');
|
|
|
|
List<BookData> bookList = [];
|
|
|
|
for (var element in books) {
|
|
var data = {
|
|
'title': element.querySelector('h3')?.text,
|
|
'thumbnail': element.querySelector('img')?.attributes['src'],
|
|
'link': element.attributes['href'],
|
|
'author': element.querySelector('div[class="truncate italic"]')?.text ??
|
|
'unknown',
|
|
'publisher':
|
|
element.querySelector('div[class="truncate text-sm"]')?.text ??
|
|
"unknown",
|
|
'info': element
|
|
.querySelector('div[class="truncate text-xs text-gray-500"]')
|
|
?.text ??
|
|
''
|
|
};
|
|
if ((data['title'] != null && data['title'] != '') &&
|
|
(data['link'] != null && data['link'] != '') &&
|
|
(data['info'] != null &&
|
|
((fileType == "") &&
|
|
(data['info']!.contains('pdf') ||
|
|
data['info']!.contains('epub') ||
|
|
data['info']!.contains('cbr') ||
|
|
data['info']!.contains('cbz')) ||
|
|
((fileType != "") && data['info']!.contains(fileType))))) {
|
|
String link = baseUrl + data['link']!;
|
|
String publisher = ((data['publisher']?.contains('0') == true &&
|
|
data['publisher']!.length < 2) ||
|
|
data['publisher'] == "") ==
|
|
true
|
|
? "unknown"
|
|
: data['publisher'].toString();
|
|
|
|
BookData book = BookData(
|
|
title: data['title'].toString(),
|
|
author: data['author'],
|
|
thumbnail: data['thumbnail'],
|
|
link: link,
|
|
md5: getMd5(data['link'].toString()),
|
|
publisher: publisher,
|
|
info: data['info'],
|
|
);
|
|
bookList.add(book);
|
|
}
|
|
}
|
|
return bookList;
|
|
}
|
|
|
|
String getFormat(String info) {
|
|
if (info.contains('pdf') == true) {
|
|
return 'pdf';
|
|
} else {
|
|
if (info.contains('cbr')) return "cbr";
|
|
if (info.contains('cbz')) return "cbz";
|
|
return "epub";
|
|
}
|
|
}
|
|
|
|
Future<String?> _getMirrorLink(
|
|
String url, String userAgent, String cookie) async {
|
|
try {
|
|
// final response = await dio.get(url);
|
|
final response = await http.get(Uri.parse(url),
|
|
headers: {"Cookie": cookie, "User-Agent": userAgent});
|
|
if (response.statusCode == 403) {
|
|
throw jsonEncode({"code": "403", "url": url});
|
|
}
|
|
var document = parse(response.body.toString());
|
|
var pTag = document.querySelector('p[class="mb-4"]');
|
|
String? link = pTag?.querySelector('a')?.attributes['href'];
|
|
return link;
|
|
} catch (e) {
|
|
// print(e);
|
|
if (e.toString().contains("403")) {
|
|
rethrow;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<BookInfoData?> _bookInfoParser(resData, url, userAgent, cookie) async {
|
|
var document = parse(resData.toString());
|
|
var main = document.querySelector('main[class="main"]');
|
|
var ul = main?.querySelectorAll('ul[class="mb-4"]');
|
|
|
|
List<String> mirrors = [];
|
|
|
|
if (ul != null) {
|
|
var anchorTags = [];
|
|
if (ul.length == 2) {
|
|
anchorTags = ul[1].querySelectorAll('a');
|
|
} else {
|
|
anchorTags = ul[0].querySelectorAll('a');
|
|
}
|
|
|
|
for (var element in anchorTags) {
|
|
if (element.attributes['href']!.startsWith('https://')) {
|
|
if (element.attributes['href'] != null &&
|
|
element.attributes['href'].startsWith('https://1lib.sk') !=
|
|
true) {
|
|
mirrors.add(element.attributes['href']!);
|
|
}
|
|
} else if (element.attributes['href'] != null &&
|
|
element.attributes['href']!.startsWith('/slow_download')) {
|
|
if (element.text.contains('Slow Partner Server #1') == true ||
|
|
true == true) {
|
|
String? url = await _getMirrorLink(
|
|
'$baseUrl${element.attributes['href']!}', userAgent, cookie);
|
|
if (url != null && url.isNotEmpty) {
|
|
mirrors.add(url);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// print(mirrors);
|
|
|
|
var data = {
|
|
'title': main?.querySelector('div[class="text-3xl font-bold"]')?.text,
|
|
'author': main?.querySelector('div[class="italic"]')?.text ?? "unknown",
|
|
'thumbnail': main?.querySelector('img')?.attributes['src'],
|
|
'link': url,
|
|
'publisher':
|
|
main?.querySelector('div[class="text-md"]')?.text ?? "unknown",
|
|
'info':
|
|
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 ??
|
|
" "
|
|
};
|
|
|
|
if ((data['title'] != null && data['title'] != '') &&
|
|
(data['link'] != null && data['link'] != '')) {
|
|
String title = data['title'].toString().characters.skipLast(1).toString();
|
|
String author =
|
|
data['author'].toString().characters.skipLast(1).toString();
|
|
String publisher = ((data['publisher']?.contains('0') == true &&
|
|
data['publisher']!.length < 2) ||
|
|
data['publisher'] == "") ==
|
|
true
|
|
? "unknown"
|
|
: data['publisher'].toString();
|
|
|
|
return BookInfoData(
|
|
title: title,
|
|
author: author,
|
|
thumbnail: main?.querySelector('img')?.attributes['src'],
|
|
publisher: publisher,
|
|
info: data['info'],
|
|
link: data['link'],
|
|
md5: getMd5(data['link'].toString()),
|
|
format: getFormat(data['info']),
|
|
mirrors: mirrors,
|
|
description: data['description'],
|
|
);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<List<BookData>> searchBooks(
|
|
{required String searchQuery,
|
|
String content = "",
|
|
String sort = "",
|
|
String fileType = ""}) async {
|
|
try {
|
|
final String encodedURL = content == ""
|
|
? '$baseUrl/search?index=&q=$searchQuery&ext=$fileType&sort=$sort'
|
|
: '$baseUrl/search?index=&q=$searchQuery&content=$content&ext=$fileType&sort=$sort';
|
|
|
|
final response = await dio.get(encodedURL);
|
|
return _parser(response.data, fileType);
|
|
} on DioException catch (e) {
|
|
if (e.type == DioExceptionType.unknown) {
|
|
throw "socketException";
|
|
}
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
Future<BookInfoData> bookInfo(
|
|
{required String url,
|
|
required String userAgent,
|
|
required String cookie}) async {
|
|
try {
|
|
final response = await dio.get(url);
|
|
BookInfoData? data =
|
|
await _bookInfoParser(response.data, url, userAgent, cookie);
|
|
if (data != null) {
|
|
return data;
|
|
} else {
|
|
throw 'unable to get data';
|
|
}
|
|
} on DioException catch (e) {
|
|
if (e.type == DioExceptionType.unknown) {
|
|
throw "socketException";
|
|
}
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|