Merge branch '0.8.0--dev' into collections_refactor

This commit is contained in:
th3r00t
2025-08-05 00:19:01 -04:00
committed by GitHub
15 changed files with 83 additions and 1749 deletions

6
.tern-config vendored
View File

@@ -1,6 +0,0 @@
{
“plugins”:
{
“node”: {}
}
}

33
_Pipfile vendored
View File

@@ -1,33 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
websockets = "*"
loguru = "*"
pypdf2 = "*"
bs4 = "*"
requests = "*"
psycopg2-binary = "*"
mobi-python = "*"
psycopg = "*"
lxml = "*"
"sqlalchemy.orm" = "*"
sqlalchemy = "==2.0.0b3"
fastapi = {extras = ["all"], version = "*"}
jinja2 = "*"
libsass = "*"
nodejs-bin = "*"
npm = "*"
brotlipy = "*"
[dev-packages]
debugpy = "*"
pudb = "*"
ptipython = "*"
chardet = "*"
pre-commit = "*"
[requires]
python_version = "3.11.2"

1579
_Pipfile.lock generated vendored

File diff suppressed because it is too large Load Diff

28
docker/Dockerfile vendored
View File

@@ -9,20 +9,30 @@
# docker login # docker login
# docker push pyshelf/pyshelf # docker push pyshelf/pyshelf
FROM ubuntu FROM ubuntu:latest
EXPOSE 8000 EXPOSE 8080
EXPOSE 1337 EXPOSE 1337
RUN apt-get update -y RUN apt-get update -y
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential python3 python3-dev python3-pip python3-venv RUN apt-get upgrade -y
RUN apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev \
libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget \
libbz2-dev curl -y
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
RUN export NVM_DIR="$HOME/.nvm" ; \
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" ; nvm install 14 npm
WORKDIR /tmp
RUN wget https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tgz
RUN tar -xf Python-3.12.0.tgz
WORKDIR /tmp/Python-3.12.0/
RUN ./configure --enable-optimizations
RUN make -j 4
RUN make install
COPY . /pyshelf COPY . /pyshelf
COPY ./docker/config.json /pyshelf/config.json COPY ./docker/config.json /pyshelf/config.json
COPY ./docker/requirements.txt /pyshelf/requirements.txt
WORKDIR /pyshelf/ WORKDIR /pyshelf/
RUN python3 -m pip install -r requirements.txt RUN python3 -m pip install --no-cache-dir -r requirements.txt
ENTRYPOINT hatch run ./pyShelf.py
ENTRYPOINT python3 configure \
&& cd src/ \
&& daphne -b 0.0.0.0 -p 8000 frontend.asgi:application

2
docker/README.md vendored
View File

@@ -2,5 +2,3 @@ Use `docker build -t pyshelf/pyshelf -f ./docker/Dockerfile .` in the project ro
Make sure the following files are in sync: Make sure the following files are in sync:
* config.json * config.json
* docker/pyshelf_nginx.conf
* uwsgi.ini

20
docker/config.json vendored
View File

@@ -1 +1,19 @@
{"TITLE": "pyShelf E-Book Server", "VERSION": "0.7.0", "BOOKPATH": "/books", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": ["localhost", "127.0.0.1", "[::1]", "0.0.0.0"], "SECRET": "", "BUILD_MODE": "production"} {
"TITLE": "pyShelf E-Book Server",
"VERSION": "0.8.0",
"BOOKPATH": "/books",
"DB_HOST": "127.0.0.1",
"DB_PORT": "5433",
"DB_ENGINE": "sqlite",
"DATABASE": "pyshelf",
"USER": "pyshelf",
"PASSWORD": "pyshelf",
"BOOKSHELF": "data/shelf.json",
"ALLOWED_HOSTS": [
"localhost",
"127.0.0.1",
"[::1]",
"0.0.0.0"
],
"BUILD_MODE": "production"
}

View File

@@ -9,14 +9,16 @@ version: "3.7"
# docker-compose -f ./docker/development.docker-compose.yml up --build # docker-compose -f ./docker/development.docker-compose.yml up --build
services: services:
db: # db:
image: "postgres" # image: "postgres"
environment: # environment:
- "POSTGRES_PASSWORD=pyshelf" # - "POSTGRES_PASSWORD=pyshelf"
- "POSTGRES_USER=pyshelf" # - "POSTGRES_USER=pyshelf"
- "POSTGRES_DB=pyshelf" # - "POSTGRES_DB=pyshelf"
volumes: # volumes:
- "db_data:/var/lib/postgresql/data/" # - "db_data:/var/lib/postgresql/data/"
# ports:
# - "5433:5432"
pyshelf: pyshelf:
build: build:
@@ -27,8 +29,8 @@ services:
- "1337:1337" - "1337:1337"
volumes: volumes:
- "${LOCAL_BOOK_DIR}:/books" - "${LOCAL_BOOK_DIR}:/books"
depends_on: # depends_on:
- db # - db
volumes: # volumes:
db_data: # db_data:

View File

@@ -1,15 +1,17 @@
version: "3.7" version: "3.7"
services: services:
db: # db:
image: "postgres" # image: "postgres"
restart: always # restart: always
environment: # environment:
- "POSTGRES_PASSWORD=pyshelf" # - "POSTGRES_PASSWORD=pyshelf"
- "POSTGRES_USER=pyshelf" # - "POSTGRES_USER=pyshelf"
- "POSTGRES_DB=pyshelf" # - "POSTGRES_DB=pyshelf"
volumes: # volumes:
- "db_data:/var/lib/postgresql/data/" # - "db_data:/var/lib/postgresql/data/"
# ports:
# - "5433:5432"
pyshelf: pyshelf:
image: "pyshelf/pyshelf" image: "pyshelf/pyshelf"
restart: always restart: always
@@ -18,7 +20,7 @@ services:
- "1337:1337" - "1337:1337"
volumes: volumes:
- "${LOCAL_BOOK_DIR}:/books" - "${LOCAL_BOOK_DIR}:/books"
depends_on: # depends_on:
- db # - db
volumes: #volumes:
db_data: # db_data:

View File

@@ -1,30 +0,0 @@
upstream django {
server unix:///tmp/pyshelf_wsgi.sock;
}
server {
listen 8000;
server_name localhost;
access_log /var/log/nginx/pyshelf.access.log;
error_log /var/log/nginx/pyshelf.error.log;
charset utf-8;
client_max_body_size 75M;
location /media {
root /pyshelf/src/interface;
}
location /static {
root /pyshelf/src/interface;
}
location /books {
internal;
alias /pyshelf;
}
location / {
uwsgi_pass django;
include uwsgi_params;
}
}

1
docker/requirements.txt vendored Normal file
View File

@@ -0,0 +1 @@
hatch

3
pyShelf.py vendored Executable file → Normal file
View File

@@ -6,7 +6,6 @@ from pathlib import Path
from threading import Thread from threading import Thread
from src.backend.lib.config import Config from src.backend.lib.config import Config
from src.backend.lib.storage import Storage from src.backend.lib.storage import Storage
from src.backend.pyShelf_MakeCollections import MakeCollections
from src.backend.pyShelf_ScanLibrary import execute_scan from src.backend.pyShelf_ScanLibrary import execute_scan
from src.frontend.lib.FastAPIServer import FastAPIServer from src.frontend.lib.FastAPIServer import FastAPIServer
# import websockets # import websockets
@@ -23,7 +22,7 @@ def run_import():
config.logger.info("Begining book import.") config.logger.info("Begining book import.")
execute_scan(PRG_PATH, config=config) execute_scan(PRG_PATH, config=config)
config.logger.info("Finished book import.") config.logger.info("Finished book import.")
MakeCollections(PRG_PATH, config=config) # MakeCollections(PRG_PATH, config=config)
return "Import Complete" return "Import Complete"

6
pyproject.toml vendored
View File

@@ -90,8 +90,4 @@ include_trailing_comma = true
line_length = 88 line_length = 88
multi_line_output = 3 multi_line_output = 3
use_parentheses = true use_parentheses = true
known_third_party = [ known_third_party = ["backend", "bs4", "django", "interface", "mobi", "prompt_toolkit", "psycopg2-binary", "pyfiglet", "requests"]
"backend", "bs4", "django", "interface", "mobi", "prompt_toolkit",
"psycopg2", "pyfiglet", "requests"
]

View File

@@ -1,5 +1,6 @@
from typing import Optional from typing import Optional
from typing_extensions import Annotated from typing_extensions import Annotated
from sqlalchemy import func, ForeignKey from sqlalchemy import func, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
import datetime import datetime
@@ -50,37 +51,3 @@ class Collection(Base):
# Each collection entry points to one book # Each collection entry points to one book
book = relationship("Book", back_populates="collections") book = relationship("Book", back_populates="collections")
# class Book(Base):
# """Book model."""
#
# __tablename__ = "Book"
#
# id: Mapped[int] = mapped_column(primary_key=True, nullable=False)
# title: Mapped[str]
# author: Mapped[Optional[str]]
# categories: Mapped[Optional[str]]
# cover: Mapped[Optional[bytes]]
# pages: Mapped[Optional[int]]
# progress: Mapped[Optional[float]]
# file_name: Mapped[str]
# description: Mapped[Optional[str]]
# date: Mapped[timestamp]
# rights: Mapped[Optional[str]]
# tags: Mapped[Optional[str]]
# identifier: Mapped[Optional[str]]
# publisher: Mapped[Optional[str]]
# collection = relationship("Collection", back_populates="book")
#
#
# class Collection(Base):
# """Collection model."""
#
# __tablename__ = "Collection"
#
# id: Mapped[int] = mapped_column(primary_key=True)
# collection: Mapped[str]
# book_id: Mapped[int] = mapped_column(ForeignKey(Book.id))
# book = relationship("Book", back_populates="collections")

View File

@@ -86,7 +86,8 @@ class Storage:
cover_image = None cover_image = None
if not book[1]: if not book[1]:
pass pass
collections = self.parse_collections_from_path(book) # collections = self.parse_collections_from_path(book)
# breakpoint()
_book = Book( _book = Book(
title=book[0], title=book[0],
author=book[1], author=book[1],
@@ -173,6 +174,7 @@ class Storage:
_q = _sess.execute( _q = _sess.execute(
select(Collection.id).where( select(Collection.id).where(
Collection.collection == _s, Collection.collection == _s,
# BUG: book.id is not the correct identifier.
Collection.book_id == book.id, Collection.book_id == book.id,
) )
) )

View File

@@ -1,6 +1,4 @@
"""pyShelf's Frontend Objects.""" """pyShelf's Frontend Objects."""
from sys import exit
from shutil import which
from subprocess import run from subprocess import run
from pathlib import Path from pathlib import Path
from ...backend.lib.config import Config from ...backend.lib.config import Config
@@ -16,16 +14,5 @@ class JSInterface():
def install(self): def install(self):
"""Install the JavaScript dependencies.""" """Install the JavaScript dependencies."""
if which("npm"): run(["npm", "install"], cwd=self.package_json.parent)
self.config.logger.info("Installing JavaScript dependencies...") run(["npx", "tsc", "static/script/pyshelf.ts"], cwd=self.package_json.parent)
run(["npm", "install"], cwd=self.package_json.parent)
else:
self.config.logger.error("npm is not installed.")
exit(1)
if which("npx"):
self.config.logger.info("Compiling TypeScript...")
run(["npx", "tsc", "static/script/pyshelf.ts"], cwd=self.package_json.parent)
else:
self.config.logger.error("npx is not installed.")
exit(1)