cista 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cista-1.0.0 → cista-1.1.0}/PKG-INFO +1 -1
- {cista-1.0.0 → cista-1.1.0}/cista/_version.py +1 -1
- {cista-1.0.0 → cista-1.1.0}/cista/api.py +5 -1
- {cista-1.0.0 → cista-1.1.0}/cista/app.py +5 -3
- {cista-1.0.0 → cista-1.1.0}/cista/preview.py +33 -21
- {cista-1.0.0 → cista-1.1.0}/cista/serve.py +0 -9
- {cista-1.0.0 → cista-1.1.0}/cista/watching.py +2 -2
- {cista-1.0.0 → cista-1.1.0}/.gitignore +0 -0
- {cista-1.0.0 → cista-1.1.0}/README.md +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/__init__.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/__main__.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/auth.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/config.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/droppy.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/fileio.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/protocol.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/server80.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/session.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/__init__.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/apphelpers.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/asynclink.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/filename.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/lrucache.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/util/pwgen.py +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/add-file-6a41e251.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/add-folder-62d934ef.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/arrow-a3a583f8.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/arrows-h-d9e36082.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/arrows-v-5223491a.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/check-f7566407.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/code-8e0123d4.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/copy-a70a3d1c.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/create-file-d995875e.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/create-folder-c448deda.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/cross-e74ed6f4.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/disk-f1376321.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/download-bad67930.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/exclamation-afec06bb.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/eye-5fde34a1.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/find-11711648.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/fullscreen-7f61e522.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/github-c9475017.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/index-0ccc4ea2.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/index-89d850f4.css +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/info-b3d76e57.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/link-5cd893e4.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/logo-6090454d.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/logo-97d1d7eb.svg +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/loop-531f6994.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/menu-ed0d8c47.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/next-ee82241a.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/open-8364df82.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/paste-0f86e193.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/pause-a2dd4670.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/pencil-bfd02151.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/play-83e40a03.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/plus-f463cfbc.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/previous-cbb778b5.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/reload-907eb866.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/rename-51dadde6.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/scissors-d32350cc.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/shuffle-00a003ad.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/signin-d7bd57fd.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/signout-4c4ff7fb.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/skip-0069d8d7.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/spinner-164c9b34.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/stop-3717c27d.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/trash-449f81ef.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/triangle-3ecaf29c.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/unfullscreen-175d46cd.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/up-arrow-164a366e.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/upload-cloud-df377f1a.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/user-3b5a32bc.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/user-cog-27e2c201.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/volume-high-f4e07edd.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/volume-low-f754322d.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/volume-medium-a5806088.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/volume-mute-405763b1.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/window-cross-86cb8236.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/window-d99968ac.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/wordwrap-cdcd3f93.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/zoomin-7d13bb9b.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/assets/zoomout-daf52018.js +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/index.html +0 -0
- {cista-1.0.0 → cista-1.1.0}/cista/wwwroot/robots.txt +0 -0
- {cista-1.0.0 → cista-1.1.0}/pyproject.toml +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# This file is automatically generated by hatch build.
|
|
2
|
-
__version__ = '1.
|
|
2
|
+
__version__ = '1.1.0'
|
|
@@ -119,8 +119,12 @@ async def watch(req, ws):
|
|
|
119
119
|
# Send updates
|
|
120
120
|
while True:
|
|
121
121
|
await ws.send(await q.get())
|
|
122
|
+
except RuntimeError as e:
|
|
123
|
+
if str(e) == "cannot schedule new futures after shutdown":
|
|
124
|
+
return # Server shutting down, drop the WebSocket
|
|
125
|
+
raise
|
|
122
126
|
finally:
|
|
123
|
-
|
|
127
|
+
watching.pubsub.pop(uuid, None) # Remove whether it got added yet or not
|
|
124
128
|
|
|
125
129
|
|
|
126
130
|
def subscribe(uuid, ws):
|
|
@@ -43,14 +43,16 @@ async def main_start(app, loop):
|
|
|
43
43
|
app.ctx.threadexec = ThreadPoolExecutor(
|
|
44
44
|
max_workers=workers, thread_name_prefix="cista-ioworker"
|
|
45
45
|
)
|
|
46
|
-
|
|
46
|
+
watching.start(app, loop)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
# Sanic sometimes fails to execute after_server_stop, so we do it before instead (potentially interrupting handlers)
|
|
50
|
+
@app.before_server_stop
|
|
50
51
|
async def main_stop(app, loop):
|
|
51
52
|
quit.set()
|
|
52
|
-
|
|
53
|
+
watching.stop(app)
|
|
53
54
|
app.ctx.threadexec.shutdown()
|
|
55
|
+
logger.debug("Cista worker threads all finished")
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
@app.on_request
|
|
@@ -24,6 +24,17 @@ pillow_heif.register_heif_opener()
|
|
|
24
24
|
|
|
25
25
|
bp = Blueprint("preview", url_prefix="/preview")
|
|
26
26
|
|
|
27
|
+
# Map EXIF Orientation value to a corresponding PIL transpose
|
|
28
|
+
EXIF_ORI = {
|
|
29
|
+
2: Image.Transpose.FLIP_LEFT_RIGHT,
|
|
30
|
+
3: Image.Transpose.ROTATE_180,
|
|
31
|
+
4: Image.Transpose.FLIP_TOP_BOTTOM,
|
|
32
|
+
5: Image.Transpose.TRANSPOSE,
|
|
33
|
+
6: Image.Transpose.ROTATE_270,
|
|
34
|
+
7: Image.Transpose.TRANSVERSE,
|
|
35
|
+
8: Image.Transpose.ROTATE_90,
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
|
|
28
39
|
@bp.get("/<path:path>")
|
|
29
40
|
async def preview(req, path):
|
|
@@ -69,34 +80,35 @@ def dispatch(path, quality, maxsize, maxzoom):
|
|
|
69
80
|
|
|
70
81
|
|
|
71
82
|
def process_image(path, *, maxsize, quality):
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
t_load = perf_counter()
|
|
84
|
+
with Image.open(path) as img:
|
|
85
|
+
# Force decode to include I/O in load timing
|
|
86
|
+
img.load()
|
|
87
|
+
t_proc = perf_counter()
|
|
88
|
+
# Resize
|
|
89
|
+
w, h = img.size
|
|
90
|
+
img.thumbnail((min(w, maxsize), min(h, maxsize)))
|
|
91
|
+
# Transpose pixels according to EXIF Orientation
|
|
92
|
+
orientation = img.getexif().get(274, 1)
|
|
93
|
+
if orientation in EXIF_ORI:
|
|
94
|
+
img = img.transpose(EXIF_ORI[orientation])
|
|
95
|
+
# Save as AVIF
|
|
96
|
+
imgdata = io.BytesIO()
|
|
97
|
+
t_save = perf_counter()
|
|
98
|
+
img.save(imgdata, format="avif", quality=quality, speed=10, max_threads=1)
|
|
99
|
+
|
|
100
|
+
t_end = perf_counter()
|
|
88
101
|
ret = imgdata.getvalue()
|
|
89
102
|
|
|
90
|
-
load_ms = (
|
|
91
|
-
proc_ms = (
|
|
92
|
-
save_ms = (
|
|
103
|
+
load_ms = (t_proc - t_load) * 1000
|
|
104
|
+
proc_ms = (t_save - t_proc) * 1000
|
|
105
|
+
save_ms = (t_end - t_save) * 1000
|
|
93
106
|
logger.debug(
|
|
94
|
-
"Preview image %s: load=%.1fms process=%.1fms save=%.1fms
|
|
107
|
+
"Preview image %s: load=%.1fms process=%.1fms save=%.1fms",
|
|
95
108
|
path.name,
|
|
96
109
|
load_ms,
|
|
97
110
|
proc_ms,
|
|
98
111
|
save_ms,
|
|
99
|
-
len(ret) / 1024,
|
|
100
112
|
)
|
|
101
113
|
|
|
102
114
|
return ret
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
|
-
import signal
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
|
|
6
5
|
from sanic import Sanic
|
|
@@ -12,14 +11,6 @@ def run(*, dev=False):
|
|
|
12
11
|
"""Run Sanic main process that spawns worker processes to serve HTTP requests."""
|
|
13
12
|
from .app import app
|
|
14
13
|
|
|
15
|
-
# Set up immediate exit on Ctrl+C for faster termination
|
|
16
|
-
def signal_handler(signum, frame):
|
|
17
|
-
print("\nReceived interrupt signal, exiting immediately...")
|
|
18
|
-
os._exit(0)
|
|
19
|
-
|
|
20
|
-
signal.signal(signal.SIGINT, signal_handler)
|
|
21
|
-
signal.signal(signal.SIGTERM, signal_handler)
|
|
22
|
-
|
|
23
14
|
url, opts = parse_listen(config.config.listen)
|
|
24
15
|
# Silence Sanic's warning about running in production rather than debug
|
|
25
16
|
os.environ["SANIC_IGNORE_PRODUCTION_WARNING"] = "1"
|
|
@@ -440,7 +440,7 @@ def watcher_poll(loop):
|
|
|
440
440
|
quit.wait(0.1 + 8 * dur)
|
|
441
441
|
|
|
442
442
|
|
|
443
|
-
|
|
443
|
+
def start(app, loop):
|
|
444
444
|
global rootpath
|
|
445
445
|
config.load_config()
|
|
446
446
|
rootpath = config.config.path
|
|
@@ -454,6 +454,6 @@ async def start(app, loop):
|
|
|
454
454
|
app.ctx.watcher.start()
|
|
455
455
|
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
def stop(app):
|
|
458
458
|
quit.set()
|
|
459
459
|
app.ctx.watcher.join()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|