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.

377 lines
19 KiB

//
// 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