From 8a6518f4b603ff85d7753409fee3203a71e964c3 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 15 Mar 2024 21:00:36 +0800 Subject: [PATCH] Add mark as non-linear division mannally --- config.py | 8 +++ db.py | 26 ++++++++- epub.py | 12 ++-- export.py | 160 ++++++++++++++++++++++++++++++++++++++---------------- key.py | 2 +- main.py | 13 ++++- 6 files changed, 164 insertions(+), 57 deletions(-) diff --git a/config.py b/config.py index 7e8fa5d..019a159 100644 --- a/config.py +++ b/config.py @@ -63,6 +63,10 @@ class Config: def db(self): return self.get_arg('db', 'cwm.db') + @cached_property + def division_id(self): + return getattr(self._args, 'division_id', None) + @cached_property def export_book_template(self): return self.get_arg('export_book_template', 'exported/ - .') # noqa: E501 @@ -116,6 +120,10 @@ class Config: def key(self): return self.get_arg('key', None) + @cached_property + def linear(self): + return getattr(self._args, 'linear', False) + @cached_property def page_size(self): return self.get_arg('page_size', 10) diff --git a/db.py b/db.py index 04b0cb1..64dfdf4 100644 --- a/db.py +++ b/db.py @@ -14,12 +14,17 @@ user_id INT, key TEXT, PRIMARY KEY (chapter_id, user_id) );''' +DIVISION_TABLE = '''CREATE TABLE division( +division_id INT, +is_linear BOOL, +PRIMARY KEY(division_id) +);''' class CwmDb: def __init__(self, db_path): self._db = sqlite3.connect(db_path, check_same_thread=False) - self.version = Version(0, 0, 0, 0) + self.version = Version(0, 0, 0, 1) if not self.__check_database(): self.__create_table() @@ -29,6 +34,8 @@ class CwmDb: if v is None: return False if v < self.version: + if v < Version(0, 0, 0, 1): + self._db.execute(DIVISION_TABLE) self.__update_exists_tables() self.__write_version() return True @@ -44,6 +51,7 @@ class CwmDb: def __write_version(self): self._db.execute('INSERT OR REPLACE INTO version VALUES (?, ?);', [ 'main', str(self.version)]) + self._db.commit() def __read_version(self) -> Optional[Version]: if 'version' not in self._exist_tables: @@ -71,7 +79,23 @@ class CwmDb: cur = self._db.execute('SELECT chapter_id, user_id, key FROM key;') return {f'{i[0]}{i[1]}': i[2] for i in cur} + def commit(self): + self._db.commit() + def get_key(self, chapter_id: int) -> List[str]: cur = self._db.execute('SELECT key FROM key WHERE chapter_id = ?;', [ chapter_id]) return [i[0] for i in cur] + + def get_mark(self, division_id: int): + cur = self._db.execute( + 'SELECT is_linear FROM division WHERE division_id = ?;', + [division_id]) + for i in cur: + return bool(i[0]) + return True + + def set_mark(self, division_id: int, is_linear: bool): + self._db.execute('INSERT OR REPLACE INTO division VALUES (?, ?);', [ + division_id, is_linear]) + self._db.commit() diff --git a/epub.py b/epub.py index 2b292ea..05a0dd0 100644 --- a/epub.py +++ b/epub.py @@ -344,7 +344,8 @@ class EpubFile: self.epub.spine.append(intro) self.last_division_name = '' - def add_chapter(self, chapter, content: str, division_name: str): + def add_chapter(self, chapter, content: str, division_name: str, + is_linear: bool): chapter_title = chapter['chapter_title'] chapter_id = chapter['chapter_id'] ch = epub.EpubHtml( @@ -353,8 +354,7 @@ class EpubFile: lang='zh-CN', uid=f'ch{chapter_id}', ) - if division_name == '作品相关': - ch.is_linear = False + ch.is_linear = is_linear parser = ContentParser(self.cfg) contents = content.splitlines() try: @@ -392,7 +392,8 @@ class EpubFile: self.EpubList.append(ch) self.epub.spine.append(ch) - def add_nodownload_chapter(self, chapter, division_name: str): + def add_nodownload_chapter(self, chapter, division_name: str, + is_linear: bool): chapter_title = chapter['chapter_title'] chapter_id = chapter['chapter_id'] ch = epub.EpubHtml( @@ -401,8 +402,7 @@ class EpubFile: lang='zh-CN', uid=f'ch{chapter_id}', ) - if division_name == '作品相关': - ch.is_linear = False + ch.is_linear = is_linear ch.content = f'

{chapter_title}

\n

本章未下载

' # noqa: E501 self.epub.add_item(ch) if self.last_division_name != division_name: diff --git a/export.py b/export.py index 5c31856..12ef6ee 100644 --- a/export.py +++ b/export.py @@ -94,6 +94,7 @@ def export_book(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew, 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']: @@ -113,13 +114,15 @@ def export_book(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew, txt.write(f"第{chapter_index}章 {chapter_title}\n") txt.write(content + '\n\n') if cfg.export_epub: - epub.add_chapter(chapter, content, division_name) + 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) + epub.add_nodownload_chapter(chapter, division_name, + is_linear) chapter_index += 1 print(f'Exported {count} chapters.') finally: @@ -139,49 +142,114 @@ def export_all(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew): print(f'Failed to export book {book_id}: {e}') -def export(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew): - action = ask_choice(cfg, [], '请选择要导出的类型:', extra=[ - ('b', '整本书', 'book'), ('c', '单章', 'chapter'), - ('a', '所有书', 'all')]) - if action == 'all': - export_all(ncw, db, cfg, bn) - return - books = ncw.get_books() - shelfs = {} - for book in books: - shelf_id = book['shelf_id'] - if shelf_id in shelfs: - shelfs[shelf_id].append(book) - else: - shelfs[shelf_id] = [book] +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 show_shelf(shelf: str): - data = f"{shelf} ({len(shelfs[shelf])} 本书)" - book = json.loads(choice(shelfs[shelf])['book_info']) - data += f"\n书架内有 {book['book_name']} - {book['author_name']}" - return data - shelf = ask_choice(cfg, [i for i in shelfs.keys()], '请选择书架:', show_shelf, - [('r', '阅读历史', 'readhistory'), ('a', '所有书', 'all')]) - if shelf == 'readhistory': - books = [json.loads(b['book_info']) for b in ncw.get_read_history()] - elif shelf == 'all': - bookids = [int(b[0]) for b in ncw.get_all_books()] - books = [] - for bid in bookids: - book = ncw.get_book_in_shelf(bid) or ncw.get_book_in_readhistory(bid) # noqa: E501 - if book: - books.append(book) - else: - books = [json.loads(b['book_info']) for b in shelfs[shelf]] - book = ask_choice(cfg, books, '请选择书:', lambda b: f"{b['book_name']} - {b['author_name']}") # noqa: E501 - book_id = int(book['book_id']) - if action == 'book': - export_book(ncw, db, cfg, bn, book_id) - elif action == 'chapter': - divisions = ncw.get_divisions_with_bookid(book_id) - division = ask_choice(cfg, divisions, '请选择卷:', lambda b: b['division_name']) # noqa: E501 - division_id = int(division['division_id']) - chapters = ncw.get_chapter_with_bookid_division(book_id, division_id) - chapter = ask_choice(cfg, chapters, '请选择章节:', lambda b: b['chapter_title']) # noqa: E501 + 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(ncw, db, cfg, bn, 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)() diff --git a/key.py b/key.py index 781c9a6..4a2187b 100644 --- a/key.py +++ b/key.py @@ -43,6 +43,6 @@ def import_keys(key: str, db: CwmDb, force=False): count += 1 print(f'Imported {count} keys.') finally: - db._db.commit() + db.commit() if is_zip: z.close() diff --git a/main.py b/main.py index 03eaba0..cb8d6be 100644 --- a/main.py +++ b/main.py @@ -23,7 +23,9 @@ parser.add_argument('-s', '--page-size', help='Maximum size of a page when askin parser.add_argument('-a', '--export-nodownload', help='export not downloaded chapter when exporting book.', type=parse_bool, metavar='BOOL') # noqa: E501 parser.add_argument('-i', '--image-type', help='How to handle images in EPUB. Available types: inline, footnote. Default: inline', choices=['inline', 'footnote'], metavar='TYPE') # noqa: E501 parser.add_argument('-f', '--force', help='Force import keys.', action='store_true') # noqa: E501 -parser.add_argument('action', help='The action to do.', choices=['importkey', 'exportchapter', 'exportbook', 'export', 'exportall', 'ik', 'ec', 'eb', 'e', 'ea'], nargs='?', default='export') # noqa: E501 +parser.add_argument('-D', '--division-id', help='The division id.', type=int, metavar='ID') # noqa: E501 +parser.add_argument('-l', '--linear', help='Mark as linear.', type=parse_bool, metavar='BOOL', default=False) # noqa: E501 +parser.add_argument('action', help='The action to do.', choices=['importkey', 'exportchapter', 'exportbook', 'export', 'exportall', 'markaslinear', 'ik', 'ec', 'eb', 'e', 'ea', 'mal'], nargs='?', default='export') # noqa: E501 def main(args=None): @@ -75,8 +77,9 @@ def main(args=None): bn = BooksNew(cfg.booksnew) if not cfg.export_epub and not cfg.export_txt: raise ValueError('At least one export type should be specified.') # noqa: E501 - from export import export - export(ncw, db, cfg, bn) + from export import ExportCli + export = ExportCli(ncw, db, cfg, bn) + export.start() elif arg.action == "exportall" or arg.action == "ea": if cfg.cwmdb is None: raise ValueError('The cwmdb is not specified.') @@ -88,6 +91,10 @@ def main(args=None): raise ValueError('At least one export type should be specified.') # noqa: E501 from export import export_all export_all(ncw, db, cfg, bn) + elif arg.action == 'markaslinear' or arg.action == 'mal': + if cfg.division_id is None: + raise ValueError('The division id is not specified.') + db.set_mark(cfg.division_id, cfg.linear) finally: cfg.save()