Add a choice
This commit is contained in:
15
README.md
15
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 <chapterid>
|
||||
# Export book with book id
|
||||
sudo python main.py eb -B <bookid>
|
||||
```
|
||||
|
||||
@@ -21,6 +21,7 @@ class Config:
|
||||
self._data['type'] = 'epub,txt'
|
||||
self._data['export_book_template'] = 'exported/<book_name> - <author_name>.<ext>' # noqa: E501
|
||||
self._data['export_chapter_template'] = 'exported/<book_id>/<chapter_id>.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)
|
||||
|
||||
40
export.py
40
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)
|
||||
|
||||
20
main.py
20
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: <ext>, <book_id>, <book_name>, <author_name> 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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
55
utils.py
Normal file
55
utils.py
Normal file
@@ -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]
|
||||
Reference in New Issue
Block a user