Skip to content

Commit

Permalink
Support 4-thread download for archive download
Browse files Browse the repository at this point in the history
归档下载切换为4线程下载
  • Loading branch information
jiangtian616 committed Mar 30, 2024
1 parent d43db76 commit d724b2d
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 35 deletions.
8 changes: 6 additions & 2 deletions lib/src/network/eh_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,12 @@ emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
return _parseResponse(response, parser);
}

static Future<Response> head<T>({required String url, Options? options}) {
return _dio.head(url, options: options);
static Future<Response> head<T>({required String url, CancelToken? cancelToken, Options? options}) {
return _dio.head(
url,
cancelToken: cancelToken,
options: options,
);
}

static Future<T> _parseResponse<T>(Response response, EHHtmlParser<T>? parser) async {
Expand Down
82 changes: 52 additions & 30 deletions lib/src/service/archive_download_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
archiveDownloadInfo.downloadPageUrl = null;
archiveDownloadInfo.downloadUrl = null;
archiveDownloadInfo.cancelToken = CancelToken();
archiveDownloadInfo.downloadTask?.pause();
archiveDownloadInfo.downloadTask = null;
await _updateArchiveInDatabase(archive);
update(['$archiveStatusId::${archive.gid}']);

Expand Down Expand Up @@ -440,7 +442,7 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
String computePackingFileDownloadPath(ArchiveDownloadedData archive) {
String title = _computeArchiveTitle(archive.title);

return join(DownloadSetting.downloadPath.value, 'Archive - ${archive.gid} - $title.zip');
return join(DownloadSetting.downloadPath.value, 'Archive - v2 - ${archive.gid} - $title.zip');
}

String computeArchiveUnpackingPath(ArchiveDownloadedData archive) {
Expand Down Expand Up @@ -486,6 +488,7 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
url: url,
savePath: computePackingFileDownloadPath(archive),
isolateCount: isolateCount,
deleteWhenUrlMismatch: false,
onProgress: (current, total) {
archiveDownloadInfos[archive.gid]!.speedComputer.downloadedBytes = current;
},
Expand All @@ -511,9 +514,44 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
);
}

bool _invalidDownload(Response response) {
Headers headers = response.headers;
Future<void> _check410Reason(String url, ArchiveDownloadedData archive) async {
try {
await EHRequest.get(
url: url,
cancelToken: archiveDownloadInfos[archive.gid]?.cancelToken,
);
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) {
return;
}

if (e.response!.data is String && e.response!.data.contains('You have clocked too many downloaded bytes on this gallery')) {
Log.download('${'410Hints'.tr} Archive: ${archive.title}');
snack('archiveError'.tr, '${'410Hints'.tr} : ${archive.title}', longDuration: true);

return await pauseDownloadArchive(archive, needReUnlock: true);
} else if (e.response!.data is String && e.response!.data.contains('IP quota exhausted')) {
Log.download('IP quota exhausted! Archive: ${archive.title}');
snack('archiveError'.tr, 'IP quota exhausted!', longDuration: true);

return await pauseDownloadArchive(archive, needReUnlock: true);
} else {
Log.download('Download archive 410, try re-parse. Archive: ${archive.title}');
return await _reParseDownloadUrlAndDownload(archive);
}
}
}

Future<void> _reParseDownloadUrlAndDownload(ArchiveDownloadedData archive) async {
ArchiveDownloadInfo archiveDownloadInfo = archiveDownloadInfos[archive.gid]!;
archiveDownloadInfo.downloadUrl = null;
_updateArchiveInDatabase(archive);

await _getDownloadUrl(archive);
await _doDownloadArchiveViaMultiIsolate(archive);
}

bool _invalidDownload(Headers headers) {
if (headers['content-transfer-encoding']?.contains('binary') ?? false) {
return false;
}
Expand Down Expand Up @@ -611,6 +649,7 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
if (e.type == DioExceptionType.cancel) {
return;
}

return await _getDownloadUrl(archive);
} on EHSiteException catch (e) {
Log.download('Download error, reason: ${e.message}');
Expand Down Expand Up @@ -660,33 +699,25 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
/// check if archive link is invalid
Response response;
try {
response = await EHRequest.head(url: archiveDownloadInfo.downloadUrl!);
response = await EHRequest.head(
url: archiveDownloadInfo.downloadUrl!,
cancelToken: archiveDownloadInfo.cancelToken,
);
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) {
return;
}

/// download too many bytes will cause 410
if (e.response?.statusCode == 410) {
if (e.response!.data is String && e.response!.data.contains('You have clocked too many downloaded bytes on this gallery')) {
Log.download('${'410Hints'.tr} Archive: ${archive.title}');
snack('archiveError'.tr, '${'410Hints'.tr} : ${archive.title}', longDuration: true);

return await pauseDownloadArchive(archive, needReUnlock: true);
} else if (e.response!.data is String && e.response!.data.contains('IP quota exhausted')) {
Log.download('IP quota exhausted! Archive: ${archive.title}');
snack('archiveError'.tr, 'IP quota exhausted!', longDuration: true);

return await pauseDownloadArchive(archive, needReUnlock: true);
} else {
Log.download('Download archive 410, try re-parse. Archive: ${archive.title}');
return await _reParseDownloadUrlAndDownload(archive);
}
return await _check410Reason(archiveDownloadInfo.downloadUrl!, archive);
}

Log.download('Check archive ${archive.title} available failed, retry. Reason: ${e.message}, url:${archiveDownloadInfo.downloadUrl!}');

await Future.delayed(const Duration(milliseconds: 1000));
return await _doDownloadArchiveViaMultiIsolate(archive);
}

if (_invalidDownload(response)) {
if (_invalidDownload(response.headers)) {
Log.error('Invalid archive!');
Log.uploadError(Exception('Invalid archive!'), extraInfos: {
'code': response.statusCode,
Expand All @@ -711,15 +742,6 @@ class ArchiveDownloadService extends GetxController with GridBasePageServiceMixi
}
}

Future<void> _reParseDownloadUrlAndDownload(ArchiveDownloadedData archive) async {
ArchiveDownloadInfo archiveDownloadInfo = archiveDownloadInfos[archive.gid]!;
archiveDownloadInfo.downloadUrl = null;
_updateArchiveInDatabase(archive);

await _getDownloadUrl(archive);
await _doDownloadArchiveViaMultiIsolate(archive);
}

Future<void> _unpackingArchive(ArchiveDownloadedData archive) async {
ArchiveDownloadInfo archiveDownloadInfo = archiveDownloadInfos[archive.gid]!;
Log.info('Unpacking archive: ${archive.title}, original: ${archive.isOriginal}');
Expand Down
5 changes: 3 additions & 2 deletions lib/src/utils/archive_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import 'package:flutter/foundation.dart';
Future<bool> extractZipArchive(String archivePath, String extractPath) {
return compute(
(List<String> path) async {
InputFileStream inputStream = InputFileStream(path[0]);
InputFileStream? inputStream;
try {
inputStream = InputFileStream(path[0]);
extractArchiveToDisk(ZipDecoder().decodeBuffer(inputStream), path[1]);
} on Exception catch (_) {
return false;
} finally {
inputStream.close();
inputStream?.close();
}
return true;
},
Expand Down
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ packages:
description:
path: "."
ref: HEAD
resolved-ref: "12eade4727588e5617749aea2393568cb97c6824"
resolved-ref: "56dd1dfe666fad690f0265e41fc5cd7bb13ecb4e"
url: "https://github.com/jiangtian616/JDownloader"
source: git
version: "0.0.1"
Expand Down

0 comments on commit d724b2d

Please sign in to comment.