From 4a39c3afb6e0d6e32b1881e2e193253c0815e961 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 8 Mar 2024 20:26:38 +0800 Subject: [PATCH] Add a choice --- README.md | 15 ++++++++++++++ config.py | 5 +++++ export.py | 40 +++++++++++++++++++++++++++++++++++-- main.py | 20 +++++++++++++++---- novelCiwei.py | 12 +++++++++++ utils.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 utils.py diff --git a/README.md b/README.md index 858b08d..85a1aba 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,18 @@ python -m venv venv source venv/bin/activate pip install -r requirements.txt ``` +# Usage +## Termux +```shell +sudo python main.py -r +# Only export as txt file +sudo python main.py --type=txt -r +# Only export as epub file +sudo python main.py --type=epub -r +# Export all supported type +sudo python main.py --type=epub,txt -r +# Export single chapter with chapter id +sudo python main.py ec -C +# Export book with book id +sudo python main.py eb -B +``` diff --git a/config.py b/config.py index a59e243..58624b9 100644 --- a/config.py +++ b/config.py @@ -21,6 +21,7 @@ class Config: self._data['type'] = 'epub,txt' self._data['export_book_template'] = 'exported/ - .' # noqa: E501 self._data['export_chapter_template'] = 'exported//.txt' # noqa: E501 + self._data['page_size'] = 10 self.save() def add_args(self, args: Namespace): @@ -100,6 +101,10 @@ class Config: def key(self): return self.get_arg('key', None) + @cached_property + def page_size(self): + return self.get_arg('page_size', 10) + @cached_property def save_to_config(self): return getattr(self._args, 'save_to_config', True) diff --git a/export.py b/export.py index 93f2502..5c9e154 100644 --- a/export.py +++ b/export.py @@ -7,6 +7,9 @@ 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 @@ -86,9 +89,9 @@ def export_book(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew, print('TODO: add division description to epub.') chapter_index = 1 for chapter in maps[division['division_id']]: + chapter_id = chapter['chapter_id'] + chapter_title = chapter['chapter_title'] if chapter['is_download']: - chapter_id = chapter['chapter_id'] - chapter_title = chapter['chapter_title'] raw_content = bn.get_chapter(book_id, chapter_id) content = try_decrypt(db, cfg, raw_content, chapter_id) if cfg.export_txt: @@ -107,3 +110,36 @@ def export_book(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew, txt.close() if cfg.export_epub: epub.save_epub_file() + + +def export(ncw: NovelCiwei, db: CwmDb, cfg: Config, bn: BooksNew): + action = ask_choice(cfg, [], '请选择要导出的类型:', extra=[ + ('b', '整本书', 'book'), ('c', '单章', 'chapter')]) + 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] + + 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) + 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 + chapter_id = int(chapter['chapter_id']) + export_chapter(ncw, db, cfg, bn, chapter_id) diff --git a/main.py b/main.py index 9f146c3..68ba141 100644 --- a/main.py +++ b/main.py @@ -18,7 +18,8 @@ parser.add_argument('-B', '--bid', '--book-id', help='The book id.', type=int) parser.add_argument('-t', '--type', help='Export type. Available types: epub, txt. Default: epub,txt') # noqa: E501 parser.add_argument('--ebt', '--export-book-template', help='The template of the exported book. Available key: , , , eta.') # noqa: E501 parser.add_argument('--icd', '--image-cache-dir', help='Path to image cache directory.') # noqa: E501 -parser.add_argument('action', help='The action to do.', choices=['importkey', 'exportchapter', 'exportbook']) # noqa: E501 +parser.add_argument('-s', '--page-size', help='Maximum size of a page when asking for choices.', type=int) # noqa: E501 +parser.add_argument('action', help='The action to do.', choices=['importkey', 'exportchapter', 'exportbook', 'export', 'ik', 'ec', 'eb', 'e'], nargs='?', default='export') # noqa: E501 def main(args=None): @@ -32,12 +33,12 @@ def main(args=None): cfg.add_args(arg) try: db = CwmDb(cfg.db) - if arg.action == 'importkey': + if arg.action == 'importkey' or arg.action == 'ik': if cfg.key is None: raise ValueError('The key is not specified.') from key import import_keys import_keys(cfg.key, db) - elif arg.action == 'exportchapter': + elif arg.action == 'exportchapter' or arg.action == 'ec': if cfg.cwmdb is None: raise ValueError('The cwmdb is not specified.') ncw = NovelCiwei(cfg.cwmdb) @@ -48,7 +49,7 @@ def main(args=None): raise ValueError('The chapter id is not specified.') from export import export_chapter export_chapter(ncw, db, cfg, bn, cfg.chapter_id) - elif arg.action == 'exportbook': + elif arg.action == 'exportbook' or arg.action == 'eb': if cfg.cwmdb is None: raise ValueError('The cwmdb is not specified.') ncw = NovelCiwei(cfg.cwmdb) @@ -61,6 +62,17 @@ def main(args=None): raise ValueError('At least one export type should be specified.') # noqa: E501 from export import export_book export_book(ncw, db, cfg, bn, cfg.book_id) + elif arg.action == 'export' or arg.action == 'e': + if cfg.cwmdb is None: + raise ValueError('The cwmdb is not specified.') + ncw = NovelCiwei(cfg.cwmdb) + if cfg.booksnew is None: + raise ValueError('The booksnew is not specified.') + 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) finally: cfg.save() diff --git a/novelCiwei.py b/novelCiwei.py index efce197..09dd4be 100644 --- a/novelCiwei.py +++ b/novelCiwei.py @@ -13,6 +13,11 @@ class NovelCiwei: for i in cur: return json.loads(i[0]) + def get_books(self): + cur = self._db.execute('SELECT * FROM shelf_book_info;') + cur.row_factory = sqlite3.Row + return cur.fetchall() + def get_chapter_with_bookid(self, book_id: int): cur = self._db.execute( 'SELECT * FROM catalog1 WHERE book_id = ? ORDER BY chapter_index;', @@ -20,6 +25,13 @@ class NovelCiwei: cur.row_factory = sqlite3.Row return cur.fetchall() + def get_chapter_with_bookid_division(self, book_id: int, division_id: int): + cur = self._db.execute( + 'SELECT * FROM catalog1 WHERE book_id = ? AND division_id = ? AND is_download = 1 ORDER BY chapter_index;', # noqa: E501 + [str(book_id), str(division_id)]) + cur.row_factory = sqlite3.Row + return cur.fetchall() + def get_divisions_with_bookid(self, book_id: int): cur = self._db.execute('SELECT * FROM division WHERE book_id = ? ORDER BY division_index;', [str(book_id)]) # noqa: E501 cur.row_factory = sqlite3.Row diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..5c9a3d0 --- /dev/null +++ b/utils.py @@ -0,0 +1,55 @@ +from config import Config +from math import ceil + + +def ask_choice(cfg: Config, choices: list, prompt='请选择:', fn=None, extra=None): + count = len(choices) + total_pages = ceil(count / cfg.page_size) + page = 1 + + def show_page(): + nonlocal page + base = (page - 1) * cfg.page_size + if total_pages > 1: + print(f"第{page}/{total_pages}页") + for i in range(cfg.page_size): + index = base + i + if index >= count: + break + s = fn(choices[index]) if fn else choices[index] + print(f"{i}. {s}") + if page > 1: + print("f. 第一页") + print("p. 上一页") + if page < total_pages: + print("n. 下一页") + print("l. 最后一页") + if extra is not None: + for t in extra: + print(f"{t[0]}. {t[1]}") + + while True: + show_page() + s = input(prompt) + if s == "f": + page = 1 + elif s == "p": + page = max(1, page - 1) + elif s == "n": + page = min(total_pages, page + 1) + elif s == "l": + page = total_pages + else: + if extra is not None: + for t in extra: + if t[0] == s: + return t[2] + try: + index = int(s) + except Exception: + continue + base = (page - 1) * cfg.page_size + index += base + if index < 0 or index >= count: + continue + return choices[index]