You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

470 lines
21 KiB

//
// WXYZ_BBBBBBBManager.m
// WXReader
//
// Created by Andrew on 2020/7/10.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_BookDownloadManager.h"
#import "TFProductionChapterModel.h"
// 下载总任务列表model
#define TaskListKey @"task_list_key"
@interface WXYZ_BookDownloadManager ()
@property (nonatomic, assign) BOOL requesting;
@property (nonatomic, strong) NSMutableArray *requestOrderArray;
@end
@implementation WXYZ_BookDownloadManager
implementation_singleton(WXYZ_BookDownloadManager)
/*
**/
// 下载多个章节
- (void)downloadChaptersWithProductionModel:(TFProductionModel *)productionModel downloadTaskModel:(TFDownloadTaskModel *)downloadTaskModel production_id:(NSInteger)production_id start_chapter_id:(NSInteger)start_chapter_id downloadNum:(NSInteger)downloadNum
{
// 作品开始下载标记
[[WXYZ_DownloadHelper sharedManager] recordDownloadProductionWithProductionModel:productionModel productionType:TFProductionTypeNovel];
// 任务加入任务队列
/*
@{
production_id:@[起始章节id, 下载章节数量, 下载任务对象]
}
*/
[self.requestOrderArray addObject:@{[TFUtilsHelper formatStringWithInteger:production_id]:@[[TFUtilsHelper formatStringWithInteger:start_chapter_id], [TFUtilsHelper formatStringWithInteger:downloadNum], downloadTaskModel]}];
if (!self.requesting) {
// 开始下载任务
[self downloadTaskRequest];
}
}
/*
**/
// 删除本地整本已下载作品
- (BOOL)removeDownloadProductionWithProduction_id:(NSInteger)production_id
{
// 删除作品文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadProductionFolderWithProduction_id:production_id productionType:TFProductionTypeNovel];
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeAllObjects];
return YES;
}
/*
**/
// 获取已下载小说文件路径
- (NSString *)getChapterFilePathWithChapterModel:(TFProductionChapterModel *)chapterModel
{
// 章节图片名称
NSString *fileName = [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@%@", [TFUtilsHelper formatStringWithInteger:chapterModel.production_id], [TFUtilsHelper formatStringWithInteger:chapterModel.chapter_id], [TFUtilsHelper formatStringWithInteger:chapterModel.is_preview], chapterModel.update_time]];
NSString *filePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:chapterModel.production_id chapter_id:chapterModel.chapter_id productionType:TFProductionTypeNovel] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.txt", fileName]];
return filePath;
}
// 获取章节内容
- (NSString *)getFileContentsWithChapterModel:(TFProductionChapterModel *)chapterModel
{
// 数据不正确
if (!chapterModel || chapterModel.production_id == 0 || chapterModel.chapter_id == 0 || !chapterModel.update_time) {
return k_Chapter_RequstFail;
}
// 本地文件地址
NSString *filePath = [self getChapterFilePathWithChapterModel:chapterModel];
// 如果文件存在则返回文件内容
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSString *body = [NSString stringWithContentsOfURL:[NSURL fileURLWithPath:filePath] usedEncoding:nil error:nil];
if (body) {
return body;
}
//如果之前不能解码,现在使用GBK解码
body = [NSString stringWithContentsOfURL:[NSURL fileURLWithPath:filePath] encoding:0x80000632 error:nil];
if (body) {
return body;
}
//再使用GB18030解码
body = [NSString stringWithContentsOfURL:[NSURL fileURLWithPath:filePath] encoding:0x80000631 error:nil];
if (body) {
return body;
} else {
return k_Chapter_RequstFail;
}
} else {
return k_Chapter_RequstFail;
}
}
// 存储章节内容
- (void)storingFilesWithChapterModel:(TFProductionChapterModel *)chapterModel storingCompletionHandler:(void (^)(BOOL finishStoring))completionHandler
{
// 数据不正确
if (!chapterModel || chapterModel.production_id == 0 || chapterModel.chapter_id == 0 || !chapterModel.update_time) {
if (completionHandler) {
completionHandler(NO);
}
return;
}
// 文件已存在
if ([[NSFileManager defaultManager] fileExistsAtPath:[self getChapterFilePathWithChapterModel:chapterModel]]) {
// 如果当前获取的是非预览章节内容,则寻找是否有预览章节文件进行删除,节省空间
chapterModel.is_preview = 1;
if ([self getChapterFilePathWithChapterModel:chapterModel]) {
[[NSFileManager defaultManager] removeItemAtPath:[self getChapterFilePathWithChapterModel:chapterModel] error:nil];
}
if (completionHandler) {
completionHandler(NO);
}
return;
}
// 文件不存在则存储文件
// 解析标题
NSString *chapter_title_string = @"";
if (chapterModel.chapter_title && chapterModel.chapter_title.length > 0) {
chapter_title_string = [NSString stringWithFormat:@"W$$X%@W$$X", chapterModel.chapter_title];
chapter_title_string = [chapter_title_string stringByAppendingString:@"\n\n"];
}
// 解析内容
NSString *chapter_content_string = @"";
if (chapterModel.content && chapterModel.content.length > 0) {
chapter_content_string = chapterModel.content;
}
// 文件内容
NSString *chapter_file_content = [NSString stringWithFormat:@"%@%@",chapter_title_string, chapter_content_string];
if ([chapter_file_content writeToFile:[self getChapterFilePathWithChapterModel:chapterModel] atomically:NO encoding:NSUTF8StringEncoding error:nil]) {
if (completionHandler) {
completionHandler(YES);
}
} else {
if (completionHandler) {
completionHandler(NO);
}
}
}
// 获取下载状态
- (WXYZ_ProductionDownloadState)getDownloadMissionStateWithProduction_id:(NSInteger)production_id downloadTaskModel:(TFDownloadTaskModel *)downloadTaskModel
{
NSMutableDictionary *t_dic = [self bookDownloadTaskDictionaryWithProduction_id:production_id];
if ([[t_dic objectForKey:downloadTaskModel.file_name] isEqual:identify_downloading]) {
return WXYZ_ProductionDownloadStateDownloading;
}
if ([[t_dic objectForKey:downloadTaskModel.file_name] isKindOfClass:[TFDownloadTaskModel class]]) {
return WXYZ_ProductionDownloadStateDownloaded;
}
TFNovelDownloadTaskListModel *taskListModel = [self getDownloadProductionModelWithProduction_id:production_id];
if (taskListModel.task_list.count > 0) {
for (TFDownloadTaskModel *t_taskModel in taskListModel.task_list) {
if (downloadTaskModel.start_order >= t_taskModel.start_order && downloadTaskModel.end_order <= t_taskModel.end_order) {
return WXYZ_ProductionDownloadStateDownloaded;
}
}
}
return WXYZ_ProductionDownloadStateNormal;
}
// 获取某一已下载作品model
- (TFNovelDownloadTaskListModel *)getDownloadProductionModelWithProduction_id:(NSInteger)production_id
{
TFNovelDownloadTaskListModel *taskListModel = [[TFNovelDownloadTaskListModel alloc] init];
taskListModel.productionModel = [[WXYZ_DownloadHelper sharedManager] getDownloadProductionModelWithProduction_id:production_id productionType:TFProductionTypeNovel];
taskListModel.task_list = [[self getDownloadProductionArrayWithProduction_id:production_id] mutableCopy];
return taskListModel;
}
// 获取某一作品的全部下载model
- (NSArray <TFDownloadTaskModel *> *)getDownloadProductionArrayWithProduction_id:(NSInteger)production_id
{
NSMutableArray *t_arr = [NSMutableArray array];
for (id taskModel in [self bookDownloadTaskDictionaryWithProduction_id:production_id].allValues) {
if ([taskModel isKindOfClass:[TFDownloadTaskModel class]]) {
[t_arr addObject:taskModel];
}
}
for (int i = 0; i < t_arr.count; i ++) {
TFDownloadTaskModel *taskModel = [t_arr objectAtIndex:i];
// 是否需要合并
BOOL isMerged = NO;
// 无交集
BOOL noIntersection = YES;
do {
isMerged = NO;
// 遍历数组 组成队列
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = taskModel.start_order; i < taskModel.end_order + 3; i++) {
[array addObject:[TFUtilsHelper formatStringWithInteger:i - 1]];
}
for (int i = 0; i < t_arr.count; i ++) {
TFDownloadTaskModel *t_task = [t_arr objectOrNilAtIndex:i];
if (t_task.start_order != taskModel.start_order || t_task.end_order != taskModel.end_order) {
if ([array containsObject:[TFUtilsHelper formatStringWithInteger:t_task.start_order]]) {
TFDownloadTaskModel *tt_task = [[TFDownloadTaskModel alloc] init];
tt_task.url = taskModel.url;
tt_task.file_name = taskModel.file_name;
tt_task.download_title = [NSString stringWithFormat:@"%@ - %@%@", [array objectOrNilAtIndex:1], [TFUtilsHelper formatStringWithInteger:t_task.end_order > taskModel.end_order?t_task.end_order:taskModel.end_order], TFLocalizedString(@"")];
tt_task.dateString = [TFUtilsHelper currentDateStringWithFormat:@"yyyy-MM-dd"];
tt_task.file_size = taskModel.file_size + t_task.file_size;
tt_task.start_order = [[array objectOrNilAtIndex:1] integerValue];
tt_task.end_order = t_task.end_order > taskModel.end_order?t_task.end_order:taskModel.end_order;
[t_arr replaceObjectAtIndex:i withObject:tt_task];
[t_arr removeObject:taskModel];
isMerged = YES;
noIntersection = NO;
} else if ([array containsObject:[TFUtilsHelper formatStringWithInteger:t_task.end_order]]) {
TFDownloadTaskModel *tt_task = [[TFDownloadTaskModel alloc] init];
tt_task.url = taskModel.url;
tt_task.file_name = taskModel.file_name;
tt_task.download_title = [NSString stringWithFormat:@"%@ - %@%@", [TFUtilsHelper formatStringWithInteger:t_task.start_order], [TFUtilsHelper formatStringWithInteger:t_task.end_order > taskModel.end_order?t_task.end_order:taskModel.end_order], TFLocalizedString(@"")];
tt_task.dateString = [TFUtilsHelper currentDateStringWithFormat:@"yyyy-MM-dd"];
tt_task.file_size = taskModel.file_size + t_task.file_size;
tt_task.start_order = t_task.start_order;
tt_task.end_order = t_task.end_order > taskModel.end_order?t_task.end_order:taskModel.end_order;
[t_arr replaceObjectAtIndex:i withObject:tt_task];
[t_arr removeObject:taskModel];
isMerged = YES;
noIntersection = NO;
}
if (isMerged) {
taskModel = [t_arr objectOrNilAtIndex:0];
break;
}
} else if (t_task.start_order == taskModel.start_order && t_task.end_order == taskModel.end_order) {
[t_arr replaceObjectAtIndex:i withObject:taskModel];
noIntersection = NO;
}
}
} while (isMerged);
if (noIntersection) {
[t_arr addObject:taskModel];
}
}
return [t_arr copy];
}
- (void)downloadTaskRequest
{
if (self.requestOrderArray.count == 0) {
return;
}
self.requesting = YES;
NSDictionary *orderDic = [self.requestOrderArray firstObject];
NSInteger production_id = [[orderDic.allKeys firstObject] integerValue];
NSString *start_chapter_id = [orderDic objectForKey:[TFUtilsHelper formatStringWithInteger:production_id]][0];
NSString *downloadNum = [orderDic objectForKey:[TFUtilsHelper formatStringWithInteger:production_id]][1];
TFDownloadTaskModel *taskModel = [orderDic objectForKey:[TFUtilsHelper formatStringWithInteger:production_id]][2];
[self.requestOrderArray removeFirstObject];
WS(weakSelf)
[TFNetworkTools POST:Book_Download_Multiple_Chapters parameters:@{@"book_id":[TFUtilsHelper formatStringWithInteger:production_id], @"chapter_id":start_chapter_id, @"num":downloadNum} model:nil success:^(BOOL isSuccess, NSDictionary * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
if (weakSelf.requestOrderArray.count == 0) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"已加入下载队列")];
}
// 开始下载
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] setObject:identify_downloading forKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务开始
dispatch_async(dispatch_get_main_queue(), ^{
if (self.downloadMissionStateChangeBlock) {
self.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionStart, production_id, taskModel, nil);
}
});
// 下载章节合集文件
AFURLSessionManager *manager = [[AFURLSessionManager alloc] init];
manager.operationQueue.maxConcurrentOperationCount = 1;
manager.completionQueue = dispatch_queue_create("com.wxyz.book_queue", NULL);
NSURL *URL = [NSURL URLWithString:[requestModel.data objectForKey:@"file_url"]];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:[NSURLRequest requestWithURL:URL] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
// 创建临时存储文件
if (![[NSFileManager defaultManager] fileExistsAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadProductionFolderPathWithProduction_id:production_id productionType:TFProductionTypeNovel]]) {
[[NSFileManager defaultManager] createDirectoryAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadProductionFolderPathWithProduction_id:production_id productionType:TFProductionTypeNovel] withIntermediateDirectories:YES attributes:nil error:nil];
}
// 临时文件地址
NSString *tempFilePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadProductionFolderPathWithProduction_id:production_id productionType:TFProductionTypeNovel] stringByAppendingPathComponent:[requestModel.data objectForKey:@"file_name"]];
return [NSURL fileURLWithPath:tempFilePath];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
weakSelf.requesting = NO;
if (error) {
// 任务下载失败删除记录
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeObjectForKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, taskModel, nil);
}
});
} else {
NSString *fileContent = [NSString stringWithContentsOfFile:filePath.path encoding:NSUTF8StringEncoding error:nil];
if (fileContent.length > 0) {
NSArray *chapterModelArray = [NSArray modelArrayWithClass:[TFProductionChapterModel class] json:fileContent];
if (chapterModelArray.count > 0) {
for (int i = 0; i < chapterModelArray.count; i ++) {
TFProductionChapterModel *chapterModel = [chapterModelArray objectAtIndex:i];
// 文件请求成功,解析文件内容
[self storingFilesWithChapterModel:chapterModel storingCompletionHandler:^(BOOL finishStoring) {
}];
}
// 存储下载任务列表
taskModel.file_size = [TFUtilsHelper getFileSize:filePath.path];
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] setObject:taskModel forKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载完成
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
NSArray<NSNumber *> *t_arr = [chapterModelArray valueForKeyPath:@"chapter_id"];
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFinished, production_id, taskModel, t_arr);
}
});
} else {
// 任务下载失败删除记录
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeObjectForKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, taskModel, nil);
}
});
}
}
}
// 移除临时文件
[[NSFileManager defaultManager] removeItemAtPath:filePath.path error:nil];
}];
[downloadTask resume];
} else if (Compare_Json_isEqualTo(requestModel.code, 701)) {
weakSelf.requesting = NO;
// 任务下载失败删除记录
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeObjectForKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionShouldPay, production_id, taskModel, nil);
}
});
} else {
weakSelf.requesting = NO;
// 任务下载失败删除记录
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeObjectForKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, taskModel, nil);
}
});
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
weakSelf.requesting = NO;
// 任务下载失败删除记录
[[self bookDownloadTaskDictionaryWithProduction_id:production_id] removeObjectForKey:taskModel.file_name];
[self bookWriteToPlistWithProduction_id:production_id];
// 任务下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, taskModel, nil);
}
});
}];
}
- (NSMutableArray *)requestOrderArray
{
if (!_requestOrderArray) {
_requestOrderArray = [NSMutableArray array];
}
return _requestOrderArray;
}
- (NSMutableDictionary *)bookDownloadTaskDictionaryWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] chaptersRecordDownloadDictionaryWithProduction_id:production_id productionType:TFProductionTypeNovel modelClass:[TFDownloadTaskModel class]];
}
- (BOOL)bookWriteToPlistWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] writeToChapterPlistFileWithProduction_id:production_id productionType:TFProductionTypeNovel modelClass:[TFDownloadTaskModel class]];
}
@end