This commit is contained in:
caiwx86 2024-03-31 15:55:14 +08:00
parent 9b3ac8878f
commit c0c77b3776
7 changed files with 343 additions and 148 deletions

View File

@ -5,14 +5,16 @@
import os,Comics.settings as settings,logging
from scrapy.item import Item, Field
from Comics.utils import ComicPath
from Comics.utils import imageUtils
from Comics.utils import imageUtils,fileUtils
from itemloaders.processors import TakeFirst
# 繁体中文转为简体中文
def serialize_to_chinese(value): return ComicPath.chinese_convert(value)
# 将路径字符串转为合法路径
def serialize_to_fix_file(value): return ComicPath.fix_file_name(ComicPath.chinese_convert(value))
def serialize_to_fix_file(value): return ComicPath.fix_file_name(value)
def serialize_name_to_chinese(value): return ComicPath.fix_file_name(ComicPath.chinese_convert(value))
# 图片数据解析(私有方法)
def _serialize_to_images(value, result_type=None):
@ -57,9 +59,13 @@ class ComicItem(Item):
# 编号
index = Field(output_processor=TakeFirst())
# 漫画名
name = Field(serializer=serialize_to_fix_file, output_processor=TakeFirst())
name = Field(serializer=serialize_name_to_chinese, output_processor=TakeFirst())
# 源漫画名
s_name = Field(serializer=serialize_to_fix_file, output_processor=TakeFirst())
# 章节名
chapter = Field(serializer=serialize_to_fix_file, output_processor=TakeFirst())
chapter = Field(serializer=serialize_name_to_chinese, output_processor=TakeFirst())
# 源章节名
s_chapter = Field(serializer=serialize_to_fix_file, output_processor=TakeFirst())
# 图片链接
list_img = Field(serializer=serialize_to_images)
# 作者
@ -135,3 +141,4 @@ class ComicInfoItem(Item):
AgeRating = Field(desc="年龄分级", info='age_rating')
Pages = Field(desc="页码", info='images', serializer=serializer_info_images)
# ComicInfo.xml and ComicChapter.json end

View File

@ -113,8 +113,12 @@ class ComicLoader(ItemLoader):
# 漫画名称
def get_name(self): return self.get_output_value("name")
def get_sname(self): return self.get_output_value("s_name")
# 漫画章节
def get_chapter(self): return self.get_output_value("chapter")
def get_schapter(self): return self.get_output_value("s_chapter")
# 漫画封面
def get_icon(self): return self.get_output_value("icon")
# 工程名
def get_project_name(self): return self.get_output_value(PROJECT_KEY)
# 章节链接
@ -124,34 +128,38 @@ class ComicLoader(ItemLoader):
def get_chapter_api(self): return self.get_output_value("chapter_api")
def get_images(self): return self.get_output_value("images")
def get_image_urls(self): return self.get_output_value("image_urls")
class ComicEntity:
### ComicEntity
def set_count(self, value): self.set_properties('count', value=value)
ENTITY = None
def set_index(self, value): self.set_properties('index', value=value)
def __init__(self, entity):
self.ENTITY = entity
def set_sname(self, value): self.set_properties('s_name', value=value)
# 属性获取
def get_dict(self, key):
try:
return self.ENTITY[key]
except:
return []
def set_chapter(self, value): self.set_properties('chapter', value=value)
def set_schapter(self, value): self.set_properties('s_chapter', value=value)
def set(self, key, value): self.ENTITY[key] = value
def set_count(self, value): self.set('count', value)
def set_index(self, value): self.set('index', value)
def images(self): return self.get_dict("images")
def image_urls(self): return self.get_dict("image_urls")
def chapters(self): return self.get_dict("chapters")
def chapter(self): return self.get_dict("chapter")
def icon(self): return self.get_dict("icon")
def count(self): return self.set_count(len(self.images()))
def index(self): return self.set_index(self.chapters().index(self.chapter()) + 1)
# 章节页码
def count(self):
len_images = len(self.get_images())
if len_images != 0: return self.set_count(len_images)
# 章节编号
def index(self):
chapters, chapter = [ self.get_chapters(), self.get_chapter() ]
if chapter != None and len(chapters) > 0: return self.set_index(chapters.index(chapter) + 1)
def item(self):
def save_sname_schapter(self):
chapter = self.get_chapter()
name = self.get_name()
if chapter != None : self.set_schapter(chapter)
if name != None : self.set_sname(name)
def load_item(self, chapter=None):
self.count()
self.index()
return self.ENTITY
if chapter != None: self.set_chapter(chapter)
self.save_sname_schapter()
return super().load_item()

View File

@ -8,8 +8,7 @@
import os,scrapy,logging
from Comics import settings
from Comics.items import ComicItem
from Comics.settings import OUTPUT_DIR
from Comics.loader import ComicEntity,ComicLoader
from Comics.loader import ComicLoader
from Comics.exporters import ComicInfoXmlItemExporter
from Comics.utils import CBZUtils,fileUtils as fu
from Comics.utils import ComicPath
@ -18,63 +17,83 @@ from Comics.exporters import JsonExport,ItemExporter
from scrapy.pipelines.images import ImagesPipeline
class ComicsPipeline():
def open_spider(self, spider):
pass
# item就是yield后面的对象
def process_item(self, item, spider):
def process_item(self, item: ComicItem, spider):
if isinstance(item, ComicItem):
# item = ComicEntity(item).item()
# 'output/rm_comic/json/壞X/第1話 壞X'
# 已存在漫画CBZ文件 调用转换
if fu.exists(ComicPath.path_cbz(item=item)): return ItemExporter().export_obj(item)
else:
if fu.exists(ComicPath(item).path_cbz()): return ItemExporter().export_obj(item)
# 不存在漫画CBZ文件
#file = os.path.join(OUTPUT_DIR, spider.name, "json", item['name'], item['chapter'])
return JsonExport(file=ComicPath.getDirJosnComicChapter(item)).export_json(ComicEntity(item).item(), if_return=True)
# image解析
else: return JsonExport(file=ComicPath(item).getDirJosnComicChapter(item)).export_json(ComicLoader(item).load_item(), if_return=True)
def close_spider(self, spider):
pass
class ImgDownloadPipeline(ImagesPipeline):
def get_file_path(self, item, file=None, result_type="image"):
return ComicPath().get_file_path(item=item, file=file, result_type= result_type)
class BaseComicImagesPipeline(ImagesPipeline):
def image_scramble_exits(self, item,image_path):
en_image_path = ComicPath().getFileScrambleImageSave(image_path, relative="fullpath")
en_image_path = ComicPath(item).getFileScrambleImageSave(image_path, relative="fullpath")
return fu.exists(fu.join(settings.IMAGES_STORE, self.get_file_path(item, en_image_path)))
## Icon Path : CBZ/NAME/CHAPTER.jpg
def download_icon(self, item, result_type="download"):
icon_path = self.get_file_path(item, result_type="icon_cache")
if result_type == "fullpath":
return fu.join(settings.IMAGES_STORE, icon_path)
if fu.exists(icon_path):
return False
else:
self.image_urls.append(item['icon'])
self.images.append(icon_path)
return True
def get_file_path(self, item, file=None, result_type="image"):
return ComicPath(item).file_path(file=file, result_type= result_type)
# 封面路径
def file_path(self, request, response=None, info=None, *, item=None): return request.meta['path']
def success_completed(self, item, results):
is_success = False
fail_data = []
for result in results:
# 失败数据
if not result[0]: fail_data.append(result[1])
if len(fail_data) == 0 and len(results) != 0: is_success = True
return is_success
# 封面下载操作类
class IconDownloadPipeline(BaseComicImagesPipeline):
# 数据处理
def get_media_requests(self, item, info):
comic = ComicEntity(item)
self.image_urls = comic.image_urls()
self.images = comic.images()
# 下载封面
self.download_icon(item)
comic = ComicLoader(item=item)
# 获取封面链接和封面保存路径
icon_url, icon_cache_path = [ comic.get_icon(), self.get_file_path(item, result_type="icon_cache") ]
# 封面已存在
if fu.exists(icon_cache_path): return False
else: yield scrapy.Request(url=icon_url, meta={'path': icon_cache_path })
# 判断是否需要更新封面
def update_icon(self, item):
# 下载后的缓存封面路径
image_path = self.get_file_path(item, result_type="down_cache_icon")
# 最终封面保存路径
save_path = self.get_file_path(item=item, result_type="down_icon")
fu.update_icon(image_path, save_path)
def item_completed(self, results, item, info):
if self.success_completed(item, results):
print(" icon download success")
# 更新封面到Icon文件夹内
self.update_icon(item)
class ImgDownloadPipeline(BaseComicImagesPipeline):
def get_media_requests(self, item, info):
comic = ComicLoader(item=item)
self.image_urls, self.images = [ comic.get_image_urls(), comic.get_images() ]
# 添加封面下载信息至下载列表中
# self.add_download_icon(item)
for image_url,image in zip(self.image_urls,self.images):
is_down = True
image_path = self.get_file_path(item, image)
if_down, image_path = [ True, self.get_file_path(item, image)]
# 图像(含加密图像)已存在
if self.image_scramble_exits(item, image_path):
if image_path == self.get_file_path(item, result_type="icon_cache"):
logging.info(f"icon file exists: IMAGE_STORE {image_path}")
else:
is_down = False
#if image_path == self.get_file_path(item, result_type="icon_cache"):
# logging.info(f"icon file exists: IMAGE_STORE {image_path}")
#else:
if_down = False
logging.info(f"file exists: IMAGE_STORE {image_path}")
if is_down:
if if_down:
logging.info(f"downloading {image_url} --> IMAGE_STORE {image_path}")
yield scrapy.Request(url=image_url, meta={'path': image_path})
@ -90,16 +109,6 @@ class ImgDownloadPipeline(ImagesPipeline):
fu.update_icon(path, cbz_icon)
# 判断是否需要更新封面
def update_icon(self, item):
# 下载后的缓存封面路径
image_path = self.get_file_path(item, result_type="down_cache_icon")
# 最终封面保存路径
save_path = self.get_file_path(item=item, result_type="down_icon")
fu.update_icon(image_path, save_path)
def item_completed(self, results, item, info):
# return item
# 打包
@ -107,10 +116,9 @@ class ImgDownloadPipeline(ImagesPipeline):
success_data = []
for result in results:
if result[0]: success_data.append(result[1])
image_urls = ComicLoader(item=item).get_image_urls()
if len(success_data) != len(image_urls): return
if len(success_data) != len(ComicLoader(item=item).get_image_urls()): return
if fu.exists(cbz_path):
self.update_icon(item)
#self.update_icon(item)
self.pack_icon(item)
else:
# ComicInfoXml 生成

View File

@ -45,7 +45,7 @@ RETRY_HTTP_CODES = [408, 401]
CONCURRENT_REQUESTS_PER_DOMAIN = 16
CONCURRENT_REQUESTS_PER_IP = 16
PROXY_LIST = [
# "http://127.0.0.1:7890",
"http://127.0.0.1:7890",
# "http://10.0.10.117:8123",
]
# Disable cookies (enabled by default)
@ -89,6 +89,7 @@ ITEM_PIPELINES = {
# 'scrapy.pipelines.images.ImagesPipeline' : 1,
'Comics.pipelines.ComicsPipeline': 300,
# 'Comics.pipelines.ImageParsePipeline': 400,
'Comics.pipelines.IconDownloadPipeline': 400,
'Comics.pipelines.ImgDownloadPipeline': 500,
}

View File

@ -2,8 +2,8 @@ import scrapy,logging,time,os,skip
from Comics.items import ComicItem
from Comics.loader import ComicLoader
from Comics.utils import ComicPath
from Comics.utils import checkUtils
from Comics.utils import Conf
from Comics.exporters import ItemExporter
class RmComicSpider(scrapy.Spider):
name = 'rm_comic'
@ -19,18 +19,27 @@ class RmComicSpider(scrapy.Spider):
# 获取多个漫画信息
def books_comic(self, response):
comics = ComicLoader(item=ComicItem(), response=response)
# 获取漫画网站//script[@id]内的json数据并获取props.pageProps.books数据并作偱环解析
for book in comics.get_exec(comics.get_xpath('//script[@id="__NEXT_DATA__"]/text()')[0], str_exec="props.pageProps.books"):
# 排除指定的漫画名
if book['name'] not in skip.skip_comic:
yield scrapy.Request(url=self.start_urls+"/"+book['id'], callback=self.parse_comic)
# 获取某个漫画的相关数据
# 获取到多个章节链接后进入下个流程
def parse_comic(self, response):
# 初始化Comic数据并根据工程名称读取配置文件并自动解析
comic_item = Conf().comic(self.name, ComicLoader(ComicItem(), response))
# 循环遍历根据配置文件自动解析并注入的章节名和章节链接
for chapter, link in zip(comic_item.get_chapters(), comic_item.get_chapter_href()):
item = comic_item.load_item()
cbz_path = ComicPath().get_file_path(item=item, result_type="cbz", convert=True, chapter=chapter)
if not checkUtils().is_error(item) and os.path.exists(cbz_path):
# 打包导出item数据
item = comic_item.load_item(chapter=chapter)
# 获取最终存放CBZ的路径
#cbz_path = ComicPath(item=item).file_path(ComicPath.PATH_CBZ, convert=True, chapter=chapter)
cbz_path = ComicPath(item=item).PATH_CBZ()
# 校验繁体和简体中文CBZ路径是否存在
# if not checkUtils().is_error(item) and os.path.exists(cbz_path):
if os.path.exists(cbz_path):
logging.info(f"漫画 {cbz_path} 已存在, 跳过中...")
yield item
else:
@ -40,6 +49,7 @@ class RmComicSpider(scrapy.Spider):
# 读取某章节下的所有图片
def parse_chapter(self, response):
# 获取传入的漫画item数据
comic_item = ComicLoader(item=response.meta['item'], response=response)
data = comic_item.get_xpath('//script[@id="__NEXT_DATA__"]/text()')[0]
item: ComicLoader = Conf().parse_chapter(item=comic_item, value=data)

View File

@ -45,7 +45,7 @@ class RmComicSpider(scrapy.Spider):
comic_item.chapters(value=chapters)
comic_item.chapter(value=chapter)
item = comic_item.load_item()
cbz_path = ComicPath.get_file_path(item=item, result_type="cbz", convert=True)
cbz_path = ComicPath(item).get_file_path(result_type="cbz", convert=True)
if os.path.exists(cbz_path):
logging.info(f"漫画 {cbz_path} 已存在, 跳过中...")
yield item

View File

@ -10,7 +10,7 @@ from zipfile import ZipFile
from Comics.settings import COMIC_INFO_XML_FILE,OUTPUT_DIR,PROJECT_KEY
import yaml
from Comics.loader import ComicLoader
from tinydb import TinyDB, Query
# 配置类
class Conf():
@ -81,11 +81,16 @@ class fileUtils:
# 保存文件
@classmethod
def save_file(cls,path,data):
def write(cls,path,data,type='file'):
root_dir = os.path.dirname(path)
if not os.path.exists(root_dir): os.makedirs(root_dir)
with open(path,'w',encoding='utf-8') as fs:
fs.write(str(data))
if type == 'file':
fs.write(data)
elif type == 'json':
fs.write(json.dumps(data,ensure_ascii=False,indent=4))
elif type == 'yaml':
fs.write(yaml.dump(data, allow_unicode=True, default_flow_style=False, indent=4))
# 返回校验后的文件路径
@classmethod
@ -104,41 +109,67 @@ class fileUtils:
# 读取文件
@classmethod
def read(cls, file):
def read(cls, file, type='file'):
if os.path.exists(file):
with open(file, "r", encoding="utf-8") as fs: return fs.read()
with open(file, "r", encoding="utf-8") as fs:
if type == "json":
return json.loads(fs.read())
elif type == 'yaml':
return yaml.safe_load(fs.read())
elif type == 'file':
return fs.read()
else:
return []
@classmethod
def get_file_md5(cls, file_path):
md5 = hashlib.md5()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b''):
md5.update(chunk)
return md5.hexdigest()
@classmethod
def write_json(cls, path, data): cls.write(path, data , type="json")
@classmethod
def read_json(cls, file): return cls.read(file, type="json")
"""
图像编号 image-1.jpg
存在image.png 返回 image-1.png 反之 image.png
"""
@classmethod
def file_check(cls, file, result="file", count=0):
temp_file_name, files_size, files_name = [file, {}, []]
# 初始化临时文件名 文件信息 文件名列表
temp_file_name, files_data, files_name = [file, {}, []]
# 默认文件名不存在
if not cls.exists(temp_file_name) and temp_file_name == file: count = 1
while count or count == 0:
# 获取格式化文件名
temp_file_name = ComicPath().images_icon(file=file, count=count)
# 格式化文件名存在
if cls.exists(temp_file_name):
# 保存存在的文件名
files_name.append(temp_file_name)
file_size = os.path.getsize(temp_file_name)
# 保存文件名和大小数据
files_size[file_size] = {"name": temp_file_name, "size": file_size}
files_data[file_size] = {"name": temp_file_name, "size": file_size}
# 格式化文件名
# temp_file_name = ComicPath().images_icon(file=file, count=count)
count += 1
else:
# 检测是否有重复数据
# 提取重复并需删除的文件名
diff_names = {value["name"] for value in files_size.values()}
diff_names = {value["name"] for value in files_data.values()}
# 不存在则返回原文件名
if len(diff_names) == 0:
# 默认为空
if result == "size": return diff_names
else:
return file
# 原文件名
else: return file
for file_name in files_name:
if file_name not in diff_names:
logging.info(f"删除文件:{file_name}")
@ -158,7 +189,7 @@ class fileUtils:
if len(set(diff_names)) != len(set(files_name)): cls.file_check(file, result=result,count=0)
if result == "size":
return {value["size"] for value in files_size.values()}
return {value["size"] for value in files_data.values()}
else:
return temp_file_name
@ -532,13 +563,14 @@ class CBZUtils:
@classmethod
def cbz_validate(cls, zip_path, comic_info_images):
if len(cls.zip_info(zip_path)) == len(comic_info_images):
cbz_info = cls.zip_info(zip_path)
if len(cbz_info) == len(comic_info_images):
# logging.info(f"validating successfully === {zip_path}")
ntfy.sendMsg(f"validating successfully === {zip_path}", alert=True)
return True
else:
os.remove(zip_path)
logging.error(f"validating fail === {zip_path}")
ntfy.sendMsg(f"validating fail === {zip_path}, cbz_info={cbz_info},zip_info={comic_info_images}", alert=True)
return False
# 检测工具类
@ -574,8 +606,51 @@ class checkUtils:
# Comic路径类
class ComicPath:
ci, project, name, chapter = [ None, "", "", ""]
def __init__(self, item = None):
if item != None: self.ci : ComicLoader = ComicLoader(item=item)
if self.ci.get_project_name() != None: self.project = self.fix_file_name(self.ci.get_project_name())
if self.ci.get_name() != None: self.name = self.fix_file_name(self.ci.get_name())
if self.ci.get_chapter() != None: self.chapter = self.fix_file_name(self.ci.get_chapter())
PREFIX_SCRAMBLE = "scramble="
PATH_IMAGE = "image"
PATH_COMIC_INFO = "comic_info"
PATH_CBZ_ICON = "cbz_icon"
PATH_DOWN_ICON = "down_icon"
PATH_DOWN_CACHE_ICON = "down_cache_icon"
PATH_ICON = "icon"
PATH_ICON_CACHE = "icon_cache"
PATH_CBZ = "cbz"
PATH_IMAGES_DIR = "images_dir"
def PATH_MAPPING(self):
if self.project == None or self.name == None or self.chapter == None: return None
return {
self.PATH_IMAGE: os.path.join(self.project, "images", self.name, self.chapter),
self.PATH_COMIC_INFO: os.path.join(self.project, "images", self.name, self.chapter),
self.PATH_CBZ_ICON: os.path.join(settings.CBZ_EXPORT_PATH, self.project, self.name, self.chapter+".jpg"),
self.PATH_DOWN_ICON: os.path.join(settings.IMAGES_STORE, self.project, "icons", self.name, self.name+".jpg"),
self.PATH_DOWN_CACHE_ICON: os.path.join(settings.IMAGES_STORE, self.project, "icons", ".cache", self.name+".jpg"),
self.PATH_ICON: os.path.join(self.project, "icons", self.name, self.name+".jpg"),
self.PATH_ICON_CACHE: os.path.join(self.project, "icons", ".cache", self.name+".jpg"),
self.PATH_CBZ: os.path.join(settings.CBZ_EXPORT_PATH, self.project, self.name, self.chapter+".CBZ"),
self.PATH_IMAGES_DIR: os.path.join(settings.IMAGES_STORE, self.project, "images", self.name, self.chapter)
}
def PATH_CBZ(self, result_type=PATH_CBZ): self.file_path(result_type=result_type)
def file_path(self, result_type=PATH_IMAGE, file=None, convert=True, chapter=None):
if chapter != None: self.chapter = chapter
path = self.PATH_MAPPING().get(result_type, None)
if result_type == self.PATH_IMAGE and os.path.sep not in file:
return os.path.join(path, file)
if convert:
path = self.chinese_convert(path)
return path
@classmethod
def getYearMonthDay(cls):
today = date.today()
@ -633,42 +708,8 @@ class ComicPath:
@classmethod
def new_file_name(cls, name): return cls.fix_file_name(cls.chinese_convert(name))
@classmethod
def get_file_path(cls, item, result_type="image", file=None, convert=False, chapter=None):
PROJECT = ComicLoader(item=item).get_project_name()
if not convert:
name = item['name']
if chapter == None: chapter = item['chapter']
else:
name = cls.fix_file_name(cls.chinese_convert(item['name']))
if chapter == None: chapter = cls.fix_file_name(cls.chinese_convert(item['chapter']))
if result_type == "image":
if os.path.sep not in file:
file = os.path.join(PROJECT, "images", name, chapter, file)
elif result_type == "comic_info":
file = os.path.join(PROJECT, "images", name, chapter)
elif result_type == "cbz_icon":
file = os.path.join(settings.CBZ_EXPORT_PATH, PROJECT, name, chapter+".jpg")
elif result_type == "down_icon":
file = os.path.join(settings.IMAGES_STORE, cls.get_file_path(item=item, result_type="icon"))
elif result_type == "down_cache_icon":
file = os.path.join(settings.IMAGES_STORE, cls.get_file_path(item=item, result_type="icon_cache"))
elif result_type == "icon":
file = os.path.join(PROJECT, "icons", name, name+".jpg")
elif result_type == "icon_cache":
file = os.path.join(PROJECT, "icons", ".cache", name+".jpg")
elif result_type == "cbz":
file = os.path.join(settings.CBZ_EXPORT_PATH, PROJECT, name, chapter+".CBZ")
elif result_type == "images_dir":
file = os.path.join(settings.IMAGES_STORE, PROJECT, "images", name, chapter)
else:
raise ValueError(f"Unsupported result_type: {result_type}")
return file
@classmethod
def path_cbz(cls, item):
return cls.get_file_path(item, result_type="cbz", convert=True)
def path_cbz(self):
return self.file_path(result_type=self.PATH_CBZ, convert=True)
@classmethod
def images_icon(cls, file, count):
@ -695,3 +736,123 @@ class ntfy:
return False
else:
return True
class logger:
def log_image_download(self, image_path):
if image_path == "":
logging.info(f"icon file exists: IMAGE_STORE {image_path}")
else:
logging.info(f"file exists: IMAGE_STORE {image_path}")
def log_image_not_downloaded(self, image_path):
logging.info(f"file does not exist: IMAGE_STORE {image_path}")
class ItemIconUtils:
def __init__(self, path, icon_item=None):
if icon_item != None: self.icon_item = icon_item
else: self.icon_item = []
self.path = path
if path != None:
self.read_icon_json()
def add(self, name, path, size, md5, url=None):
self.icon_item.append({ 'name': name, 'path': path, 'size': size, 'md5':md5, 'url': url })
def toString(self):
return self.icon_item
def _get_values(self, key): return [ item.get(key) for item in self.icon_item ]
def get_names(self): return self._get_values("name")
def get_file_count_by_md5(self, md5):
md5_list = self._get_values("md5")
md5_count = md5_list.count(md5)
if md5_count > 1:
logging.info(f" {md5_list} == 存在md5重复文件")
return md5_count
def get_file_by_key_value(self, key, value):
list_item = []
for item in self.icon_item:
if item.get(key) == value: return list_item.append(item)
return list_item
def get_file_by_md5(self, md5):
list_item = []
for item in self.icon_item:
if item.get("md5") == md5 and self.get_file_count_by_md5(md5) == 1: list_item.append(item)
return list_item
def get_file_by_url(self, url): return self.get_file_by_key_value('url', url)
def update_file_by_md5_to_url(self, md5, url):
file_item = self.get_file_by_md5(md5)
if len(file_item) > 1 :
logging.info(f" {file_item} == 存在多个结果")
if len(file_item) == 1:
file_item = file_item[0]
self.icon_item.remove(file_item)
file_item['url'] = url
self.icon_item.append(file_item)
return self.write_icon_json()
def get_files_info(self, directory, filter_suffix=None):
for root, dirs, files in os.walk(directory):
for file in files:
name, suffix = os.path.splitext(file)
if suffix != filter_suffix:
file_path = os.path.join(root, file)
file_size = os.path.getsize(file_path)
self.add(name= name, path=file_path, size=file_size, md5=fileUtils.get_file_md5(file_path))
return self.toString()
def write_icon_json(self):
if self.path != None:
self.get_files_info(self.path, filter_suffix='.json')
fileUtils.write_json(os.path.join(self.path,"icons.json"), self.toString())
def read_icon_json(self):
if self.path != None: self.icon_item = fileUtils.read_json(os.path.join(self.path, "icons.json"))
return self.icon_item
class DBUtils:
def __init__(self, db_name, suffix="json"):
self.db = TinyDB(ComicPath().getDirConfDefault(db_name,suffix=suffix))
@classmethod
def init_db(cls,db_name):
return TinyDB(ComicPath.getDirConfDefault(db_name,suffix="json"))
@classmethod
def set(cls,name,progress,db_name):
if name == None or progress == None or db_name == None:
print("dbUtils set 数据为空")
return False
db = cls.init_db(db_name)
comic = Query()
if len(db.search(comic.name == name)) == 0: db.insert({"name":name,"progress":progress})
else: db.update({"progress":progress},comic.name== name)
msg = "失败"
if cls.query(name,progress,db_name): msg = "成功"
logger.debug(f"设置{msg}, name={name} value={progress} db={db_name}")
@classmethod
def query(cls,name,progress=None,db_name=None):
result = False
db = cls.init_db(db_name)
if db == None: return None
data = db.search(Query().name == name)
logger.debug(f"result query= {data}")
if progress != None:
try:
if len(db.search((Query().name == name) & (Query().progress == progress))) != 0: result = True
except Exception as e:
print(e)
return result
@classmethod
def remove(cls,name,db_name=None):
db = cls.init_db(db_name)
db.remove(Query().name == name)