mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-22 00:21:57 +00:00
added support for epubs
embedded images not supported yet
This commit is contained in:
parent
d6d674c270
commit
3677938bf8
19 changed files with 149 additions and 89 deletions
|
|
@ -11,25 +11,32 @@ import '../schema/opf/epub_metadata_meta.dart';
|
||||||
|
|
||||||
class BookCoverReader {
|
class BookCoverReader {
|
||||||
static Future<images.Image?> readBookCover(EpubBookRef bookRef) async {
|
static Future<images.Image?> readBookCover(EpubBookRef bookRef) async {
|
||||||
var metaItems = bookRef.Schema!.Package!.Metadata!.MetaItems;
|
EpubManifestItem? coverManifestItem =
|
||||||
if (metaItems == null || metaItems.isEmpty) return null;
|
bookRef.Schema!.Package!.Manifest!.Items!.firstWhereOrNull(
|
||||||
|
(i) => i.Properties == "cover-image",
|
||||||
|
);
|
||||||
|
|
||||||
var coverMetaItem = metaItems.firstWhereOrNull(
|
if (coverManifestItem == null) {
|
||||||
(EpubMetadataMeta metaItem) =>
|
var metaItems = bookRef.Schema!.Package!.Metadata!.MetaItems;
|
||||||
metaItem.Name != null && metaItem.Name!.toLowerCase() == 'cover');
|
if (metaItems == null || metaItems.isEmpty) return null;
|
||||||
if (coverMetaItem == null) return null;
|
|
||||||
if (coverMetaItem.Content == null || coverMetaItem.Content!.isEmpty) {
|
var coverMetaItem = metaItems.firstWhereOrNull(
|
||||||
throw Exception(
|
(EpubMetadataMeta metaItem) =>
|
||||||
'Incorrect EPUB metadata: cover item content is missing.');
|
metaItem.Name != null && metaItem.Name!.toLowerCase() == 'cover');
|
||||||
|
if (coverMetaItem == null) return null;
|
||||||
|
if (coverMetaItem.Content == null || coverMetaItem.Content!.isEmpty) {
|
||||||
|
throw Exception(
|
||||||
|
'Incorrect EPUB metadata: cover item content is missing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
coverManifestItem = bookRef.Schema!.Package!.Manifest!.Items!
|
||||||
|
.firstWhereOrNull((EpubManifestItem manifestItem) =>
|
||||||
|
manifestItem.Id!.toLowerCase() ==
|
||||||
|
coverMetaItem.Content!.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
var coverManifestItem = bookRef.Schema!.Package!.Manifest!.Items!
|
|
||||||
.firstWhereOrNull((EpubManifestItem manifestItem) =>
|
|
||||||
manifestItem.Id!.toLowerCase() ==
|
|
||||||
coverMetaItem.Content!.toLowerCase());
|
|
||||||
if (coverManifestItem == null) {
|
if (coverManifestItem == null) {
|
||||||
throw Exception(
|
throw Exception('Incorrect EPUB manifest');
|
||||||
'Incorrect EPUB manifest: item with ID = \"${coverMetaItem.Content}\" is missing.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EpubByteContentFileRef? coverImageContentFileRef;
|
EpubByteContentFileRef? coverImageContentFileRef;
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ class ChapterReader {
|
||||||
EpubBookRef bookRef, List<EpubNavigationPoint> navigationPoints) {
|
EpubBookRef bookRef, List<EpubNavigationPoint> navigationPoints) {
|
||||||
var result = <EpubChapterRef>[];
|
var result = <EpubChapterRef>[];
|
||||||
// navigationPoints.forEach((EpubNavigationPoint navigationPoint) {
|
// navigationPoints.forEach((EpubNavigationPoint navigationPoint) {
|
||||||
for (var navigationPoint in navigationPoints){
|
for (var navigationPoint in navigationPoints) {
|
||||||
String? contentFileName;
|
String? contentFileName;
|
||||||
String? anchor;
|
String? anchor;
|
||||||
if (navigationPoint.Content?.Source ==null) continue;
|
if (navigationPoint.Content?.Source == null) continue;
|
||||||
var contentSourceAnchorCharIndex =
|
var contentSourceAnchorCharIndex =
|
||||||
navigationPoint.Content!.Source!.indexOf('#');
|
navigationPoint.Content!.Source!.indexOf('#');
|
||||||
if (contentSourceAnchorCharIndex == -1) {
|
if (contentSourceAnchorCharIndex == -1) {
|
||||||
|
|
@ -31,7 +31,7 @@ class ChapterReader {
|
||||||
anchor = navigationPoint.Content!.Source!
|
anchor = navigationPoint.Content!.Source!
|
||||||
.substring(contentSourceAnchorCharIndex + 1);
|
.substring(contentSourceAnchorCharIndex + 1);
|
||||||
}
|
}
|
||||||
contentFileName = Uri.decodeFull(contentFileName!);
|
contentFileName = Uri.decodeFull(contentFileName!).replaceAll("\\", "/");
|
||||||
EpubTextContentFileRef? htmlContentFileRef;
|
EpubTextContentFileRef? htmlContentFileRef;
|
||||||
if (!bookRef.Content!.Html!.containsKey(contentFileName)) {
|
if (!bookRef.Content!.Html!.containsKey(contentFileName)) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
|
|
@ -45,21 +45,23 @@ class ChapterReader {
|
||||||
chapterRef.Title = navigationPoint.NavigationLabels!.first.Text;
|
chapterRef.Title = navigationPoint.NavigationLabels!.first.Text;
|
||||||
chapterRef.SubChapters =
|
chapterRef.SubChapters =
|
||||||
getChaptersImpl(bookRef, navigationPoint.ChildNavigationPoints!);
|
getChaptersImpl(bookRef, navigationPoint.ChildNavigationPoints!);
|
||||||
if(chapterRef.ContentFileName!.contains('_split_')) {
|
if (chapterRef.ContentFileName!.contains('_split_')) {
|
||||||
var fileNamePart = chapterRef.ContentFileName!.split('_split_')[0];
|
var fileNamePart = chapterRef.ContentFileName!.split('_split_')[0];
|
||||||
for (var fileName in bookRef.Content!.Html!.keys) {
|
for (var fileName in bookRef.Content!.Html!.keys) {
|
||||||
if(fileName.contains(fileNamePart)) {
|
if (fileName.contains(fileNamePart)) {
|
||||||
if (fileName == contentFileName) {
|
if (fileName == contentFileName) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chapterRef.otherTextContentFileRefs.add(bookRef.Content!.Html![fileName]!);
|
chapterRef.otherTextContentFileRefs
|
||||||
|
.add(bookRef.Content!.Html![fileName]!);
|
||||||
chapterRef.OtherContentFileNames.add(fileName);
|
chapterRef.OtherContentFileNames.add(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.add(chapterRef);
|
result.add(chapterRef);
|
||||||
};
|
}
|
||||||
|
;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -308,9 +308,15 @@ class PackageReader {
|
||||||
case 'scheme':
|
case 'scheme':
|
||||||
result.Scheme = attributeValue;
|
result.Scheme = attributeValue;
|
||||||
break;
|
break;
|
||||||
|
case 'content':
|
||||||
|
result.Content = attributeValue;
|
||||||
|
break;
|
||||||
|
case 'name':
|
||||||
|
result.Name = attributeValue;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
result.Content = metadataMetaNode.text;
|
result.Content = result.Content ?? metadataMetaNode.text;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,14 +64,22 @@ abstract class EpubContentFileRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List> readContentAsBytes() async {
|
Future<Uint8List> readContentAsBytes() async {
|
||||||
var contentFileEntry = getContentFileEntry();
|
try {
|
||||||
var content = openContentStream(contentFileEntry);
|
var contentFileEntry = getContentFileEntry();
|
||||||
return Uint8List.fromList(content);
|
var content = openContentStream(contentFileEntry);
|
||||||
|
return Uint8List.fromList(content);
|
||||||
|
} catch (_) {
|
||||||
|
return Uint8List.fromList([]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> readContentAsText() async {
|
Future<String> readContentAsText() async {
|
||||||
var contentStream = getContentStream();
|
try {
|
||||||
var result = convert.utf8.decode(contentStream);
|
var contentStream = getContentStream();
|
||||||
return result;
|
var result = convert.utf8.decode(contentStream);
|
||||||
|
return result;
|
||||||
|
} catch (_) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ name: epubx
|
||||||
description: Epub Parser for Dart. Epub package fork. Suitable for use on the Server, the Web, or in Flutter
|
description: Epub Parser for Dart. Epub package fork. Suitable for use on the Server, the Web, or in Flutter
|
||||||
homepage: https://github.com/rbcprolabs/epubx.dart
|
homepage: https://github.com/rbcprolabs/epubx.dart
|
||||||
issue_tracker: https://github.com/rbcprolabs/epubx.dart
|
issue_tracker: https://github.com/rbcprolabs/epubx.dart
|
||||||
version: 4.0.2
|
version: 4.0.3
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.0 <4.0.0"
|
sdk: ">=3.0.0 <4.0.0"
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,11 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
||||||
BridgeTypeRef(CoreTypes.future, [BridgeTypeRef(CoreTypes.string)]),
|
BridgeTypeRef(CoreTypes.future, [BridgeTypeRef(CoreTypes.string)]),
|
||||||
),
|
),
|
||||||
params: [
|
params: [
|
||||||
|
BridgeParameter(
|
||||||
|
'name',
|
||||||
|
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
|
||||||
|
false,
|
||||||
|
),
|
||||||
BridgeParameter(
|
BridgeParameter(
|
||||||
'url',
|
'url',
|
||||||
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
|
BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
|
||||||
|
|
@ -1673,8 +1678,8 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> getHtmlContent(String url) async =>
|
Future<String> getHtmlContent(String name, String url) async =>
|
||||||
await $_invoke('getHtmlContent', [$String(url)]);
|
await $_invoke('getHtmlContent', [$String(name), $String(url)]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> cleanHtmlContent(String html) async =>
|
Future<String> cleanHtmlContent(String html) async =>
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,8 @@ class DartExtensionService implements ExtensionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> getHtmlContent(String url) async {
|
Future<String> getHtmlContent(String name, String url) async {
|
||||||
return await _executeLib().getHtmlContent(url);
|
return await _executeLib().getHtmlContent(name, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ abstract interface class ExtensionService {
|
||||||
|
|
||||||
Future<List<Video>> getVideoList(String url);
|
Future<List<Video>> getVideoList(String url);
|
||||||
|
|
||||||
Future<String> getHtmlContent(String url);
|
Future<String> getHtmlContent(String name, String url);
|
||||||
|
|
||||||
Future<String> cleanHtmlContent(String html);
|
Future<String> cleanHtmlContent(String html);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:flutter_qjs/flutter_qjs.dart';
|
import 'package:flutter_qjs/flutter_qjs.dart';
|
||||||
import 'package:http_interceptor/http_interceptor.dart';
|
import 'package:http_interceptor/http_interceptor.dart';
|
||||||
import 'package:mangayomi/services/http/m_client.dart';
|
import 'package:mangayomi/services/http/m_client.dart';
|
||||||
|
|
@ -17,9 +16,6 @@ class JsHttpClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.onMessage('bytes_get', (dynamic args) async {
|
|
||||||
return await _toBytesResponse(client(args[1]), "GET", args);
|
|
||||||
});
|
|
||||||
runtime.onMessage('http_head', (dynamic args) async {
|
runtime.onMessage('http_head', (dynamic args) async {
|
||||||
return await _toHttpResponse(client(args[1]), "HEAD", args);
|
return await _toHttpResponse(client(args[1]), "HEAD", args);
|
||||||
});
|
});
|
||||||
|
|
@ -43,14 +39,6 @@ class Client {
|
||||||
constructor(reqcopyWith) {
|
constructor(reqcopyWith) {
|
||||||
this.reqcopyWith = reqcopyWith;
|
this.reqcopyWith = reqcopyWith;
|
||||||
}
|
}
|
||||||
async getBytes(url, headers) {
|
|
||||||
headers = headers;
|
|
||||||
const result = await sendMessage(
|
|
||||||
"bytes_get",
|
|
||||||
JSON.stringify([null, this.reqcopyWith, url, headers])
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
async head(url, headers) {
|
async head(url, headers) {
|
||||||
headers = headers;
|
headers = headers;
|
||||||
const result = await sendMessage(
|
const result = await sendMessage(
|
||||||
|
|
@ -148,29 +136,6 @@ Future<String> _toHttpResponse(Client client, String method, List args) async {
|
||||||
return jsonEncode((await future).toJson());
|
return jsonEncode((await future).toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uint8List> _toBytesResponse(Client client, String method, List args) async {
|
|
||||||
final url = args[2] as String;
|
|
||||||
final headers = (args[3] as Map?)?.toMapStringString;
|
|
||||||
final body =
|
|
||||||
args.length >= 5
|
|
||||||
? args[4] is List
|
|
||||||
? args[4] as List
|
|
||||||
: args[4] is String
|
|
||||||
? args[4] as String
|
|
||||||
: (args[4] as Map?)?.toMapStringDynamic
|
|
||||||
: null;
|
|
||||||
var request = http.Request(method, Uri.parse(url));
|
|
||||||
request.headers.addAll(headers ?? {});
|
|
||||||
final future = switch (method) {
|
|
||||||
"GET" => client.get(Uri.parse(url), headers: headers),
|
|
||||||
"POST" => client.post(Uri.parse(url), headers: headers, body: body),
|
|
||||||
"PUT" => client.put(Uri.parse(url), headers: headers, body: body),
|
|
||||||
"DELETE" => client.delete(Uri.parse(url), headers: headers, body: body),
|
|
||||||
_ => client.patch(Uri.parse(url), headers: headers, body: body),
|
|
||||||
};
|
|
||||||
return (await future).bodyBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ResponseExtexsion on Response {
|
extension ResponseExtexsion on Response {
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'body': body,
|
'body': body,
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class MProvider {
|
||||||
async getVideoList(url) {
|
async getVideoList(url) {
|
||||||
throw new Error("getVideoList not implemented");
|
throw new Error("getVideoList not implemented");
|
||||||
}
|
}
|
||||||
async getHtmlContent(url) {
|
async getHtmlContent(name, url) {
|
||||||
throw new Error("getHtmlContent not implemented");
|
throw new Error("getHtmlContent not implemented");
|
||||||
}
|
}
|
||||||
async cleanHtmlContent(html) {
|
async cleanHtmlContent(html) {
|
||||||
|
|
@ -150,12 +150,12 @@ var extention = new DefaultExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> getHtmlContent(String url) async {
|
Future<String> getHtmlContent(String name, String url) async {
|
||||||
_init();
|
_init();
|
||||||
final res =
|
final res =
|
||||||
(await runtime.handlePromise(
|
(await runtime.handlePromise(
|
||||||
await runtime.evaluateAsync(
|
await runtime.evaluateAsync(
|
||||||
'jsonStringify(() => extention.getHtmlContent(`$url`))',
|
'jsonStringify(() => extention.getHtmlContent(`$name`, `$url`))',
|
||||||
),
|
),
|
||||||
)).stringResult;
|
)).stringResult;
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:epubx/epubx.dart';
|
import 'package:epubx/epubx.dart';
|
||||||
import 'package:flutter_qjs/flutter_qjs.dart';
|
import 'package:flutter_qjs/flutter_qjs.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:http_interceptor/http/intercepted_client.dart';
|
||||||
import 'package:js_packer/js_packer.dart';
|
import 'package:js_packer/js_packer.dart';
|
||||||
import 'package:mangayomi/eval/javascript/http.dart';
|
import 'package:mangayomi/eval/javascript/http.dart';
|
||||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||||
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
|
import 'package:mangayomi/services/http/m_client.dart';
|
||||||
import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart';
|
import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart';
|
||||||
import 'package:mangayomi/utils/log/log.dart';
|
import 'package:mangayomi/utils/log/log.dart';
|
||||||
|
|
||||||
|
|
@ -14,6 +20,10 @@ class JsUtils {
|
||||||
JsUtils(this.runtime);
|
JsUtils(this.runtime);
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
|
InterceptedClient client() {
|
||||||
|
return MClient.init();
|
||||||
|
}
|
||||||
|
|
||||||
runtime.onMessage('log', (dynamic args) {
|
runtime.onMessage('log', (dynamic args) {
|
||||||
Logger.add(LoggerLevel.warning, "${args[0]}");
|
Logger.add(LoggerLevel.warning, "${args[0]}");
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -44,10 +54,11 @@ class JsUtils {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
runtime.onMessage('parseEpub', (dynamic args) async {
|
runtime.onMessage('parseEpub', (dynamic args) async {
|
||||||
final book = await EpubReader.readBook(decodeBytes(args[0]));
|
final bytes = await _toBytesResponse(client(), "GET", args);
|
||||||
|
final book = await EpubReader.readBook(bytes);
|
||||||
final List<String> chapters = [];
|
final List<String> chapters = [];
|
||||||
for (var chapter in book.Chapters ?? []) {
|
for (var chapter in book.Chapters ?? []) {
|
||||||
String chapterTitle = chapter.Title;
|
final chapterTitle = chapter.Title;
|
||||||
chapters.add(chapterTitle);
|
chapters.add(chapterTitle);
|
||||||
}
|
}
|
||||||
return jsonEncode({
|
return jsonEncode({
|
||||||
|
|
@ -57,10 +68,11 @@ class JsUtils {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
runtime.onMessage('parseEpubChapter', (dynamic args) async {
|
runtime.onMessage('parseEpubChapter', (dynamic args) async {
|
||||||
final book = await EpubReader.readBook(decodeBytes(args[0]));
|
final bytes = await _toBytesResponse(client(), "GET", args);
|
||||||
|
final book = await EpubReader.readBook(bytes);
|
||||||
final chapter =
|
final chapter =
|
||||||
book.Chapters?.where(
|
book.Chapters?.where(
|
||||||
(element) => element.Title == args[1],
|
(element) => element.Title == args[3],
|
||||||
).firstOrNull;
|
).firstOrNull;
|
||||||
return chapter?.HtmlContent;
|
return chapter?.HtmlContent;
|
||||||
});
|
});
|
||||||
|
|
@ -168,23 +180,62 @@ async function evaluateJavascriptViaWebview(url, headers, scripts) {
|
||||||
JSON.stringify([url, headers, scripts])
|
JSON.stringify([url, headers, scripts])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function parseEpub(bytes) {
|
async function parseEpub(bookName, url, headers) {
|
||||||
return JSON.parse(await sendMessage(
|
return JSON.parse(await sendMessage(
|
||||||
"parseEpub",
|
"parseEpub",
|
||||||
JSON.stringify([bytes])
|
JSON.stringify([bookName, url, headers])
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
async function parseEpubChapter(bytes, chapterTitle) {
|
async function parseEpubChapter(bookName, url, headers, chapterTitle) {
|
||||||
return await sendMessage(
|
return await sendMessage(
|
||||||
"parseEpubChapter",
|
"parseEpubChapter",
|
||||||
JSON.stringify([bytes, chapterTitle])
|
JSON.stringify([bookName, url, headers, chapterTitle])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint8List decodeBytes(String value) {
|
Future<Uint8List> _toBytesResponse(
|
||||||
var bytes = Uint8List.fromList(value.codeUnits);
|
http.Client client,
|
||||||
|
String method,
|
||||||
|
List args,
|
||||||
|
) async {
|
||||||
|
final bookName = args[0] as String;
|
||||||
|
final url = args[1] as String;
|
||||||
|
final headers = (args[2] as Map?)?.toMapStringString;
|
||||||
|
final body =
|
||||||
|
args.length >= 4
|
||||||
|
? args[3] is List
|
||||||
|
? args[3] as List
|
||||||
|
: args[3] is String
|
||||||
|
? args[3] as String
|
||||||
|
: (args[3] as Map?)?.toMapStringDynamic
|
||||||
|
: null;
|
||||||
|
|
||||||
|
final tmpDirectory = (await StorageProvider().getTmpDirectory())!;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
if (!(await File(p.join(tmpDirectory.path, ".nomedia")).exists())) {
|
||||||
|
await File(p.join(tmpDirectory.path, ".nomedia")).create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final file = File(
|
||||||
|
p.join(tmpDirectory.path, "$bookName.epub"),
|
||||||
|
);
|
||||||
|
if (await file.exists()) {
|
||||||
|
return await file.readAsBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = http.Request(method, Uri.parse(url));
|
||||||
|
request.headers.addAll(headers ?? {});
|
||||||
|
final future = switch (method) {
|
||||||
|
"GET" => client.get(Uri.parse(url), headers: headers),
|
||||||
|
"POST" => client.post(Uri.parse(url), headers: headers, body: body),
|
||||||
|
"PUT" => client.put(Uri.parse(url), headers: headers, body: body),
|
||||||
|
"DELETE" => client.delete(Uri.parse(url), headers: headers, body: body),
|
||||||
|
_ => client.patch(Uri.parse(url), headers: headers, body: body),
|
||||||
|
};
|
||||||
|
final bytes = (await future).bodyBytes;
|
||||||
|
await file.writeAsBytes(bytes);
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ abstract class MProvider {
|
||||||
|
|
||||||
Future<List<Video>> getVideoList(String url);
|
Future<List<Video>> getVideoList(String url);
|
||||||
|
|
||||||
Future<String> getHtmlContent(String url);
|
Future<String> getHtmlContent(String name, String url);
|
||||||
|
|
||||||
Future<String> cleanHtmlContent(String html);
|
Future<String> cleanHtmlContent(String html);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:bot_toast/bot_toast.dart';
|
||||||
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,7 @@ class _CodeEditorPageState extends ConsumerState<CodeEditorPage> {
|
||||||
)).map((e) => e.toJson()).toList();
|
)).map((e) => e.toJson()).toList();
|
||||||
} else if (_serviceIndex == 6) {
|
} else if (_serviceIndex == 6) {
|
||||||
result = (await service.getHtmlContent(
|
result = (await service.getHtmlContent(
|
||||||
|
"test",
|
||||||
_url,
|
_url,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ class TestSource extends MProvider {
|
||||||
|
|
||||||
// For novel html content
|
// For novel html content
|
||||||
@override
|
@override
|
||||||
Future<String> getHtmlContent(String url) async {
|
Future<String> getHtmlContent(String name, String url) async {
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -409,7 +409,7 @@ class DefaultExtension extends MProvider {
|
||||||
throw new Error("getDetail not implemented");
|
throw new Error("getDetail not implemented");
|
||||||
}
|
}
|
||||||
// For novel html content
|
// For novel html content
|
||||||
async getHtmlContent(url) {
|
async getHtmlContent(name, url) {
|
||||||
throw new Error("getHtmlContent not implemented");
|
throw new Error("getHtmlContent not implemented");
|
||||||
}
|
}
|
||||||
// Clean html up for reader
|
// Clean html up for reader
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||||
import 'package:mangayomi/main.dart';
|
import 'package:mangayomi/main.dart';
|
||||||
import 'package:mangayomi/models/settings.dart';
|
import 'package:mangayomi/models/settings.dart';
|
||||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||||
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
import 'package:mangayomi/router/router.dart';
|
import 'package:mangayomi/router/router.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
@ -37,6 +38,9 @@ class TotalChapterCacheSizeState extends _$TotalChapterCacheSizeState {
|
||||||
}
|
}
|
||||||
msg = "0.00 B";
|
msg = "0.00 B";
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
try {
|
||||||
|
await StorageProvider().deleteTmpDirectory();
|
||||||
|
} catch (_) {}
|
||||||
if (msg != null && showToast) {
|
if (msg != null && showToast) {
|
||||||
state = msg;
|
state = msg;
|
||||||
botToast(
|
botToast(
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,11 @@ class StorageProvider {
|
||||||
await Directory(d!.path).delete(recursive: true);
|
await Directory(d!.path).delete(recursive: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> deleteTmpDirectory() async {
|
||||||
|
final d = await getTmpDirectory();
|
||||||
|
await Directory(d!.path).delete(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Directory?> getDefaultDirectory() async {
|
Future<Directory?> getDefaultDirectory() async {
|
||||||
Directory? directory;
|
Directory? directory;
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
|
|
@ -60,6 +65,13 @@ class StorageProvider {
|
||||||
return Directory(dbDir);
|
return Directory(dbDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Directory?> getTmpDirectory() async {
|
||||||
|
final gefaultDirectory = await getDirectory();
|
||||||
|
String dbDir = path.join(gefaultDirectory!.path, 'tmp');
|
||||||
|
await Directory(dbDir).create(recursive: true);
|
||||||
|
return Directory(dbDir);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Directory?> getIosBackupDirectory() async {
|
Future<Directory?> getIosBackupDirectory() async {
|
||||||
final gefaultDirectory = await getDefaultDirectory();
|
final gefaultDirectory = await getDefaultDirectory();
|
||||||
String dbDir = path.join(gefaultDirectory!.path, 'backup');
|
String dbDir = path.join(gefaultDirectory!.path, 'backup');
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ Future<String> getHtmlContent(Ref ref, {required Chapter chapter}) async {
|
||||||
if (htmlContent != null) {
|
if (htmlContent != null) {
|
||||||
html = await getExtensionService(source!).cleanHtmlContent(htmlContent);
|
html = await getExtensionService(source!).cleanHtmlContent(htmlContent);
|
||||||
} else {
|
} else {
|
||||||
html = await getExtensionService(source!).getHtmlContent(chapter.url!);
|
html = await getExtensionService(source!).getHtmlContent(chapter.manga.value!.name!, chapter.url!);
|
||||||
}
|
}
|
||||||
return '''<div id="readerViewContent"><div style="padding: 2em;">${html.substring(1, html.length - 1)}</div></div>'''
|
return '''<div id="readerViewContent"><div style="padding: 2em;">${html.substring(1, html.length - 1)}</div></div>'''
|
||||||
.replaceAll("\\n", "")
|
.replaceAll("\\n", "")
|
||||||
|
|
|
||||||
|
|
@ -445,7 +445,7 @@ packages:
|
||||||
path: epubx
|
path: epubx
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "4.0.2"
|
version: "4.0.3"
|
||||||
exception_templates:
|
exception_templates:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue