小说绘上架版本

This commit is contained in:
xtfei2011
2021-02-07 11:24:08 +08:00
commit ee5c1c8b12
1762 changed files with 115892 additions and 0 deletions
@@ -0,0 +1,30 @@
//
// WXYZ_AudioDownloadManager.h
// WXReader
//
// Created by Andrew on 2020/3/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_DownloadHelper.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_AudioDownloadManager : NSObject <WXYZ_DownloadManagerProtocol>
@property (nonatomic, copy) void (^downloadDeleteFinishBlock)(NSArray *success_chapter_ids, NSArray *fail_chapter);
// 章节下载状态改变
@property (nonatomic, copy) void (^downloadChapterStateChangeBlock)(WXYZ_DownloadChapterState state, NSInteger production_id, NSInteger chapter_id);
// 总体任务下载完成
@property (nonatomic, copy) void (^downloadMissionStateChangeBlock)(WXYZ_DownloadMissionState state, NSInteger production_id, NSArray *chapter_ids);
interface_singleton
// 获取已下载音频文件路径
- (NSString *)chapterDownloadedFilePathWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id chapter_update_time:(NSString *)chapter_update_time;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,374 @@
//
// WXYZ_AudioDownloadManager.m
// WXReader
//
// Created by Andrew on 2020/3/28.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_AudioDownloadManager.h"
static dispatch_group_t url_session_manager_completion_group() {
static dispatch_group_t af_url_session_manager_completion_group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_url_session_manager_completion_group = dispatch_group_create();
});
return af_url_session_manager_completion_group;
}
@interface WXYZ_AudioDownloadManager () <NSURLSessionDataDelegate>
@property (nonatomic, assign) BOOL requesting;
@property (nonatomic, strong) NSMutableArray *requestOrderArray;
@end
@implementation WXYZ_AudioDownloadManager
implementation_singleton(WXYZ_AudioDownloadManager)
/*
**/
// 下载章节
- (void)downloadChapterWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
[self downloadChaptersWithProductionModel:productionModel production_id:production_id chapter_ids:@[[TFUtilsHelper formatStringWithInteger:chapter_id]]];
}
// 下载多个章节
- (void)downloadChaptersWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids
{
[[WXYZ_DownloadHelper sharedManager] recordDownloadProductionWithProductionModel:productionModel productionType:TFProductionTypeAudio];
WS(weakSelf)
[TFNetworkTools POST:Audio_Chapter_Download parameters:@{@"audio_id":[TFUtilsHelper formatStringWithInteger:production_id], @"chapter_id":[chapter_ids componentsJoinedByString:@","]} model:nil success:^(BOOL isSuccess, NSDictionary * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
dispatch_async(dispatch_get_main_queue(), ^{
// 任务开始
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionStart, production_id, chapter_ids);
}
// 任务加入任务队列
NSArray *taskArray = [t_model objectForKey:@"data"];
if (taskArray.count > 0) {
for (NSDictionary *t_dic in taskArray) {
TFProductionChapterModel *imageCollectionModel = [TFProductionChapterModel modelWithDictionary:t_dic];
if (imageCollectionModel) {
// 开始下载
[[self audioChaptersRecordDictionaryWithProduction_id:imageCollectionModel.production_id] setObject:identify_downloading forKey:chapterRecordKey(imageCollectionModel.production_id, imageCollectionModel.chapter_id)];
dispatch_async(dispatch_get_main_queue(), ^{
if (self.downloadChapterStateChangeBlock) {
self.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadStart, imageCollectionModel.production_id, imageCollectionModel.chapter_id);
}
});
}
}
[weakSelf.requestOrderArray addObject:taskArray];
if (!weakSelf.requesting) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"已加入下载列表")];
}
// 开始下载任务
[weakSelf downloadTaskRequest];
} else {
// 任务失败
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
}
});
} else if (Compare_Json_isEqualTo(requestModel.code, 701)) { // 请求购买
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionShouldPay, production_id, chapter_ids);
}
});
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
});
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
});
}];
}
/*
**/
// 删除本地已下载作品
- (BOOL)removeDownloadProductionWithProduction_id:(NSInteger)production_id
{
// 删除作品文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadProductionFolderWithProduction_id:production_id productionType:TFProductionTypeAudio];
// 删除缓存
[[self audioChaptersRecordDictionaryWithProduction_id:production_id] removeAllObjects];
// 写入
[self audioRecordWriteToPlistWithProduction_id:production_id];
return YES;
}
// 删除本地多个已下载章节
- (void)removeDownloadChaptersWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *> *)chapter_ids
{
if (chapter_ids.count == 0) {
return;
}
// 删除文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadChapterFolderWithProduction_id:production_id chapter_ids:chapter_ids productionType:TFProductionTypeAudio];
// 删除下载记录
NSMutableDictionary *t_dic = [self audioChaptersRecordDictionaryWithProduction_id:production_id];
NSMutableArray *t_delete_arr = [NSMutableArray array];
for (NSString *chapter_id in chapter_ids) {
[t_delete_arr addObject:chapterRecordKey(production_id, [chapter_id integerValue])];
}
[t_dic removeObjectsForKeys:t_delete_arr];
// 如果全部章节已经删除,则删除整体作品文件夹
if ([self getDownloadChapterCountWithProduction_id:production_id] == 0) {
[self removeDownloadProductionWithProduction_id:production_id];
} else {
[self audioRecordWriteToPlistWithProduction_id:production_id];
}
// 删除回调
dispatch_async(dispatch_get_main_queue(), ^{
if (self.downloadDeleteFinishBlock) {
self.downloadDeleteFinishBlock(chapter_ids, @[]);
}
});
}
/*
**/
// 获取下载章节数
- (NSInteger)getDownloadChapterCountWithProduction_id:(NSInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] getDownloadChapterCountWithProduction_id:production_id productionType:TFProductionTypeAudio];
}
// 获取全部已下载章节model
- (NSArray *)getDownloadChapterModelArrayWithProduction_id:(NSInteger)production_id
{
NSMutableDictionary *t_dic = [self audioChaptersRecordDictionaryWithProduction_id:production_id];
NSMutableArray *t_arr = [NSMutableArray array];
for (id value in t_dic.allValues) {
if ([value isKindOfClass:[TFProductionChapterModel class]]) {
[t_arr addObject:value];
}
}
return [t_arr copy];
}
// 获取已下载章节model
- (id)getDownloadChapterModelWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [self audioChaptersRecordDictionaryWithProduction_id:production_id];
id value = [t_dic objectForKey:chapterRecordKey(production_id, chapter_id)];
if ([value isKindOfClass:[TFProductionChapterModel class]]) {
return value;
}
return nil;
}
// 获取章节下载状态
- (WXYZ_ProductionDownloadState)getChapterDownloadStateWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [self audioChaptersRecordDictionaryWithProduction_id:production_id];
if ([[t_dic objectForKey:chapterRecordKey(production_id, chapter_id)] isEqual:identify_downloading]) {
return WXYZ_ProductionDownloadStateDownloading;
}
if ([[t_dic objectForKey:chapterRecordKey(production_id, chapter_id)] isKindOfClass:[TFProductionChapterModel class]]) {
return WXYZ_ProductionDownloadStateDownloaded;
}
return WXYZ_ProductionDownloadStateNormal;
}
// 作品章节是否下载
- (BOOL)isChapterDownloadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
return [[WXYZ_DownloadHelper sharedManager] isChapterDownloadedWithProduction_id:production_id chapter_id:chapter_id productionType:TFProductionTypeAudio];
}
// 获取文件地址
- (NSString *)chapterDownloadedFilePathWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id chapter_update_time:(NSString *)chapter_update_time
{
// 章节文件名称
NSString *chapterFileName = [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@", [TFUtilsHelper formatStringWithInteger:production_id], [TFUtilsHelper formatStringWithInteger:chapter_id], [TFUtilsHelper formatStringWithObject:chapter_update_time]]];
NSString *chapterFilePath = @"";
NSArray *extensionArr = @[@"mp3", @"wav", @"wma"];
for (NSString *extension in extensionArr) {
chapterFilePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:production_id chapter_id:chapter_id productionType:TFProductionTypeAudio] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", chapterFileName, extension]];
if (chapterFilePath && chapterFilePath.length > 0 && [[NSFileManager defaultManager] fileExistsAtPath:chapterFilePath]) {
return chapterFilePath;
}
}
return chapterFilePath;
}
- (void)downloadTaskRequest
{
if (self.requestOrderArray.count == 0) {
return;
}
if (self.requesting) {
return;
}
self.requesting = YES;
NSArray *taskArray = [self.requestOrderArray firstObject];
[self.requestOrderArray removeFirstObject];
WS(weakSelf)
dispatch_group_async(url_session_manager_completion_group(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_queue_t audio_queue = dispatch_queue_create("wxyz_audio_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t audio_group = dispatch_group_create();
for (NSDictionary *t_dic in taskArray) {
dispatch_group_async(audio_group, audio_queue, ^{
dispatch_group_enter(audio_group);
TFProductionChapterModel *t_model = [TFProductionChapterModel modelWithDictionary:t_dic];
if (!t_model) {
// 单个章节下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFail, t_model.production_id, t_model.chapter_id);
}
});
}
AFURLSessionManager *manager = [[AFURLSessionManager alloc] init];
manager.operationQueue.maxConcurrentOperationCount = 2;
NSURL *URL = [NSURL URLWithString:t_model.content];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:[NSURLRequest requestWithURL:URL] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
// 存储文件夹创建
if (![[NSFileManager defaultManager] fileExistsAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:t_model.production_id chapter_id:t_model.chapter_id productionType:TFProductionTypeAudio]]) {
[[NSFileManager defaultManager] createDirectoryAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:t_model.production_id chapter_id:t_model.chapter_id productionType:TFProductionTypeAudio] withIntermediateDirectories:YES attributes:nil error:nil];
}
// 获取图片名称
NSString *audioFileName = [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@", [TFUtilsHelper formatStringWithInteger:t_model.production_id], [TFUtilsHelper formatStringWithInteger:t_model.chapter_id], [TFUtilsHelper formatStringWithObject:t_model.update_time]]];
// 图片地址
NSString *audioFilePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:t_model.production_id chapter_id:t_model.chapter_id productionType:TFProductionTypeAudio] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", audioFileName, [TFViewHelper audioExtensionWithFormatString:[response MIMEType]]]];
return [NSURL fileURLWithPath:audioFilePath];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
if (error) {
// 删除出错章节文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadChapterFolderWithProduction_id:t_model.production_id chapter_ids:@[[TFUtilsHelper formatStringWithInteger:t_model.chapter_id]] productionType:TFProductionTypeAudio];
[[weakSelf audioChaptersRecordDictionaryWithProduction_id:t_model.production_id] setObject:identify_fail forKey:chapterRecordKey(t_model.production_id, t_model.chapter_id)];
[weakSelf audioRecordWriteToPlistWithProduction_id:t_model.production_id];
// 章节下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFail, t_model.production_id, t_model.chapter_id);
}
});
} else {
// 下载成功 覆盖临时下载记录
[[weakSelf audioChaptersRecordDictionaryWithProduction_id:t_model.production_id] setObject:t_model forKey:chapterRecordKey(t_model.production_id, t_model.chapter_id)];
[weakSelf audioRecordWriteToPlistWithProduction_id:t_model.production_id];
// 章节下载成功
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFinished, t_model.production_id, t_model.chapter_id);
}
});
}
dispatch_group_leave(audio_group);
}];
[downloadTask resume];
});
}
dispatch_group_notify(audio_group, audio_queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.requesting = NO;
if (weakSelf.requestOrderArray.count == 0) {
// 任务完成
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFinished, 0, @[]);
}
} else {
[weakSelf downloadTaskRequest];
}
});
});
});
}
- (NSMutableArray *)requestOrderArray
{
if (!_requestOrderArray) {
_requestOrderArray = [NSMutableArray array];
}
return _requestOrderArray;
}
- (NSMutableDictionary *)audioChaptersRecordDictionaryWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] chaptersRecordDownloadDictionaryWithProduction_id:production_id productionType:TFProductionTypeAudio modelClass:[TFProductionChapterModel class]];
}
- (BOOL)audioRecordWriteToPlistWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] writeToChapterPlistFileWithProduction_id:production_id productionType:TFProductionTypeAudio modelClass:[TFProductionChapterModel class]];
}
@end
@@ -0,0 +1,58 @@
//
// WXYZ_BBBBBBBManager.h
// WXReader
//
// Created by Andrew on 2020/7/10.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WXYZ_DownloadHelper.h"
#import "TFNovelDownloadTaskListModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_BookDownloadManager : NSObject <WXYZ_DownloadManagerEnumProtocol>
@property (nonatomic, copy) void (^downloadDeleteFinishBlock)(NSArray *success_chapter_ids, NSArray *fail_chapter);
// 总体任务下载回调
@property (nonatomic, copy) void (^downloadMissionStateChangeBlock)(WXYZ_DownloadMissionState state, NSInteger production_id, TFDownloadTaskModel *downloadTaskModel, NSArray<NSNumber *> * _Nullable chapterIDArray);
interface_singleton
/*
**/
// 下载章节(不支持自动订阅 && 支持多章下载)
- (void)downloadChaptersWithProductionModel:(TFProductionModel *)productionModel downloadTaskModel:(TFDownloadTaskModel *)downloadTaskModel production_id:(NSInteger)production_id start_chapter_id:(NSInteger)start_chapter_id downloadNum:(NSInteger)downloadNum;
/*
**/
// 删除本地已下载作品
- (BOOL)removeDownloadProductionWithProduction_id:(NSInteger)production_id;
/*
**/
// 获取已下载文件路径
- (NSString *)getChapterFilePathWithChapterModel:(TFProductionChapterModel *)chapterModel;
// 获取章节内容
- (NSString *)getFileContentsWithChapterModel:(TFProductionChapterModel * __nullable)chapterModel;
// 存储章节内容
- (void)storingFilesWithChapterModel:(TFProductionChapterModel * __nullable)chapterModel storingCompletionHandler:(void (^)(BOOL finishStoring))completionHandler;
// 获取下载状态
- (WXYZ_ProductionDownloadState)getDownloadMissionStateWithProduction_id:(NSInteger)production_id downloadTaskModel:(TFDownloadTaskModel *)downloadTaskModel;
// 获取某一已下载作品model
- (TFNovelDownloadTaskListModel *)getDownloadProductionModelWithProduction_id:(NSInteger)production_id;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,470 @@
//
// 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
@@ -0,0 +1,32 @@
//
// WXYZ_ComicDownloadManager.h
// WXReader
//
// Created by Andrew on 2020/3/29.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_DownloadHelper.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXYZ_ComicDownloadManager : NSObject <WXYZ_DownloadManagerProtocol>
@property (nonatomic, copy) void (^downloadDeleteFinishBlock)(NSArray *success_chapter_ids, NSArray *fail_chapter);
// 章节下载状态改变
@property (nonatomic, copy) void (^downloadChapterStateChangeBlock)(WXYZ_DownloadChapterState state, NSInteger production_id, NSInteger chapter_id);
// 总体任务下载完成
@property (nonatomic, copy) void (^downloadMissionStateChangeBlock)(WXYZ_DownloadMissionState state, NSInteger production_id, NSArray *chapter_ids);
interface_singleton
- (NSArray *)getDownloadChapterModelArrayWithProduction_id:(NSInteger)production_id;
// 获取本地图片
- (UIImage *)getDownloadLocalImageWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id image_id:(NSInteger)image_id image_update_time:(NSInteger)image_update_time;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,429 @@
//
// WXYZ_ComicDownloadManager.m
// WXReader
//
// Created by Andrew on 2020/3/29.
// Copyright © 2020 Andrew. All rights reserved.
//
#import "WXYZ_ComicDownloadManager.h"
static dispatch_group_t url_session_manager_completion_group() {
static dispatch_group_t af_url_session_manager_completion_group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_url_session_manager_completion_group = dispatch_group_create();
});
return af_url_session_manager_completion_group;
}
@interface WXYZ_ComicDownloadManager ()
@property (nonatomic, assign) BOOL requesting;
@property (nonatomic, strong) NSMutableArray *requestOrderArray;
@end
@implementation WXYZ_ComicDownloadManager
implementation_singleton(WXYZ_ComicDownloadManager)
/*
**/
// 下载章节
- (void)downloadChapterWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
[self downloadChaptersWithProductionModel:productionModel production_id:production_id chapter_ids:@[[TFUtilsHelper formatStringWithInteger:chapter_id]]];
}
// 下载多个章节
- (void)downloadChaptersWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids
{
// 作品开始下载标记
[[WXYZ_DownloadHelper sharedManager] recordDownloadProductionWithProductionModel:productionModel productionType:TFProductionTypeComic];
WS(weakSelf)
[TFNetworkTools POST:Comic_Download parameters:@{@"comic_id":[TFUtilsHelper formatStringWithInteger:production_id], @"chapter_id":[chapter_ids componentsJoinedByString:@","]} model:nil success:^(BOOL isSuccess, NSDictionary * _Nullable t_model, TFNetworkRequestModel * _Nonnull requestModel) {
if (isSuccess) {
dispatch_async(dispatch_get_main_queue(), ^{
// 任务开始
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionStart, production_id, chapter_ids);
}
// 任务加入任务队列
NSArray *taskArray = [t_model objectForKey:@"data"];
if (taskArray.count > 0) {
for (NSDictionary *t_dic in taskArray) {
TFProductionChapterModel *imageCollectionModel = [TFProductionChapterModel modelWithDictionary:t_dic];
if (imageCollectionModel) {
// 开始下载
[[self comicChaptersRecordDictionaryWithProduction_id:imageCollectionModel.production_id] setObject:identify_downloading forKey:chapterRecordKey(imageCollectionModel.production_id, imageCollectionModel.chapter_id)];
dispatch_async(dispatch_get_main_queue(), ^{
if (self.downloadChapterStateChangeBlock) {
self.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadStart, imageCollectionModel.production_id, imageCollectionModel.chapter_id);
}
});
}
}
[weakSelf.requestOrderArray addObject:taskArray];
if (!weakSelf.requesting) {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusSuccess promptTitle:TFLocalizedString(@"已加入下载列表")];
}
// 开始下载任务
[weakSelf downloadTaskRequestWithProduction_id:production_id];
} else {
// 任务失败
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
}
});
} else if (Compare_Json_isEqualTo(requestModel.code, 701)) { // 请求购买
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionShouldPay, production_id, chapter_ids);
}
});
} else {
[TFPromptManager showPromptViewWithStatus:TFPromptStatusError promptTitle:requestModel.msg];
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
});
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 任务失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFail, production_id, chapter_ids);
}
});
}];
}
/*
**/
// 删除本地整本已下载作品
- (BOOL)removeDownloadProductionWithProduction_id:(NSInteger)production_id
{
// 删除作品文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadProductionFolderWithProduction_id:production_id productionType:TFProductionTypeComic];
// 删除缓存
[[self comicChaptersRecordDictionaryWithProduction_id:production_id] removeAllObjects];
// 写入
[self comicRecordWriteToPlistWithProduction_id:production_id];
return YES;
}
// 删除本地多个已下载章节
- (void)removeDownloadChaptersWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *> *)chapter_ids
{
if (chapter_ids.count == 0) {
return;
}
// 删除文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadChapterFolderWithProduction_id:production_id chapter_ids:chapter_ids productionType:TFProductionTypeComic];
// 删除下载记录
NSMutableDictionary *t_dic = [self comicChaptersRecordDictionaryWithProduction_id:production_id];
NSMutableArray *t_delete_arr = [NSMutableArray array];
for (NSString *chapter_id in chapter_ids) {
[t_delete_arr addObject:chapterRecordKey(production_id, [chapter_id integerValue])];
}
[t_dic removeObjectsForKeys:t_delete_arr];
// 如果全部章节已经删除,则删除整体作品文件夹
if ([self getDownloadChapterCountWithProduction_id:production_id] == 0) {
[self removeDownloadProductionWithProduction_id:production_id];
} else {
[self comicRecordWriteToPlistWithProduction_id:production_id];
}
// 删除回调
dispatch_async(dispatch_get_main_queue(), ^{
if (self.downloadDeleteFinishBlock) {
self.downloadDeleteFinishBlock(chapter_ids, @[]);
}
});
}
/*
**/
// 获取下载章节数
- (NSInteger)getDownloadChapterCountWithProduction_id:(NSInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] getDownloadChapterCountWithProduction_id:production_id productionType:TFProductionTypeComic];
}
// 获取全部已下载章节model
- (NSArray *)getDownloadChapterModelArrayWithProduction_id:(NSInteger)production_id
{
NSMutableDictionary *t_dic = [self comicChaptersRecordDictionaryWithProduction_id:production_id];
NSMutableArray *t_arr = [NSMutableArray array];
for (id value in t_dic.allValues) {
if ([value isKindOfClass:[TFProductionChapterModel class]]) {
[t_arr addObject:value];
}
}
return [t_arr copy];
}
// 获取已下载章节model
- (id)getDownloadChapterModelWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [self comicChaptersRecordDictionaryWithProduction_id:production_id];
id value = [t_dic objectForKey:chapterRecordKey(production_id, chapter_id)];
if ([value isKindOfClass:[TFProductionChapterModel class]]) {
return value;
}
return nil;
}
// 获取下载状态
- (WXYZ_ProductionDownloadState)getChapterDownloadStateWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [self comicChaptersRecordDictionaryWithProduction_id:production_id];
if ([[t_dic objectForKey:chapterRecordKey(production_id, chapter_id)] isEqual:identify_downloading]) {
return WXYZ_ProductionDownloadStateDownloading;
}
if ([[t_dic objectForKey:chapterRecordKey(production_id, chapter_id)] isEqual:identify_fail]) {
return WXYZ_ProductionDownloadStateFail;
}
if ([[t_dic objectForKey:chapterRecordKey(production_id, chapter_id)] isKindOfClass:[TFProductionChapterModel class]]) {
return WXYZ_ProductionDownloadStateDownloaded;
}
return WXYZ_ProductionDownloadStateNormal;
}
// 作品章节是否下载
- (BOOL)isChapterDownloadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
return [[WXYZ_DownloadHelper sharedManager] isChapterDownloadedWithProduction_id:production_id chapter_id:chapter_id productionType:TFProductionTypeComic];
}
- (UIImage *)getDownloadLocalImageWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id image_id:(NSInteger)image_id image_update_time:(NSInteger)image_update_time
{
UIImage *t_image = [UIImage imageWithContentsOfFile:[self chapterImageFilePathWithProduction_id:production_id chapter_id:chapter_id image_id:image_id image_update_time:image_update_time]];
if (!t_image) {
return nil;
}
return t_image;
}
- (NSString *)chapterImageFilePathWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id image_id:(NSInteger)image_id image_update_time:(NSInteger)image_update_time
{
// 章节图片名称
NSString *imageFileName = [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@%@", [TFUtilsHelper formatStringWithInteger:production_id], [TFUtilsHelper formatStringWithInteger:chapter_id], [TFUtilsHelper formatStringWithInteger:image_id], [TFUtilsHelper formatStringWithInteger:image_update_time]]];
NSString *imageFilePath = @"";
NSArray *extensionArr = @[@"jpeg", @"png", @"gif", @"tiff", @"webp"];
for (NSString *extension in extensionArr) {
imageFilePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:production_id chapter_id:chapter_id productionType:TFProductionTypeComic] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageFileName, extension]];
if (imageFilePath && imageFilePath.length > 0 && [[NSFileManager defaultManager] fileExistsAtPath:imageFilePath]) {
return imageFilePath;
}
}
return imageFilePath;
}
- (void)downloadTaskRequestWithProduction_id:(NSInteger)production_id
{
if (self.requestOrderArray.count == 0) {
return;
}
if (self.requesting) {
return;
}
self.requesting = YES;
NSArray *taskArray = [self.requestOrderArray firstObject];
[self.requestOrderArray removeFirstObject];
WS(weakSelf)
dispatch_group_async(url_session_manager_completion_group(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 记录出错章节
NSMutableArray __block *errorChapter = [NSMutableArray array];
dispatch_semaphore_t collection_semaphore = dispatch_semaphore_create(0);
// 记录章节model内容
NSMutableArray *t_chapterModelArray = [NSMutableArray array];
for (NSDictionary *t_dic in taskArray) {
dispatch_queue_t image_queue = dispatch_queue_create("wxyz_image_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t image_group = dispatch_group_create();
TFProductionChapterModel *imageCollectionModel = [TFProductionChapterModel modelWithDictionary:t_dic];
if (!imageCollectionModel) {
// 单个章节下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFail, imageCollectionModel.production_id, imageCollectionModel.chapter_id);
}
});
continue;
}
[t_chapterModelArray addObject:imageCollectionModel];
// 解析任务 下载一话内的图片组
for (TFImageListModel *imageModel in imageCollectionModel.image_list) {
dispatch_group_async(image_group, image_queue, ^{
dispatch_group_enter(image_group);
// 创建图片下载器
AFURLSessionManager *manager = [[AFURLSessionManager alloc] init];
manager.operationQueue.maxConcurrentOperationCount = 2;
NSURL *URL = [NSURL URLWithString:imageModel.image];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:[NSURLRequest requestWithURL:URL] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
// 存储文件夹创建
if (![[NSFileManager defaultManager] fileExistsAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:imageCollectionModel.production_id chapter_id:imageCollectionModel.chapter_id productionType:TFProductionTypeComic]]) {
[[NSFileManager defaultManager] createDirectoryAtPath:[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:imageCollectionModel.production_id chapter_id:imageCollectionModel.chapter_id productionType:TFProductionTypeComic] withIntermediateDirectories:YES attributes:nil error:nil];
}
// 获取图片名称
NSString *imageFileName = [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@%@", [TFUtilsHelper formatStringWithInteger:imageCollectionModel.production_id], [TFUtilsHelper formatStringWithInteger:imageCollectionModel.chapter_id], [TFUtilsHelper formatStringWithInteger:imageModel.image_id], [TFUtilsHelper formatStringWithInteger:imageModel.image_update_time]]];
// 图片地址
NSString *imageFilePath = [[[WXYZ_DownloadHelper sharedManager] getDownloadChapterFolderPathWithProduction_id:imageCollectionModel.production_id chapter_id:imageCollectionModel.chapter_id productionType:TFProductionTypeComic] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageFileName, [TFViewHelper imageExtensionWithFormatString:[response MIMEType]]]];
return [NSURL fileURLWithPath:imageFilePath];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
// 如果某一张出错就取消下载,删除该章节文件夹
if (error) {
[errorChapter addObject:[TFUtilsHelper formatStringWithInteger:imageCollectionModel.chapter_id]];
}
dispatch_group_leave(image_group);
}];
[downloadTask resume];
});
}
dispatch_group_notify(image_group, image_queue, ^{
// 删除图片出错章节
if (errorChapter.count > 0) {
// 删除出错章节文件夹
[[WXYZ_DownloadHelper sharedManager] removeDownloadChapterFolderWithProduction_id:imageCollectionModel.production_id chapter_ids:errorChapter productionType:TFProductionTypeComic];
[[weakSelf comicChaptersRecordDictionaryWithProduction_id:imageCollectionModel.production_id] setObject:identify_fail forKey:chapterRecordKey(imageCollectionModel.production_id, imageCollectionModel.chapter_id)];
[weakSelf comicRecordWriteToPlistWithProduction_id:imageCollectionModel.production_id];
// 单个章节下载失败
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFail, imageCollectionModel.production_id, imageCollectionModel.chapter_id);
}
});
} else {
// 下载成功 覆盖临时下载记录
[[weakSelf comicChaptersRecordDictionaryWithProduction_id:imageCollectionModel.production_id] setObject:imageCollectionModel forKey:chapterRecordKey(imageCollectionModel.production_id, imageCollectionModel.chapter_id)];
[weakSelf comicRecordWriteToPlistWithProduction_id:imageCollectionModel.production_id];
// 单个章节下载完成
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf.downloadChapterStateChangeBlock) {
weakSelf.downloadChapterStateChangeBlock(WXYZ_DownloadStateChapterDownloadFinished, imageCollectionModel.production_id, imageCollectionModel.chapter_id);
}
});
}
dispatch_semaphore_signal(collection_semaphore);
});
dispatch_semaphore_wait(collection_semaphore, DISPATCH_TIME_FOREVER);
}
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.requesting = NO;
if (weakSelf.requestOrderArray.count == 0) {
// 替换已下载记录章节目录内容
TFProductionModel *t_productionModel = [[WXYZ_DownloadHelper sharedManager] getDownloadProductionModelWithProduction_id:production_id productionType:TFProductionTypeComic];
NSMutableArray *t_chapterList = [t_productionModel.chapter_list mutableCopy];
for (int i = 0; i < t_chapterList.count; i++) {
TFProductionChapterModel *t_chapterModel = [t_chapterList objectAtIndex:i];
for (TFProductionChapterModel *tt_chapterModel in t_chapterModelArray) {
if (tt_chapterModel.chapter_id == t_chapterModel.chapter_id) {
[t_chapterList replaceObjectAtIndex:i withObject:tt_chapterModel];
break;
}
}
}
t_productionModel.chapter_list = [t_chapterList copy];
[[WXYZ_DownloadHelper sharedManager] recordDownloadProductionWithProductionModel:t_productionModel productionType:TFProductionTypeComic];
// 任务完成
if (weakSelf.downloadMissionStateChangeBlock) {
weakSelf.downloadMissionStateChangeBlock(WXYZ_DownloadStateMissionFinished, 0, @[]);
}
} else {
[weakSelf downloadTaskRequestWithProduction_id:production_id];
}
});
});
}
- (NSMutableArray *)requestOrderArray
{
if (!_requestOrderArray) {
_requestOrderArray = [NSMutableArray array];
}
return _requestOrderArray;
}
- (NSMutableDictionary *)comicChaptersRecordDictionaryWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] chaptersRecordDownloadDictionaryWithProduction_id:production_id productionType:TFProductionTypeComic modelClass:[TFProductionChapterModel class]];
}
- (BOOL)comicRecordWriteToPlistWithProduction_id:(NSUInteger)production_id
{
return [[WXYZ_DownloadHelper sharedManager] writeToChapterPlistFileWithProduction_id:production_id productionType:TFProductionTypeComic modelClass:[TFProductionChapterModel class]];
}
@end
@@ -0,0 +1,71 @@
//
// WXYZ_DownloadHelper.h
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WXYZ_DownloadManagerProtocol.h"
NS_ASSUME_NONNULL_BEGIN
// 章节记录文件key
#define chapterRecordKey(production_id, chapter_id) [TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@", [TFUtilsHelper formatStringWithInteger:production_id], [TFUtilsHelper formatStringWithInteger:chapter_id]]]
@interface WXYZ_DownloadHelper : NSObject
interface_singleton
/*
**/
// 作品下载记录
- (void)recordDownloadProductionWithProductionModel:(TFProductionModel *)productionModel productionType:(TFProductionType)productionType;
/*
**/
// 删除作品文件夹
- (void)removeDownloadProductionFolderWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType;
// 删除章节文件夹
- (BOOL)removeDownloadChapterFolderWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids productionType:(TFProductionType)productionType;
/*
**/
// 作品章节是否下载
- (BOOL)isChapterDownloadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id productionType:(TFProductionType)productionType;
// 下载作品文件夹路径
- (NSString *)getDownloadProductionFolderPathWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType;
// 下载章节文件夹路径
- (NSString *)getDownloadChapterFolderPathWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id productionType:(TFProductionType)productionType;
// 下载作品记录文件路径
- (NSString *)getDownloadProductionRecordPlistFilePathWithProductionType:(TFProductionType)productionType;
// 获取下载章节数
- (NSInteger)getDownloadChapterCountWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType;
// 获取类别下的所有下载作品model
- (NSArray <TFProductionModel *> *)getDownloadProductionArrayWithProductionType:(TFProductionType)productionType;
// 获取某一已下载作品model
- (TFProductionModel *)getDownloadProductionModelWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType;
// 章节记录缓存变量
- (NSMutableDictionary *)chaptersRecordDownloadDictionaryWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType modelClass:(__nullable Class)modelClass;
// 写入章节记录文件
- (BOOL)writeToChapterPlistFileWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType modelClass:(Class)modelClass;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,376 @@
//
// WXYZ_DownloadHelper.m
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
/* 下载缓存结构示意
WXYZ_DownloadFileFolder ━┳━ BookDownloadFileFolder ━┳━ WXYZ_DownloadProductionRecordFile.plist
┃ ┃
┃ ┃
┃ ┣━ 作品文件夹(production_id) ━┳━ WXYZ_DownloadChapterRecordFile.plist
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┣━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┗━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┃ ┃
┃ ┗━ 作品文件夹(production_id)
┣━ ComicDownloadFileFolder ━┳━ WXYZ_DownloadProductionRecordFile.plist
┃ ┃
┃ ┃
┃ ┣━ 作品文件夹(production_id) ━┳━ WXYZ_DownloadChapterRecordFile.plist
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┣━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┃ ┃ ┃
┃ ┃ ┃
┃ ┃ ┗━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┃ ┃
┃ ┗━ 作品文件夹(production_id)
┗━ AudioDownloadFileFolder ━┳━ WXYZ_DownloadProductionRecordFile.plist
┣━ 作品文件夹(production_id) ━┳━ WXYZ_DownloadChapterRecordFile.plist
┃ ┃
┃ ┃
┃ ┣━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┃ ┃
┃ ┃
┃ ┗━ 章节文件夹(production_id + chapter_id) ━━ 对应文件 比如.txt/.jpg/.png/.mp3
┗━ 作品文件夹(production_id)
*/
#import "WXYZ_DownloadHelper.h"
@implementation WXYZ_DownloadHelper
implementation_singleton(WXYZ_DownloadHelper)
// 作品下载记录
- (void)recordDownloadProductionWithProductionModel:(TFProductionModel *)productionModel productionType:(TFProductionType)productionType
{
if (!productionModel) {
return;
}
NSMutableArray *t_arr = [self productionRecordDownloadArrayWithProductionType:productionType];
for (TFProductionModel *t_model in t_arr) {
if (t_model.production_id == productionModel.production_id) {
return;
}
}
[[self productionRecordDownloadArrayWithProductionType:productionType] addObject:productionModel];
[self writeToPlistFileWithProductionType:productionType];
}
// 删除作品下载记录
- (void)removeRecordDownloadProductionWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
NSMutableArray *t_arr = [[self productionRecordDownloadArrayWithProductionType:productionType] mutableCopy];
for (TFProductionModel *t_model in t_arr) {
if (t_model.production_id == production_id) {
[[self productionRecordDownloadArrayWithProductionType:productionType] removeObject:t_model];
[self writeToPlistFileWithProductionType:productionType];
return;
}
}
}
// 删除章节下载记录(返回是否成功,如果成功那么需要在对应的downloadManager中,重置记录变量,从本地重新获取)
- (BOOL)removeRecordDownloadChapterWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids productionType:(TFProductionType)productionType
{
NSMutableDictionary *localCacheDic = [NSMutableDictionary dictionaryWithContentsOfFile:[[WXYZ_DownloadHelper sharedManager] getDownloadChapterRecordPlistFilePathWithProduction_id:production_id productionType:productionType]];
for (NSString *chapter_id in chapter_ids) {
[localCacheDic removeObjectForKey:chapterRecordKey(production_id, [chapter_id integerValue])];
}
NSMutableDictionary *save_dic = [NSMutableDictionary dictionary];
for (NSString *key in localCacheDic.allKeys) {
id value = [localCacheDic objectForKey:key];
if ([value isKindOfClass:[NSClassFromString(@"WXYZ_ComicReaderModel") class]]) {
value = [value modelToJSONString];
}
[save_dic setObject:value forKey:key];
}
// 写入文件
if (![save_dic writeToFile:[self getDownloadChapterRecordPlistFilePathWithProduction_id:production_id productionType:productionType] atomically:NO]) {
return NO;
}
return YES;
}
// 删除作品文件夹
- (void)removeDownloadProductionFolderWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
// 删除plist文件记录
[self removeRecordDownloadProductionWithProduction_id:production_id productionType:productionType];
// 删除对应作品整体文件夹
[[NSFileManager defaultManager] removeItemAtPath:[self getDownloadProductionFolderPathWithProduction_id:production_id productionType:productionType] error:nil];
}
// 删除章节文件夹
- (BOOL)removeDownloadChapterFolderWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids productionType:(TFProductionType)productionType
{
for (NSString *chapter_id in chapter_ids) {
if ([[NSFileManager defaultManager] fileExistsAtPath:[self getDownloadChapterFolderPathWithProduction_id:production_id chapter_id:[chapter_id integerValue] productionType:productionType]]) {
[[NSFileManager defaultManager] removeItemAtPath:[self getDownloadChapterFolderPathWithProduction_id:production_id chapter_id:[chapter_id integerValue] productionType:productionType] error:nil];
}
}
// 删除章节plist文件记录
return [self removeRecordDownloadChapterWithProduction_id:production_id chapter_ids:chapter_ids productionType:productionType];
}
// 作品章节是否下载
- (BOOL)isChapterDownloadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id productionType:(TFProductionType)productionType
{
if ([[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self getDownloadChapterFolderPathWithProduction_id:production_id chapter_id:chapter_id productionType:productionType] error:nil].count > 0) {
return YES;
}
return NO;
}
// 获取下载章节数
- (NSInteger)getDownloadChapterCountWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
// 存在已下载章节内容文件夹数量
CGFloat chapterDownloadNumber = 0;
// 获取作品下全部章节文件夹名称
NSArray <NSString *>*chapterFolderNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self getDownloadProductionFolderPathWithProduction_id:production_id productionType:productionType] error:nil];
for (NSString *folderName in chapterFolderNames) {
NSString *chapterFloderPath = [[self getDownloadProductionFolderPathWithProduction_id:production_id productionType:productionType] stringByAppendingPathComponent:folderName];
BOOL isDirectory = NO;
[[NSFileManager defaultManager] fileExistsAtPath:chapterFloderPath isDirectory:&isDirectory];
if (isDirectory && [[NSFileManager defaultManager] contentsOfDirectoryAtPath:chapterFloderPath error:nil].count > 0) {
chapterDownloadNumber ++;
}
}
return chapterDownloadNumber;
}
// 获取类别下的所有下载作品
- (NSArray <TFProductionModel *> *)getDownloadProductionArrayWithProductionType:(TFProductionType)productionType
{
return [self productionRecordDownloadArrayWithProductionType:productionType];
}
- (TFProductionModel *)getDownloadProductionModelWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
for (TFProductionModel *t_model in [self productionRecordDownloadArrayWithProductionType:productionType]) {
if (t_model.production_id == production_id) {
return t_model;
}
}
return nil;
}
// 主文件夹路径
- (NSString *)getDownloadRootFolderPathWithProductionType:(TFProductionType)productionType
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectOrNilAtIndex:0];
// 主目录文件夹
NSString *rootFolderPath = [documentPath stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:@"WXYZ_DownloadFileFolder"]];
// 创建章节文件夹
if (![[NSFileManager defaultManager] fileExistsAtPath:rootFolderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:rootFolderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
// 作品类别文件夹
NSString *typeFolderPath = @"";
switch (productionType) {
case TFProductionTypeNovel: // 存储全部下载书籍
typeFolderPath = [rootFolderPath stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:@"BookDownloadFileFolder"]];
break;
case TFProductionTypeComic: // 存储全部下载漫画
typeFolderPath = [rootFolderPath stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:@"ComicDownloadFileFolder"]];
break;
case TFProductionTypeAudio: // 存储全部下载听书
typeFolderPath = [rootFolderPath stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:@"AudioDownloadFileFolder"]];
break;
default:
break;
}
// 创建章节文件夹
if (![[NSFileManager defaultManager] fileExistsAtPath:typeFolderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:typeFolderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
return typeFolderPath;
}
// 下载作品文件夹
- (NSString *)getDownloadProductionFolderPathWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
NSString *productionFolderPath = [[self getDownloadRootFolderPathWithProductionType:productionType] stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@", [TFUtilsHelper formatStringWithInteger:productionType], [TFUtilsHelper formatStringWithInteger:production_id]]]];
// 创建章节文件夹
if (![[NSFileManager defaultManager] fileExistsAtPath:productionFolderPath] && production_id != 0) {
[[NSFileManager defaultManager] createDirectoryAtPath:productionFolderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
return productionFolderPath;
}
// 下载章节文件夹
- (NSString *)getDownloadChapterFolderPathWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id productionType:(TFProductionType)productionType
{
NSString *chapterFolderPath = [[self getDownloadProductionFolderPathWithProduction_id:production_id productionType:productionType] stringByAppendingPathComponent:[TFUtilsHelper stringToMD5:[NSString stringWithFormat:@"%@%@%@", [TFUtilsHelper formatStringWithInteger:productionType], [TFUtilsHelper formatStringWithInteger:production_id], [TFUtilsHelper formatStringWithInteger:chapter_id]]]];
// 创建章节文件夹
if (![[NSFileManager defaultManager] fileExistsAtPath:chapterFolderPath] && production_id != 0) {
[[NSFileManager defaultManager] createDirectoryAtPath:chapterFolderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
return chapterFolderPath;
}
// 下载作品记录文件路径
- (NSString *)getDownloadProductionRecordPlistFilePathWithProductionType:(TFProductionType)productionType
{
NSString *productionRecordFilePath = [[self getDownloadRootFolderPathWithProductionType:productionType] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [TFUtilsHelper stringToMD5:@"WXYZ_DownloadProductionRecordFile"]]];
if (![[NSFileManager defaultManager] fileExistsAtPath:productionRecordFilePath]) {
[@[] writeToFile:productionRecordFilePath atomically:NO];
}
return productionRecordFilePath;
}
// 下载章节记录文件路径
- (NSString *)getDownloadChapterRecordPlistFilePathWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType
{
// 记录下载状态plist文件地址
NSString *chapterRecordFilePath = [[self getDownloadProductionFolderPathWithProduction_id:production_id productionType:productionType] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [TFUtilsHelper stringToMD5:@"WXYZ_DownloadChapterRecordFile"]]];
if (![[NSFileManager defaultManager] fileExistsAtPath:chapterRecordFilePath]) {
[@{} writeToFile:chapterRecordFilePath atomically:NO];
}
return chapterRecordFilePath;
}
// 作品记录缓存变量
static NSMutableDictionary *_productionsRecordDictionary;
- (NSMutableArray *)productionRecordDownloadArrayWithProductionType:(TFProductionType)productionType;
{
if (!_productionsRecordDictionary) {
// 此全局临时变量的作用是记录不同作品的下载记录,减少了文件的读写,增加访问效率
_productionsRecordDictionary = [NSMutableDictionary dictionary];
}
NSMutableArray *t_arr = [_productionsRecordDictionary objectForKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:productionType]]];
if (!t_arr) {
NSMutableArray *localArr = [NSMutableArray arrayWithContentsOfFile:[self getDownloadProductionRecordPlistFilePathWithProductionType:productionType]];
t_arr = [NSMutableArray array];
for (NSString *json in localArr) {
[t_arr addObject:[TFProductionModel modelWithJSON:json]];
}
[_productionsRecordDictionary setObject:t_arr forKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:productionType]]];
}
return t_arr;
}
// 写入作品记录文件
- (BOOL)writeToPlistFileWithProductionType:(TFProductionType)productionType;
{
NSMutableArray *t_downloadArr = [self productionRecordDownloadArrayWithProductionType:productionType];
NSMutableArray *saveArr = [NSMutableArray array];
for (TFProductionModel *t_model in t_downloadArr) {
[saveArr addObject:[t_model modelToJSONString]];
}
// 写入文件
if (![saveArr writeToFile:[self getDownloadProductionRecordPlistFilePathWithProductionType:productionType] atomically:NO]) {
return NO;
}
return YES;
}
// 章节记录缓存变量
static NSMutableDictionary *_chaptersRecordDictionary;
- (NSMutableDictionary *)chaptersRecordDownloadDictionaryWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType modelClass:(Class)modelClass
{
if (!_chaptersRecordDictionary) {
// 此全局临时变量的作用是记录不同作品的下载记录,减少了文件的读写,增加访问效率
_chaptersRecordDictionary = [NSMutableDictionary dictionary];
}
NSMutableDictionary *t_dic = [_chaptersRecordDictionary objectForKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:production_id]]];
if (!t_dic || t_dic.count == 0) {
NSMutableDictionary *localDic = [NSMutableDictionary dictionaryWithContentsOfFile:[self getDownloadChapterRecordPlistFilePathWithProduction_id:production_id productionType:productionType]];
t_dic = [NSMutableDictionary dictionary];
for (NSString *key in localDic.allKeys) {
id value = [localDic objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
[t_dic setObject:value forKey:key];
} else if ([value isEqualToString:identify_fail]) {
[t_dic setObject:value forKey:key];
} else if (![value isEqual:identify_downloading] && value) {
[t_dic setObject:[modelClass modelWithJSON:value] forKey:key];
}
}
[_chaptersRecordDictionary setObject:t_dic forKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:production_id]]];
}
return t_dic;
}
// 写入章节记录文件
- (BOOL)writeToChapterPlistFileWithProduction_id:(NSInteger)production_id productionType:(TFProductionType)productionType modelClass:(Class)modelClass
{
NSMutableDictionary *t_downloadDic = [self chaptersRecordDownloadDictionaryWithProduction_id:production_id productionType:productionType modelClass:modelClass];
if (t_downloadDic.count == 0) {
return NO;
}
NSMutableDictionary *save_dic = [NSMutableDictionary dictionary];
for (NSString *key in t_downloadDic.allKeys) {
id value = [t_downloadDic objectForKey:key];
if ([value isKindOfClass:[modelClass class]]) {
value = [value modelToJSONString];
}
[save_dic setObject:value forKey:key];
}
// 写入文件
if (![save_dic writeToFile:[self getDownloadChapterRecordPlistFilePathWithProduction_id:production_id productionType:productionType] atomically:NO]) {
return NO;
}
return YES;
}
@end
@@ -0,0 +1,44 @@
//
// WXYZ_DownloadManagerEnumProtocol.h
// WXReader
//
// Created by Andrew on 2020/7/13.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, WXYZ_DownloadChapterState) {
WXYZ_DownloadStateChapterDownloadNormal, // 章节下载未开始
WXYZ_DownloadStateChapterDownloadStart, // 章节下载开始
WXYZ_DownloadStateChapterDownloadFinished, // 章节下载完成
WXYZ_DownloadStateChapterDownloadFail // 章节下载失败
};
typedef NS_ENUM(NSUInteger, WXYZ_DownloadMissionState) {
WXYZ_DownloadStateMissionShouldPay, // 任务失败需要支付
WXYZ_DownloadStateMissionNormal, // 任务未开始
WXYZ_DownloadStateMissionStart, // 任务开始
WXYZ_DownloadStateMissionFinished, // 任务完成
WXYZ_DownloadStateMissionFail // 任务失败
};
typedef NS_ENUM(NSUInteger, WXYZ_ProductionDownloadState) {
WXYZ_ProductionDownloadStateNormal = 0, // 普通状态
WXYZ_ProductionDownloadStateDownloading = 1, // 下载中
WXYZ_ProductionDownloadStateDownloaded = 2, // 已下载
WXYZ_ProductionDownloadStateFail = 3, // 失败
WXYZ_ProductionDownloadStateSelected = 4 // 选中
};
#define identify_downloading @"id_downloading"
#define identify_fail @"id_fail"
@protocol WXYZ_DownloadManagerEnumProtocol <NSObject>
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,58 @@
//
// WXYZ_DownloadHelperProtocol.h
// WXReader
//
// Created by Andrew on 2020/4/1.
// Copyright © 2020 Andrew. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WXYZ_DownloadManagerEnumProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@protocol WXYZ_DownloadManagerProtocol <NSObject>
@optional
/*
**/
// 下载章节
- (void)downloadChapterWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 下载多个章节
- (void)downloadChaptersWithProductionModel:(TFProductionModel *)productionModel production_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *>*)chapter_ids;
/*
**/
// 删除本地已下载作品
- (BOOL)removeDownloadProductionWithProduction_id:(NSInteger)production_id;
// 删除本地已下载章节
- (void)removeDownloadChaptersWithProduction_id:(NSInteger)production_id chapter_ids:(NSArray <NSString *> *)chapter_ids;
/*
**/
// 获取下载章节数
- (NSInteger)getDownloadChapterCountWithProduction_id:(NSInteger)production_id;
// 获取全部已下载章节model
- (NSArray *__nullable)getDownloadChapterModelArrayWithProduction_id:(NSInteger)production_id;
// 获取已下载章节model
- (id)getDownloadChapterModelWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 获取章节下载状态
- (WXYZ_ProductionDownloadState)getChapterDownloadStateWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 章节是否下载
- (BOOL)isChapterDownloadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
@end
NS_ASSUME_NONNULL_END