From 09d8e2bf2d8123b1e3146f996959f790388538ef Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Sat, 15 Feb 2020 14:41:11 +0000 Subject: [PATCH] Add black --- .pre-commit-config.yaml | 6 ++ backend.py | 139 ++++++++++++++++++++++++---------------- disk_cache.py | 6 +- local_reader.py | 36 +++++------ mangareader.py | 52 +++++++++------ 5 files changed, 141 insertions(+), 98 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c86af76 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: + - repo: https://github.com/psf/black + rev: stable + hooks: + - id: black + language_version: python3.7 diff --git a/backend.py b/backend.py index 943bfa3..2598fb7 100644 --- a/backend.py +++ b/backend.py @@ -12,9 +12,9 @@ DEFAULT_WEBP_QUALITY = 80 DEFAULT_WEBP_METHOD = 0 DEFAULT_WEBP_SIZE = 1908 # width of FullHD monitor without scroll bar in full screen -mimetypes['.webp'] = 'image/webp' +mimetypes[".webp"] = "image/webp" -if os.environ.get('DISK_CACHE', '1') == '0': +if os.environ.get("DISK_CACHE", "1") == "0": disk_cache = DiskCache(enabled=False) else: disk_cache = DiskCache() @@ -44,27 +44,29 @@ class BaseDB: webp_lossless = False self.webp_config = { - 'quality': webp_quality, - 'method': webp_method, - 'lossless': webp_lossless, - 'size': webp_size + "quality": webp_quality, + "method": webp_method, + "lossless": webp_lossless, + "size": webp_size, } def _generate_webp(self, fp, max_size=None): if max_size is None: - max_size = tuple([self.webp_config['size']] * 2) + max_size = tuple([self.webp_config["size"]] * 2) image = Image.open(fp) image.thumbnail(max_size) image_buffer = BytesIO() image.save( image_buffer, - format='webp', - save_all=True, # - append_images=[image], # https://github.com/python-pillow/Pillow/issues/4042 - quality=self.webp_config['quality'], - method=self.webp_config['method'], - lossless=self.webp_config['lossless'] + format="webp", + save_all=True, + append_images=[ + image + ], # https://github.com/python-pillow/Pillow/issues/4042 + quality=self.webp_config["quality"], + method=self.webp_config["method"], + lossless=self.webp_config["lossless"], ) image_buffer.seek(0) @@ -79,35 +81,39 @@ class BaseDB: etag = str(crc32(data)) thumbnail_cache[filepath] = { - 'data_raw': data, - 'etag': etag, - 'mimetype': 'image/webp' + "data_raw": data, + "etag": etag, + "mimetype": "image/webp", } thumbnail = thumbnail_cache[filepath] - thumbnail['buffer'] = BytesIO() - thumbnail['buffer'].write(thumbnail['data_raw']) - thumbnail['buffer'].seek(0) + thumbnail["buffer"] = BytesIO() + thumbnail["buffer"].write(thumbnail["data_raw"]) + thumbnail["buffer"].seek(0) return thumbnail def _generate_page(self, page_buffer, volume, page): page_buffer = self._generate_webp(page_buffer) - disk_cache.set(f'{volume}-{page}', page_buffer) + disk_cache.set(f"{volume}-{page}", page_buffer) page_buffer.seek(0) return page_buffer class CalibreDB(BaseDB): - def __init__(self, path='metadata.db', webp_quality=DEFAULT_WEBP_QUALITY, webp_method=DEFAULT_WEBP_METHOD, webp_size=DEFAULT_WEBP_SIZE): + def __init__( + self, + path="metadata.db", + webp_quality=DEFAULT_WEBP_QUALITY, + webp_method=DEFAULT_WEBP_METHOD, + webp_size=DEFAULT_WEBP_SIZE, + ): super().__init__( - webp_quality=webp_quality, - webp_method=webp_method, - webp_size=webp_size + webp_quality=webp_quality, webp_method=webp_method, webp_size=webp_size ) - self.database_path = f'file:{path}?mode=ro' + self.database_path = f"file:{path}?mode=ro" def create_cursor(self): conn = sqlite3.connect(self.database_path, uri=True) @@ -116,7 +122,8 @@ class CalibreDB(BaseDB): def get_series_list(self): cursor = self.create_cursor() - series = cursor.execute(''' + series = cursor.execute( + """ select series.id as id, series.name as name, @@ -133,13 +140,15 @@ class CalibreDB(BaseDB): data.format = \'CBZ\' group by series.name having min(books.series_index) - ''') + """ + ) return series def get_series_cover(self, series_id): cursor = self.create_cursor() - first_volume = cursor.execute(''' + first_volume = cursor.execute( + """ select books.id from @@ -152,27 +161,33 @@ class CalibreDB(BaseDB): series.id = ? group by series.name having min(books.series_index) - ''', (str(series_id),)).fetchone() + """, + (str(series_id),), + ).fetchone() if first_volume is None: raise exceptions.NotFound() - return self.get_volume_cover(first_volume['id']) + return self.get_volume_cover(first_volume["id"]) def get_series_cover_thumbnail(self, series_id): return self._generate_thumbnail(self.get_series_cover(series_id)) def get_series_volumes(self, series_id): cursor = self.create_cursor() - title = cursor.execute(''' + title = cursor.execute( + """ select series.name from series where series.id = ? - ''', (str(series_id),)).fetchone()['name'] - volumes = cursor.execute(''' + """, + (str(series_id),), + ).fetchone()["name"] + volumes = cursor.execute( + """ select books.id, books.title, @@ -186,16 +201,16 @@ class CalibreDB(BaseDB): books_series_link.series = series.id and series.id = ? order by books.series_index - ''', (str(series_id),)).fetchall() + """, + (str(series_id),), + ).fetchall() - return { - 'title': title, - 'volumes': volumes - } + return {"title": title, "volumes": volumes} def get_volume_cover(self, volume_id): cursor = self.create_cursor() - volume = cursor.execute(''' + volume = cursor.execute( + """ select books.has_cover as has_cover, books.path as path @@ -204,10 +219,12 @@ class CalibreDB(BaseDB): where books.id = ? order by books.series_index - ''', (str(volume_id),)).fetchone() + """, + (str(volume_id),), + ).fetchone() - if volume['has_cover']: - return volume['path'] + '/cover.jpg' + if volume["has_cover"]: + return volume["path"] + "/cover.jpg" else: raise exceptions.NotFound() @@ -216,7 +233,8 @@ class CalibreDB(BaseDB): def get_volume_filepath(self, volume_id): cursor = self.create_cursor() - location = cursor.execute(''' + location = cursor.execute( + """ select books.path as path, data.name as filename, @@ -227,16 +245,21 @@ class CalibreDB(BaseDB): where data.book = books.id and books.id = ? - ''', (str(volume_id),)).fetchone() + """, + (str(volume_id),), + ).fetchone() if location is None: raise exceptions.NotFound() - return location['path'] + '/' + location['filename'] + '.' + location['extension'] + return ( + location["path"] + "/" + location["filename"] + "." + location["extension"] + ) def get_volume_info(self, volume_id): cursor = self.create_cursor() - volume_info = cursor.execute(''' + volume_info = cursor.execute( + """ select books.title, books_series_link.series @@ -246,15 +269,17 @@ class CalibreDB(BaseDB): where books_series_link.book = books.id and books.id = ? - ''', (str(volume_id),)).fetchone() + """, + (str(volume_id),), + ).fetchone() - volume_info['pages'] = self.get_volume_page_number(volume_id) + volume_info["pages"] = self.get_volume_page_number(volume_id) return volume_info def get_volume_page_number(self, volume_id): path = self.get_volume_filepath(volume_id) - with ZipFile(path, 'r') as volume: + with ZipFile(path, "r") as volume: filelist = filter_zip_filelist(volume.filelist) return len(filelist) @@ -262,7 +287,7 @@ class CalibreDB(BaseDB): if page_number < 1: raise exceptions.NotFound() path = self.get_volume_filepath(volume_id) - with ZipFile(path, 'r') as volume: + with ZipFile(path, "r") as volume: try: filelist = filter_zip_filelist(volume.filelist) zip_info = filelist[page_number - 1] @@ -279,16 +304,18 @@ class CalibreDB(BaseDB): page_buffer.write(volume.read(page_filename)) page_buffer.seek(0) else: - mimetype = 'image/webp' + mimetype = "image/webp" try: - page_buffer = disk_cache.get(f'{volume_id}-{page_number}') + page_buffer = disk_cache.get(f"{volume_id}-{page_number}") except FileNotFoundError: with volume.open(page_filename) as orig_page_buffer: - page_buffer = self._generate_page(orig_page_buffer, volume_id, page_number) + page_buffer = self._generate_page( + orig_page_buffer, volume_id, page_number + ) return { - 'buffer': page_buffer, - 'mimetype': mimetype, - 'etag': str(zip_info.CRC) + "buffer": page_buffer, + "mimetype": mimetype, + "etag": str(zip_info.CRC), } diff --git a/disk_cache.py b/disk_cache.py index e25b1dd..b8b7418 100644 --- a/disk_cache.py +++ b/disk_cache.py @@ -5,7 +5,7 @@ import os class DiskCache: def __init__(self, path=None, enabled=True): if path is None: - self.path = os.path.join(os.path.dirname(__file__), 'cache') + self.path = os.path.join(os.path.dirname(__file__), "cache") else: self.path = path @@ -19,14 +19,14 @@ class DiskCache: if self.enabled is False: return - with open(self._build_path(identifier), 'wb') as f: + with open(self._build_path(identifier), "wb") as f: f.write(buf.read()) def get(self, identifier): if self.enabled is False: raise FileNotFoundError - with open(self._build_path(identifier), 'rb') as f: + with open(self._build_path(identifier), "rb") as f: return BytesIO(f.read()) def _build_path(self, identifier): diff --git a/local_reader.py b/local_reader.py index aa61bd5..1e3a443 100755 --- a/local_reader.py +++ b/local_reader.py @@ -9,33 +9,31 @@ import webbrowser import werkzeug.exceptions as exceptions # disable access log -log = logging.getLogger('werkzeug') +log = logging.getLogger("werkzeug") log.setLevel(logging.ERROR) # disable flask startup message -os.environ['WERKZEUG_RUN_MAIN'] = 'true' +os.environ["WERKZEUG_RUN_MAIN"] = "true" -mimetypes['.webp'] = 'image/webp' -archive = ZipFile(sys.argv[1], 'r') -app = Flask(__name__, static_folder='frontend/dist/static', template_folder='frontend/dist') +mimetypes[".webp"] = "image/webp" +archive = ZipFile(sys.argv[1], "r") +app = Flask( + __name__, static_folder="frontend/dist/static", template_folder="frontend/dist" +) # kind of redundant, but avoids returning 200 if page does not exist -@app.route('/') -@app.route('/series/0') -@app.route('/volume/0') +@app.route("/") +@app.route("/series/0") +@app.route("/volume/0") def serve_app(**kwargs): - return render_template('index.html') + return render_template("index.html") -@app.route('/api/volume/0') +@app.route("/api/volume/0") def get_volume_info(): - return jsonify({ - 'pages': len(archive.filelist), - 'series': 0, - 'title': sys.argv[1] - }) + return jsonify({"pages": len(archive.filelist), "series": 0, "title": sys.argv[1]}) -@app.route('/api/volume/0/page/') +@app.route("/api/volume/0/page/") def get_volume_page(page_number): try: page = archive.filelist[page_number - 1] @@ -45,6 +43,6 @@ def get_volume_page(page_number): return Response(archive.read(page.filename), mimetype=mimetype) -if __name__ == '__main__': - webbrowser.open('http://localhost:5051/volume/0') - app.run(host='127.0.0.1', port=5051) +if __name__ == "__main__": + webbrowser.open("http://localhost:5051/volume/0") + app.run(host="127.0.0.1", port=5051) diff --git a/mangareader.py b/mangareader.py index b1ff1ac..3301785 100755 --- a/mangareader.py +++ b/mangareader.py @@ -1,6 +1,13 @@ #!/usr/bin/env python3 from backend import CalibreDB -from flask import Flask, jsonify, send_from_directory, send_file, render_template, request +from flask import ( + Flask, + jsonify, + send_from_directory, + send_file, + render_template, + request, +) from flask_cors import CORS from werkzeug.routing import BaseConverter import os @@ -12,7 +19,7 @@ def send_from_cwd(filename): def send_file_with_etag(fp, etag, **kwargs): if request.if_none_match and etag in request.if_none_match: - return '', 304 + return "", 304 response = send_file(fp, **kwargs) response.set_etag(etag) @@ -21,70 +28,75 @@ def send_file_with_etag(fp, etag, **kwargs): def send_image(image): - return send_file_with_etag(image['buffer'], image['etag'], mimetype=image['mimetype']) + return send_file_with_etag( + image["buffer"], image["etag"], mimetype=image["mimetype"] + ) -app = Flask(__name__, static_folder='frontend/dist/static', template_folder='frontend/dist') -app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 604800 # 1 week +app = Flask( + __name__, static_folder="frontend/dist/static", template_folder="frontend/dist" +) +app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 604800 # 1 week CORS(app) db = CalibreDB() # kind of redundant, but avoids returning 200 if page does not exist -@app.route('/') -@app.route('/series/') -@app.route('/volume/') +@app.route("/") +@app.route("/series/") +@app.route("/volume/") def serve_app(**kwargs): - return render_template('index.html') + return render_template("index.html") -@app.route('/api/series') +@app.route("/api/series") def get_series_list(): return jsonify(list(db.get_series_list())) -@app.route('/api/series//cover') +@app.route("/api/series//cover") def get_series_cover(series_id): return send_from_cwd(db.get_series_cover(series_id)) -@app.route('/api/series//cover/thumbnail') +@app.route("/api/series//cover/thumbnail") def get_series_cover_thumbnail(series_id): thumbnail = db.get_series_cover_thumbnail(series_id) return send_image(thumbnail) -@app.route('/api/series/') +@app.route("/api/series/") def get_series_info(series_id): return jsonify(db.get_series_volumes(series_id)) -@app.route('/api/volume//cover') +@app.route("/api/volume//cover") def get_volume_cover(volume_id): return send_from_cwd(db.get_volume_cover(volume_id)) -@app.route('/api/volume//cover/thumbnail') +@app.route("/api/volume//cover/thumbnail") def get_volume_cover_thumbnail(volume_id): thumbnail = db.get_volume_cover_thumbnail(volume_id) return send_image(thumbnail) -@app.route('/api/volume/') +@app.route("/api/volume/") def get_volume_info(volume_id): return jsonify(db.get_volume_info(volume_id)) -@app.route('/api/volume//page/') +@app.route("/api/volume//page/") def get_volume_page(volume_id, page_number): page = db.get_volume_page(volume_id, page_number) return send_image(page) -@app.route('/api/volume//page//original') + +@app.route("/api/volume//page//original") def get_volume_page_original(volume_id, page_number): page = db.get_volume_page(volume_id, page_number, original=True) return send_image(page) -if __name__ == '__main__': - app.run(host='0.0.0.0') +if __name__ == "__main__": + app.run(host="0.0.0.0")