pdfdesk 0.1.0__py3-none-any.whl
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.
- pdfdesk/__init__.py +3 -0
- pdfdesk/__main__.py +3 -0
- pdfdesk/cli.py +107 -0
- pdfdesk/static/app.js +683 -0
- pdfdesk/static/index.html +35 -0
- pdfdesk/static/styles.css +294 -0
- pdfdesk/static/vendor/fonts/OFL-ibmplexmono.txt +93 -0
- pdfdesk/static/vendor/fonts/OFL-ibmplexsans.txt +93 -0
- pdfdesk/static/vendor/fonts/OFL-sourceserif4.txt +93 -0
- pdfdesk/static/vendor/fonts/fonts.css +151 -0
- pdfdesk/static/vendor/fonts/ibm-plex-mono-400-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-mono-400-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-mono-500-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-mono-500-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-400-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-500-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-600-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-400-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-400-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-600-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-600-latin.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-700-latin-ext.woff2 +0 -0
- pdfdesk/static/vendor/fonts/source-serif-4-700-latin.woff2 +0 -0
- pdfdesk/static/vendor/pdfjs/LICENSE +177 -0
- pdfdesk/static/vendor/pdfjs/pdf.min.js +22 -0
- pdfdesk/static/vendor/pdfjs/pdf.worker.min.js +22 -0
- pdfdesk-0.1.0.dist-info/METADATA +209 -0
- pdfdesk-0.1.0.dist-info/RECORD +34 -0
- pdfdesk-0.1.0.dist-info/WHEEL +4 -0
- pdfdesk-0.1.0.dist-info/entry_points.txt +2 -0
- pdfdesk-0.1.0.dist-info/licenses/LICENSE +21 -0
pdfdesk/__init__.py
ADDED
pdfdesk/__main__.py
ADDED
pdfdesk/cli.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""`pdfdesk` command: serve the bundled browser app on localhost and open it."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import errno
|
|
7
|
+
import functools
|
|
8
|
+
import http.server
|
|
9
|
+
import socket
|
|
10
|
+
import sys
|
|
11
|
+
import threading
|
|
12
|
+
import webbrowser
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from pdfdesk import __version__
|
|
16
|
+
|
|
17
|
+
DEFAULT_PORT = 5173
|
|
18
|
+
|
|
19
|
+
# Windows can map .js to text/plain through the registry, which browsers refuse to run.
|
|
20
|
+
TYPES = {
|
|
21
|
+
".html": "text/html; charset=utf-8",
|
|
22
|
+
".js": "text/javascript; charset=utf-8",
|
|
23
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
24
|
+
".css": "text/css; charset=utf-8",
|
|
25
|
+
".json": "application/json; charset=utf-8",
|
|
26
|
+
".svg": "image/svg+xml",
|
|
27
|
+
".png": "image/png",
|
|
28
|
+
".pdf": "application/pdf",
|
|
29
|
+
".woff2": "font/woff2",
|
|
30
|
+
".txt": "text/plain; charset=utf-8",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def static_dir() -> Path:
|
|
35
|
+
"""The app files: bundled inside the wheel, or prototype/ when run from a checkout."""
|
|
36
|
+
bundled = Path(__file__).parent / "static"
|
|
37
|
+
if (bundled / "index.html").is_file():
|
|
38
|
+
return bundled
|
|
39
|
+
checkout = Path(__file__).parent.parent / "prototype"
|
|
40
|
+
if (checkout / "index.html").is_file():
|
|
41
|
+
return checkout
|
|
42
|
+
raise SystemExit("pdfdesk: app files are missing from this install. Reinstall with `pip install --force-reinstall pdfdesk`.")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Handler(http.server.SimpleHTTPRequestHandler):
|
|
46
|
+
extensions_map = {**http.server.SimpleHTTPRequestHandler.extensions_map, **TYPES}
|
|
47
|
+
|
|
48
|
+
def end_headers(self) -> None:
|
|
49
|
+
# Revalidate every load, so an upgraded install never runs a stale app.js.
|
|
50
|
+
self.send_header("Cache-Control", "no-cache")
|
|
51
|
+
super().end_headers()
|
|
52
|
+
|
|
53
|
+
def log_message(self, format: str, *args) -> None: # quiet by default
|
|
54
|
+
if self.server.verbose: # type: ignore[attr-defined]
|
|
55
|
+
super().log_message(format, *args)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Server(http.server.ThreadingHTTPServer):
|
|
59
|
+
# On Windows SO_REUSEADDR lets a second server bind the same port silently, so two copies would
|
|
60
|
+
# "run" at once. Claim the port exclusively there instead; elsewhere keep fast restarts.
|
|
61
|
+
allow_reuse_address = sys.platform != "win32"
|
|
62
|
+
daemon_threads = True
|
|
63
|
+
|
|
64
|
+
def server_bind(self) -> None:
|
|
65
|
+
if sys.platform == "win32" and hasattr(socket, "SO_EXCLUSIVEADDRUSE"):
|
|
66
|
+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
|
|
67
|
+
super().server_bind()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def main(argv: list[str] | None = None) -> int:
|
|
71
|
+
parser = argparse.ArgumentParser(
|
|
72
|
+
prog="pdfdesk",
|
|
73
|
+
description="Start PDFDesk on this computer and open it in your browser.",
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument("--port", type=int, default=DEFAULT_PORT,
|
|
76
|
+
help=f"port to serve on (default {DEFAULT_PORT}). Your library is stored per port, so keep it the same.")
|
|
77
|
+
parser.add_argument("--no-browser", action="store_true", help="don't open a browser window")
|
|
78
|
+
parser.add_argument("--verbose", action="store_true", help="log every request")
|
|
79
|
+
parser.add_argument("--version", action="version", version=f"pdfdesk {__version__}")
|
|
80
|
+
args = parser.parse_args(argv)
|
|
81
|
+
|
|
82
|
+
handler = functools.partial(Handler, directory=str(static_dir()))
|
|
83
|
+
try:
|
|
84
|
+
server = Server(("127.0.0.1", args.port), handler)
|
|
85
|
+
except OSError as e:
|
|
86
|
+
if e.errno in (errno.EADDRINUSE, errno.EACCES) or getattr(e, "winerror", None) in (10048, 10013):
|
|
87
|
+
print(
|
|
88
|
+
f"pdfdesk: port {args.port} is already in use. PDFDesk may already be running at http://localhost:{args.port}\n"
|
|
89
|
+
"Your library is saved per port, so a different port starts with an empty library.\n"
|
|
90
|
+
"To use another port anyway: pdfdesk --port <number>",
|
|
91
|
+
file=sys.stderr,
|
|
92
|
+
)
|
|
93
|
+
return 1
|
|
94
|
+
raise
|
|
95
|
+
server.verbose = args.verbose # type: ignore[attr-defined]
|
|
96
|
+
|
|
97
|
+
url = f"http://localhost:{args.port}/"
|
|
98
|
+
print(f"PDFDesk {__version__} running at {url} (Ctrl+C to stop)")
|
|
99
|
+
if not args.no_browser:
|
|
100
|
+
threading.Timer(0.3, webbrowser.open, args=(url,)).start()
|
|
101
|
+
try:
|
|
102
|
+
server.serve_forever()
|
|
103
|
+
except KeyboardInterrupt:
|
|
104
|
+
print("\nStopped.")
|
|
105
|
+
finally:
|
|
106
|
+
server.server_close()
|
|
107
|
+
return 0
|