update
This commit is contained in:
commit
a3583d9e4e
176
Downloader.py
Normal file
176
Downloader.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup # 用于代替正则式 取源码中相应标签中的内容
|
||||||
|
import os
|
||||||
|
from rich.progress import track as tqdm
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, wait
|
||||||
|
import time
|
||||||
|
from PIL import Image
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
class Downloader(object):
|
||||||
|
def __init__(self, comic_name, root_path = './', url_prev='.site', high_quality=False):
|
||||||
|
self.comic_name = comic_name
|
||||||
|
self.root_path = root_path
|
||||||
|
self.url_prev = url_prev
|
||||||
|
self.high_quality = high_quality
|
||||||
|
self.comic_msg_url = f"https://api.copymanga{url_prev}/api/v3/comic2/{comic_name}"
|
||||||
|
self.comic_url_api = 'https://api.copymanga{}/api/v3/comic/{}/group/{}/chapters?limit=500&offset=0&platform=3'
|
||||||
|
self.chap_url_api = 'https://api.copymanga{}/api/v3/comic/{}/chapter2/{}?platform=3'
|
||||||
|
|
||||||
|
|
||||||
|
self.header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 Edg/87.0.664.47', 'platform': '1'}
|
||||||
|
|
||||||
|
self.max_thread_num = 16
|
||||||
|
self.pool = ThreadPoolExecutor(self.max_thread_num)
|
||||||
|
self.buffer_map = {}
|
||||||
|
|
||||||
|
def get_comic_msg(self, is_gui=False, signal=None, editline=None):
|
||||||
|
req = requests.get(self.comic_msg_url, headers=self.header).json()
|
||||||
|
req = req['results']
|
||||||
|
self.comic_title = req['comic']['name']
|
||||||
|
self.comic_author = req['comic']['author'][0]['name']
|
||||||
|
self.cover_url = req['comic']['cover']
|
||||||
|
cls_dict = req['groups']
|
||||||
|
self.cls_dict = {}
|
||||||
|
for key in cls_dict.keys():
|
||||||
|
self.cls_dict[cls_dict[key]['name']] = cls_dict[key]['path_word']
|
||||||
|
if len(cls_dict.keys())==1:
|
||||||
|
self.url_cls = list(self.cls_dict.values())[0]
|
||||||
|
elif len(cls_dict.keys())>1:
|
||||||
|
choise_name = self.get_choise(list(self.cls_dict.keys()), is_gui, signal, editline)
|
||||||
|
self.url_cls = self.cls_dict[choise_name]
|
||||||
|
self.comic_url = self.comic_url_api.format(self.url_prev, self.comic_name, self.url_cls)
|
||||||
|
|
||||||
|
def get_comic_chaps(self):
|
||||||
|
req = requests.get(self.comic_url, headers=self.header)
|
||||||
|
comic_urls = req.json()['results']['list']
|
||||||
|
num_chaps = comic_urls[0]['count']
|
||||||
|
offset = 0
|
||||||
|
while offset<num_chaps:
|
||||||
|
offset += 500
|
||||||
|
req = requests.get(self.comic_url.replace('offset=0&', f'offset={offset}&'), headers=self.header)
|
||||||
|
comic_urls += req.json()['results']['list']
|
||||||
|
self.chap_name_list = []
|
||||||
|
self.chap_uuid_list = []
|
||||||
|
self.chap_pagenum_list = []
|
||||||
|
for comic_url in comic_urls:
|
||||||
|
self.chap_name_list.append(comic_url['name'])
|
||||||
|
self.chap_uuid_list.append(comic_url['uuid'])
|
||||||
|
self.chap_pagenum_list.append(comic_url['size'])
|
||||||
|
self.comic_path = os.path.join(self.root_path, check_chars(self.comic_title))
|
||||||
|
return self.chap_name_list, self.chap_uuid_list, self.chap_pagenum_list
|
||||||
|
|
||||||
|
def get_image(self, is_gui=False, signal=None):
|
||||||
|
self.pre_request_img()
|
||||||
|
img_path = self.img_path
|
||||||
|
if is_gui:
|
||||||
|
len_iter = len(self.img_url_map.items())
|
||||||
|
signal.emit('start')
|
||||||
|
for i, (img_url, img_name) in enumerate(self.img_url_map.items()):
|
||||||
|
content = self.get_html_img(img_url, is_buffer=True)
|
||||||
|
with open(img_path+f'/{img_name}.jpg', 'wb') as f:
|
||||||
|
f.write(content) #写入二进制内容
|
||||||
|
signal.emit(int(100*(i+1)/len_iter))
|
||||||
|
|
||||||
|
|
||||||
|
def download_single_chap(self, chap_name, uuid, page_num, multithread=True, is_gui=False, signal=None):
|
||||||
|
print('正在下载'+chap_name)
|
||||||
|
chap_path = os.path.join(self.comic_path, chap_name)
|
||||||
|
os.makedirs(chap_path, exist_ok=True)
|
||||||
|
if len(os.listdir(chap_path))==page_num:
|
||||||
|
return
|
||||||
|
img_url = self.chap_url_api.format(self.url_prev, self.comic_name, uuid)
|
||||||
|
while True:
|
||||||
|
req = requests.get(img_url, headers=self.header)
|
||||||
|
try:
|
||||||
|
req = req.json()['results']
|
||||||
|
except:
|
||||||
|
req = 'throttled'
|
||||||
|
if 'throttled' not in str(req):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print('触发访问频率上限,重新请求.....')
|
||||||
|
time.sleep(10)
|
||||||
|
img_urls = [url['url'] for url in req['chapter']['contents']]
|
||||||
|
|
||||||
|
if self.high_quality:
|
||||||
|
img_urls = [url.replace('c800x', 'c1500x') for url in img_urls]
|
||||||
|
img_nos = req['chapter']['words']
|
||||||
|
if multithread:
|
||||||
|
for img_url in img_urls:
|
||||||
|
self.pool.submit(self.prev_buffer, img_url)
|
||||||
|
len_iter = len(img_urls)
|
||||||
|
|
||||||
|
if is_gui:
|
||||||
|
signal.emit('start')
|
||||||
|
for i, (img_no, img_url) in enumerate(zip(img_nos, img_urls)):
|
||||||
|
chap_name = os.path.join(chap_path, str(int(img_no)+1).zfill(3)+'.jpg')
|
||||||
|
self.download_img(img_url, chap_name, is_buffer=multithread)
|
||||||
|
signal.emit(int(100*(i+1)/len_iter))
|
||||||
|
signal.emit('end')
|
||||||
|
else:
|
||||||
|
for i in tqdm(range(len_iter)):
|
||||||
|
img_no, img_url = img_nos[i], img_urls[i]
|
||||||
|
chap_name = os.path.join(chap_path, str(img_no+1).zfill(3)+'.jpg')
|
||||||
|
self.download_img(img_url, chap_name, is_buffer=multithread)
|
||||||
|
|
||||||
|
def download_cover(self):
|
||||||
|
os.makedirs(self.comic_path, exist_ok=True)
|
||||||
|
cover_img_name = os.path.join(self.comic_path, 'cover.jpg')
|
||||||
|
self.download_img(self.cover_url, cover_img_name)
|
||||||
|
|
||||||
|
def download_img(self, img_url, file_name, is_buffer=False):
|
||||||
|
if is_buffer:
|
||||||
|
while img_url not in self.buffer_map.keys():
|
||||||
|
time.sleep(1)
|
||||||
|
req = self.buffer_map[img_url]
|
||||||
|
else:
|
||||||
|
req = requests.get(img_url, headers=self.header).content
|
||||||
|
with open(file_name, 'wb') as f:
|
||||||
|
f.write(req)
|
||||||
|
|
||||||
|
def prev_buffer(self, url):
|
||||||
|
if url not in self.buffer_map.keys():
|
||||||
|
req = requests.get(url, headers=self.header).content
|
||||||
|
self.buffer_map[url] = req
|
||||||
|
|
||||||
|
def get_cover(self, chap_name, is_gui=False, signal=None):
|
||||||
|
chap_path = os.path.join(self.comic_path, chap_name)
|
||||||
|
imgfile = os.path.join(chap_path, '001.jpg')
|
||||||
|
img = Image.open(imgfile)
|
||||||
|
img_w, img_h = img.size
|
||||||
|
signal_msg = (imgfile, img_h, img_w)
|
||||||
|
if is_gui:
|
||||||
|
signal.emit(signal_msg)
|
||||||
|
|
||||||
|
def get_choise(self, choise_list, is_gui=False, signal=None, editline=None):
|
||||||
|
if is_gui:
|
||||||
|
error_msg = '漫画有多个部分, 请下拉选择框选择想下载的部分'
|
||||||
|
editline.addItems(choise_list)
|
||||||
|
editline.setCurrentIndex(0)
|
||||||
|
print(error_msg)
|
||||||
|
signal.emit('hang')
|
||||||
|
time.sleep(1)
|
||||||
|
while not editline.isHidden():
|
||||||
|
time.sleep(1)
|
||||||
|
choise = editline.text()
|
||||||
|
editline.clear()
|
||||||
|
else:
|
||||||
|
error_msg = '漫画有多个部分, 请输入想下载的部分的序号'
|
||||||
|
print(error_msg)
|
||||||
|
for choise_no, choise in enumerate(choise_list):
|
||||||
|
print(f'[{str(choise_no+1)}]', choise)
|
||||||
|
choise_no = input('请输入序号:')
|
||||||
|
choise_no = int(choise_no)-1
|
||||||
|
choise = choise_list[choise_no]
|
||||||
|
return choise
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
comic_name = 'yaoyeluying'
|
||||||
|
# comic_name = 'zgmsbywt'
|
||||||
|
downloader = Downloader(comic_name=comic_name)
|
||||||
|
for i in range(0, 3):
|
||||||
|
chap_name = downloader.chap_name_list[i]
|
||||||
|
chap_uuid = downloader.chap_uuid_list[i]
|
||||||
|
downloader.download_single_chap(chap_name, chap_uuid)
|
112
Editer.py
Normal file
112
Editer.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import zipfile
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from utils import *
|
||||||
|
from PIL import Image
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class Editer(object):
|
||||||
|
def __init__(self, title, author, chap_list, comic_root, out_root, delete_comic=False):
|
||||||
|
|
||||||
|
self.title = self.get_epub_title(title, chap_list)
|
||||||
|
self.author = author
|
||||||
|
self.chap_list = chap_list
|
||||||
|
self.comic_root = comic_root
|
||||||
|
self.out_root = out_root
|
||||||
|
|
||||||
|
self.img_list = []
|
||||||
|
self.chap_first_imgs = []
|
||||||
|
self.delete_comic = delete_comic
|
||||||
|
|
||||||
|
def pack_img(self):
|
||||||
|
|
||||||
|
self.epub_path = os.path.join(self.out_root, 'tmp')
|
||||||
|
self.epub_oebps_path = os.path.join(self.out_root, 'tmp/OEBPS')
|
||||||
|
self.epub_img_path = os.path.join(self.out_root, 'tmp/OEBPS/Images')
|
||||||
|
self.epub_text_path = os.path.join(self.out_root, 'tmp/OEBPS/Text')
|
||||||
|
os.makedirs(self.epub_path, exist_ok=True)
|
||||||
|
os.makedirs(self.epub_oebps_path, exist_ok=True)
|
||||||
|
os.makedirs(self.epub_img_path, exist_ok=True)
|
||||||
|
os.makedirs(self.epub_text_path, exist_ok=True)
|
||||||
|
|
||||||
|
print('正在打包处理图片......')
|
||||||
|
for chap_no, chap in enumerate(self.chap_list):
|
||||||
|
img_path = os.path.join(self.comic_root, chap)
|
||||||
|
imgs = os.listdir(img_path)
|
||||||
|
img_no = 0
|
||||||
|
self.chap_first_imgs.append(str(chap_no+1).zfill(3) + '_' + str(0).zfill(4) + '.jpg')
|
||||||
|
for img_no, img in enumerate(imgs):
|
||||||
|
img_old_path = os.path.join(img_path, img)
|
||||||
|
img_new = str(chap_no + 1).zfill(3) + '_' + str(img_no).zfill(4) + '.jpg'
|
||||||
|
img_epub_path = os.path.join(self.epub_img_path, img_new)
|
||||||
|
shutil.copyfile(img_old_path, img_epub_path)
|
||||||
|
self.img_list.append(img_new)
|
||||||
|
|
||||||
|
def get_epub_title(self, title, chap_list):
|
||||||
|
if len(chap_list)==1:
|
||||||
|
title = title + '-' + chap_list[0]
|
||||||
|
else:
|
||||||
|
title = title + '-' + chap_list[0] + '-' + chap_list[-1]
|
||||||
|
return title
|
||||||
|
|
||||||
|
def typesetting(self):
|
||||||
|
print('正在生成排版......')
|
||||||
|
for img in self.img_list:
|
||||||
|
text_file = os.path.join(self.epub_text_path, img.replace('.jpg', '.xhtml'))
|
||||||
|
text_htmls = get_xhtml(img)
|
||||||
|
with open(text_file, 'w+', encoding='utf-8') as f:
|
||||||
|
f.writelines(text_htmls)
|
||||||
|
|
||||||
|
|
||||||
|
print('正在生成元数据......')
|
||||||
|
|
||||||
|
|
||||||
|
#封面
|
||||||
|
cover_path = os.path.join(self.epub_img_path, '000_0000.jpg')
|
||||||
|
shutil.copyfile(os.path.join(self.comic_root, 'cover.jpg'), cover_path)
|
||||||
|
textfile = os.path.join(self.epub_text_path, 'cover.xhtml')
|
||||||
|
# img = cv2.imread(cover_path)
|
||||||
|
img = Image.open(cover_path)
|
||||||
|
img = np.array(img)
|
||||||
|
img_htmls = get_cover_html(img.shape[1], img.shape[0])
|
||||||
|
with open(textfile, 'w+', encoding='utf-8') as f:
|
||||||
|
f.writelines(img_htmls)
|
||||||
|
|
||||||
|
|
||||||
|
#内容页
|
||||||
|
content_htmls = get_content_html(self.title, self.author, self.img_list)
|
||||||
|
textfile = os.path.join(self.epub_oebps_path, 'content.opf')
|
||||||
|
with open(textfile, 'w+', encoding='utf-8') as f:
|
||||||
|
f.writelines(content_htmls)
|
||||||
|
|
||||||
|
#目录
|
||||||
|
toc_htmls = get_toc_html(self.title, self.chap_list, self.chap_first_imgs)
|
||||||
|
textfile = os.path.join(self.epub_oebps_path, 'toc.ncx')
|
||||||
|
with open(textfile, 'w+', encoding='utf-8') as f:
|
||||||
|
f.writelines(toc_htmls)
|
||||||
|
|
||||||
|
#get epub_head
|
||||||
|
mimetype = 'application/epub+zip'
|
||||||
|
mimetypefile = os.path.join(self.epub_path, 'mimetype')
|
||||||
|
with open(mimetypefile, 'w+', encoding='utf-8') as f:
|
||||||
|
f.write(mimetype)
|
||||||
|
metainf_folder = os.path.join(self.epub_path, 'META-INF')
|
||||||
|
os.makedirs(metainf_folder, exist_ok=True)
|
||||||
|
container = metainf_folder + '/container.xml'
|
||||||
|
container_htmls = get_container_html()
|
||||||
|
with open(container, 'w+', encoding='utf-8') as f:
|
||||||
|
f.writelines(container_htmls)
|
||||||
|
|
||||||
|
def get_epub(self):
|
||||||
|
print('正在打包EPUB......')
|
||||||
|
epub_file = os.path.join(self.out_root, check_chars(self.title) + '.epub')
|
||||||
|
with zipfile.ZipFile(epub_file, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||||
|
for dirpath, dirnames, filenames in os.walk(self.epub_path):
|
||||||
|
fpath = dirpath.replace(self.epub_path,'')
|
||||||
|
fpath = fpath and fpath + os.sep or ''
|
||||||
|
for filename in filenames:
|
||||||
|
zf.write(os.path.join(dirpath, filename), fpath+filename)
|
||||||
|
shutil.rmtree(self.epub_path)
|
||||||
|
if self.delete_comic:
|
||||||
|
shutil.rmtree(self.comic_root)
|
||||||
|
print('EPUB生成成功, 路径【{}】'.format(epub_file))
|
74
README.md
Normal file
74
README.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="resource/logo.png" width="150" style="margin-right: 3000px;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 align="center">
|
||||||
|
拷贝漫画EPUB下载器
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[拷贝漫画](https://www.copymanga.site)(copymanga)下载, 并打包为EPUB格式。
|
||||||
|
|
||||||
|
特性:
|
||||||
|
|
||||||
|
* Fluent Design风格界面,下载进度与书籍封面显示,主题切换,下载目录自定义。
|
||||||
|
* 前后端分离,同时支持命令行版本。
|
||||||
|
* 章节批量下载。
|
||||||
|
* EPUB格式自动打包。
|
||||||
|
* 图片质量自定义选择。
|
||||||
|
* 断点续传,避免重复下载。
|
||||||
|
* 多线程预缓存策略,下载速度快。
|
||||||
|
* 网站域名自定义更换,防止被墙。
|
||||||
|
* ...................
|
||||||
|
|
||||||
|
|
||||||
|
有建议或bug可以提issue,也可以加QQ群获得更多信息:563072544
|
||||||
|
|
||||||
|
图形界面使用[PyQt-Fluent-Widgets](https://pyqt-fluent-widgets.readthedocs.io/en/latest/index.html)界面编写。
|
||||||
|
|
||||||
|
[release](https://github.com/ShqWW/copymanga-download/releases)页面发布了已经打包好的exe可执行程序,包括图形化版本和命令行版本(系统最低要求Windows 10)。
|
||||||
|
|
||||||
|
界面样例:
|
||||||
|
<div align="center">
|
||||||
|
<img src="resource/example1.png" width="400"/>
|
||||||
|
<img src="resource/example2.png" width="400"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 使用前安装需要的包
|
||||||
|
```
|
||||||
|
pip install -r requirements.txt -i https://pypi.org/simple/
|
||||||
|
```
|
||||||
|
## 使用命令行模式运行(无需安装图形界面库,支持Linux):
|
||||||
|
```
|
||||||
|
python copymanga.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用图形界面运行:
|
||||||
|
```
|
||||||
|
python copymanga_gui.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用pyinstaller打包:
|
||||||
|
```
|
||||||
|
pip install pyinstaller
|
||||||
|
```
|
||||||
|
```
|
||||||
|
pyinstaller -F -w -i .\resource\logo.png .\copymanga_gui.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 相关项目:
|
||||||
|
|
||||||
|
* [轻小说文库EPUB下载器](https://github.com/ShqWW/lightnovel-download)
|
||||||
|
|
||||||
|
* [哔哩轻小说EPUB下载器](https://github.com/ShqWW/bilinovel-download)
|
||||||
|
|
||||||
|
* [拷贝漫画EPUB下载器](https://github.com/ShqWW/copymanga-download)
|
||||||
|
|
||||||
|
## EPUB书籍漫画编辑和管理工具推荐:
|
||||||
|
1. [Sigil](https://sigil-ebook.com/)
|
||||||
|
2. [Calibre](https://www.calibre-ebook.com/)
|
||||||
|
|
BIN
__pycache__/Downloader.cpython-311.pyc
Normal file
BIN
__pycache__/Downloader.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/Editer.cpython-311.pyc
Normal file
BIN
__pycache__/Editer.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/copymanga.cpython-311.pyc
Normal file
BIN
__pycache__/copymanga.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/utils.cpython-311.pyc
Normal file
BIN
__pycache__/utils.cpython-311.pyc
Normal file
Binary file not shown.
146
comic.py
Normal file
146
comic.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
import requests # 用来抓取网页的html源码
|
||||||
|
import random # 取随机数
|
||||||
|
from bs4 import BeautifulSoup # 用于代替正则式 取源码中相应标签中的内容
|
||||||
|
import sys
|
||||||
|
import time # 时间相关操作
|
||||||
|
import js2py
|
||||||
|
import os
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
|
||||||
|
class downloader(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.server = 'https://www.iimanhua.cc/'
|
||||||
|
self.target = 'https://www.iimanhua.cc/comic/2189/'
|
||||||
|
self.names = [] # 章节名
|
||||||
|
self.urls = [] # 章节链接
|
||||||
|
self.nums = 0 # 章节数
|
||||||
|
|
||||||
|
"""
|
||||||
|
获取html文档内容
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_content(self, url):
|
||||||
|
# 设置headers是为了模拟浏览器访问 否则的话可能会被拒绝 可通过浏览器获取,这里不用修改
|
||||||
|
header = {
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'Accept-Encoding': 'gzip, deflate, br',
|
||||||
|
'Accept-Language': 'zh-CN, zh',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 设置一个超时时间 取随机数 是为了防止网站被认定为爬虫,不用修改
|
||||||
|
timeout = random.choice(range(80, 180))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
req = requests.get(url=url, headers=header)
|
||||||
|
req.encoding = 'GBK' #这里是网页的编码转换,根据网页的实际需要进行修改,经测试这个编码没有问题
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print('3', e)
|
||||||
|
time.sleep(random.choice(range(5, 10)))
|
||||||
|
return req.text
|
||||||
|
|
||||||
|
"""
|
||||||
|
获取下载的章节目录
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_download_catalogue(self, url):
|
||||||
|
# html = self.get_content(url)
|
||||||
|
# bf = BeautifulSoup(html, 'html.parser')
|
||||||
|
# print(bf)
|
||||||
|
# texts = bf.find_all('div', {'class': 'listmain'})
|
||||||
|
|
||||||
|
finename = "./kkk.txt"
|
||||||
|
|
||||||
|
f = open(finename,'r', encoding='utf-8') # 返回一个文件对象
|
||||||
|
line = f.readline()
|
||||||
|
while line:
|
||||||
|
# print(line.strip('\n'))
|
||||||
|
name, url = self.get_url(line)
|
||||||
|
self.names.append(name)
|
||||||
|
self.urls.append(self.server + url)
|
||||||
|
line = f.readline()
|
||||||
|
# print(self.urls)
|
||||||
|
self.nums = len(self.urls)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
获取下载的具体章节
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_url(self, url_str):
|
||||||
|
st = url_str.find("/comic")
|
||||||
|
ed = url_str.find("\" title")
|
||||||
|
st2 = url_str.find(")")
|
||||||
|
ed2 = url_str.find("\">")
|
||||||
|
url = url_str[st:ed]
|
||||||
|
name = url_str[st2+1:ed2]
|
||||||
|
return name, url
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_download_content(self, chap, path, name, url):
|
||||||
|
#html = self.get_content(url)
|
||||||
|
chappath = os.path.join(path, str(chap).zfill(3)+ '话 ' +name)
|
||||||
|
os.makedirs(chappath, exist_ok=True)
|
||||||
|
html = self.get_content(url)
|
||||||
|
bf = BeautifulSoup(html, 'html.parser')
|
||||||
|
jscmd = bf.find('script', {'language': 'javascript', 'type': 'text/javascript'}).text
|
||||||
|
# print(jscmd)
|
||||||
|
jscmd += '''
|
||||||
|
\nvar b=base64decode(packed).slice(4);
|
||||||
|
var a = eval(b);
|
||||||
|
'''
|
||||||
|
# print(jscmd)
|
||||||
|
jsres = js2py.eval_js(jscmd) #执行js代码
|
||||||
|
imgurls = self.get_img_url(jsres)
|
||||||
|
page_no = 1
|
||||||
|
for imgurl in tqdm(imgurls):
|
||||||
|
r=requests.get(imgurl)
|
||||||
|
with open(chappath+'/'+str(page_no)+'.jpg','wb') as f:
|
||||||
|
f.write(r.content) #写入二进制内容
|
||||||
|
page_no += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
解析url
|
||||||
|
"""
|
||||||
|
def get_img_url(self, jsres):
|
||||||
|
imgserver = 'https://res.img.96youhuiquan.com/'
|
||||||
|
imgstrs = jsres.split(";")
|
||||||
|
imgurls = []
|
||||||
|
for imgstr in imgstrs:
|
||||||
|
if len(imgstr)>1:
|
||||||
|
st = imgstr.find("]=")
|
||||||
|
imgurl = imgstr[st+3:-1]
|
||||||
|
imgurls.append(imgserver+imgurl)
|
||||||
|
return imgurls
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def writer(self, path, name, text):
|
||||||
|
write_flag = True
|
||||||
|
with open(path, 'a', encoding='utf-8') as f:
|
||||||
|
f.writelines(name)
|
||||||
|
f.write('\n')
|
||||||
|
f.writelines(text)
|
||||||
|
f.write('\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
path = './duannao/'
|
||||||
|
dl = downloader()
|
||||||
|
dl.get_download_catalogue(dl.target)
|
||||||
|
for chap_no in range(77-1, dl.nums):
|
||||||
|
print("第" + str(chap_no+1) + "话")
|
||||||
|
dl.get_download_content(chap_no+1, path, dl.names[chap_no], dl.urls[chap_no])
|
131
copymanga.py
Normal file
131
copymanga.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import argparse
|
||||||
|
from Downloader import Downloader
|
||||||
|
from Editer import Editer
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
"""Parse input arguments."""
|
||||||
|
parser = argparse.ArgumentParser(description='config')
|
||||||
|
parser.add_argument('--comic_no', default='0000', type=str)
|
||||||
|
parser.add_argument('--volume_no', default='1', type=int)
|
||||||
|
parser.add_argument('--no_input', default=False, type=bool)
|
||||||
|
args = parser.parse_args()
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def query_chaps(comic_name, url_prev, is_gui=False, hang_signal=None, edit_line_hang=None):
|
||||||
|
print('未输入卷号,将返回书籍目录信息......')
|
||||||
|
editer = Downloader(comic_name=comic_name, root_path='./out', url_prev=url_prev)
|
||||||
|
print('*******************************')
|
||||||
|
editer.get_comic_msg(is_gui, hang_signal, edit_line_hang)
|
||||||
|
editer.get_comic_chaps()
|
||||||
|
print(editer.comic_title, editer.comic_author)
|
||||||
|
print('*******************************')
|
||||||
|
|
||||||
|
for i, chap_name in enumerate(editer.chap_name_list):
|
||||||
|
print(f'[{str(i+1)}]', chap_name)
|
||||||
|
|
||||||
|
print('*******************************')
|
||||||
|
print('请输入所需要的卷号进行下载(多卷可以用英文逗号分隔或直接使用连字符,详情见说明)')
|
||||||
|
|
||||||
|
def download_task(root_path,
|
||||||
|
comic_name,
|
||||||
|
chap_no_list,
|
||||||
|
url_prev,
|
||||||
|
high_quality,
|
||||||
|
is_gui=False,
|
||||||
|
multi_thread=False,
|
||||||
|
hang_signal=None,
|
||||||
|
progressring_signal=None,
|
||||||
|
cover_signal=None,
|
||||||
|
edit_line_hang=None):
|
||||||
|
|
||||||
|
downloader = Downloader(comic_name=comic_name, root_path=root_path, url_prev=url_prev, high_quality=high_quality)
|
||||||
|
print('正在积极地获取书籍信息....')
|
||||||
|
downloader.get_comic_msg(is_gui, hang_signal, edit_line_hang)
|
||||||
|
downloader.get_comic_chaps()
|
||||||
|
print(downloader.comic_title, downloader.comic_author)
|
||||||
|
|
||||||
|
print('****************************')
|
||||||
|
print('正在下载漫画....')
|
||||||
|
for chap_no in chap_no_list:
|
||||||
|
chap_name = downloader.chap_name_list[chap_no-1]
|
||||||
|
chap_uuid = downloader.chap_uuid_list[chap_no-1]
|
||||||
|
page_num = downloader.chap_pagenum_list[chap_no-1]
|
||||||
|
downloader.download_single_chap(chap_name, chap_uuid, page_num, multithread=multi_thread, is_gui=is_gui, signal=progressring_signal)
|
||||||
|
downloader.get_cover(chap_name=chap_name, is_gui=is_gui, signal=cover_signal)
|
||||||
|
downloader.download_cover()
|
||||||
|
print('漫画下载成功!', f'漫画路径【{downloader.comic_path}】')
|
||||||
|
chap_list = [downloader.chap_name_list[chap_no-1] for chap_no in chap_no_list]
|
||||||
|
editer = Editer(downloader.comic_title, downloader.comic_author, chap_list, downloader.comic_path, root_path, delete_comic=0)
|
||||||
|
editer.pack_img()
|
||||||
|
editer.typesetting()
|
||||||
|
editer.get_epub()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def downloader_router(root_path,
|
||||||
|
comic_name,
|
||||||
|
chap_no,
|
||||||
|
url_prev,
|
||||||
|
high_quality,
|
||||||
|
is_gui=False,
|
||||||
|
multi_thread=False,
|
||||||
|
hang_signal=None,
|
||||||
|
progressring_signal=None,
|
||||||
|
cover_signal=None,
|
||||||
|
edit_line_hang=None):
|
||||||
|
if len(comic_name)==0:
|
||||||
|
print('请检查输入是否完整正确!')
|
||||||
|
return
|
||||||
|
elif chap_no == '':
|
||||||
|
query_chaps(comic_name, url_prev, is_gui, hang_signal, edit_line_hang)
|
||||||
|
return
|
||||||
|
elif chap_no.isdigit():
|
||||||
|
chap_no = int(chap_no)
|
||||||
|
chap_no_list = [chap_no]
|
||||||
|
if chap_no<=0:
|
||||||
|
print('请检查输入是否完整正确!')
|
||||||
|
return
|
||||||
|
elif "-" in chap_no:
|
||||||
|
start, end = map(str, chap_no.split("-"))
|
||||||
|
if start.isdigit() and end.isdigit() and int(start)>0 and int(start)<int(end):
|
||||||
|
chap_no_list = list(range(int(start), int(end) + 1))
|
||||||
|
else:
|
||||||
|
print('请检查输入是否完整正确!')
|
||||||
|
return
|
||||||
|
elif "," in chap_no:
|
||||||
|
chap_no_list = [num for num in chap_no.split(",")]
|
||||||
|
if all([num.isdigit() for num in chap_no_list]):
|
||||||
|
chap_no_list = [int(num) for num in chap_no_list]
|
||||||
|
else:
|
||||||
|
print('请检查输入是否完整正确!')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print('请检查输入是否完整正确!')
|
||||||
|
return
|
||||||
|
download_task(root_path, comic_name, chap_no_list, url_prev, high_quality, is_gui, multi_thread, hang_signal, progressring_signal, cover_signal, edit_line_hang)
|
||||||
|
print('所有下载任务都已经完成!')
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
args = parse_args()
|
||||||
|
download_path = os.path.join(os.path.expanduser('~'), 'Downloads')
|
||||||
|
|
||||||
|
if args.no_input:
|
||||||
|
downloader_router(root_path='out', comic_name=args.comic_no, chap_no=args.volume_no)
|
||||||
|
else:
|
||||||
|
while True:
|
||||||
|
args.comic_name = input('请输入书籍号:')
|
||||||
|
args.volume_no = input('请输入卷号(查看目录信息不输入直接按回车,下载多卷请使用逗号分隔或者连字符-):')
|
||||||
|
# args.comic_name = 'xinglingganying'
|
||||||
|
# args.volume_no = '40'
|
||||||
|
downloader_router(root_path='out', comic_name=args.comic_name, chap_no=args.volume_no, url_prev='.tv', high_quality=True, multi_thread=True)
|
||||||
|
# exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
411
copymanga_gui.py
Normal file
411
copymanga_gui.py
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
# coding:utf-8
|
||||||
|
from PyQt5.QtCore import Qt, pyqtSignal, QObject, QThread, QRegExp
|
||||||
|
from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QColor,QRegExpValidator
|
||||||
|
from PyQt5.QtWidgets import QApplication, QFrame, QGridLayout, QFileDialog
|
||||||
|
from qfluentwidgets import (setTheme, Theme, PushSettingCard, SettingCardGroup, ExpandLayout, TextEdit, ImageLabel, LineEdit, PushButton, Theme, ProgressRing, setTheme, Theme, OptionsSettingCard, OptionsConfigItem, OptionsValidator, FluentWindow, SubtitleLabel, NavigationItemPosition, setThemeColor, qconfig, ComboBox, SwitchSettingCard, BoolValidator, MessageBox)
|
||||||
|
from qfluentwidgets import FluentIcon as FIF
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
|
import shutil
|
||||||
|
from resource.logo import logo_base64
|
||||||
|
from resource.book import book_base64
|
||||||
|
from copymanga import *
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
font_label = QFont('微软雅黑', 18)
|
||||||
|
font_msg = QFont('微软雅黑', 11)
|
||||||
|
|
||||||
|
class MainThread(QThread):
|
||||||
|
def __init__(self, parent):
|
||||||
|
super().__init__()
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.parent.clear_signal.emit('')
|
||||||
|
try:
|
||||||
|
comic_no = self.parent.editline_book.text()
|
||||||
|
chap_no = self.parent.editline_volumn.text()
|
||||||
|
downloader_router(self.parent.parent.out_path, comic_no, chap_no, self.parent.parent.url_prev, self.parent.parent.high_quality, True, self.parent.parent.multi_thread, self.parent.hang_signal, self.parent.progressring_signal, self.parent.cover_signal, self.parent.editline_hang)
|
||||||
|
self.parent.end_signal.emit('')
|
||||||
|
except Exception as e:
|
||||||
|
self.parent.end_signal.emit('')
|
||||||
|
print('错误,请检查网络情况或确认输入是否正确')
|
||||||
|
print('错误信息:')
|
||||||
|
print(e)
|
||||||
|
def terminate(self) -> None:
|
||||||
|
result = super().terminate()
|
||||||
|
return result
|
||||||
|
|
||||||
|
class EmittingStr(QObject):
|
||||||
|
textWritten = pyqtSignal(str) # 定义一个发送str的信号
|
||||||
|
def write(self, text):
|
||||||
|
self.textWritten.emit(str(text))
|
||||||
|
def flush(self):
|
||||||
|
pass
|
||||||
|
def isatty(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UrlPrev(Enum):
|
||||||
|
""" Theme enumeration """
|
||||||
|
|
||||||
|
SITE = ".site"
|
||||||
|
COM= ".com"
|
||||||
|
ORG = ".org"
|
||||||
|
NET = ".net"
|
||||||
|
TV = ".tv"
|
||||||
|
INFO = ".info"
|
||||||
|
|
||||||
|
class SettingWidget(QFrame):
|
||||||
|
def __init__(self, text: str, parent=None):
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
|
||||||
|
self.parent = parent
|
||||||
|
self.expandLayout = ExpandLayout(self)
|
||||||
|
self.setObjectName(text.replace(' ', '-'))
|
||||||
|
self.setting_group = SettingCardGroup(self.tr("下载设置"), self)
|
||||||
|
|
||||||
|
self.download_path_card = PushSettingCard(
|
||||||
|
self.tr('选择文件夹'),
|
||||||
|
FIF.DOWNLOAD,
|
||||||
|
self.tr("下载目录"),
|
||||||
|
self.parent.out_path,
|
||||||
|
self.setting_group
|
||||||
|
)
|
||||||
|
self.themeMode = OptionsConfigItem(None, "ThemeMode", Theme.DARK, OptionsValidator(Theme), None)
|
||||||
|
self.urlMode = OptionsConfigItem(None, "urlMode", UrlPrev.SITE, OptionsValidator(UrlPrev), None)
|
||||||
|
|
||||||
|
self.threadMode = OptionsConfigItem(None, "ThreadMode", True, BoolValidator())
|
||||||
|
self.qualityMode = OptionsConfigItem(None, "QualityMode", True, BoolValidator())
|
||||||
|
|
||||||
|
self.theme_card = OptionsSettingCard(
|
||||||
|
self.themeMode,
|
||||||
|
FIF.BRUSH,
|
||||||
|
self.tr('应用主题'),
|
||||||
|
self.tr("更改外观"),
|
||||||
|
texts=[
|
||||||
|
self.tr('亮'), self.tr('暗'),
|
||||||
|
self.tr('跟随系统设置')
|
||||||
|
],
|
||||||
|
parent=self.parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.url_card = OptionsSettingCard(
|
||||||
|
self.urlMode,
|
||||||
|
FIF.VPN,
|
||||||
|
self.tr('漫画域名后缀'),
|
||||||
|
self.tr("漫画域名切换"),
|
||||||
|
texts=[
|
||||||
|
self.tr('.tv'), self.tr('.org'),
|
||||||
|
self.tr('.com'), self.tr('.info'),
|
||||||
|
self.tr('.site'), self.tr('.net')
|
||||||
|
],
|
||||||
|
parent=self.parent
|
||||||
|
)
|
||||||
|
|
||||||
|
self.thread_card = SwitchSettingCard(
|
||||||
|
FIF.SPEED_HIGH,
|
||||||
|
self.tr('多线程缓存'),
|
||||||
|
self.tr('开启后理论上会加快下载速度,但可能会增加服务端压力'),
|
||||||
|
parent=self.parent,
|
||||||
|
configItem=self.threadMode
|
||||||
|
)
|
||||||
|
|
||||||
|
self.quality_card = SwitchSettingCard(
|
||||||
|
FIF.LEAF,
|
||||||
|
self.tr('下载高质量图片'),
|
||||||
|
self.tr('开启后会提高漫画清晰度,但会增加下载漫画的体积'),
|
||||||
|
parent=self.parent,
|
||||||
|
configItem=self.qualityMode
|
||||||
|
)
|
||||||
|
self.thread_card.setValue(True)
|
||||||
|
self.quality_card.setValue(True)
|
||||||
|
self.thread_changed()
|
||||||
|
self.quality_changed()
|
||||||
|
|
||||||
|
self.setting_group.addSettingCard(self.download_path_card)
|
||||||
|
self.setting_group.addSettingCard(self.thread_card)
|
||||||
|
self.setting_group.addSettingCard(self.quality_card)
|
||||||
|
self.setting_group.addSettingCard(self.url_card)
|
||||||
|
self.setting_group.addSettingCard(self.theme_card)
|
||||||
|
|
||||||
|
self.expandLayout.setSpacing(28)
|
||||||
|
self.expandLayout.setContentsMargins(20, 10, 20, 0)
|
||||||
|
self.expandLayout.addWidget(self.setting_group)
|
||||||
|
|
||||||
|
self.download_path_card.clicked.connect(self.download_path_changed)
|
||||||
|
self.theme_card.optionChanged.connect(self.theme_changed)
|
||||||
|
self.url_card.optionChanged.connect(self.url_changed)
|
||||||
|
self.thread_card.checkedChanged.connect(self.thread_changed)
|
||||||
|
self.quality_card.checkedChanged.connect(self.quality_changed)
|
||||||
|
|
||||||
|
def download_path_changed(self):
|
||||||
|
""" download folder card clicked slot """
|
||||||
|
self.parent.out_path = QFileDialog.getExistingDirectory(
|
||||||
|
self, self.tr("Choose folder"), self.parent.out_path)
|
||||||
|
self.download_path_card.contentLabel.setText(self.parent.out_path)
|
||||||
|
|
||||||
|
def theme_changed(self):
|
||||||
|
theme_name = self.theme_card.choiceLabel.text()
|
||||||
|
self.parent.set_theme(theme_name)
|
||||||
|
if os.path.exists('./config'):
|
||||||
|
shutil.rmtree('./config')
|
||||||
|
|
||||||
|
def url_changed(self):
|
||||||
|
self.parent.url_prev = self.url_card.choiceLabel.text()
|
||||||
|
if os.path.exists('./config'):
|
||||||
|
shutil.rmtree('./config')
|
||||||
|
|
||||||
|
def thread_changed(self):
|
||||||
|
is_checked = self.thread_card.isChecked()
|
||||||
|
self.thread_card.switchButton.setText(
|
||||||
|
self.tr('开') if is_checked else self.tr('关'))
|
||||||
|
self.parent.multi_thread = is_checked
|
||||||
|
if os.path.exists('./config'):
|
||||||
|
shutil.rmtree('./config')
|
||||||
|
def quality_changed(self):
|
||||||
|
is_checked = self.quality_card.isChecked()
|
||||||
|
self.quality_card.switchButton.setText(
|
||||||
|
self.tr('高') if is_checked else self.tr('低'))
|
||||||
|
self.parent.high_quality = is_checked
|
||||||
|
if os.path.exists('./config'):
|
||||||
|
shutil.rmtree('./config')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class HomeWidget(QFrame):
|
||||||
|
|
||||||
|
progressring_signal = pyqtSignal(object)
|
||||||
|
end_signal = pyqtSignal(object)
|
||||||
|
hang_signal = pyqtSignal(object)
|
||||||
|
clear_signal = pyqtSignal(object)
|
||||||
|
cover_signal = pyqtSignal(object)
|
||||||
|
|
||||||
|
def __init__(self, text: str, parent=None):
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
self.setObjectName(text)
|
||||||
|
self.parent = parent
|
||||||
|
self.label_book = SubtitleLabel('名称:', self)
|
||||||
|
self.label_volumn = SubtitleLabel('卷号:', self)
|
||||||
|
self.editline_book = LineEdit(self)
|
||||||
|
self.editline_volumn = LineEdit(self)
|
||||||
|
|
||||||
|
|
||||||
|
# self.editline_book.setText('yaoyeluying')
|
||||||
|
# self.editline_volumn.setText('3')
|
||||||
|
|
||||||
|
self.book_icon = QPixmap()
|
||||||
|
self.book_icon.loadFromData(base64.b64decode(book_base64))
|
||||||
|
self.cover_w, self.cover_h = 152, 230
|
||||||
|
|
||||||
|
self.label_cover = ImageLabel(self.book_icon, self)
|
||||||
|
self.label_cover.setBorderRadius(8, 8, 8, 8)
|
||||||
|
self.label_cover.setFixedSize(self.cover_w, self.cover_h)
|
||||||
|
|
||||||
|
self.text_screen = TextEdit()
|
||||||
|
self.text_screen.setReadOnly(True)
|
||||||
|
self.text_screen.setFixedHeight(self.cover_h)
|
||||||
|
|
||||||
|
self.progressRing = ProgressRing(self)
|
||||||
|
self.progressRing.setValue(0)
|
||||||
|
self.progressRing.setTextVisible(True)
|
||||||
|
self.progressRing.setFixedSize(50, 50)
|
||||||
|
|
||||||
|
self.btn_run = PushButton('确定', self)
|
||||||
|
self.btn_run.setShortcut(Qt.Key_Return)
|
||||||
|
self.btn_stop = PushButton('取消', self)
|
||||||
|
self.btn_hang = PushButton('确定', self)
|
||||||
|
|
||||||
|
self.editline_hang = ComboBox(self)
|
||||||
|
self.gridLayout = QGridLayout(self)
|
||||||
|
self.screen_layout = QGridLayout()
|
||||||
|
self.btn_layout = QGridLayout()
|
||||||
|
self.hang_layout = QGridLayout()
|
||||||
|
|
||||||
|
self.label_book.setFont(font_label)
|
||||||
|
self.label_volumn.setFont(font_label)
|
||||||
|
self.editline_book.setFont(font_label)
|
||||||
|
self.editline_volumn.setFont(font_label)
|
||||||
|
self.text_screen.setFont(font_msg)
|
||||||
|
self.editline_hang.setFont(font_msg)
|
||||||
|
|
||||||
|
self.gridLayout.addWidget(self.editline_book, 0, 1)
|
||||||
|
self.gridLayout.addWidget(self.editline_volumn, 1, 1)
|
||||||
|
self.gridLayout.addWidget(self.label_book, 0, 0)
|
||||||
|
self.gridLayout.addWidget(self.label_volumn, 1, 0)
|
||||||
|
|
||||||
|
self.gridLayout.addLayout(self.btn_layout, 2, 1, 1, 1)
|
||||||
|
self.btn_layout.addWidget(self.btn_run, 2, 1)
|
||||||
|
self.btn_layout.addWidget(self.btn_stop, 2, 2)
|
||||||
|
|
||||||
|
self.gridLayout.addLayout(self.screen_layout, 3, 0, 2, 2)
|
||||||
|
|
||||||
|
self.screen_layout.addWidget(self.progressRing, 0, 0, Qt.AlignRight|Qt.AlignBottom)
|
||||||
|
self.screen_layout.addWidget(self.text_screen, 0, 0)
|
||||||
|
self.screen_layout.addWidget(self.label_cover, 0, 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.gridLayout.addLayout(self.hang_layout, 5, 0, 1, 2)
|
||||||
|
self.hang_layout.addWidget(self.editline_hang, 0, 0)
|
||||||
|
self.hang_layout.addWidget(self.btn_hang, 0, 1)
|
||||||
|
|
||||||
|
self.screen_layout.setContentsMargins(0,0,0,0)
|
||||||
|
self.btn_layout.setContentsMargins(0,0,0,0)
|
||||||
|
self.gridLayout.setContentsMargins(20, 10, 20, 10)
|
||||||
|
|
||||||
|
self.btn_run.clicked.connect(self.process_start)
|
||||||
|
self.btn_stop.clicked.connect(self.process_stop)
|
||||||
|
self.btn_hang.clicked.connect(self.process_continue)
|
||||||
|
|
||||||
|
self.progressring_signal.connect(self.progressring_msg)
|
||||||
|
self.end_signal.connect(self.process_end)
|
||||||
|
self.hang_signal.connect(self.process_hang)
|
||||||
|
self.clear_signal.connect(self.clear_screen)
|
||||||
|
self.cover_signal.connect(self.display_cover)
|
||||||
|
|
||||||
|
self.progressRing.hide()
|
||||||
|
self.btn_hang.hide()
|
||||||
|
self.editline_hang.hide()
|
||||||
|
self.btn_stop.setEnabled(False)
|
||||||
|
|
||||||
|
sys.stdout = EmittingStr(textWritten=self.outputWritten)
|
||||||
|
sys.stderr = EmittingStr(textWritten=self.outputWritten)
|
||||||
|
self.text_screen.setText(self.parent.welcome_text)
|
||||||
|
|
||||||
|
def process_start(self):
|
||||||
|
self.label_cover.setImage(self.book_icon)
|
||||||
|
self.label_cover.setFixedSize(self.cover_w, self.cover_h)
|
||||||
|
self.btn_run.setEnabled(False)
|
||||||
|
self.btn_run.setText('正在下载')
|
||||||
|
self.btn_stop.setEnabled(True)
|
||||||
|
self.main_thread = MainThread(self)
|
||||||
|
self.main_thread.start()
|
||||||
|
|
||||||
|
def process_end(self, input=None):
|
||||||
|
self.btn_run.setEnabled(True)
|
||||||
|
self.btn_run.setText('开始下载')
|
||||||
|
self.btn_run.setShortcut(Qt.Key_Return)
|
||||||
|
self.btn_stop.setEnabled(False)
|
||||||
|
self.progressRing.hide()
|
||||||
|
self.btn_hang.hide()
|
||||||
|
self.editline_hang.clear()
|
||||||
|
self.editline_hang.hide()
|
||||||
|
if input=='refresh':
|
||||||
|
self.label_cover.setImage(self.book_icon)
|
||||||
|
self.label_cover.setFixedSize(self.cover_w, self.cover_h)
|
||||||
|
self.clear_signal.emit('')
|
||||||
|
self.text_screen.setText(self.parent.welcome_text)
|
||||||
|
|
||||||
|
def outputWritten(self, text):
|
||||||
|
cursor = self.text_screen.textCursor()
|
||||||
|
scrollbar=self.text_screen.verticalScrollBar()
|
||||||
|
is_bottom = (scrollbar.value()>=scrollbar.maximum() - 15)
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
cursor.insertText(text)
|
||||||
|
if is_bottom:
|
||||||
|
self.text_screen.setTextCursor(cursor)
|
||||||
|
# self.text_screen.ensureCursorVisible()
|
||||||
|
|
||||||
|
def clear_screen(self):
|
||||||
|
self.text_screen.clear()
|
||||||
|
|
||||||
|
def display_cover(self, signal_msg):
|
||||||
|
filepath, img_h, img_w = signal_msg
|
||||||
|
self.label_cover.setImage(filepath)
|
||||||
|
self.label_cover.setFixedSize(int(img_w*self.cover_h/img_h), self.cover_h)
|
||||||
|
|
||||||
|
def progressring_msg(self, input):
|
||||||
|
if input == 'start':
|
||||||
|
self.progressRing.setValue(0)
|
||||||
|
self.progressRing.show()
|
||||||
|
elif input == 'end':
|
||||||
|
self.progressRing.hide()
|
||||||
|
self.progressRing.setValue(0)
|
||||||
|
else:
|
||||||
|
self.progressRing.setValue(input)
|
||||||
|
|
||||||
|
def process_hang(self, input=None):
|
||||||
|
self.btn_hang.setEnabled(True)
|
||||||
|
self.btn_hang.setShortcut(Qt.Key_Return)
|
||||||
|
self.btn_hang.show()
|
||||||
|
self.editline_hang.show()
|
||||||
|
|
||||||
|
def process_continue(self, input=None):
|
||||||
|
self.btn_hang.hide()
|
||||||
|
self.btn_hang.setEnabled(False)
|
||||||
|
self.editline_hang.hide()
|
||||||
|
|
||||||
|
|
||||||
|
def process_stop(self):
|
||||||
|
self.main_thread.terminate()
|
||||||
|
self.end_signal.emit('refresh')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Window(FluentWindow):
|
||||||
|
update_signal = pyqtSignal(object)
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.out_path = os.path.join(os.path.expanduser('~'), 'Downloads')
|
||||||
|
self.url_prev = '.tv'
|
||||||
|
self.head = 'https://www.copymanga.tv'
|
||||||
|
split_str = '**************************************\n '
|
||||||
|
self.welcome_text = f'使用说明(共4条,记得下拉):\n{split_str}1.拷贝漫画{self.head},根据书籍网址输入漫画名以及下载的卷号。\n{split_str}2.例如漫画网址是{self.head}/comic/yaoyeluying,则漫画名输入yaoyeluying。\n{split_str}3.要查询漫画卷号卷名等信息,则可以只输入漫画名不输入卷号,点击确定会返回漫画卷名称和对应的卷号。\n{split_str}4.根据上一步返回的信息确定自己想下载的卷号,要下载编号[2]对应卷,则卷号输入2。想下载多卷比如[1]至[3]对应卷,则卷号输入1-3或1,2,3(英文逗号分隔,编号也可以不连续)并点击确定。'
|
||||||
|
self.homeInterface = HomeWidget('Home Interface', self)
|
||||||
|
self.settingInterface = SettingWidget('Setting Interface', self)
|
||||||
|
self.initNavigation()
|
||||||
|
self.initWindow()
|
||||||
|
self.multi_thread = True
|
||||||
|
self.high_quality = True
|
||||||
|
|
||||||
|
def initNavigation(self):
|
||||||
|
self.addSubInterface(self.homeInterface, FIF.HOME, '主界面')
|
||||||
|
self.addSubInterface(self.settingInterface, FIF.SETTING, '设置', NavigationItemPosition.BOTTOM)
|
||||||
|
|
||||||
|
def initWindow(self):
|
||||||
|
self.resize(700, 460)
|
||||||
|
pixmap = QPixmap()
|
||||||
|
pixmap.loadFromData(base64.b64decode(logo_base64))
|
||||||
|
self.setWindowIcon(QIcon(pixmap))
|
||||||
|
self.setWindowTitle('拷贝漫画下载器')
|
||||||
|
self.setFont(font_label)
|
||||||
|
|
||||||
|
desktop = QApplication.desktop().availableGeometry()
|
||||||
|
w, h = desktop.width(), desktop.height()
|
||||||
|
self.move(w//2 - self.width()//2, h//2 - self.height()//2)
|
||||||
|
|
||||||
|
def set_theme(self, mode=None):
|
||||||
|
if mode=='亮':
|
||||||
|
setTheme(Theme.LIGHT)
|
||||||
|
elif mode=='暗':
|
||||||
|
setTheme(Theme.DARK)
|
||||||
|
elif mode=='跟随系统设置':
|
||||||
|
setTheme(Theme.AUTO)
|
||||||
|
theme = qconfig.theme
|
||||||
|
if theme == Theme.DARK:
|
||||||
|
self.homeInterface.label_book.setTextColor(QColor(255,255,255))
|
||||||
|
self.homeInterface.label_volumn.setTextColor(QColor(255,255,255))
|
||||||
|
elif theme == Theme.LIGHT:
|
||||||
|
self.homeInterface.label_book.setTextColor(QColor(0,0,0))
|
||||||
|
self.homeInterface.label_volumn.setTextColor(QColor(0,0,0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
|
||||||
|
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||||
|
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
||||||
|
|
||||||
|
setTheme(Theme.DARK)
|
||||||
|
setThemeColor('#1E90FF')
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
w = Window()
|
||||||
|
w.show()
|
||||||
|
app.exec_()
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# pip install -r requirements.txt -i https://pypi.org/simple/
|
||||||
|
requests
|
||||||
|
bs4
|
||||||
|
rich
|
||||||
|
pyqt5
|
||||||
|
PyQt-Fluent-Widgets[full]
|
BIN
resource/__pycache__/book.cpython-311.pyc
Normal file
BIN
resource/__pycache__/book.cpython-311.pyc
Normal file
Binary file not shown.
BIN
resource/__pycache__/logo.cpython-311.pyc
Normal file
BIN
resource/__pycache__/logo.cpython-311.pyc
Normal file
Binary file not shown.
BIN
resource/book.png
Normal file
BIN
resource/book.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
1
resource/book.py
Normal file
1
resource/book.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
book_base64 = 'iVBORw0KGgoAAAANSUhEUgAAAQ8AAAGKCAMAAAAljDRnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACHUExURQAAAL+/v7Ompq+vr66oqK+qqq+rq66qqq6rq6+pqa2rq6+tra6srK6pqa+rq62pqbCsrK+srK+srK6pqa+srK+srK+rq66qqq+rq6+rq7CsrK+rq6+rq7Crq66rq66qqrCrq6+rq6+rq6+rq6+rq6+rq66qqq6rq6+qqq+rq6+srLCrq7CsrNpNNrIAAAAmdFJOUwAEFCMsMEBITFNkZnJ0fICHnJ+go6+/wcLDx8/S19rf5+/w9fn7jVpzpgAAAAlwSFlzAAAywAAAMsABKGRa2wAABoxJREFUeF7t3Wl3ozYARuF0Y7q7q7t3mi5pM+3//32VxOuEFwOSHMAeuM+H2rFlQHdkO9A5Z+4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwck1zDB5b4d7h0OiZPWpOJVyoogH7ctD8B+2viSY+7rirJJOr42RHq2T4s+PcXpJouiV2UURzLbODIpppqc2/bTTPCtsuoklW2XIRTbHSdotogtW2WkTTq7fRUz7NrpX+0JvmcCj6Le3lS6SJdP9GaG6t7gybgijVRVLr50sLXekyw5UvNITD09G0+vPLNikPEjZVemoQrzSsnaV7AejZ0PQySQqKlKy0Aetdfxm5ADQ6ucPUSfD0QV/Y4snSTeKVQe1qwPjOp6Y19qqwL414kbmuv2jm7edU/Bxv0uanTO2591HTNfSymWK00g7id1H6NI6P1Ec6O/wH3U7I7GS0SP91s8YYU1fkbDEU5MjvYqzIUc8na8SIaoJMfQKOK9jD2IZPX5BrxYjKv5TzHxWDioqPFEkHt2aN3qqcdHbMJe+W4hU4XCR8YK9ao6bHhQdW+o4cDvKTbtejw8nT+Frln1BjHyPr0sHkaXyt8h4vem/Ec4V47hZ/K0q3QfnZTYeOJU/ja1X0uGSJhArT5/cpT0UYvSxP4yfFP6TGv4iqelQFibvSywqUXoHR8DyNH3c8HZ1+btX1KP1WP152zafgVFAj8zR+RPfqgh5qVfYo+B67sEUruwA1Lk/jR3SnrYda1T2mgzwtwgu9hT3Gg7xoZbQW6hFnqbutOXuMBHnp0ki8x9hDJTS+tWyPoSAXbefc29mjv6pnWRrJFnrMV2MbPfTgLOjh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OHo4ejh6OGu3uOif/xpwz2i+E+xVmXZeI9WRZRd9EhCFI2asp8eSbbJznoEx8n3zv56RONJ9tkjGEmy2x7xjaNXdW2rR/ZffO45L7KtHoX/JnhH/1t4Wz38mVLdj5KN9ah9w8jzItlYj94uyp2KbK1H1LQOh8OxYr2029liDxe6FFaJW9p+j1ZRlLCpvfSIDr7/Ib0heuEsbq9H0OSWiT+tV83iJntEpR8ngV4xi5vtEVeJXpuj8bO4To/TN21HfETPPiv4LAk0OGdgp0Fvt6v2iMdznP5tI15ajgcZh0cli0RDB6UEmX0GT1e01+pxrPqtK4ll4jFmi6Td9+XTDwhHqXuttKVFelwuZPlad0e0+3/WNNUhRqTN3ViP5LVuB7X7T+ZLkaRt3mKPx8cH3Q5o9x9izNoiSpu9zR4TReLew8LQT3OKW77ZHqNF4srQ3Zmlid1uj5EgC8UI0sRuuMfkx8gC0sRuuse6QdLEbrvHqtLE5uqx3Nt6Lcc0sbl61P9vllJrvWfiLObrMbJAwllFezb7fF6ZfkqnnoW/UVUHCTtNp0ORdto67VfjTLs85uvRDxIOaeCc/lw6xHnebWmXJfsMew071atayjFjj06Q6b/PMSyeqevlffkFcjwWdnDPTU455uxxF8+545+RfrzARBQ5a3NhipN0yaXz1x7n6BEP6kx8o/akN7TT5ky/ycTyGGuhrRsdRIeOtEvbPdHm8jR+Cem4XnfO+bs9Ovfv739KQ2c/z+3QbPM0fkkPti4mFsmCNNs8jV+YJ7kCzTZP45d33SKabZ7GL+yf+J/eIok/pcfXoNnmafw6Hq72vtFs8zR+LQ+9982/ul2aZpu34Hfck7UmPe7pt9as5U5nb8npF+8CKyyQ/3R7NeXL49oL5I1ul1V1XrR8kIlJr/KFW3maGM+6dAJhtLUlvflbd+agw3bh4cocVXSK2aVzTKODOfn5Dx1yz5+/aECHttClHRkdz1vqw79UwH2sp/fno++VoOPXT/TkHr37xb0ynHz7vp7aqfc+/U4lgt+/fKWHd+ydV59/88Nvj/c/fvXZB3oIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUuLv7Hzo1zyb0ghw2AAAAAElFTkSuQmCC'
|
BIN
resource/example1.png
Normal file
BIN
resource/example1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
resource/example2.png
Normal file
BIN
resource/example2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 204 KiB |
BIN
resource/logo.png
Normal file
BIN
resource/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
1
resource/logo.py
Normal file
1
resource/logo.py
Normal file
File diff suppressed because one or more lines are too long
23
resource/trans_base64.py
Normal file
23
resource/trans_base64.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from PIL import Image
|
||||||
|
import base64
|
||||||
|
# from resource.logo import logo_base64
|
||||||
|
import io
|
||||||
|
|
||||||
|
# # 从Base64编码数据中获取图像数据
|
||||||
|
# image_bytes = base64.b64decode(logo_base64)
|
||||||
|
|
||||||
|
# # 将图像数据解码为Image对象
|
||||||
|
# image = Image.open(io.BytesIO(image_bytes))
|
||||||
|
|
||||||
|
# # 显示图像
|
||||||
|
# image.show()
|
||||||
|
|
||||||
|
|
||||||
|
def image_to_base64(image_path):
|
||||||
|
with open(image_path, "rb") as image_file:
|
||||||
|
encoded_string = base64.b64encode(image_file.read())
|
||||||
|
return encoded_string.decode("utf-8")
|
||||||
|
|
||||||
|
image_path = "resource/logo.png "
|
||||||
|
base64_string = image_to_base64(image_path)
|
||||||
|
print(base64_string)
|
197
utils.py
Normal file
197
utils.py
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
def get_cover_html(img_w, img_h):
|
||||||
|
img_htmls = []
|
||||||
|
img_msg = ' <image width=\"'+ str(img_w)+'\" height=\"'+ str(img_h)+'\" xlink:href="../Images/000_0000.jpg"/>\n'
|
||||||
|
img_htmls.append('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
|
||||||
|
img_htmls.append('<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n')
|
||||||
|
img_htmls.append('\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n')
|
||||||
|
img_htmls.append('<html xmlns=\"http://www.w3.org/1999/xhtml\">\n')
|
||||||
|
img_htmls.append('<head>\n')
|
||||||
|
img_htmls.append(' <title>Cover</title>\n')
|
||||||
|
img_htmls.append('</head>\n')
|
||||||
|
img_htmls.append('<body>\n')
|
||||||
|
img_htmls.append(' <div style="text-align: center; padding: 0pt; margin: 0pt;">\n')
|
||||||
|
img_htmls.append(' <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"100%\" preserveAspectRatio=\"xMidYMid meet\" version=\"1.1\" viewBox=\"0 0 '+ str(img_w)+' '+ str(img_h)+'\" width=\"100%\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n')
|
||||||
|
img_htmls.append(img_msg)
|
||||||
|
img_htmls.append(' </svg>\n')
|
||||||
|
img_htmls.append(' </div>\n')
|
||||||
|
img_htmls.append('</body>\n')
|
||||||
|
img_htmls.append('</html>')
|
||||||
|
return img_htmls
|
||||||
|
|
||||||
|
|
||||||
|
def get_xhtml(img):
|
||||||
|
text_body = []
|
||||||
|
text_body.append('<body>\n')
|
||||||
|
text_body.append(' <img alt=\"'+ img.replace('.jpg', '') +'\" src=\"../Images/'+ img +'\"/>\n')
|
||||||
|
text_body.append('</body>\n')
|
||||||
|
text_head = []
|
||||||
|
text_head.append('<head>\n')
|
||||||
|
text_head.append(' <title></title>\n')
|
||||||
|
text_head.append('</head>\n')
|
||||||
|
text_htmls = ['<?xml version="1.0" encoding="utf-8"?>\n', '<html>\n'] + text_head + text_body + ['</html>']
|
||||||
|
return text_htmls
|
||||||
|
|
||||||
|
def get_toc_html(title, chap_names, chap_imgs):
|
||||||
|
toc_htmls = []
|
||||||
|
toc_htmls.append('<?xml version=\"1.0\" encoding=\"utf-8\"?>\n')
|
||||||
|
toc_htmls.append('<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n')
|
||||||
|
toc_htmls.append(' \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n\n')
|
||||||
|
toc_htmls.append('<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\">\n')
|
||||||
|
toc_htmls.append(' <head>\n')
|
||||||
|
toc_htmls.append(' <meta name=\"dtb:uid\" content=\"urn:uuid:a18aac05-497d-476d-b66f-0211f609743d\" />\n')
|
||||||
|
toc_htmls.append(' <meta name=\"dtb:depth\" content=\"0\" />\n')
|
||||||
|
toc_htmls.append(' <meta name=\"dtb:totalPageCount\" content=\"0\" />\n')
|
||||||
|
toc_htmls.append(' <meta name=\"dtb:maxPageNumber\" content=\"0\" />\n')
|
||||||
|
toc_htmls.append(' </head>\n')
|
||||||
|
toc_htmls.append('<docTitle>\n')
|
||||||
|
toc_htmls.append(' <text>'+ title +'</text>\n')
|
||||||
|
toc_htmls.append('</docTitle>\n')
|
||||||
|
toc_htmls.append('<navMap>\n')
|
||||||
|
for chap_no, (chap_name, chap_img) in enumerate(zip(chap_names, chap_imgs)):
|
||||||
|
toc_htmls.append(' <navPoint id=\"navPoint-'+str(chap_no+1)+'\" playOrder=\"'+str(chap_no+1)+'\">\n')
|
||||||
|
toc_htmls.append(' <navLabel>\n')
|
||||||
|
toc_htmls.append(' <text>'+ chap_name +'</text>\n')
|
||||||
|
toc_htmls.append(' </navLabel>\n')
|
||||||
|
toc_htmls.append(' <content src="Text/'+chap_img.replace('.jpg', '.xhtml')+'"/>\n')
|
||||||
|
toc_htmls.append(' </navPoint>\n')
|
||||||
|
toc_htmls.append('</navMap>\n')
|
||||||
|
toc_htmls.append('</ncx>')
|
||||||
|
return toc_htmls
|
||||||
|
|
||||||
|
|
||||||
|
def get_content_html(title, author, img_list):
|
||||||
|
content_htmls = []
|
||||||
|
content_htmls.append('<?xml version=\"1.0\" encoding=\"utf-8\"?>\n')
|
||||||
|
content_htmls.append('<package version=\"2.0\" unique-identifier=\"BookId\" xmlns=\"http://www.idpf.org/2007/opf\">\n')
|
||||||
|
content_htmls.append(' <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:opf=\"http://www.idpf.org/2007/opf\">\n')
|
||||||
|
content_htmls.append(' <dc:identifier id=\"BookId\" opf:scheme=\"UUID\">urn:uuid:942b8224-476b-463b-9078-cdfab0ee2686</dc:identifier>\n')
|
||||||
|
content_htmls.append(' <dc:language>zh</dc:language>\n')
|
||||||
|
content_htmls.append(' <dc:title>'+ title +'</dc:title>\n')
|
||||||
|
content_htmls.append(' <dc:creator opf:role="aut" opf:file-as="未知">'+ author +'</dc:creator>\n')
|
||||||
|
content_htmls.append(' <meta name=\"cover\" content=\"x000_0000.jpg\"/>\n')
|
||||||
|
content_htmls.append(' </metadata>\n')
|
||||||
|
content_htmls.append(' <manifest>\n')
|
||||||
|
content_htmls.append(' <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>\n')
|
||||||
|
for img in img_list:
|
||||||
|
text = img.replace('.jpg', '.xhtml')
|
||||||
|
content_htmls.append(' <item id=\"x'+ text +'\" href=\"Text/'+ text +'\" media-type=\"application/xhtml+xml\"/>\n')
|
||||||
|
|
||||||
|
content_htmls.append(' <item id="cover.xhtml" href="Text/cover.xhtml" media-type="application/xhtml+xml"/>\n')
|
||||||
|
|
||||||
|
for img in img_list:
|
||||||
|
content_htmls.append(' <item id=\"x'+ img + '\" href=\"Images/'+ img +'\" media-type=\"image/jpeg\"/>\n')
|
||||||
|
|
||||||
|
content_htmls.append(' <item id=\"x000_0000.jpg\" href=\"Images/000_0000.jpg\" media-type=\"image/jpeg\"/>\n')
|
||||||
|
content_htmls.append(' </manifest>\n')
|
||||||
|
content_htmls.append(' <spine toc="ncx">\n')
|
||||||
|
|
||||||
|
content_htmls.append(' <itemref idref="xcolor"/>\n')
|
||||||
|
for img in img_list:
|
||||||
|
text = img.replace('.jpg', '.xhtml')
|
||||||
|
content_htmls.append(' <itemref idref=\"x'+ text + '\"/>\n')
|
||||||
|
|
||||||
|
content_htmls.append(' <itemref idref="cover.xhtml"/>\n')
|
||||||
|
content_htmls.append(' </spine>\n')
|
||||||
|
content_htmls.append(' <guide>\n')
|
||||||
|
content_htmls.append(' <reference type="cover" title="封面" href="Text/cover.xhtml"/>\n')
|
||||||
|
content_htmls.append(' </guide>\n')
|
||||||
|
content_htmls.append('</package>\n')
|
||||||
|
return content_htmls
|
||||||
|
|
||||||
|
|
||||||
|
def get_container_html():
|
||||||
|
container_htmls = []
|
||||||
|
container_htmls.append('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||||
|
container_htmls.append('<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">\n')
|
||||||
|
container_htmls.append(' <rootfiles>\n')
|
||||||
|
container_htmls.append(' <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>\n')
|
||||||
|
container_htmls.append(' </rootfiles>\n')
|
||||||
|
container_htmls.append('</container>\n')
|
||||||
|
return container_htmls
|
||||||
|
|
||||||
|
|
||||||
|
def get_color_html(colorimg_num):
|
||||||
|
color_htmls = []
|
||||||
|
color_htmls.append('<?xml version=\"1.0\" encoding=\"utf-8\"?>\n')
|
||||||
|
color_htmls.append('<html>\n')
|
||||||
|
color_htmls.append('<head>\n')
|
||||||
|
|
||||||
|
color_htmls.append(' <title>彩插</title>\n')
|
||||||
|
color_htmls.append('</head>\n')
|
||||||
|
color_htmls.append('<body>\n')
|
||||||
|
for i in range(1, colorimg_num):
|
||||||
|
color_htmls.append(' <img alt=\"'+str(i).zfill(2)+'\" src=\"../Images/'+str(i).zfill(2)+'.jpg\"/>\n')
|
||||||
|
color_htmls.append('</body>\n')
|
||||||
|
color_htmls.append('</html>')
|
||||||
|
return color_htmls
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_vol(vol_no):
|
||||||
|
vol_no = str(vol_no)
|
||||||
|
s="零一二三四五六七八九"
|
||||||
|
for c in "0123456789":
|
||||||
|
vol_no=vol_no.replace(c,s[eval(c)])
|
||||||
|
vol_no = '第' + vol_no + '卷'
|
||||||
|
return vol_no
|
||||||
|
|
||||||
|
|
||||||
|
def check_chars(win_chars):
|
||||||
|
win_illegal_chars = '?*"<>|:/\\'
|
||||||
|
new_chars = ''
|
||||||
|
for char in win_chars:
|
||||||
|
if char in win_illegal_chars:
|
||||||
|
new_chars += '\u25A0'
|
||||||
|
else:
|
||||||
|
new_chars += char
|
||||||
|
return new_chars
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user