小说绘上架版本

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,79 @@
//
// TFReadRecordManager.h
// WXReader
//
// Created by 谢腾飞 on 2020/12/3.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFBookMarkModel;
@interface TFReadRecordManager : NSObject
+ (instancetype)shareManagerWithProductionType:(TFProductionType)productionType;
// 添加阅读记录
- (BOOL)addReadingRecordWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id chapterTitle:(NSString *)chapterTitle;
// 获取某个作品当前阅读章节id
- (NSInteger)getReadingRecordChapter_idWithProduction_id:(NSInteger)production_id;
// 获取某个作品当前阅读章节名称
- (NSString *)getReadingRecordChapterTitleWithProduction_id:(NSInteger)production_id;
// 作品章节是否已读
- (BOOL)chapterHasReadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 作品是否已读
- (BOOL)productionHasReadedWithProduction_id:(NSInteger)production_id;
// 设置漫画阅读记录(仅限漫画使用)
- (void)setComicReadingRecord:(NSInteger)comic_id chapter_id:(NSInteger)chapter_id offsetY:(CGFloat)offsetY;
/// 获取漫画阅读记录(章节ID :offsetY)(仅限漫画使用)
- (NSDictionary *)getComicReadingRecord:(NSInteger)comic_id;
// 设置播放器进度(仅限有声功能使用)
- (void)addPlayingProgress:(CGFloat)progress production_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 播放作品进度(仅限有声功能使用)
- (CGFloat)getPlayingProgressWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
// 是否是当前正在播放的作品(仅限有声功能使用)
- (BOOL)isCurrentPlayingProductionWithProduction_id:(NSInteger)production_id;
// 是否是当前正在播放的章节(仅限有声功能使用)
- (BOOL)isCurrentPlayingChapterWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id;
/* 添加书签
@param bookID 书籍ID
@param chapterID 章节ID
@param chapterSort 章节索引
@param chapterTitle 章节标题
@param chapterContent 章节内容
@param pageContent 当前页内容
**/
+ (TFBookMarkModel *)addBookMark:(NSString *)bookID chapterID:(NSString *)chapterID chapterSort:(NSInteger)chapterSort chapterTitle:(NSString *)chapterTitle chapterContent:(NSString *)chapterContent pageContent:(NSString *)pageContent;
/* 获取书籍所有书签
@param bookID 书籍ID
**/
+ (NSArray<TFBookMarkModel *> *)bookMark:(NSString *)bookID;
/* 获取章节所有书签
@param bookID 书籍ID
@param chapterID 章节ID
**/
+ (NSArray<TFBookMarkModel *> *)bookMark:(NSString *)bookID chapterID:(NSString *)chapterID;
/* 删除指定书签
@param markModel 书签Model
**/
+ (void)removeBookMark:(TFBookMarkModel *)markModel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,350 @@
//
// TFReadRecordManager.m
// WXReader
//
// Created by 谢腾飞 on 2020/12/3.
// Copyright © 2020 xtfei_2011@126.com. All rights reserved.
//
#import "TFReadRecordManager.h"
#import "TFBookMarkModel.h"
// 当前正在阅读作品id key
#define current_read_production_id_cache_key(type) ([NSString stringWithFormat:@"%@_%@", @"UkhU98p5", [TFUtilsHelper formatStringWithInteger:type]])
// 某个作品正在阅读的章节标题 key
#define current_read_production_title_cache_key(type, production_id) ([NSString stringWithFormat:@"%@%@%@", @"SOdYb5CO", [TFUtilsHelper formatStringWithInteger:type], [TFUtilsHelper formatStringWithInteger:production_id]])
// 某个作品正在阅读的章节id
#define current_read_chapter_id_cache_key(type, production_id) ([NSString stringWithFormat:@"%@_%@_%@", @"KBOwoFvR", [TFUtilsHelper formatStringWithInteger:type], [TFUtilsHelper formatStringWithInteger:production_id]])
// 某个章节的播放进度 key
#define current_playing_chapter_progress(type, production_id) ([NSString stringWithFormat:@"%@_%@_%@", @"TLIo2gaz", [TFUtilsHelper formatStringWithInteger:type], [TFUtilsHelper formatStringWithInteger:production_id]])
// 某个章节是否已读 key
#define has_readed_cache_key(type, production_id ) ([NSString stringWithFormat:@"%@%@%@", @"KNU5HliF", [TFUtilsHelper formatStringWithInteger:type], [TFUtilsHelper formatStringWithInteger:production_id]])
@interface TFReadRecordManager ()
@property (nonatomic ,strong) NSMutableDictionary *readRecordDictionary;
@end
@implementation TFReadRecordManager
static TFProductionType _productionType;
static TFReadRecordManager *_instance_record;
+ (instancetype)shareManagerWithProductionType:(TFProductionType)productionType
{
static dispatch_once_t once_token_record;
dispatch_once(&once_token_record, ^{
_instance_record = [[self alloc] init];
});
_productionType = productionType;
return _instance_record;
}
// 添加阅读记录
- (BOOL)addReadingRecordWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id chapterTitle:(NSString *)chapterTitle
{
// 记录当前正在阅读作品id
[self.readRecordDictionary setObject:[TFUtilsHelper formatStringWithInteger:production_id] forKey:current_read_production_id_cache_key(_productionType)];
// 记录当前正在阅读章节id
[self.readRecordDictionary setObject:[TFUtilsHelper formatStringWithInteger:chapter_id] forKey:current_read_chapter_id_cache_key(_productionType, production_id)];
// 记录当前阅读章节名称
[self.readRecordDictionary setObject:chapterTitle?:@"" forKey:current_read_production_title_cache_key(_productionType, production_id)];
// 设置已读作品
if (![self chapterHasReadedWithProduction_id:production_id chapter_id:chapter_id]) {
NSMutableDictionary *t_dic = [[self.readRecordDictionary objectForKey:has_readed_cache_key(_productionType, production_id)] mutableCopy];
if (!t_dic) {
t_dic = [NSMutableDictionary dictionary];
}
[t_dic setObject:@"1" forKey:[TFUtilsHelper formatStringWithInteger:chapter_id]];
[self.readRecordDictionary setObject:[t_dic copy] forKey:has_readed_cache_key(_productionType, production_id)];
}
return [self writeToPlistFile];
}
// 获取某个作品当前阅读章节id
- (NSInteger)getReadingRecordChapter_idWithProduction_id:(NSInteger)production_id
{
NSString *chapter_id_string = [self.readRecordDictionary objectForKey:current_read_chapter_id_cache_key(_productionType, production_id)];
return [chapter_id_string integerValue];
}
// 获取某个作品当前阅读章节名称
- (NSString *)getReadingRecordChapterTitleWithProduction_id:(NSInteger)production_id
{
NSString *chapter_id_string = [self.readRecordDictionary objectForKey:current_read_production_title_cache_key(_productionType, production_id)];
return chapter_id_string;
}
// 作品章节是否已读
- (BOOL)chapterHasReadedWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [[self.readRecordDictionary objectForKey:has_readed_cache_key(_productionType, production_id)] mutableCopy];
if (t_dic.count == 0) {
return NO;
}
return [t_dic objectForKey:[TFUtilsHelper formatStringWithInteger:chapter_id]]?YES:NO;
}
// 作品是否已读
- (BOOL)productionHasReadedWithProduction_id:(NSInteger)production_id
{
NSMutableDictionary *t_dic = [[self.readRecordDictionary objectForKey:has_readed_cache_key(_productionType, production_id)] mutableCopy];
if (t_dic.count == 0) {
return NO;
}
return YES;
}
// 设置播放器进度(仅限有声功能使用)
- (void)addPlayingProgress:(CGFloat)progress production_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSMutableDictionary *t_dic = [[self.readRecordDictionary objectForKey:current_playing_chapter_progress(_productionType, production_id)] mutableCopy];
if (!t_dic) {
t_dic = [NSMutableDictionary dictionary];
}
[t_dic setObject:[TFUtilsHelper formatStringWithFloat:progress] forKey:[TFUtilsHelper formatStringWithInteger:chapter_id]];
[self.readRecordDictionary setObject:[t_dic copy] forKey:current_playing_chapter_progress(_productionType, production_id)];
}
// 播放作品进度(仅限有声功能使用)
- (CGFloat)getPlayingProgressWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
NSDictionary *t_dic = [[self.readRecordDictionary objectForKey:current_playing_chapter_progress(_productionType, production_id)] copy];
NSString *progress = [t_dic objectForKey:[TFUtilsHelper formatStringWithInteger:chapter_id]];
if (progress && progress.length > 0) {
if ([progress floatValue] > 0.95) {
return 0;
}
return [progress floatValue];
}
return 0.f;
}
// 是否是当前正在播放的作品(仅限有声功能使用)
- (BOOL)isCurrentPlayingProductionWithProduction_id:(NSInteger)production_id
{
if ([[self.readRecordDictionary objectForKey:current_read_production_id_cache_key(_productionType)] isEqualToString:[TFUtilsHelper formatStringWithInteger:production_id]]) {
return YES;
}
return NO;
}
// 是否是当前正在播放的章节(仅限有声功能使用)
- (BOOL)isCurrentPlayingChapterWithProduction_id:(NSInteger)production_id chapter_id:(NSInteger)chapter_id
{
if ([self getReadingRecordChapter_idWithProduction_id:production_id] == chapter_id) {
return YES;
}
return NO;
}
- (NSMutableDictionary *)readRecordDictionary
{
if (!_readRecordDictionary) {
_readRecordDictionary = [NSMutableDictionary dictionary];
}
NSMutableDictionary *t_dic = [_readRecordDictionary objectForKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:_productionType]]];
if (!t_dic) {
t_dic = [NSMutableDictionary dictionaryWithContentsOfFile:[self cacheFilePath]];
[_readRecordDictionary setObject:t_dic forKey:[NSString stringWithFormat:@"%@", [TFUtilsHelper formatStringWithInteger:_productionType]]];
}
return t_dic;
}
- (NSString *)cacheFilePath
{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectOrNilAtIndex:0];
NSString *rootFloderPath = [documentPath stringByAppendingPathComponent:[@"WXYZ_ReadingRecordFileFloder" md5String]];
// 创建章节文件夹
if (![[NSFileManager defaultManager] fileExistsAtPath:rootFloderPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:rootFloderPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString *cacheFilePath = @"";
switch (_productionType) {
case TFProductionTypeNovel:
cacheFilePath = [rootFloderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [@"BookReadingRecordFile" md5String]]];
break;
case TFProductionTypeComic:
cacheFilePath = [rootFloderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [@"ComicReadingRecordFile" md5String]]];
break;
case TFProductionTypeAudio:
cacheFilePath = [rootFloderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [@"AudioReadingRecordFile" md5String]]];
break;
case TFProductionTypeAi:
cacheFilePath = [rootFloderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", [@"AiReadingRecordFile" md5String]]];
break;
default:
break;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:cacheFilePath]) {
[@{} writeToFile:cacheFilePath atomically:NO];
}
return cacheFilePath;
}
// 写入文件
- (BOOL)writeToPlistFile
{
NSDictionary *t_dic = [self.readRecordDictionary copy];
if (t_dic.count == 0) {
return NO;
}
// 写入文件
if (![t_dic writeToFile:[self cacheFilePath] atomically:NO]) {
return NO;
}
return YES;
}
+ (TFBookMarkModel *)addBookMark:(NSString *)bookID chapterID:(NSString *)chapterID chapterSort:(NSInteger)chapterSort chapterTitle:(NSString *)chapterTitle chapterContent:(NSString *)chapterContent pageContent:(NSString *)pageContent
{
NSString *fullPath = [[self bookMarkRootPath] stringByAppendingFormat:@"/bookMark_%@.plist", bookID];
NSMutableDictionary *t_dict = [NSMutableDictionary dictionaryWithContentsOfFile:fullPath];
if (!t_dict) {
t_dict = [NSMutableDictionary dictionary];
}
NSMutableArray<NSString *> *t_arr = t_dict[chapterID];
if (!t_arr) {
t_arr = [NSMutableArray array];
}
TFBookMarkModel *t_model = [[TFBookMarkModel alloc] init];
t_model.chapterID = chapterID;
t_model.chapterSort = chapterSort;
t_model.chapterTitle = chapterTitle;
t_model.timestamp = [TFUtilsHelper getTimeStamp];
t_model.pageContent = pageContent;
t_model.bookID = bookID;
t_model.specificIndex = [chapterContent rangeOfString:pageContent].location;
// 将Model转换成String
NSString *bookMark = [t_model modelToJSONString];
[t_arr addObject:bookMark];
[t_dict setValue:t_arr forKey:chapterID];
[t_dict writeToFile:fullPath atomically:YES];
return t_model;
}
+ (NSArray<TFBookMarkModel *> *)bookMark:(NSString *)bookID
{
NSString *fullPath = [[self bookMarkRootPath] stringByAppendingFormat:@"/bookMark_%@.plist", bookID];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) return @[];
NSMutableDictionary *t_dict = [NSMutableDictionary dictionaryWithContentsOfFile:fullPath];
NSMutableArray<TFBookMarkModel *> *markArr = [NSMutableArray array];
for (NSString *key in t_dict) {
NSArray<NSString *> *t_arr = t_dict[key];
for (NSString *obj in t_arr) {
NSDictionary *dict = [TFUtilsHelper dictionaryWithJsonString:obj];
TFBookMarkModel *t_model = [TFBookMarkModel modelWithDictionary:dict];
[markArr addObject:t_model];
}
}
return markArr;
}
+ (NSArray<TFBookMarkModel *> *)bookMark:(NSString *)bookID chapterID:(NSString *)chapterID
{
NSString *fullPath = [[self bookMarkRootPath] stringByAppendingFormat:@"/bookMark_%@.plist", bookID];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) return @[];
NSMutableDictionary *t_dict = [NSMutableDictionary dictionaryWithContentsOfFile:fullPath];
NSArray<NSString *> *t_arr = t_dict[chapterID];
if (!t_arr) return @[];
NSMutableArray<TFBookMarkModel *> *markArr = [NSMutableArray array];
for (NSString *obj in t_arr) {
NSDictionary *dict = [TFUtilsHelper dictionaryWithJsonString:obj];
TFBookMarkModel *t_model = [TFBookMarkModel modelWithDictionary:dict];
[markArr addObject:t_model];
}
return markArr;
}
+ (void)removeBookMark:(TFBookMarkModel *)markModel
{
NSString *fullPath = [[self bookMarkRootPath] stringByAppendingFormat:@"/bookMark_%@.plist", markModel.bookID];
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) return;
NSMutableDictionary *t_dict = [NSMutableDictionary dictionaryWithContentsOfFile:fullPath];
NSMutableArray<NSString *> *t_arr = t_dict[markModel.chapterID];
if (!t_arr) return;
NSString *bookMark = [markModel modelToJSONString];
[t_arr removeObject:bookMark];
[t_dict setValue:t_arr forKey:markModel.chapterID];
[t_dict writeToFile:fullPath atomically:YES];
}
+ (NSString *)bookMarkRootPath
{
NSString *rootPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
rootPath = [rootPath stringByAppendingPathComponent:@"bookMark"];
if (![[NSFileManager defaultManager] fileExistsAtPath:rootPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:rootPath withIntermediateDirectories:YES attributes:@{} error:nil];
}
return rootPath;
}
- (void)setComicReadingRecord:(NSInteger)comic_id chapter_id:(NSInteger)chapter_id offsetY:(CGFloat)offsetY
{
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
path = [path stringByAppendingPathComponent:@"comic_record.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] createFileAtPath:path contents:[NSData data] attributes:@{}];
}
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
if (!dict) {
dict = [NSMutableDictionary dictionary];
}
NSDictionary *params = @{
[NSString stringWithFormat:@"%zd", chapter_id] : [NSString stringWithFormat:@"%f", offsetY]
};
[dict setValue:params forKey:[NSString stringWithFormat:@"%zd", comic_id]];
[dict writeToFile:path atomically:NO];
}
- (NSDictionary *)getComicReadingRecord:(NSInteger)comic_id
{
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
path = [path stringByAppendingPathComponent:@"comic_record.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) return @{};
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
if ([dict valueForKey:[NSString stringWithFormat:@"%zd", comic_id]]) {
return [dict valueForKey:[NSString stringWithFormat:@"%zd", comic_id]];
} else {
return @{};
}
}
@end