aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris2023-09-16 18:28:16 +0200
committerJoris2023-09-16 18:31:24 +0200
commit06f045e90bb57c36738e58ee6830e2a2391bc6a3 (patch)
treea5b65b048c103b4ea0e5d3c0fa5e115cbaf3cf5f
parent230f2e0623d22af6e68466884bd5dea5dcb846dc (diff)
Migrate CLI to python
-rw-r--r--.gitignore3
-rw-r--r--README.md14
-rwxr-xr-xbin/dev-server11
-rwxr-xr-xbin/get-books24
-rwxr-xr-xbin/view16
-rw-r--r--flake.nix13
-rw-r--r--src/library/__init__.py0
-rw-r--r--src/library/command.py21
-rw-r--r--src/main.py56
-rw-r--r--src/view/__init__.py0
-rw-r--r--src/view/client/book.ts (renamed from src/book.ts)0
-rw-r--r--src/view/client/lib/functions.ts (renamed from src/lib/functions.ts)0
-rw-r--r--src/view/client/lib/i18n.ts (renamed from src/lib/i18n.ts)0
-rw-r--r--src/view/client/lib/rx.ts (renamed from src/lib/rx.ts)0
-rw-r--r--src/view/client/lib/search.ts (renamed from src/lib/search.ts)0
-rw-r--r--src/view/client/main.ts (renamed from src/main.ts)0
-rw-r--r--src/view/client/view/books.ts (renamed from src/view/books.ts)1
-rw-r--r--src/view/client/view/components/modal.ts (renamed from src/view/components/modal.ts)0
-rw-r--r--src/view/client/view/filters.ts (renamed from src/view/filters.ts)0
-rw-r--r--src/view/command.py17
-rw-r--r--src/view/public/index.html (renamed from public/index.html)0
-rw-r--r--src/view/public/main.css (renamed from public/main.css)0
-rw-r--r--src/view/tsconfig.json (renamed from tsconfig.json)4
23 files changed, 120 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore
index 6bb7df2..f7a3017 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-public/*.js
+__pycache__
+src/view/public/*.js
diff --git a/README.md b/README.md
index 9c530de..d9ec3fd 100644
--- a/README.md
+++ b/README.md
@@ -25,18 +25,12 @@ read = "Read"
Each `metadata.toml` file correspond to a book, and there **must** be a cover
named `cover.ext` in the same directory. Any extension works.
-## Show library
-
-View the book library by running:
-
- ./bin/view browser-cmd path-to-books
-
## Dev server
-Enter nix shell:
+In nix shell (`nix develop`), run:
- nix develop
+ ./bin/dev-server path-to-books
-Then run the dev-server:
+## Show library
- ./bin/dev-server path-to-books
+ BOOK_LIBRARY=path-to-books python src/main.py library
diff --git a/bin/dev-server b/bin/dev-server
index 2d1bf99..c98fdc5 100755
--- a/bin/dev-server
+++ b/bin/dev-server
@@ -3,7 +3,7 @@ set -euo pipefail
cd $(dirname "$0")/..
if [ "$#" == 1 ]; then
- BOOK_DIR="$1"
+ BOOK_LIBRARY="$1"
else
echo "usage: $0 path-to-book-directory"
exit 1
@@ -11,17 +11,18 @@ fi
# Watch books
-BUILD_BOOKS_CMD="./bin/get-books $BOOK_DIR > public/books.js && echo public/books.js updated."
+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."
watchexec \
- --watch "$BOOK_DIR" \
+ --watch "$BOOK_LIBRARY" \
-- "$BUILD_BOOKS_CMD" &
# Watch TypeScript
+cd src/view
CHECK="echo -e 'Checking TypeScript…\n' && tsc --checkJs"
-BUILD="esbuild --bundle src/main.ts --target=es2017 --outdir=public"
+BUILD="esbuild --bundle main.ts --target=es2017 --outdir=public"
SHOW="echo -e '\nOpen $PWD/public/index.html'"
watchexec \
--clear \
- --watch src \
+ --watch client \
-- "$CHECK && $BUILD && $SHOW"
diff --git a/bin/get-books b/bin/get-books
deleted file mode 100755
index 1c9bf67..0000000
--- a/bin/get-books
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-cd $(dirname "$0")/..
-
-if [ "$#" == 1 ]; then
- BOOK_DIR="$1"
-else
- echo "usage: $0 path-to-book-directory"
- exit 1
-fi
-
-echo "const bookLibrary = ["
-
-for METADATA in $(find "$BOOK_DIR" -name 'metadata.toml'); do
- DIR=$(dirname "$METADATA")
- COVER=$(ls $DIR/cover.*)
-
- TOML=$(cat "$METADATA")
- WITH_COVER=$(echo -e "$TOML\ncover = \"$COVER\"")
- echo "$WITH_COVER" | toml2json
- echo ","
-done
-
-echo "]"
diff --git a/bin/view b/bin/view
deleted file mode 100755
index 4fd4efc..0000000
--- a/bin/view
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-cd $(dirname "$0")/..
-
-if [ "$#" == 2 ]; then
- BROWSER="$1"
- BOOK_DIR="$2"
-else
- echo "usage: $0 browser-cmd path-to-book-directory"
- exit 1
-fi
-
-TMP_DIR=$(mktemp --directory)
-cp public/* "$TMP_DIR"
-bin/get-books "$BOOK_DIR" > "$TMP_DIR/books.js"
-eval "$BROWSER $TMP_DIR/index.html"
diff --git a/flake.nix b/flake.nix
index 0f50d16..10c1430 100644
--- a/flake.nix
+++ b/flake.nix
@@ -8,15 +8,24 @@
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
+
+ ebook-convert = with pkgs; writeShellScriptBin "ebook-convert" ''
+ set -euo pipefail
+ ${calibre}/bin/ebook-convert "$@"
+ '';
in with pkgs; {
devShell = mkShell {
buildInputs = [
esbuild
nodePackages.typescript
psmisc # fuser
- python3
- toml2json
watchexec
+
+ # CLI
+ python311
+ python311Packages.requests
+ python311Packages.pillow
+ ebook-convert
];
};
}
diff --git a/src/library/__init__.py b/src/library/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/library/__init__.py
diff --git a/src/library/command.py b/src/library/command.py
new file mode 100644
index 0000000..6b8577e
--- /dev/null
+++ b/src/library/command.py
@@ -0,0 +1,21 @@
+import glob
+import json
+import os
+import tomllib
+
+def run(book_library):
+ print(get(book_library))
+
+def get(book_library):
+ metadatas = []
+
+ for path in glob.glob(f'{book_library}/**/metadata.toml', recursive=True):
+ with open(path, 'rb') as f:
+ directory = os.path.dirname(os.path.realpath(path))
+ metadata = tomllib.load(f)
+ for p in glob.glob(f'{directory}/cover.*'):
+ metadata['cover'] = p
+ break
+ metadatas.append(metadata)
+
+ return json.dumps(metadatas)
diff --git a/src/main.py b/src/main.py
new file mode 100644
index 0000000..618cc5a
--- /dev/null
+++ b/src/main.py
@@ -0,0 +1,56 @@
+# 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
+
+def print_help(title='Manage book library'):
+ print(f"""{title}
+
+- 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 [ _, '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/__init__.py b/src/view/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/view/__init__.py
diff --git a/src/book.ts b/src/view/client/book.ts
index 680cc11..680cc11 100644
--- a/src/book.ts
+++ b/src/view/client/book.ts
diff --git a/src/lib/functions.ts b/src/view/client/lib/functions.ts
index 21fdad9..21fdad9 100644
--- a/src/lib/functions.ts
+++ b/src/view/client/lib/functions.ts
diff --git a/src/lib/i18n.ts b/src/view/client/lib/i18n.ts
index 3716367..3716367 100644
--- a/src/lib/i18n.ts
+++ b/src/view/client/lib/i18n.ts
diff --git a/src/lib/rx.ts b/src/view/client/lib/rx.ts
index bf01b6d..bf01b6d 100644
--- a/src/lib/rx.ts
+++ b/src/view/client/lib/rx.ts
diff --git a/src/lib/search.ts b/src/view/client/lib/search.ts
index 026cb94..026cb94 100644
--- a/src/lib/search.ts
+++ b/src/view/client/lib/search.ts
diff --git a/src/main.ts b/src/view/client/main.ts
index 5885871..5885871 100644
--- a/src/main.ts
+++ b/src/view/client/main.ts
diff --git a/src/view/books.ts b/src/view/client/view/books.ts
index 5ec019a..aba55c1 100644
--- a/src/view/books.ts
+++ b/src/view/client/view/books.ts
@@ -66,6 +66,7 @@ function viewBook({ book, onSelect }: ViewBookParams): Html {
{ className: 'g-Book' },
h('img',
{ src: book.cover,
+ alt: book.title,
className: 'g-Book__Image',
onclick: () => onSelect(book)
}
diff --git a/src/view/components/modal.ts b/src/view/client/view/components/modal.ts
index 5e845e1..5e845e1 100644
--- a/src/view/components/modal.ts
+++ b/src/view/client/view/components/modal.ts
diff --git a/src/view/filters.ts b/src/view/client/view/filters.ts
index efe4115..efe4115 100644
--- a/src/view/filters.ts
+++ b/src/view/client/view/filters.ts
diff --git a/src/view/command.py b/src/view/command.py
new file mode 100644
index 0000000..e50027f
--- /dev/null
+++ b/src/view/command.py
@@ -0,0 +1,17 @@
+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(' '))
diff --git a/public/index.html b/src/view/public/index.html
index ce4d568..ce4d568 100644
--- a/public/index.html
+++ b/src/view/public/index.html
diff --git a/public/main.css b/src/view/public/main.css
index f361cbe..f361cbe 100644
--- a/public/main.css
+++ b/src/view/public/main.css
diff --git a/tsconfig.json b/src/view/tsconfig.json
index 6c9e683..1e07c37 100644
--- a/tsconfig.json
+++ b/src/view/tsconfig.json
@@ -2,12 +2,12 @@
"compilerOptions": {
"module": "amd",
"target": "es2020",
- "baseUrl": "src",
+ "baseUrl": "client",
"outFile": "public/main.js",
"noImplicitAny": true,
"strictNullChecks": true,
"removeComments": true,
"preserveConstEnums": true
},
- "include": ["src/**/*"]
+ "include": ["client/**/*"]
}