Files
cwm_export/export.py

256 lines
9.6 KiB
Python

from novelCiwei import NovelCiwei
from db import CwmDb
from config import Config
from key import import_keys
from booksnew import BooksNew
from crypto import decrypt
from os.path import dirname
from os import makedirs
from epub import EpubFile
from utils import ask_choice
import json
from random import choice
key_imported = False
key_force_imported = False
def get_key(db: CwmDb, cfg: Config, chapter_id: int):
global key_imported
keys = db.get_key(chapter_id)
if len(keys) == 0:
if key_imported:
raise ValueError('The key is not found.')
else:
import_keys(cfg.key, db)
key_imported = True
keys = db.get_key(chapter_id)
if len(keys) == 0:
raise ValueError('The key is not found.')
return keys
def try_decrypt(db: CwmDb, cfg: Config, content, chapter_id: int):
global key_force_imported
keys = get_key(db, cfg, chapter_id)
for key in keys:
try:
return decrypt(content, key).decode()
except Exception:
pass
if not key_force_imported:
import_keys(cfg.key, db, True)
key_force_imported = True
return try_decrypt(db, cfg, content, chapter_id)
raise ValueError('Failed to decrypt the content.')
def export_chapter(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew,
chapter_id: int):
chapter = ncw.get_chapter(chapter_id)
book_id = int(chapter['book_id'])
raw_content = bn.get_chapter(book_id, chapter_id)
content = try_decrypt(db, cfg, raw_content, chapter_id)
filename = cfg.get_export_chapter(chapter)
d = dirname(filename)
makedirs(d, exist_ok=True)
with open(filename, 'w', encoding='UTF-8') as f:
f.write(chapter['chapter_title'] + '\n')
f.write(content)
def export_book(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew,
book_id: int):
book = ncw.get_book_in_shelf(book_id)
if book is None:
book = ncw.get_book_in_readhistory(book_id)
if book is None:
raise ValueError('The book is not found.')
if cfg.export_txt:
txt_filename = cfg.get_export_book(book, 'txt')
d = dirname(txt_filename)
makedirs(d, exist_ok=True)
txt = open(txt_filename, 'w', encoding='UTF-8')
if cfg.export_epub:
try:
epub = EpubFile(cfg, cfg.get_export_book(book, 'epub'))
epub.set_book(book)
except Exception as e:
if cfg.export_txt:
txt.close()
raise e
try:
chapters = ncw.get_chapter_with_bookid(book_id)
divisions = ncw.get_divisions_with_bookid(book_id)
maps = {}
count = 0
for chapter in chapters:
division_id = chapter['division_id']
if division_id in maps:
maps[division_id].append(chapter)
else:
maps[division_id] = [chapter]
for division in divisions:
division_name = division['division_name']
division_id = division['division_id']
is_linear = db.get_mark(division_id)
if cfg.export_txt:
txt.write(f"{division['division_index']}{division_name}\n")
if division['description']:
txt.write(division['description'] + '\n\n')
if cfg.export_epub and division['description']:
print('TODO: add division description to epub.')
if division_id not in maps:
continue
chapter_index = 1
for chapter in maps[division_id]:
chapter_id = chapter['chapter_id']
chapter_title = chapter['chapter_title']
if chapter['is_download']:
raw_content = bn.get_chapter(book_id, chapter_id)
content = try_decrypt(db, cfg, raw_content, chapter_id)
if cfg.export_txt:
txt.write(f"{chapter_index}{chapter_title}\n")
txt.write(content + '\n\n')
if cfg.export_epub:
epub.add_chapter(chapter, content, division_name,
is_linear)
count += 1
elif cfg.export_nodownload:
if cfg.export_txt:
txt.write(f"{chapter_index}{chapter_title} (未下载)\n\n") # noqa: E501
if cfg.export_epub:
epub.add_nodownload_chapter(chapter, division_name,
is_linear)
chapter_index += 1
print(f'Exported {count} chapters.')
finally:
if cfg.export_txt:
txt.close()
if cfg.export_epub:
epub.save_epub_file()
def export_all(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew):
books = ncw.get_all_books()
for book in books:
book_id = int(book[0])
try:
export_book(ncw, db, cfg, bn, book_id)
except Exception as e:
print(f'Failed to export book {book_id}: {e}')
class ExportCli:
def __init__(self, ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew):
self.ncw = ncw
self.db = db
self.cfg = cfg
self.bn = bn
self.action = None
self.shelf = None
self.shelfs = None
self.book = None
self.book_id = None
self.division_id = None
self.fns = [self.ask_action]
def ask_action(self):
self.action = ask_choice(self.cfg, [], '请选择要导出的类型:', extra=[
('b', '整本书', 'book'), ('c', '单章', 'chapter'), ('a', '所有书', 'all'),
('m', '标记为非线性卷', 'mark')])
if self.action == 'all':
export_all(self.ncw, self.db, self.cfg, self.bn)
return
self.fns.append(self.ask_shelf)
def ask_book(self):
if self.shelf == 'readhistory':
books = [json.loads(b['book_info']) for b in self.ncw.get_read_history()] # noqa: E501
elif self.shelf == 'all':
bookids = [int(b[0]) for b in self.ncw.get_all_books()]
books = []
for bid in bookids:
book = self.ncw.get_book_in_shelf(bid) or self.ncw.get_book_in_readhistory(bid) # noqa: E501
if book:
books.append(book)
else:
books = [json.loads(b['book_info']) for b in self.shelfs[self.shelf]] # noqa: E501
self.book = ask_choice(self.cfg, books, '请选择书:', lambda b: f"{b['book_name']} - {b['author_name']}", [('b', '返回', 'back')]) # noqa: E501
if self.book == 'back':
self.fns.append(self.ask_shelf)
return
self.book_id = int(self.book['book_id'])
if self.action == 'book':
export_book(self.ncw, self.db, self.cfg, self.bn, self.book_id)
return
self.fns.append(self.ask_division)
def ask_chapter(self):
chapters = self.ncw.get_chapter_with_bookid_division(self.book_id, self.division_id) # noqa: E501
chapter = ask_choice(self.cfg, chapters, '请选择章节:', lambda b: b['chapter_title'], [('b', '返回', 'back')]) # noqa: E501
if chapter == 'back':
self.fns.append(self.ask_division)
return
chapter_id = int(chapter['chapter_id'])
export_chapter(self.ncw, self.db, self.cfg, self.bn, chapter_id)
def ask_division(self):
divisions = self.ncw.get_divisions_with_bookid(self.book_id)
extras = [('b', '返回', 'back')]
if self.action == 'mark':
extras.append(('q', '退出', 'quit'))
def show_division(division):
name = division['division_name']
if self.action == 'mark':
division_id = int(division['division_id'])
if not self.db.get_mark(division_id):
name += ' (非线性卷)'
return name
division = ask_choice(self.cfg, divisions, '请选择卷:', show_division, extras) # noqa: E501
if division == 'back':
self.fns.append(self.ask_book)
return
if division == 'quit':
return
self.division_id = int(division['division_id'])
if self.action == 'mark':
now = self.db.get_mark(self.division_id)
self.db.set_mark(self.division_id, not now)
self.fns.append(self.ask_division)
return
self.fns.append(self.ask_chapter)
def ask_shelf(self):
books = self.ncw.get_books()
self.shelfs = {}
for book in books:
shelf_id = book['shelf_id']
if shelf_id in self.shelfs:
self.shelfs[shelf_id].append(book)
else:
self.shelfs[shelf_id] = [book]
def show_shelf(shelf: str):
data = f"{shelf} ({len(self.shelfs[shelf])} 本书)"
book = json.loads(choice(self.shelfs[shelf])['book_info'])
data += f"\n书架内有 {book['book_name']} - {book['author_name']}"
return data
self.shelf = ask_choice(self.cfg, [i for i in self.shelfs.keys()],
'请选择书架:', show_shelf,
[('r', '阅读历史', 'readhistory'),
('a', '所有书', 'all'),
('b', '返回', 'back')])
if self.shelf == 'back':
self.fns.append(self.ask_action)
return
self.fns.append(self.ask_book)
def start(self):
while True:
if len(self.fns) == 0:
break
self.fns.pop(0)()