diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README.md | 5 | ||||
-rwxr-xr-x | bin/dev-server | 8 | ||||
-rwxr-xr-x | books | 6 | ||||
-rw-r--r-- | cli/__init__.py (renamed from src/library/__init__.py) | 0 | ||||
-rw-r--r-- | cli/library/__init__.py (renamed from src/new/__init__.py) | 0 | ||||
-rw-r--r-- | cli/library/command.py (renamed from src/library/command.py) | 8 | ||||
-rw-r--r-- | cli/main.py | 80 | ||||
-rw-r--r-- | cli/new/__init__.py (renamed from src/view/__init__.py) | 0 | ||||
-rw-r--r-- | cli/new/command.py (renamed from src/new/command.py) | 14 | ||||
-rw-r--r-- | cli/new/format.py (renamed from src/new/format.py) | 8 | ||||
-rw-r--r-- | cli/new/reader.py (renamed from src/new/reader.py) | 0 | ||||
-rw-r--r-- | cli/view/__init__.py | 0 | ||||
-rw-r--r-- | cli/view/command.py | 16 | ||||
-rw-r--r-- | flake.nix | 2 | ||||
-rw-r--r-- | library/client/book.ts (renamed from src/view/client/book.ts) | 0 | ||||
-rw-r--r-- | library/client/lib/functions.ts (renamed from src/view/client/lib/functions.ts) | 0 | ||||
-rw-r--r-- | library/client/lib/i18n.ts (renamed from src/view/client/lib/i18n.ts) | 0 | ||||
-rw-r--r-- | library/client/lib/rx.ts (renamed from src/view/client/lib/rx.ts) | 0 | ||||
-rw-r--r-- | library/client/lib/search.ts (renamed from src/view/client/lib/search.ts) | 0 | ||||
-rw-r--r-- | library/client/main.ts (renamed from src/view/client/main.ts) | 0 | ||||
-rw-r--r-- | library/client/view/books.ts (renamed from src/view/client/view/books.ts) | 0 | ||||
-rw-r--r-- | library/client/view/components/modal.ts (renamed from src/view/client/view/components/modal.ts) | 0 | ||||
-rw-r--r-- | library/client/view/filters.ts (renamed from src/view/client/view/filters.ts) | 0 | ||||
-rw-r--r-- | library/public/index.html (renamed from src/view/public/index.html) | 0 | ||||
-rw-r--r-- | library/public/main.css (renamed from src/view/public/main.css) | 0 | ||||
-rw-r--r-- | library/tsconfig.json (renamed from src/view/tsconfig.json) | 0 | ||||
-rw-r--r-- | setup.py | 12 | ||||
-rw-r--r-- | src/main.py | 71 | ||||
-rw-r--r-- | src/view/command.py | 17 |
31 files changed, 137 insertions, 122 deletions
@@ -1,2 +1,2 @@ __pycache__ -src/view/public/*.js +library/public/*.js @@ -1,9 +1,11 @@ -build: +build: library/public/main.js + +library/public/main.js: @esbuild \ - --bundle src/main.ts \ + --bundle library/client/main.ts \ --minify \ --target=es2017 \ - --outdir=public + --outdir=library/public clean: - @rm -f public/main.js + @rm -f library/public/*.js @@ -33,8 +33,9 @@ In nix shell (`nix develop`), run: ## Show library - BOOK_LIBRARY=path-to-books python src/main.py library + make + BOOKS_LIBRARY=path-to-books BOOKS_BROWSER=firefox python src/main.py library ## Add book - BOOK_LIBRARY=path-to-books python src/main.py new optional-path-to-ebook + BOOKS_LIBRARY=path-to-books python src/main.py new optional-path-to-ebook diff --git a/bin/dev-server b/bin/dev-server index c98fdc5..7351209 100755 --- a/bin/dev-server +++ b/bin/dev-server @@ -3,7 +3,7 @@ set -euo pipefail cd $(dirname "$0")/.. if [ "$#" == 1 ]; then - BOOK_LIBRARY="$1" + BOOKS_LIBRARY="$1" else echo "usage: $0 path-to-book-directory" exit 1 @@ -11,14 +11,14 @@ fi # Watch books -BUILD_BOOKS_CMD="echo \"const bookLibrary=\" > src/view/public/books.js && python src/main.py library >> src/view/public/books.js && echo src/view/public/books.js updated." +BUILD_BOOKS_CMD="echo \"const bookLibrary=\" > library/public/books.js && ./books library >> library/public/books.js && echo library/public/books.js updated." watchexec \ - --watch "$BOOK_LIBRARY" \ + --watch "$BOOKS_LIBRARY" \ -- "$BUILD_BOOKS_CMD" & # Watch TypeScript -cd src/view +cd library CHECK="echo -e 'Checking TypeScript…\n' && tsc --checkJs" BUILD="esbuild --bundle main.ts --target=es2017 --outdir=public" SHOW="echo -e '\nOpen $PWD/public/index.html'" @@ -0,0 +1,6 @@ +#!/usr/bin/env python +import cli.main +import os + +bin_dir = os.path.dirname(os.path.realpath(__file__)) +cli.main.main(bin_dir) diff --git a/src/library/__init__.py b/cli/__init__.py index e69de29..e69de29 100644 --- a/src/library/__init__.py +++ b/cli/__init__.py diff --git a/src/new/__init__.py b/cli/library/__init__.py index e69de29..e69de29 100644 --- a/src/new/__init__.py +++ b/cli/library/__init__.py diff --git a/src/library/command.py b/cli/library/command.py index 6b8577e..1c4d20c 100644 --- a/src/library/command.py +++ b/cli/library/command.py @@ -3,13 +3,13 @@ import json import os import tomllib -def run(book_library): - print(get(book_library)) +def run(books_library): + print(get(books_library)) -def get(book_library): +def get(books_library): metadatas = [] - for path in glob.glob(f'{book_library}/**/metadata.toml', recursive=True): + for path in glob.glob(f'{books_library}/**/metadata.toml', recursive=True): with open(path, 'rb') as f: directory = os.path.dirname(os.path.realpath(path)) metadata = tomllib.load(f) diff --git a/cli/main.py b/cli/main.py new file mode 100644 index 0000000..01434fa --- /dev/null +++ b/cli/main.py @@ -0,0 +1,80 @@ +# Manage book library. +# +# Required dependencies: +# +# - python >= 3.11 +# - requests +# - pillow +# - ebook-convert CLI (from calibre) + +import cli.library.command +import cli.new.command +import cli.view.command +import os +import sys + +def main(bin_dir): + match sys.argv: + case [ _, 'new' ]: + books_library = get_books_library() + cli.new.command.run(books_library) + case [ _, 'new', book_source ]: + if os.path.isfile(book_source): + books_library = get_books_library() + cli.new.command.run(books_library, book_source) + else: + print_help(title=f'File not found: {book_source}.') + exit(1) + case [ _, 'library' ]: + books_library = get_books_library() + cli.library.command.run(books_library) + case [ _, 'view' ]: + books_library = get_books_library() + books_browser = get_env_var('BOOKS_BROWSER') + cli.view.command.run(books_library, books_browser, bin_dir) + case [ _, '--help' ]: + print_help() + case [ _, '-h' ]: + print_help() + case _: + print_help('Command not found.') + exit(1) + +def get_books_library(): + books_library = get_env_var('BOOKS_LIBRARY') + if os.path.isdir(books_library): + return books_library + else: + print_help(title=f'BOOKS_LIBRARY {books_library} not found.') + exit(1) + +def get_env_var(key): + value = os.getenv(key) + if value: + return value + else: + print_help(title=f'{key} environment variable is required.') + exit(1) + +def print_help(title='Manage book library'): + print(f"""{title} + +- Insert book entry with optional ebook file: + + $ python {sys.argv[0]} new [path-to-book] + +- Print library metadata as json: + + $ python {sys.argv[0]} library + +- View books in web page: + + $ python {sys.argv[0]} view + +Environment variables: + + BOOKS_LIBRARY: path to book library, + BOOKS_BROWSER: browser command executed to view the library.""") + +if __name__ == "__main__": + main() diff --git a/src/view/__init__.py b/cli/new/__init__.py index e69de29..e69de29 100644 --- a/src/view/__init__.py +++ b/cli/new/__init__.py diff --git a/src/new/command.py b/cli/new/command.py index fe706c2..9f5e5dc 100644 --- a/src/new/command.py +++ b/cli/new/command.py @@ -1,19 +1,14 @@ import PIL.Image +import cli.new.format as format +import cli.new.reader as reader import io import os import pathlib -import re import requests import shutil import subprocess -import sys -import unicodedata -import urllib.request -import new.reader as reader -import new.format as format - -def run(book_library, book_source=None): +def run(books_library, book_source=None): # Get data @@ -33,8 +28,7 @@ def run(book_library, book_source=None): author_path = format.path_part(author_sort) title_path = format.path_part(title) - library_path = '/home/joris/documents/books' - output_dir = f'{library_path}/{author_path}/{title_path}' + output_dir = f'{books_library}/{author_path}/{title_path}' metadata_path = f'{output_dir}/metadata.toml' cover_path = f'{output_dir}/cover.webp' diff --git a/src/new/format.py b/cli/new/format.py index a712544..c004f82 100644 --- a/src/new/format.py +++ b/cli/new/format.py @@ -1,14 +1,6 @@ -import PIL.Image -import io -import os import pathlib import re -import requests -import shutil -import subprocess -import sys import unicodedata -import urllib.request def format_list(xs): return '[ ' + ', '.join([f'"{x}"' for x in xs]) + ' ]' diff --git a/src/new/reader.py b/cli/new/reader.py index eacd70b..eacd70b 100644 --- a/src/new/reader.py +++ b/cli/new/reader.py diff --git a/cli/view/__init__.py b/cli/view/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cli/view/__init__.py diff --git a/cli/view/command.py b/cli/view/command.py new file mode 100644 index 0000000..72e44dd --- /dev/null +++ b/cli/view/command.py @@ -0,0 +1,16 @@ +import cli.library.command +import shutil +import subprocess +import subprocess +import tempfile +import time + +def run(books_library, books_browser, bin_dir): + tmp_dir = tempfile.mkdtemp() + shutil.copytree(f'{bin_dir}/library/public', tmp_dir, dirs_exist_ok=True) + subprocess.run(['chmod', 'u+w', tmp_dir]) + with open(f'{tmp_dir}/books.js', 'w') as f: + json = cli.library.command.get(books_library) + f.write(f'const bookLibrary = {json}') + browser_cmd = f'{books_browser} {tmp_dir}/index.html' + subprocess.run(browser_cmd.split(' ')) @@ -23,8 +23,8 @@ # CLI python311 - python311Packages.requests python311Packages.pillow + python311Packages.requests ebook-convert ]; }; diff --git a/src/view/client/book.ts b/library/client/book.ts index 680cc11..680cc11 100644 --- a/src/view/client/book.ts +++ b/library/client/book.ts diff --git a/src/view/client/lib/functions.ts b/library/client/lib/functions.ts index 21fdad9..21fdad9 100644 --- a/src/view/client/lib/functions.ts +++ b/library/client/lib/functions.ts diff --git a/src/view/client/lib/i18n.ts b/library/client/lib/i18n.ts index 3716367..3716367 100644 --- a/src/view/client/lib/i18n.ts +++ b/library/client/lib/i18n.ts diff --git a/src/view/client/lib/rx.ts b/library/client/lib/rx.ts index bf01b6d..bf01b6d 100644 --- a/src/view/client/lib/rx.ts +++ b/library/client/lib/rx.ts diff --git a/src/view/client/lib/search.ts b/library/client/lib/search.ts index 026cb94..026cb94 100644 --- a/src/view/client/lib/search.ts +++ b/library/client/lib/search.ts diff --git a/src/view/client/main.ts b/library/client/main.ts index 5885871..5885871 100644 --- a/src/view/client/main.ts +++ b/library/client/main.ts diff --git a/src/view/client/view/books.ts b/library/client/view/books.ts index aba55c1..aba55c1 100644 --- a/src/view/client/view/books.ts +++ b/library/client/view/books.ts diff --git a/src/view/client/view/components/modal.ts b/library/client/view/components/modal.ts index 5e845e1..5e845e1 100644 --- a/src/view/client/view/components/modal.ts +++ b/library/client/view/components/modal.ts diff --git a/src/view/client/view/filters.ts b/library/client/view/filters.ts index efe4115..efe4115 100644 --- a/src/view/client/view/filters.ts +++ b/library/client/view/filters.ts diff --git a/src/view/public/index.html b/library/public/index.html index ce4d568..ce4d568 100644 --- a/src/view/public/index.html +++ b/library/public/index.html diff --git a/src/view/public/main.css b/library/public/main.css index f361cbe..f361cbe 100644 --- a/src/view/public/main.css +++ b/library/public/main.css diff --git a/src/view/tsconfig.json b/library/tsconfig.json index 1e07c37..1e07c37 100644 --- a/src/view/tsconfig.json +++ b/library/tsconfig.json diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..c2bae59 --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +import setuptools + +setuptools.setup( + name="books", + version="1.0.0", + author="Joris Guyonvarch", + description="Visualize a book library", + long_description_content_type="text/markdown", + url="https://git.guyonvarch.me/books", + packages=setuptools.find_packages(), + scripts=['./books'] +) diff --git a/src/main.py b/src/main.py deleted file mode 100644 index 1f07785..0000000 --- a/src/main.py +++ /dev/null @@ -1,71 +0,0 @@ -# Manage book library. -# -# Required dependencies: -# -# - python >= 3.11 -# - requests -# - pillow -# - ebook-convert CLI (from calibre) - -import sys -import os - -import library.command -import view.command -import new.command - -def print_help(title='Manage book library'): - print(f"""{title} - -- Insert book entry with optional ebook file: - - $ python {sys.argv[0]} new [path-to-book] - -- Print library metadata as json: - - $ python {sys.argv[0]} library - -- View books in web page: - - $ python {sys.argv[0]} view browser-cmd - -Environment variables: - - BOOK_LIBRARY: path to book library.""") - -def get_book_library(): - path = os.getenv('BOOK_LIBRARY') - if path is None or not os.path.isdir(path): - print_help(title='BOOK_LIBRARY environment variable is required.') - exit(1) - else: - return path - -def main(): - match sys.argv: - case [ _, 'new' ]: - book_library = get_book_library() - new.command.run(book_library) - case [ _, 'new', book_source ]: - if os.path.isfile(book_source): - book_library = get_book_library() - new.command.run(book_library, book_source) - else: - print_help(title=f'File not found: {book_source}.') - exit(1) - case [ _, 'library' ]: - book_library = get_book_library() - library.command.run(book_library) - case [ _, 'view', browser_cmd ]: - book_library = get_book_library() - view.command.run(book_library, browser_cmd) - case [ _, '--help' ]: - print_help() - case [ _, '-h' ]: - print_help() - case _: - print_help('Command not found.') - exit(1) - -if __name__ == "__main__": - main() diff --git a/src/view/command.py b/src/view/command.py deleted file mode 100644 index e50027f..0000000 --- a/src/view/command.py +++ /dev/null @@ -1,17 +0,0 @@ -import os -import shutil -import subprocess -import tempfile -import time - -import library.command - -def run(book_library, browser_cmd): - tmp_dir = tempfile.mkdtemp() - directory = os.path.dirname(os.path.realpath(__file__)) - shutil.copytree(f'{directory}/public', tmp_dir, dirs_exist_ok=True) - with open(f'{tmp_dir}/books.js', 'w') as f: - json = library.command.get(book_library) - f.write(f'const bookLibrary = {json}') - browser_cmd = f'{browser_cmd} {tmp_dir}/index.html' - subprocess.run(browser_cmd.split(' ')) |