pyrotechny-eu/cmd/calibre_to_torrent.py

146 lines
3.8 KiB
Python
Executable File

#!/Applications/calibre.app/Contents/MacOS/calibre-debug calibre_to_torrent.py
# See: https://manual.calibre-ebook.com/db_api.html
import os
import json
import copy
import shutil
import pathlib
import hashlib
import urllib
import calibre.library
import config
class CalibreLibrary: pass
class CalibreLibraryBook:
_db: CalibreLibrary
id: int
title: str
authors: str
filepath: str
filehash: str
filename: str
cover: str
def __init__(self, db: CalibreLibrary):
self._db = db
self.cover = None
self.filehash = None
""" Get book properties for JSON serialize """
def to_json(self):
data = {}
for key in list(self.__dict__.keys()):
if key.startswith("_"):
continue
data[key] = self.__dict__[key]
return data
""" Generate the ebook filename based on the ebook file hash """
def ebook_filename(self) -> str:
title = self.title
ext = pathlib.Path(self.filepath).suffix
self.filename = f"{title}{ext}"
self.filename = self.filename.replace(",", ".")
self.filename = self.filename.replace(";", "")
self.filename = self.filename.replace(":", ".")
self.filename = self.filename.replace("/", "-")
self.filename = self.filename.replace("'", "")
self.filename = self.filename.replace(" ", ".")
self.filename = self.filename.replace("..", ".")
return self.filename
""" Save the ebook from the calibre library to the path """
def ebook_save(self, path: str) -> str:
filepath = os.path.join(path, self.ebook_filename())
if os.path.exists(filepath):
return
print(f"COPY {self.filepath} -> {filepath}")
shutil.copyfile(self.filepath, filepath)
return filepath
class CalibreLibrary:
def __init__(self, library_path: str):
# First open the Calibre library and get a list of the book IDs
self._db = calibre.library.db(library_path).new_api
@staticmethod
def _get_filesize_str(path: str) -> str:
size = os.path.getsize(path)
if size < 1024:
return f"{size} bytes"
elif size < pow(1024,2):
return f"{round(size/1024, 2)} KB"
elif size < pow(1024,3):
return f"{round(size/(pow(1024,2)), 2)} MB"
elif size < pow(1024,4):
return f"{round(size/(pow(1024,3)), 2)} GB"
def books(self) -> 'list[CalibreLibraryBook]':
books = []
book_ids = self._db.all_book_ids()
for book_id in book_ids:
# TODO check loaded state with state of calibre based on book.id
# hashing takes way to long...
book = CalibreLibraryBook(self._db)
book.id = book_id
book.title = self._db.field_for("title", book.id)
book.authors = self._db.field_for("authors", book.id)
book.comments = self._db.field_for("comments", book.id)
book._metadata = self._db.get_metadata(book.id)
book.ids = book._metadata.get_identifiers()
# Select only first ebook format
formats = self._db.formats(book.id, verify_formats=True)
if len(formats) > 0:
book.filepath = self._db.format_abspath(book.id, formats[0])
book.filesize = self._get_filesize_str(book.filepath)
else:
book.filepath = None
book.filesize = 0
books.append(book)
return books
class PyroTechnyEbookLibraryTorrent:
_calibre_library : CalibreLibrary
_path: str
_tempdir: str
_google_drive_file_db: list
def __init__(self, path: str, calibre_library: CalibreLibrary):
self._books = []
self._calibre_library = calibre_library
self._path = path
self._state = {}
self._state["books"] = []
# Create cache pat
if not os.path.exists(self._path):
print(f"CREATE {self._path}")
os.makedirs(self._path, 0o755)
def synchronize(self):
# Load books from calibre
books = self._calibre_library.books()
for book in books:
#print(f"{book.to_json()}")
book.ebook_save(self._path)
def main():
calibre_library = CalibreLibrary(config.CALIBRE_LIBRARY_PATH)
pyrotechny_library = PyroTechnyEbookLibraryTorrent(config.EBOOK_LIBRARY_TORRENT_CACHE_DIR, calibre_library)
pyrotechny_library.synchronize()
if __name__ == "__main__":
main()