mirror of
https://github.com/9001/copyparty.git
synced 2026-08-15 14:53:08 -06:00
Compare commits
No commits in common. "hovudstraum" and "v1.20.20" have entirely different histories.
hovudstrau
...
v1.20.20
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -4,5 +4,4 @@
|
||||||
|
|
||||||
*.png binary
|
*.png binary
|
||||||
*.gif binary
|
*.gif binary
|
||||||
*.ico binary
|
|
||||||
*.gz binary
|
*.gz binary
|
||||||
|
|
|
||||||
20
README.md
20
README.md
|
|
@ -84,7 +84,6 @@ built in Norway 🇳🇴 with contributions from [not-norway](https://github.com
|
||||||
* [exclude-patterns](#exclude-patterns) - to save some time
|
* [exclude-patterns](#exclude-patterns) - to save some time
|
||||||
* [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
|
* [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
|
||||||
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
* [periodic rescan](#periodic-rescan) - filesystem monitoring
|
||||||
* [u2sz](#u2sz) - configure upload-chunking
|
|
||||||
* [upload rules](#upload-rules) - set upload rules using volflags
|
* [upload rules](#upload-rules) - set upload rules using volflags
|
||||||
* [compress uploads](#compress-uploads) - files can be autocompressed on upload
|
* [compress uploads](#compress-uploads) - files can be autocompressed on upload
|
||||||
* [chmod and chown](#chmod-and-chown) - per-volume filesystem-permissions and ownership
|
* [chmod and chown](#chmod-and-chown) - per-volume filesystem-permissions and ownership
|
||||||
|
|
@ -923,7 +922,7 @@ note that since up2k has to read each file twice, `[🎈] bup` can *theoreticall
|
||||||
|
|
||||||
if you are resuming a massive upload and want to skip hashing the files which already finished, you can enable `turbo` in the `[⚙️] config` tab, but please read the tooltip on that button
|
if you are resuming a massive upload and want to skip hashing the files which already finished, you can enable `turbo` in the `[⚙️] config` tab, but please read the tooltip on that button
|
||||||
|
|
||||||
if the server is behind a proxy which imposes a request-size limit, you can configure up2k to sneak below the limit with server-option [--u2sz](#u2sz)
|
if the server is behind a proxy which imposes a request-size limit, you can configure up2k to sneak below the limit with server-option `--u2sz` (the default is 96 MiB to support Cloudflare)
|
||||||
|
|
||||||
if you want to replace existing files on the server with new uploads by default, run with `--u2ow 2` (only works if users have the delete-permission, and can still be disabled with `🛡️` in the UI)
|
if you want to replace existing files on the server with new uploads by default, run with `--u2ow 2` (only works if users have the delete-permission, and can still be disabled with `🛡️` in the UI)
|
||||||
|
|
||||||
|
|
@ -1827,23 +1826,6 @@ config file example:
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## u2sz
|
|
||||||
|
|
||||||
configure upload-chunking; the default `64,96` is optimal for nearly every scenario, however:
|
|
||||||
|
|
||||||
* if you are seeing the message `bad server config; see "u2sz" in readme` then you have a proxy/CDN/whatever with a `max-request-body-size` which is too small, and you must either increase the limit in the reverseproxy config to at least 96 MiB (recommended) or reduce the target chunksize in copyparty (continue reading)
|
|
||||||
|
|
||||||
the global-option `--u2sz` is two numbers, `target,max` MiB of each chunk to send, aiming for `target` MiB and allowing up-to-and-including `max` MiB [depending on filesize](./docs/devnotes.md#list-of-chunk-sizes), and if you only specify one number then it sets that for both
|
|
||||||
|
|
||||||
cloudflare max is 96 MiB, but if you have a reverseproxy (or CDN/WAF/whatever) which is more restrictive, then try some of the following:
|
|
||||||
|
|
||||||
* `u2sz: 32` is still acceptable performance in most cases
|
|
||||||
* `u2sz: 8` is the lowest recommended value; anything lower will reduce performance over long physical distances and/or shitty routes
|
|
||||||
* `u2sz: 1` is the absolute minimum, and will be slow in many cases
|
|
||||||
|
|
||||||
the setting can also be changed in the web-UI; the textbox next to `date-chk` in the settings tab
|
|
||||||
|
|
||||||
|
|
||||||
## upload rules
|
## upload rules
|
||||||
|
|
||||||
set upload rules using volflags, some examples:
|
set upload rules using volflags, some examples:
|
||||||
|
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
# thumbnail extractors
|
|
||||||
|
|
||||||
extract (or generate) thumbnails for custom file formats or override default thumbnail extraction for standard media files
|
|
||||||
|
|
||||||
|
|
||||||
## usage
|
|
||||||
|
|
||||||
* load plugins with `--th-extract baz=~/dev/copyparty/bin/thumbs/randomcolor.py`
|
|
||||||
* `baz` is the file extension (may be comma-separated list of extensions)
|
|
||||||
* add multiple different extractor plugins by repeating the `--th-extract` argument
|
|
||||||
|
|
||||||
|
|
||||||
## api
|
|
||||||
|
|
||||||
### in
|
|
||||||
|
|
||||||
each plugin must define a function `main(abspath, **kwargs)`:
|
|
||||||
* `abspath` is the path to a file to extract thumbnail for
|
|
||||||
* `kwargs` currently receives these keyword arguments:
|
|
||||||
* `vn` is the VFS which contains the requested file
|
|
||||||
* `th_srv` is an instance of [copyparty/th_srv](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/th_srv.py)
|
|
||||||
|
|
||||||
### out
|
|
||||||
|
|
||||||
the `main()` function must
|
|
||||||
* return `None` or raise an `Exception` in case it is unable to extract thumbnail
|
|
||||||
* return tuple `fmt, stream, offset, whence, size` otherwise:
|
|
||||||
* `fmt: str` – format (filename extension) of the thumbnail; should be one of the image formats supported by copyparty (see `--th-r-*` options)
|
|
||||||
* `stream: IO[bytes]` – binary file-like object supporting `seek()`, `read()`, `close()` methods; should contain extracted thumbnail image
|
|
||||||
* `offset: int, whence: int` – arguments to `stream.seek()`; copyparty will call `stream.seek(offset, whence)` once before starting reading the stream contents
|
|
||||||
* `size: int | None` – number of bytes to read from the `stream`; if `size` is negative or `None`, copyparty will read until the end of the stream
|
|
||||||
|
|
||||||
|
|
||||||
### notes
|
|
||||||
|
|
||||||
it is possible to extract or generate custom thumbnails for standard media files too,
|
|
||||||
e.g. run copyparty with `--th-extract mp3,m4a,aac,flac,opus=~/dev/copyparty/bin/thumbs/my_custom_mp3_th_extractor.py` and do your magic with audio file thumbnails
|
|
||||||
|
|
||||||
in case copyparty doesn't like the `fmt` option, it will `close()` the `stream` without ever calling `seek()` or `read()`
|
|
||||||
|
|
||||||
if your scenario involves heavy computation or i/o, it is better to defer the heavy parts until the first `seek()` or `read()` to avoid redundant work in case the result gets rejected based on `fmt` value
|
|
||||||
|
|
||||||
if you provide custom `stream` object:
|
|
||||||
copyparty performs buffered reading, so expect multiple `read()` calls, respect `size` argument in `read(size)` calls, and maintain correct seek position
|
|
||||||
|
|
||||||
|
|
||||||
## examples
|
|
||||||
|
|
||||||
* [randomcolor](https://github.com/9001/copyparty/blob/hovudstraum/bin/thumbs/randomcolor.py) generates a random .gif image
|
|
||||||
|
|
||||||
|
|
||||||
## some other known plugins seen on the internets
|
|
||||||
|
|
||||||
* [fpkg_thumb](https://github.com/kamaeff/copyparty-dumb-fpkgi-handler/blob/master/fpkg_thumb.py) extracts cover images from playstation4 software installation packages ("pkg" and "fpkg" files)
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import io
|
|
||||||
import os
|
|
||||||
import struct
|
|
||||||
from base64 import b64decode
|
|
||||||
|
|
||||||
|
|
||||||
def create_gif() -> bytes:
|
|
||||||
head = r"R0lGODdhIAAgAIAB"
|
|
||||||
tail = r"AAD/LAAAAAAgACAAAAIehI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC5sFADs="
|
|
||||||
#color = struct.pack(">L", random.randrange(0xffffff)) # wow, way too stable
|
|
||||||
color = b"\x00" + os.urandom(3)
|
|
||||||
return b64decode(head) + color + b64decode(tail)
|
|
||||||
|
|
||||||
|
|
||||||
def main(abspath, **ka) -> Optional[tuple[str, IO[bytes], int, int, Optional[int]]]:
|
|
||||||
print("hello from randomcolor.py pretending to extract a thumb from " + abspath)
|
|
||||||
|
|
||||||
# need to return a file-like object
|
|
||||||
gif_bytes = create_gif()
|
|
||||||
file_obj = io.BytesIO(gif_bytes)
|
|
||||||
|
|
||||||
# where copyparty should seek to in the "file" to start reading from
|
|
||||||
seek_offset = 0
|
|
||||||
seek_whence = 0
|
|
||||||
|
|
||||||
filesize = None # auto; read until end
|
|
||||||
|
|
||||||
# "gif" is the file-extension to decode the file as
|
|
||||||
return "gif", file_obj, seek_offset, seek_whence, filesize
|
|
||||||
|
|
@ -1576,7 +1576,7 @@ NOTE: if server has --usernames enabled, then password is "username:password"
|
||||||
ap.add_argument("url", type=unicode, help="server url, including destination folder")
|
ap.add_argument("url", type=unicode, help="server url, including destination folder")
|
||||||
ap.add_argument("files", type=files_decoder, nargs="+", help="files and/or folders to process")
|
ap.add_argument("files", type=files_decoder, nargs="+", help="files and/or folders to process")
|
||||||
ap.add_argument("-v", action="store_true", help="verbose")
|
ap.add_argument("-v", action="store_true", help="verbose")
|
||||||
ap.add_argument("-a", metavar="PASSWD", default="", help="password (or $filepath) for copyparty (is sent in header 'PW'), default is env.var U2C_PW")
|
ap.add_argument("-a", metavar="PASSWD", default="", help="password (or $filepath) for copyparty (is sent in header 'PW')")
|
||||||
ap.add_argument("--ba", metavar="PASSWD", default="", help="password (or $filepath) for basic-auth (usually not necessary)")
|
ap.add_argument("--ba", metavar="PASSWD", default="", help="password (or $filepath) for basic-auth (usually not necessary)")
|
||||||
ap.add_argument("-s", action="store_true", help="file-search (disables upload)")
|
ap.add_argument("-s", action="store_true", help="file-search (disables upload)")
|
||||||
ap.add_argument("-x", type=unicode, metavar="REGEX", action="append", help="skip file if filesystem-abspath matches REGEX (option can be repeated), example: '.*/\\.hist/.*'")
|
ap.add_argument("-x", type=unicode, metavar="REGEX", action="append", help="skip file if filesystem-abspath matches REGEX (option can be repeated), example: '.*/\\.hist/.*'")
|
||||||
|
|
@ -1729,9 +1729,6 @@ NOTE: if server has --usernames enabled, then password is "username:password"
|
||||||
with open(zs[1:], "rb") as f:
|
with open(zs[1:], "rb") as f:
|
||||||
setattr(ar, k, f.read().decode("utf-8").strip())
|
setattr(ar, k, f.read().decode("utf-8").strip())
|
||||||
|
|
||||||
if not ar.a:
|
|
||||||
ar.a = os.environ.get("U2C_PW", "")
|
|
||||||
|
|
||||||
if ar.ba:
|
if ar.ba:
|
||||||
ar.ba = "Basic " + base64.b64encode(ar.ba.encode("utf-8")).decode("utf-8")
|
ar.ba = "Basic " + base64.b64encode(ar.ba.encode("utf-8")).decode("utf-8")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,8 @@ defaults
|
||||||
|
|
||||||
listen foo1
|
listen foo1
|
||||||
bind *:8081
|
bind *:8081
|
||||||
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
|
||||||
http-request add-header X-Forwarded-Proto http unless { ssl_fc }
|
|
||||||
server srv1 127.0.0.1:3923 maxconn 512
|
server srv1 127.0.0.1:3923 maxconn 512
|
||||||
|
|
||||||
listen foo2
|
listen foo2
|
||||||
bind *:8082
|
bind *:8082
|
||||||
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
|
||||||
http-request add-header X-Forwarded-Proto http unless { ssl_fc }
|
|
||||||
server srv1 /dev/shm/party.sock maxconn 512
|
server srv1 /dev/shm/party.sock maxconn 512
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead.
|
# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead.
|
||||||
|
|
||||||
pkgname=copyparty
|
pkgname=copyparty
|
||||||
pkgver="1.20.20"
|
pkgver="1.20.19"
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
||||||
arch=("any")
|
arch=("any")
|
||||||
|
|
@ -24,7 +24,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
|
||||||
)
|
)
|
||||||
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||||
backup=("etc/${pkgname}/copyparty.conf" )
|
backup=("etc/${pkgname}/copyparty.conf" )
|
||||||
sha256sums=("a31f9e4a43e56608765e108353140784d50181c37e705e9ce8ed9f3899f57dfa")
|
sha256sums=("834d97d637575cb9b2d53052790b6512f462b3241dff489cf641539ef624fd6c")
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
|
|
||||||
pkgname=copyparty
|
pkgname=copyparty
|
||||||
pkgver=1.20.20
|
pkgver=1.20.19
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
||||||
arch=("any")
|
arch=("any")
|
||||||
|
|
@ -21,7 +21,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
|
||||||
)
|
)
|
||||||
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||||
backup=("/etc/${pkgname}.d/init" )
|
backup=("/etc/${pkgname}.d/init" )
|
||||||
sha256sums=("a31f9e4a43e56608765e108353140784d50181c37e705e9ce8ed9f3899f57dfa")
|
sha256sums=("834d97d637575cb9b2d53052790b6512f462b3241dff489cf641539ef624fd6c")
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"url": "https://github.com/9001/copyparty/releases/download/v1.20.20/copyparty-1.20.20.tar.gz",
|
"url": "https://github.com/9001/copyparty/releases/download/v1.20.19/copyparty-1.20.19.tar.gz",
|
||||||
"version": "1.20.20",
|
"version": "1.20.19",
|
||||||
"hash": "sha256-ox+eSkPlZgh2XhCDUxQHhNUBgcN+cF6c6O2fOJn1ffo="
|
"hash": "sha256-g02X1jdXXLmy1TBSeQtlEvRisyQd/0ic9kFTnvYk/Ww="
|
||||||
}
|
}
|
||||||
|
|
@ -40,9 +40,6 @@ VT100 = "--ansi" in sys.argv or (
|
||||||
)
|
)
|
||||||
# introduced in anniversary update
|
# introduced in anniversary update
|
||||||
|
|
||||||
zs = os.environ.get("PRTY_CONFIG", "")
|
|
||||||
CFG_DEF = [zs] if zs else []
|
|
||||||
|
|
||||||
ANYWIN = WINDOWS or sys.platform in ["msys", "cygwin"]
|
ANYWIN = WINDOWS or sys.platform in ["msys", "cygwin"]
|
||||||
|
|
||||||
MACOS = platform.system() == "Darwin"
|
MACOS = platform.system() == "Darwin"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import uuid
|
||||||
|
|
||||||
from .__init__ import (
|
from .__init__ import (
|
||||||
ANYWIN,
|
ANYWIN,
|
||||||
CFG_DEF,
|
|
||||||
CORES,
|
CORES,
|
||||||
EXE,
|
EXE,
|
||||||
MACOS,
|
MACOS,
|
||||||
|
|
@ -64,7 +63,6 @@ from .util import (
|
||||||
URL_BUG,
|
URL_BUG,
|
||||||
URL_PRJ,
|
URL_PRJ,
|
||||||
Daemon,
|
Daemon,
|
||||||
absreal,
|
|
||||||
align_tab,
|
align_tab,
|
||||||
b64enc,
|
b64enc,
|
||||||
ctypes,
|
ctypes,
|
||||||
|
|
@ -107,6 +105,10 @@ except:
|
||||||
u = unicode
|
u = unicode
|
||||||
zsid = uuid.uuid4().urn[4:]
|
zsid = uuid.uuid4().urn[4:]
|
||||||
|
|
||||||
|
CFG_DEF = [os.environ.get("PRTY_CONFIG", "")]
|
||||||
|
if not CFG_DEF[0]:
|
||||||
|
CFG_DEF.pop()
|
||||||
|
|
||||||
FULL_HELP = os.environ.get("PRTY_FULL_HELP", "")
|
FULL_HELP = os.environ.get("PRTY_FULL_HELP", "")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -777,54 +779,6 @@ def get_sects():
|
||||||
).rstrip()
|
).rstrip()
|
||||||
+ build_flags_desc(),
|
+ build_flags_desc(),
|
||||||
],
|
],
|
||||||
[
|
|
||||||
"thumb-ex",
|
|
||||||
"extract thumbnails from custom file formats with python scripts",
|
|
||||||
dedent(
|
|
||||||
"""
|
|
||||||
copyparty is able to extract thumbnails from various media formats:
|
|
||||||
images, audio, video, ebooks
|
|
||||||
|
|
||||||
if you want to extract thumbnails from unsupported file formats,
|
|
||||||
you can load a plugin, which extracts image data from custom formats
|
|
||||||
|
|
||||||
load the plugin using --args; for example \033[36m
|
|
||||||
--tx-extract iso,mdf,dmg=~/party-thumb-extractors/th_diskimg.py
|
|
||||||
\033[0m
|
|
||||||
the file must define the function \033[35mmain(abspath, **kwargs)\033[0m:
|
|
||||||
\033[35mabspath\033[0m: path to the file to extract thumbnail from
|
|
||||||
\033[35mkwargs\033[0m currently have:
|
|
||||||
\033[35mvn\033[0m: the VFS which contains the requested file
|
|
||||||
\033[35mrth_srv\033[0m: the copyparty ThumbSrv instance
|
|
||||||
|
|
||||||
if `main` couldn't extract a thumbnail, it must return None;
|
|
||||||
otherwise the return value must be a tuple:
|
|
||||||
\033[35mreturn fmt, stream, offset, whence, size\033[0m
|
|
||||||
|
|
||||||
> \033[32mfmt\033[0m: thumbnail format, should be one of the formats
|
|
||||||
supported by copyparty; e.g. "png", "jpg"
|
|
||||||
|
|
||||||
> \033[32mstream\033[0m: binary file-like object containing the thumbnail,
|
|
||||||
supporting seek(), read(), and close() methods
|
|
||||||
|
|
||||||
> \033[32moffset, whence\033[0m: arguments to seek() method;
|
|
||||||
stream.seek(offset, whence) will be called once before copyparty
|
|
||||||
starts reading from the stream
|
|
||||||
|
|
||||||
> \033[32msize\033[0m: number of bytes to read ftom the stream;
|
|
||||||
if negative, copyparty will read through the end of the stream;
|
|
||||||
|
|
||||||
you can also supply extractors for standard formats to override default
|
|
||||||
thumbnail extraction behaviour; for example \033[36m
|
|
||||||
--tx-extract mp3=~/party-thumb-extractors/th_mp3.py
|
|
||||||
\033[0mwill let you extract or generate custom thumbnails for mp3 files
|
|
||||||
|
|
||||||
\033[1;35mPS!\033[0m the folder that contains the python file should ideally
|
|
||||||
not contain many other python files, and especially nothing
|
|
||||||
with filenames that overlap with modules used by copyparty
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"handlers",
|
"handlers",
|
||||||
"use plugins to handle certain events",
|
"use plugins to handle certain events",
|
||||||
|
|
@ -1384,7 +1338,7 @@ def add_upload(ap):
|
||||||
ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck")
|
ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck")
|
||||||
ap2.add_argument("--nosubtle", metavar="N", type=int, default=0, help="when to use a wasm-hasher instead of the browser's builtin; faster on chrome, but buggy in older chrome versions. [\033[32m0\033[0m] = only when necessary (non-https), [\033[32m1\033[0m] = always (all browsers), [\033[32m2\033[0m] = always on chrome/firefox, [\033[32m3\033[0m] = always on chrome, [\033[32mN\033[0m] = chrome-version N and newer (recommendation: 137)")
|
ap2.add_argument("--nosubtle", metavar="N", type=int, default=0, help="when to use a wasm-hasher instead of the browser's builtin; faster on chrome, but buggy in older chrome versions. [\033[32m0\033[0m] = only when necessary (non-https), [\033[32m1\033[0m] = always (all browsers), [\033[32m2\033[0m] = always on chrome/firefox, [\033[32m3\033[0m] = always on chrome, [\033[32mN\033[0m] = chrome-version N and newer (recommendation: 137)")
|
||||||
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed")
|
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed")
|
||||||
ap2.add_argument("--u2sz", metavar="N,N", type=u, default="64,96", help="web-client: default upload chunksize in MiB, either \033[33mtarget,max\033[0m or just \033[33mtarget\033[0m (sets both); this is \033[33mtarget\033[0m in the web-UI. Each HTTP POST will aim for \033[33mtarget\033[0m and never exceed \033[33mmax\033[0m. Cloudflare max is 96. Minimum is [\033[32m1\033[0m] and will be slow. Lowest recommended is [\033[32m8\033[0m]. Big values are good for cross-atlantic but may increase HDD fragmentation on some FS. Disable this optimization with [\033[32mno\033[0m]")
|
ap2.add_argument("--u2sz", metavar="N,N,N", type=u, default="1,64,96", help="web-client: default upload chunksize (MiB); sets \033[33mmin,default,max\033[0m in the settings gui. Each HTTP POST will aim for \033[33mdefault\033[0m, and never exceed \033[33mmax\033[0m. Cloudflare max is 96. Big values are good for cross-atlantic but may increase HDD fragmentation on some FS. Disable this optimization with [\033[32m1,1,1\033[0m]")
|
||||||
ap2.add_argument("--u2ow", metavar="NUM", type=int, default=0, help="web-client: default setting for when to replace/overwrite existing files; [\033[32m0\033[0m]=never, [\033[32m1\033[0m]=if-client-newer, [\033[32m2\033[0m]=always (volflag=u2ow)")
|
ap2.add_argument("--u2ow", metavar="NUM", type=int, default=0, help="web-client: default setting for when to replace/overwrite existing files; [\033[32m0\033[0m]=never, [\033[32m1\033[0m]=if-client-newer, [\033[32m2\033[0m]=always (volflag=u2ow)")
|
||||||
ap2.add_argument("--u2sort", metavar="TXT", type=u, default="s", help="upload order; [\033[32ms\033[0m]=smallest-first, [\033[32mn\033[0m]=alphabetical, [\033[32mfs\033[0m]=force-s, [\033[32mfn\033[0m]=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine")
|
ap2.add_argument("--u2sort", metavar="TXT", type=u, default="s", help="upload order; [\033[32ms\033[0m]=smallest-first, [\033[32mn\033[0m]=alphabetical, [\033[32mfs\033[0m]=force-s, [\033[32mfn\033[0m]=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine")
|
||||||
ap2.add_argument("--write-uplog", action="store_true", help="write POST reports to textfiles in working-directory")
|
ap2.add_argument("--write-uplog", action="store_true", help="write POST reports to textfiles in working-directory")
|
||||||
|
|
@ -1633,7 +1587,7 @@ def add_wopi(ap):
|
||||||
ap2.add_argument("--wopi", action="store_true", help="enable integration with office suites using WOPI")
|
ap2.add_argument("--wopi", action="store_true", help="enable integration with office suites using WOPI")
|
||||||
ap2.add_argument("--wopi-api", metavar="URL", type=u, default="", help="URL that the WOPI-client should use to communicate with copyparty; default is same as user's webbrowser. Example: [\033[32mhttps://party.example.com/\033[0m]")
|
ap2.add_argument("--wopi-api", metavar="URL", type=u, default="", help="URL that the WOPI-client should use to communicate with copyparty; default is same as user's webbrowser. Example: [\033[32mhttps://party.example.com/\033[0m]")
|
||||||
ap2.add_argument("--wopi-url", metavar="URL", type=u, default="", help="URL to your WOPI client; the host of e.g. Collabora Online. Example: [\033[32mhttps://code.example.com/\033[0m]")
|
ap2.add_argument("--wopi-url", metavar="URL", type=u, default="", help="URL to your WOPI client; the host of e.g. Collabora Online. Example: [\033[32mhttps://code.example.com/\033[0m]")
|
||||||
ap2.add_argument("--wopi-urls", metavar="H=U", type=u, action="append", help="\033[34mREPEATABLE:\033[0m maps http \033[33mH\033[0mOST copyparty being accessed by to specific WOPI client instance \033[33mU\033[0mRL; falls back to \033[33m--wopi-url\033[0m; examples: [\033[32mparty.public.com=https://office.public.com/\033[0m], [\033[32mparty.internal.net:8443=https://office.internal.net:8443/\033[0m]")
|
ap2.add_argument("--wopi-urls", metavar="HOST=URL", type=u, action="append", help="\033[34mREPEATABLE:\033[0m maps http \033[33mHOST\033[0m copyparty being accessed by to specific WOPI client instance \033[33mURL\033[0m; falls back to \033[33m--wopi-url\033[0m; examples: [\033[32mparty.public.com=https://office.public.com/\033[0m], [\033[32mparty.internal.net:8443=https://office.internal.net:8443/\033[0m]")
|
||||||
ap2.add_argument("--wopi-crt", metavar="TXT", type=u, default="", help="if \033[33m--wopi-url\033[0m is selfsigned: path to ca.pem or cert.pem to expect/verify (can be [\033[32mno\033[0m] for full-yolo)")
|
ap2.add_argument("--wopi-crt", metavar="TXT", type=u, default="", help="if \033[33m--wopi-url\033[0m is selfsigned: path to ca.pem or cert.pem to expect/verify (can be [\033[32mno\033[0m] for full-yolo)")
|
||||||
ap2.add_argument("--wopi-crt-icn", action="store_true", help="if \033[33m--wopi-url\033[0m is selfsigned: ignore the CN (server ip/name) in cert")
|
ap2.add_argument("--wopi-crt-icn", action="store_true", help="if \033[33m--wopi-url\033[0m is selfsigned: ignore the CN (server ip/name) in cert")
|
||||||
ap2.add_argument("--wopi-ttl", metavar="SEC", type=int, default=1800, help="session lifetime; allow editing for this many seconds (default is 30 min)")
|
ap2.add_argument("--wopi-ttl", metavar="SEC", type=int, default=1800, help="session lifetime; allow editing for this many seconds (default is 30 min)")
|
||||||
|
|
@ -1783,7 +1737,7 @@ def add_safety(ap):
|
||||||
ap2.add_argument("--use-bwrap", metavar="TXT", type=u, default="n", help=argparse.SUPPRESS)
|
ap2.add_argument("--use-bwrap", metavar="TXT", type=u, default="n", help=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
|
||||||
def add_salt(ap, fk_salt, dk_salt, ah_salt, wopi_salt):
|
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
||||||
ap2 = ap.add_argument_group("salting options")
|
ap2 = ap.add_argument_group("salting options")
|
||||||
ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)")
|
ap2.add_argument("--ah-alg", metavar="ALG", type=u, default="none", help="account-pw hashing algorithm; one of these, best to worst: \033[32margon2 scrypt sha2 none\033[0m (each optionally followed by alg-specific comma-sep. config)")
|
||||||
ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)")
|
ap2.add_argument("--ah-salt", metavar="SALT", type=u, default=ah_salt, help="account-pw salt; ignored if \033[33m--ah-alg\033[0m is none (default)")
|
||||||
|
|
@ -1792,7 +1746,6 @@ def add_salt(ap, fk_salt, dk_salt, ah_salt, wopi_salt):
|
||||||
ap2.add_argument("--fk-salt", metavar="SALT", type=u, default=fk_salt, help="per-file accesskey salt; used to generate unpredictable URLs for hidden files")
|
ap2.add_argument("--fk-salt", metavar="SALT", type=u, default=fk_salt, help="per-file accesskey salt; used to generate unpredictable URLs for hidden files")
|
||||||
ap2.add_argument("--dk-salt", metavar="SALT", type=u, default=dk_salt, help="per-directory accesskey salt; used to generate unpredictable URLs to share folders with users who only have the 'get' permission")
|
ap2.add_argument("--dk-salt", metavar="SALT", type=u, default=dk_salt, help="per-directory accesskey salt; used to generate unpredictable URLs to share folders with users who only have the 'get' permission")
|
||||||
ap2.add_argument("--warksalt", metavar="SALT", type=u, default="hunter2", help="up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do)")
|
ap2.add_argument("--warksalt", metavar="SALT", type=u, default="hunter2", help="up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do)")
|
||||||
ap2.add_argument("--wopi-salt", metavar="TXT", type=u, default=wopi_salt, help="WOPI file ID salt; used by \033[33m--wopi\033[0m for persistent file IDs")
|
|
||||||
ap2.add_argument("--show-ah-salt", action="store_true", help="on startup, print the effective value of \033[33m--ah-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
ap2.add_argument("--show-ah-salt", action="store_true", help="on startup, print the effective value of \033[33m--ah-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
||||||
ap2.add_argument("--show-fk-salt", action="store_true", help="on startup, print the effective value of \033[33m--fk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
ap2.add_argument("--show-fk-salt", action="store_true", help="on startup, print the effective value of \033[33m--fk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
||||||
ap2.add_argument("--show-dk-salt", action="store_true", help="on startup, print the effective value of \033[33m--dk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
ap2.add_argument("--show-dk-salt", action="store_true", help="on startup, print the effective value of \033[33m--dk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
||||||
|
|
@ -1886,19 +1839,8 @@ def add_thumbnail(ap):
|
||||||
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,epub,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,kra,ora,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,epub,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,kra,ora,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
||||||
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
||||||
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bcstm,bfstm,brstm,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,m4b,m4r,mdgz,mdxz,mdz,mka,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,oga,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bcstm,bfstm,brstm,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,m4b,m4r,mdgz,mdxz,mdz,mka,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,oga,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
||||||
|
|
||||||
ap2.add_argument("--th-pil-add", metavar="T", type=u, default="", help="add or remove image formats to decode using pillow listed in \033[33m--th-r-pil\033[0m; example: [\033[32mfb2,pdf,-psd,-bmp\033[0m] (add fb2 and pdf, remove psd and bmp)")
|
|
||||||
ap2.add_argument("--th-vips-add", metavar="T", type=u, default="", help="add or remove formats; same as \033[33m--th-pil-add\033[0m but for pyvips")
|
|
||||||
ap2.add_argument("--th-raw-add", metavar="T", type=u, default="", help="add or remove formats; same as \033[33m--th-pil-add\033[0m but for rawpy/libraw")
|
|
||||||
ap2.add_argument("--th-ffi-add", metavar="T", type=u, default="", help="add or remove formats; same as \033[33m--th-pil-add\033[0m but for ffmpeg images")
|
|
||||||
ap2.add_argument("--th-ffv-add", metavar="T", type=u, default="", help="add or remove formats; same as \033[33m--th-pil-add\033[0m but for ffmpeg videos")
|
|
||||||
ap2.add_argument("--th-ffa-add", metavar="T", type=u, default="", help="add or remove formats; same as \033[33m--th-pil-add\033[0m but for ffmpeg audio")
|
|
||||||
|
|
||||||
ap2.add_argument("--th-spec-cnv", metavar="T", type=u, default="it,itgz,itxz,itz,mdgz,mdxz,mdz,mo3,mod,s3m,s3gz,s3xz,s3z,xm,xmgz,xmxz,xmz,xpk", help="audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms)")
|
ap2.add_argument("--th-spec-cnv", metavar="T", type=u, default="it,itgz,itxz,itz,mdgz,mdxz,mdz,mo3,mod,s3m,s3gz,s3xz,s3z,xm,xmgz,xmxz,xmz,xpk", help="audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms)")
|
||||||
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz, epub=jpg.epub, kra=png.kra, ora=png.ora", help="audio/image formats to decompress before passing to ffmpeg")
|
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz, epub=jpg.epub, kra=png.kra, ora=png.ora", help="audio/image formats to decompress before passing to ffmpeg")
|
||||||
ap2.add_argument("--th-extract", metavar="T", type=u, action="append", help="\033[34mREPEATABLE:\033[0m list of file extensions to thumbnail using a custom plugin (a python script); example: [\033[32mmdf,iso,dmg=/thumbs/diskimg.py\033[0m], see --help-thumb-ex")
|
|
||||||
ap2.add_argument("--th-extr-sz", metavar="M", type=int, default=16, help="max num megabytes to allow \033[33m--th-extract\033[0m plugins to extract from each file")
|
|
||||||
ap2.add_argument("--hot-th-extr", action="store_true", help="recompile extractors on each thumbnail extraction -- expensive but convenient when hacking on stuff")
|
|
||||||
|
|
||||||
|
|
||||||
def add_transcoding(ap):
|
def add_transcoding(ap):
|
||||||
|
|
@ -2136,7 +2078,6 @@ def run_argparse(
|
||||||
fk_salt = get_salt("fk", 18)
|
fk_salt = get_salt("fk", 18)
|
||||||
dk_salt = get_salt("dk", 30)
|
dk_salt = get_salt("dk", 30)
|
||||||
ah_salt = get_salt("ah", 18)
|
ah_salt = get_salt("ah", 18)
|
||||||
wopi_salt = get_salt("wopi", 18)
|
|
||||||
|
|
||||||
# alpine peaks at 5 threads for some reason,
|
# alpine peaks at 5 threads for some reason,
|
||||||
# all others scale past that (but try to avoid SMT),
|
# all others scale past that (but try to avoid SMT),
|
||||||
|
|
@ -2173,7 +2114,7 @@ def run_argparse(
|
||||||
add_opds(ap)
|
add_opds(ap)
|
||||||
add_wopi(ap)
|
add_wopi(ap)
|
||||||
add_safety(ap)
|
add_safety(ap)
|
||||||
add_salt(ap, fk_salt, dk_salt, ah_salt, wopi_salt)
|
add_salt(ap, fk_salt, dk_salt, ah_salt)
|
||||||
add_optouts(ap)
|
add_optouts(ap)
|
||||||
add_shutdown(ap)
|
add_shutdown(ap)
|
||||||
add_yolo(ap)
|
add_yolo(ap)
|
||||||
|
|
@ -2276,9 +2217,6 @@ def main(argv: Optional[list[str]] = None) -> None:
|
||||||
argv.pop(n)
|
argv.pop(n)
|
||||||
break
|
break
|
||||||
|
|
||||||
if CFG_DEF:
|
|
||||||
CFG_DEF[0] = absreal(CFG_DEF[0])
|
|
||||||
|
|
||||||
ensure_locale()
|
ensure_locale()
|
||||||
|
|
||||||
ensure_webdeps()
|
ensure_webdeps()
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from .__init__ import ANYWIN, CFG_DEF, MACOS, PY2, TYPE_CHECKING, WINDOWS, E
|
from .__init__ import ANYWIN, MACOS, PY2, TYPE_CHECKING, WINDOWS, E
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
|
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
|
||||||
from .pwhash import PWHash
|
from .pwhash import PWHash
|
||||||
|
|
@ -25,7 +25,6 @@ from .util import (
|
||||||
FN_EMB,
|
FN_EMB,
|
||||||
HAVE_SQLITE3,
|
HAVE_SQLITE3,
|
||||||
IMPLICATIONS,
|
IMPLICATIONS,
|
||||||
LOG,
|
|
||||||
META_NOBOTS,
|
META_NOBOTS,
|
||||||
MIMES,
|
MIMES,
|
||||||
SQLITE_VER,
|
SQLITE_VER,
|
||||||
|
|
@ -2379,7 +2378,6 @@ class AuthSrv(object):
|
||||||
vol.flags["dvthumb"] = True
|
vol.flags["dvthumb"] = True
|
||||||
vol.flags["dathumb"] = True
|
vol.flags["dathumb"] = True
|
||||||
vol.flags["dithumb"] = True
|
vol.flags["dithumb"] = True
|
||||||
vol.flags["dethumb"] = True
|
|
||||||
|
|
||||||
have_fk = False
|
have_fk = False
|
||||||
for vol in vfs.all_nodes.values():
|
for vol in vfs.all_nodes.values():
|
||||||
|
|
@ -4081,11 +4079,6 @@ def expand_config_file(
|
||||||
if fp2 in ipath:
|
if fp2 in ipath:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if CFG_DEF and CFG_DEF[0] == fp2:
|
|
||||||
t = "ignoring PRTY_CONFIG because it was also autodiscovered by %s -> %s"
|
|
||||||
LOG[0]("root", t % (ipath, fp))
|
|
||||||
continue
|
|
||||||
|
|
||||||
expand_config_file(log, shenvexp, ret, fp2, ipath)
|
expand_config_file(log, shenvexp, ret, fp2, ipath)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,6 @@ flagcats = {
|
||||||
"dvthumb": "disables video thumbnails",
|
"dvthumb": "disables video thumbnails",
|
||||||
"dathumb": "disables audio thumbnails (spectrograms)",
|
"dathumb": "disables audio thumbnails (spectrograms)",
|
||||||
"dithumb": "disables image thumbnails",
|
"dithumb": "disables image thumbnails",
|
||||||
"dethumb": "disables custom thumbnails (--th-extract)",
|
|
||||||
"pngquant": "compress audio waveforms 33% better",
|
"pngquant": "compress audio waveforms 33% better",
|
||||||
"thsize": "thumbnail res; WxH",
|
"thsize": "thumbnail res; WxH",
|
||||||
"crop": "center-cropping (y/n/fy/fn)",
|
"crop": "center-cropping (y/n/fy/fn)",
|
||||||
|
|
|
||||||
|
|
@ -1649,8 +1649,7 @@ class HttpCli(object):
|
||||||
raise Pebkac(500, "too many wopi sessions")
|
raise Pebkac(500, "too many wopi sessions")
|
||||||
if not found:
|
if not found:
|
||||||
atoken = ub64enc(os.urandom(18)).decode("ascii") # 18 = 144b = 24c
|
atoken = ub64enc(os.urandom(18)).decode("ascii") # 18 = 144b = 24c
|
||||||
zb = (vpath + self.args.wopi_salt).encode("utf-8", "replace")
|
file_id = ub64enc(os.urandom(15)).decode("ascii") # 15 = 120b = 20c
|
||||||
file_id = ub64enc(hashlib.sha512(zb).digest()[:15]).decode("ascii")
|
|
||||||
wopi_files[atoken] = session = {
|
wopi_files[atoken] = session = {
|
||||||
"vp": vpath,
|
"vp": vpath,
|
||||||
"uname": self.uname,
|
"uname": self.uname,
|
||||||
|
|
@ -1658,7 +1657,7 @@ class HttpCli(object):
|
||||||
"expires": time.time() + self.args.wopi_ttl,
|
"expires": time.time() + self.args.wopi_ttl,
|
||||||
}
|
}
|
||||||
|
|
||||||
xml = url = "?"
|
xml = "?"
|
||||||
try:
|
try:
|
||||||
from .dxml import parse_xml
|
from .dxml import parse_xml
|
||||||
|
|
||||||
|
|
@ -1696,8 +1695,7 @@ class HttpCli(object):
|
||||||
url += quotep(zs + "/wopi/files/" + session["file_id"])
|
url += quotep(zs + "/wopi/files/" + session["file_id"])
|
||||||
except:
|
except:
|
||||||
del wopi_files[atoken] # dont reuse an atoken wopi-client doesnt like
|
del wopi_files[atoken] # dont reuse an atoken wopi-client doesnt like
|
||||||
t = "reading WOPI-client response from %s failed; %s\n%s"
|
self.log("reading WOPI-client response failed; %s\n%s" % (min_ex(), xml), 3)
|
||||||
self.log(t % (url, min_ex(), xml), 3)
|
|
||||||
raise Pebkac(500, "wopi error (see fileserver log)")
|
raise Pebkac(500, "wopi error (see fileserver log)")
|
||||||
|
|
||||||
html = self.j2s(
|
html = self.j2s(
|
||||||
|
|
@ -1705,7 +1703,7 @@ class HttpCli(object):
|
||||||
title=self.uparam["wopi"],
|
title=self.uparam["wopi"],
|
||||||
url=url,
|
url=url,
|
||||||
atoken=atoken,
|
atoken=atoken,
|
||||||
ttl=int(session["expires"] * 1000),
|
ttl=session["expires"],
|
||||||
).encode("utf-8", "replace")
|
).encode("utf-8", "replace")
|
||||||
|
|
||||||
self.reply(html, 200, "text/html; charset=utf-8")
|
self.reply(html, 200, "text/html; charset=utf-8")
|
||||||
|
|
@ -7447,18 +7445,20 @@ class HttpCli(object):
|
||||||
dirs = []
|
dirs = []
|
||||||
files = []
|
files = []
|
||||||
ptn_hr = RE_HR
|
ptn_hr = RE_HR
|
||||||
|
use_abs_url = is_opds or (
|
||||||
base = ""
|
vpath and not is_ls and not is_js and not self.trailing_slash
|
||||||
if is_opds or (vpath and not (is_ls or is_js or self.trailing_slash)):
|
)
|
||||||
if is_opds:
|
|
||||||
base = self.args.SRS
|
|
||||||
if vpath:
|
|
||||||
base += vpath + "/"
|
|
||||||
else:
|
|
||||||
base = "/" + vpath + "/"
|
|
||||||
|
|
||||||
for fn in ls_names:
|
for fn in ls_names:
|
||||||
href = base + fn
|
base = ""
|
||||||
|
href = fn
|
||||||
|
if use_abs_url:
|
||||||
|
if is_opds:
|
||||||
|
base = self.args.SRS
|
||||||
|
if vpath:
|
||||||
|
base += vpath + "/"
|
||||||
|
else:
|
||||||
|
base = "/" + vpath + "/"
|
||||||
|
href = base + fn
|
||||||
|
|
||||||
if fn in vfs_virt:
|
if fn in vfs_virt:
|
||||||
fspath = vfs_virt[fn].realpath
|
fspath = vfs_virt[fn].realpath
|
||||||
|
|
@ -7893,10 +7893,6 @@ class HttpCli(object):
|
||||||
ext in self.thumbcli.fmt_pil
|
ext in self.thumbcli.fmt_pil
|
||||||
or ext in self.thumbcli.fmt_vips
|
or ext in self.thumbcli.fmt_vips
|
||||||
or ext in self.thumbcli.fmt_ffi
|
or ext in self.thumbcli.fmt_ffi
|
||||||
or (
|
|
||||||
ext in self.thumbcli.thumbable
|
|
||||||
and ext not in self.thumbcli.thumbable_native
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
is_vid = ext in self.thumbcli.fmt_ffv
|
is_vid = ext in self.thumbcli.fmt_ffv
|
||||||
is_au = ext in self.thumbcli.fmt_ffa
|
is_au = ext in self.thumbcli.fmt_ffa
|
||||||
|
|
|
||||||
|
|
@ -133,19 +133,6 @@ VER_SHARES_DB = 2
|
||||||
CVE_SEVS = {"low": 1, "medium": 2, "moderate": 2, "high": 3, "critical": 4}
|
CVE_SEVS = {"low": 1, "medium": 2, "moderate": 2, "high": 3, "critical": 4}
|
||||||
|
|
||||||
|
|
||||||
def _build_th_fset(f: str, fadd: str) -> set[str]:
|
|
||||||
fset = {x for x in f.replace(" ", "").split(",")}
|
|
||||||
rmset = {""}
|
|
||||||
|
|
||||||
for x in fadd.replace(" ", "").split(","):
|
|
||||||
if x.startswith("-"):
|
|
||||||
rmset.add(x.lstrip("-"))
|
|
||||||
else:
|
|
||||||
fset.add(x)
|
|
||||||
|
|
||||||
return fset - rmset
|
|
||||||
|
|
||||||
|
|
||||||
class SvcHub(object):
|
class SvcHub(object):
|
||||||
"""
|
"""
|
||||||
Hosts all services which cannot be parallelized due to reliance on monolithic resources.
|
Hosts all services which cannot be parallelized due to reliance on monolithic resources.
|
||||||
|
|
@ -454,20 +441,6 @@ class SvcHub(object):
|
||||||
zlss = [x.strip().lower().split("=", 1) for x in args.au_unpk.split(",")]
|
zlss = [x.strip().lower().split("=", 1) for x in args.au_unpk.split(",")]
|
||||||
args.au_unpk = {x[0]: x[1] for x in zlss}
|
args.au_unpk = {x[0]: x[1] for x in zlss}
|
||||||
|
|
||||||
args.th_r_pil = _build_th_fset(args.th_r_pil, args.th_pil_add)
|
|
||||||
args.th_r_vips = _build_th_fset(args.th_r_vips, args.th_vips_add)
|
|
||||||
args.th_r_raw = _build_th_fset(args.th_r_raw, args.th_raw_add)
|
|
||||||
args.th_r_ffi = _build_th_fset(args.th_r_ffi, args.th_ffi_add)
|
|
||||||
args.th_r_ffv = _build_th_fset(args.th_r_ffv, args.th_ffv_add)
|
|
||||||
args.th_r_ffa = _build_th_fset(args.th_r_ffa, args.th_ffa_add)
|
|
||||||
|
|
||||||
th_extract = args.th_extract or []
|
|
||||||
args.th_extract = {}
|
|
||||||
for arg in th_extract:
|
|
||||||
exts, script = arg.split("=", 1)
|
|
||||||
for ext in exts.split(","):
|
|
||||||
args.th_extract[ext.strip().lower()] = script
|
|
||||||
|
|
||||||
self.args.th_dec = list(decs.keys())
|
self.args.th_dec = list(decs.keys())
|
||||||
self.thumbsrv = None
|
self.thumbsrv = None
|
||||||
want_ff = False
|
want_ff = False
|
||||||
|
|
@ -505,7 +478,7 @@ class SvcHub(object):
|
||||||
t = "invalid mp3 transcoding quality [%s] specified; only supports [0] to disable, a CBR value such as [192k], or a CQ/CRF value such as [v2]"
|
t = "invalid mp3 transcoding quality [%s] specified; only supports [0] to disable, a CBR value such as [192k], or a CQ/CRF value such as [v2]"
|
||||||
raise Exception(t % (args.q_mp3,))
|
raise Exception(t % (args.q_mp3,))
|
||||||
else:
|
else:
|
||||||
zss = args.th_r_ffa | args.th_r_ffv
|
zss = set(args.th_r_ffa.split(",") + args.th_r_ffv.split(","))
|
||||||
args.au_unpk = {
|
args.au_unpk = {
|
||||||
k: v for k, v in args.au_unpk.items() if v.split(".")[0] not in zss
|
k: v for k, v in args.au_unpk.items() if v.split(".")[0] not in zss
|
||||||
}
|
}
|
||||||
|
|
@ -1154,10 +1127,6 @@ class SvcHub(object):
|
||||||
t = "not listening on any ip-addresses (only unix-sockets and/or FDs); cannot enable zeroconf/mdns/ssdp as requested"
|
t = "not listening on any ip-addresses (only unix-sockets and/or FDs); cannot enable zeroconf/mdns/ssdp as requested"
|
||||||
self.log("root", t, 3)
|
self.log("root", t, 3)
|
||||||
|
|
||||||
if al.wopi and not al.wopi_url and not al.wopi_urls:
|
|
||||||
self.log("root", "disabling wopi; need either wopi-url or wopi-urls", 1)
|
|
||||||
al.wopi = False
|
|
||||||
|
|
||||||
if self.args.wopi or not self.args.no_dav:
|
if self.args.wopi or not self.args.no_dav:
|
||||||
from .dxml import DXML_OK
|
from .dxml import DXML_OK
|
||||||
|
|
||||||
|
|
@ -1414,20 +1383,18 @@ class SvcHub(object):
|
||||||
self.args.name_html = zs
|
self.args.name_html = zs
|
||||||
|
|
||||||
zs = al.u2sz
|
zs = al.u2sz
|
||||||
if zs in ("no", "1,1,1"):
|
|
||||||
zs = "0"
|
|
||||||
zsl = [x.strip() for x in zs.split(",")]
|
zsl = [x.strip() for x in zs.split(",")]
|
||||||
if len(zsl) not in (1, 2):
|
if len(zsl) not in (1, 3):
|
||||||
t = "invalid --u2sz; must be either one number, or a comma-separated list of two numbers (target,max)"
|
t = "invalid --u2sz; must be either one number, or a comma-separated list of three numbers (min,default,max)"
|
||||||
raise Exception(t)
|
raise Exception(t)
|
||||||
if len(zsl) < 2:
|
if len(zsl) < 3:
|
||||||
zsl = [zs, zs]
|
zsl = ["1", zs, zs]
|
||||||
zi2 = 0
|
zi2 = 1
|
||||||
for zs in zsl:
|
for zs in zsl:
|
||||||
zi = int(zs)
|
zi = int(zs)
|
||||||
# arbitrary constraint (anything above 2 GiB is probably unintended)
|
# arbitrary constraint (anything above 2 GiB is probably unintended)
|
||||||
if zi < 0 or zi > 2047:
|
if zi < 1 or zi > 2047:
|
||||||
raise Exception("invalid --u2sz; minimum is 0, max is 2047")
|
raise Exception("invalid --u2sz; minimum is 1, max is 2047")
|
||||||
if zi < zi2:
|
if zi < zi2:
|
||||||
raise Exception("invalid --u2sz; values must be equal or ascending")
|
raise Exception("invalid --u2sz; values must be equal or ascending")
|
||||||
zi2 = zi
|
zi2 = zi
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ class ThumbCli(object):
|
||||||
self.cooldown = Cooldown(self.args.th_poke) if self.args.th_poke else None
|
self.cooldown = Cooldown(self.args.th_poke) if self.args.th_poke else None
|
||||||
|
|
||||||
self.thumbable = c["thumbable"]
|
self.thumbable = c["thumbable"]
|
||||||
self.thumbable_native = c["thumbable_native"]
|
|
||||||
self.fmt_pil = c["pil"]
|
self.fmt_pil = c["pil"]
|
||||||
self.fmt_vips = c["vips"]
|
self.fmt_vips = c["vips"]
|
||||||
self.fmt_raw = c["raw"]
|
self.fmt_raw = c["raw"]
|
||||||
|
|
@ -60,10 +59,6 @@ class ThumbCli(object):
|
||||||
if is_vid and "dvthumb" in dbv.flags:
|
if is_vid and "dvthumb" in dbv.flags:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
is_custom = ext not in self.thumbable_native
|
|
||||||
if is_custom and "dethumb" in dbv.flags:
|
|
||||||
return None
|
|
||||||
|
|
||||||
want_opus = fmt in EXTS_AC
|
want_opus = fmt in EXTS_AC
|
||||||
is_au = ext in self.fmt_ffa
|
is_au = ext in self.fmt_ffa
|
||||||
is_vau = want_opus and ext in self.fmt_ffv
|
is_vau = want_opus and ext in self.fmt_ffv
|
||||||
|
|
@ -81,7 +76,7 @@ class ThumbCli(object):
|
||||||
elif want_opus:
|
elif want_opus:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
is_img = not is_vid and not is_au and not is_custom
|
is_img = not is_vid and not is_au
|
||||||
if is_img and "dithumb" in dbv.flags:
|
if is_img and "dithumb" in dbv.flags:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,6 @@ from .util import (
|
||||||
afsenc,
|
afsenc,
|
||||||
atomic_move,
|
atomic_move,
|
||||||
fsenc,
|
fsenc,
|
||||||
loadpy,
|
|
||||||
min_ex,
|
min_ex,
|
||||||
runcmd,
|
runcmd,
|
||||||
statdir,
|
statdir,
|
||||||
|
|
@ -324,12 +323,24 @@ class ThumbSrv(object):
|
||||||
if self.args.th_clean:
|
if self.args.th_clean:
|
||||||
Daemon(self.cleaner, "thumb.cln")
|
Daemon(self.cleaner, "thumb.cln")
|
||||||
|
|
||||||
self.fmt_pil = self.args.th_r_pil
|
(
|
||||||
self.fmt_vips = self.args.th_r_vips
|
self.fmt_pil,
|
||||||
self.fmt_raw = self.args.th_r_raw
|
self.fmt_vips,
|
||||||
self.fmt_ffi = self.args.th_r_ffi
|
self.fmt_raw,
|
||||||
self.fmt_ffv = self.args.th_r_ffv
|
self.fmt_ffi,
|
||||||
self.fmt_ffa = self.args.th_r_ffa
|
self.fmt_ffv,
|
||||||
|
self.fmt_ffa,
|
||||||
|
) = [
|
||||||
|
set(y.split(","))
|
||||||
|
for y in [
|
||||||
|
self.args.th_r_pil,
|
||||||
|
self.args.th_r_vips,
|
||||||
|
self.args.th_r_raw,
|
||||||
|
self.args.th_r_ffi,
|
||||||
|
self.args.th_r_ffv,
|
||||||
|
self.args.th_r_ffa,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
if not H_PIL_HEIF:
|
if not H_PIL_HEIF:
|
||||||
for f in "heif heifs heic heics".split(" "):
|
for f in "heif heifs heic heics".split(" "):
|
||||||
|
|
@ -348,26 +359,23 @@ class ThumbSrv(object):
|
||||||
self.fmt_pil.discard(f)
|
self.fmt_pil.discard(f)
|
||||||
|
|
||||||
self.thumbable: set[str] = set()
|
self.thumbable: set[str] = set()
|
||||||
self.thumbable_native: set[str] = set()
|
|
||||||
self._build_thumbable()
|
self._build_thumbable()
|
||||||
|
|
||||||
def _build_thumbable(self) -> None:
|
def _build_thumbable(self) -> None:
|
||||||
self.thumbable_native.clear()
|
self.thumbable.clear()
|
||||||
|
|
||||||
if "pil" in self.args.th_dec:
|
if "pil" in self.args.th_dec:
|
||||||
self.thumbable_native |= self.fmt_pil
|
self.thumbable |= self.fmt_pil
|
||||||
|
|
||||||
if "vips" in self.args.th_dec:
|
if "vips" in self.args.th_dec:
|
||||||
self.thumbable_native |= self.fmt_vips
|
self.thumbable |= self.fmt_vips
|
||||||
|
|
||||||
if "raw" in self.args.th_dec:
|
if "raw" in self.args.th_dec:
|
||||||
self.thumbable_native |= self.fmt_raw
|
self.thumbable |= self.fmt_raw
|
||||||
|
|
||||||
if "ff" in self.args.th_dec:
|
if "ff" in self.args.th_dec:
|
||||||
for zss in [self.fmt_ffi, self.fmt_ffv, self.fmt_ffa]:
|
for zss in [self.fmt_ffi, self.fmt_ffv, self.fmt_ffa]:
|
||||||
self.thumbable_native |= zss
|
self.thumbable |= zss
|
||||||
|
|
||||||
self.thumbable = self.thumbable_native | set(self.args.th_extract)
|
|
||||||
|
|
||||||
def _log(self, msg: str, c: Union[int, str] = 0) -> None:
|
def _log(self, msg: str, c: Union[int, str] = 0) -> None:
|
||||||
self.log_func("thumb", msg, c)
|
self.log_func("thumb", msg, c)
|
||||||
|
|
@ -459,7 +467,6 @@ class ThumbSrv(object):
|
||||||
def getcfg(self) -> dict[str, set[str]]:
|
def getcfg(self) -> dict[str, set[str]]:
|
||||||
return {
|
return {
|
||||||
"thumbable": self.thumbable,
|
"thumbable": self.thumbable,
|
||||||
"thumbable_native": self.thumbable_native,
|
|
||||||
"pil": self.fmt_pil,
|
"pil": self.fmt_pil,
|
||||||
"vips": self.fmt_vips,
|
"vips": self.fmt_vips,
|
||||||
"raw": self.fmt_raw,
|
"raw": self.fmt_raw,
|
||||||
|
|
@ -542,36 +549,19 @@ class ThumbSrv(object):
|
||||||
png_ok = False
|
png_ok = False
|
||||||
funs = []
|
funs = []
|
||||||
|
|
||||||
tex = tpath.rsplit(".", 1)[-1]
|
|
||||||
want_mp3 = tex == "mp3"
|
|
||||||
want_opus = tex in ("opus", "owa", "caf")
|
|
||||||
want_flac = tex == "flac"
|
|
||||||
want_wav = tex == "wav"
|
|
||||||
want_png = tex == "png"
|
|
||||||
want_au = want_mp3 or want_opus or want_flac or want_wav
|
|
||||||
|
|
||||||
ap_extr = abspath
|
|
||||||
if (
|
|
||||||
ext in self.args.th_extract
|
|
||||||
and not want_au
|
|
||||||
and not want_png
|
|
||||||
and "dethumb" not in vn.flags
|
|
||||||
):
|
|
||||||
ap_extr = self.run_extractor(self.args.th_extract[ext], abspath, vn)
|
|
||||||
if ap_extr:
|
|
||||||
ext = ap_extr.rsplit(".", 1)[-1]
|
|
||||||
|
|
||||||
if ext in self.args.au_unpk:
|
if ext in self.args.au_unpk:
|
||||||
ap_unpk = au_unpk(self.log, self.args.au_unpk, ap_extr, vn)
|
ap_unpk = au_unpk(self.log, self.args.au_unpk, abspath, vn)
|
||||||
elif ext in self.thumbable_native:
|
|
||||||
ap_unpk = ap_extr
|
|
||||||
else:
|
else:
|
||||||
ap_unpk = ""
|
ap_unpk = abspath
|
||||||
|
|
||||||
if ap_extr and ap_extr != ap_unpk and ap_extr != abspath:
|
|
||||||
wunlink(self.log, ap_extr, vn.flags)
|
|
||||||
|
|
||||||
if ap_unpk and not bos.path.exists(tpath):
|
if ap_unpk and not bos.path.exists(tpath):
|
||||||
|
tex = tpath.rsplit(".", 1)[-1]
|
||||||
|
want_mp3 = tex == "mp3"
|
||||||
|
want_opus = tex in ("opus", "owa", "caf")
|
||||||
|
want_flac = tex == "flac"
|
||||||
|
want_wav = tex == "wav"
|
||||||
|
want_png = tex == "png"
|
||||||
|
want_au = want_mp3 or want_opus or want_flac or want_wav
|
||||||
for lib in self.args.th_dec:
|
for lib in self.args.th_dec:
|
||||||
can_au = lib == "ff" and (
|
can_au = lib == "ff" and (
|
||||||
ext in self.fmt_ffa or ext in self.fmt_ffv
|
ext in self.fmt_ffa or ext in self.fmt_ffv
|
||||||
|
|
@ -679,66 +669,6 @@ class ThumbSrv(object):
|
||||||
with self.mutex:
|
with self.mutex:
|
||||||
self.nthr -= 1
|
self.nthr -= 1
|
||||||
|
|
||||||
def run_extractor(self, extr: str, abspath: str, vn: VFS) -> str:
|
|
||||||
try:
|
|
||||||
mod = loadpy(extr, self.args.hot_th_extr)
|
|
||||||
except Exception as ex:
|
|
||||||
self.log("extractor import failed; " + min_ex(), 1)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
fd = 0
|
|
||||||
ret = ""
|
|
||||||
stream = None
|
|
||||||
try:
|
|
||||||
res = mod.main(abspath, vn=vn, th_srv=self)
|
|
||||||
if not res:
|
|
||||||
t = "extractor %r returned no data for file %r"
|
|
||||||
self.log(t % (extr, abspath))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
outext, stream, offset, whence, size = res
|
|
||||||
if (
|
|
||||||
outext not in self.thumbable_native
|
|
||||||
or outext in self.fmt_ffa
|
|
||||||
or outext in self.fmt_ffv
|
|
||||||
):
|
|
||||||
t = "extractor %r returned unsupported format %r"
|
|
||||||
self.log(t % (extr, outext))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
remains = size if size is not None and size >= 0 else -1
|
|
||||||
|
|
||||||
stream.seek(offset, whence)
|
|
||||||
fd, ret = tempfile.mkstemp("." + outext)
|
|
||||||
bufsz = rsz = self.args.iobuf
|
|
||||||
maxsz = self.args.th_extr_sz * 1048576
|
|
||||||
outsz = 0
|
|
||||||
with os.fdopen(fd, "wb", rsz) as f:
|
|
||||||
fd = 0
|
|
||||||
while True:
|
|
||||||
if remains < rsz and remains >= 0:
|
|
||||||
bufsz = remains
|
|
||||||
buf = stream.read(bufsz)
|
|
||||||
if not buf:
|
|
||||||
break
|
|
||||||
remains -= len(buf)
|
|
||||||
outsz += len(buf)
|
|
||||||
if outsz >= maxsz:
|
|
||||||
raise Exception("too large")
|
|
||||||
f.write(buf)
|
|
||||||
return ret
|
|
||||||
except Exception as e:
|
|
||||||
if fd:
|
|
||||||
os.close(fd)
|
|
||||||
if ret:
|
|
||||||
wunlink(self.log, ret, vn.flags)
|
|
||||||
t = "failed to extract thumbnail from %r: %s"
|
|
||||||
self.log(t % (abspath, min_ex()))
|
|
||||||
return ""
|
|
||||||
finally:
|
|
||||||
if stream:
|
|
||||||
stream.close()
|
|
||||||
|
|
||||||
def fancy_pillow(self, im: "Image.Image", fmt: str, vn: VFS) -> "Image.Image":
|
def fancy_pillow(self, im: "Image.Image", fmt: str, vn: VFS) -> "Image.Image":
|
||||||
# exif_transpose is expensive (loads full image + unconditional copy)
|
# exif_transpose is expensive (loads full image + unconditional copy)
|
||||||
res = self.getres(vn, fmt)
|
res = self.getres(vn, fmt)
|
||||||
|
|
|
||||||
|
|
@ -758,7 +758,7 @@ if (window.glang && navigator.languages && !/\bcplng=/.test(document.cookie))
|
||||||
if (window.stop)
|
if (window.stop)
|
||||||
window.stop();
|
window.stop();
|
||||||
document.body.innerHTML = 'Loading ' + n;
|
document.body.innerHTML = 'Loading ' + n;
|
||||||
setck("cplng=" + n, relod);
|
setck("cplng=" + n, location.reload.bind(location));
|
||||||
crashed = true;
|
crashed = true;
|
||||||
throw 1;
|
throw 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1246,8 +1246,8 @@ check_image_support('jxl', "data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgA=");
|
||||||
|
|
||||||
|
|
||||||
var img_re = APPLE ?
|
var img_re = APPLE ?
|
||||||
/\.(a?png|avif|bmp|gif|hei[cf]s?|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov|svg)(\?|$)/i :
|
/\.(a?png|avif|bmp|gif|hei[cf]s?|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov)(\?|$)/i :
|
||||||
/\.(a?png|avif|bmp|gif|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov|svg)(\?|$)/i;
|
/\.(a?png|avif|bmp|gif|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov)(\?|$)/i;
|
||||||
|
|
||||||
var wopi_set = !window.have_wopi ? null :
|
var wopi_set = !window.have_wopi ? null :
|
||||||
new Set('odt fodt ott doc docx dotx rtf odm ods fods ots xls xlsx odp fodp otp ppt pptx ppsx odg fodg otg odf'.split(' '));
|
new Set('odt fodt ott doc docx dotx rtf odm ods fods ots xls xlsx odp fodp otp ppt pptx ppsx odg fodg otg odf'.split(' '));
|
||||||
|
|
@ -5694,8 +5694,8 @@ var thegrid = (function () {
|
||||||
fid = oth.getAttribute('id'),
|
fid = oth.getAttribute('id'),
|
||||||
aplay = ebi('a' + fid),
|
aplay = ebi('a' + fid),
|
||||||
atext = ebi('t' + fid),
|
atext = ebi('t' + fid),
|
||||||
|
is_txt = atext && !/\.ts$/.test(href) && showfile.getlang(href),
|
||||||
is_img = img_re.test(href),
|
is_img = img_re.test(href),
|
||||||
is_txt = atext && !is_img && !/\.ts$/.test(href) && showfile.getlang(href),
|
|
||||||
is_dir = href.endsWith('/'),
|
is_dir = href.endsWith('/'),
|
||||||
is_srch = !!ebi('unsearch'),
|
is_srch = !!ebi('unsearch'),
|
||||||
in_tree = is_dir && treectl.find(oth.textContent.slice(0, -1)),
|
in_tree = is_dir && treectl.find(oth.textContent.slice(0, -1)),
|
||||||
|
|
@ -7696,7 +7696,7 @@ var treectl = (function () {
|
||||||
|
|
||||||
if (wopi_set && wopi_set.has(tn.ext))
|
if (wopi_set && wopi_set.has(tn.ext))
|
||||||
tn.lead = '<a href="?wopi=' + bhref +
|
tn.lead = '<a href="?wopi=' + bhref +
|
||||||
'" rel="nofollow" target="_blank" name="' + hname + '">📄</a>';
|
'" rel="nofollow" name="' + hname + '">📄</a>';
|
||||||
|
|
||||||
if (tn.lead == '-')
|
if (tn.lead == '-')
|
||||||
tn.lead = '<a href="?doc=' + bhref + '" id="t' + id +
|
tn.lead = '<a href="?doc=' + bhref + '" id="t' + id +
|
||||||
|
|
@ -8626,7 +8626,7 @@ var setfszf = (function () {
|
||||||
setck('cplng=' + lang);
|
setck('cplng=' + lang);
|
||||||
freshen();
|
freshen();
|
||||||
var t = L.tt == 'English' ? '' : Ls.eng.lang_set;
|
var t = L.tt == 'English' ? '' : Ls.eng.lang_set;
|
||||||
modal.confirm(L.lang_set + "\n\n" + t, relod, null);
|
modal.confirm(L.lang_set + "\n\n" + t, location.reload.bind(location), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
freshen();
|
freshen();
|
||||||
|
|
|
||||||
|
|
@ -325,9 +325,6 @@ var modpoll = new Modpoll();
|
||||||
|
|
||||||
|
|
||||||
window.onbeforeunload = function (e) {
|
window.onbeforeunload = function (e) {
|
||||||
if (window.gtfo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((ebi("save").className + '').indexOf('disabled') >= 0)
|
if ((ebi("save").className + '').indexOf('disabled') >= 0)
|
||||||
return; //nice (todo)
|
return; //nice (todo)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -888,8 +888,9 @@ function up2k_init(subtle) {
|
||||||
setmsg(suggest_up2k, 'msg');
|
setmsg(suggest_up2k, 'msg');
|
||||||
|
|
||||||
var u2szs = u2sz.split(','),
|
var u2szs = u2sz.split(','),
|
||||||
u2sz_tgt = parseInt(u2szs[0]),
|
u2sz_min = parseInt(u2szs[0]),
|
||||||
u2sz_max = parseInt(u2szs[1]);
|
u2sz_tgt = parseInt(u2szs[1]),
|
||||||
|
u2sz_max = parseInt(u2szs[2]);
|
||||||
|
|
||||||
var parallel_uploads = ebi('nthread').value = icfg_get('nthread', u2j),
|
var parallel_uploads = ebi('nthread').value = icfg_get('nthread', u2j),
|
||||||
stitch_tgt = ebi('u2szg').value = icfg_get('u2sz', u2sz_tgt),
|
stitch_tgt = ebi('u2szg').value = icfg_get('u2sz', u2sz_tgt),
|
||||||
|
|
@ -2676,7 +2677,7 @@ function up2k_init(subtle) {
|
||||||
ccs += stp; stp *= 2;
|
ccs += stp; stp *= 2;
|
||||||
}
|
}
|
||||||
ocs = Math.floor(ocs / 1024 / 1024);
|
ocs = Math.floor(ocs / 1024 / 1024);
|
||||||
t.stitch_sz = Math.min(ocs, stitch_tgt || 1);
|
t.stitch_sz = Math.min(ocs, stitch_tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var a = 0; a < t.postlist.length; a++) {
|
for (var a = 0; a < t.postlist.length; a++) {
|
||||||
|
|
@ -2878,8 +2879,7 @@ function up2k_init(subtle) {
|
||||||
nparts = upt.nparts,
|
nparts = upt.nparts,
|
||||||
pcar = nparts[0],
|
pcar = nparts[0],
|
||||||
pcdr = nparts[nparts.length - 1],
|
pcdr = nparts[nparts.length - 1],
|
||||||
maxmsz = stitch_tgt == u2sz_tgt ? u2sz_max : stitch_tgt,
|
maxsz = (u2sz_max > 1 ? u2sz_max : 2040) * 1024 * 1024;
|
||||||
maxsz = (maxmsz > 0 ? maxmsz : 2040) * 1024 * 1024;
|
|
||||||
|
|
||||||
if (t.done)
|
if (t.done)
|
||||||
return console.log('done; skip chunk', t.name, t);
|
return console.log('done; skip chunk', t.name, t);
|
||||||
|
|
@ -2951,9 +2951,6 @@ function up2k_init(subtle) {
|
||||||
st.etac.u++;
|
st.etac.u++;
|
||||||
st.etac.t++;
|
st.etac.t++;
|
||||||
}
|
}
|
||||||
else if (xhr.status == 413) {
|
|
||||||
modal.die('bad server config; see "u2sz" in readme');
|
|
||||||
}
|
|
||||||
else if (txt.indexOf('already got that') + 1) {
|
else if (txt.indexOf('already got that') + 1) {
|
||||||
unqueue_up(t);
|
unqueue_up(t);
|
||||||
}
|
}
|
||||||
|
|
@ -3166,7 +3163,7 @@ function up2k_init(subtle) {
|
||||||
var el = ebi('u2szg'), n = parseInt(el.value);
|
var el = ebi('u2szg'), n = parseInt(el.value);
|
||||||
stitch_tgt = n = (
|
stitch_tgt = n = (
|
||||||
isNaN(n) ? u2sz_tgt :
|
isNaN(n) ? u2sz_tgt :
|
||||||
n < 0 ? 0 :
|
n < u2sz_min ? u2sz_min :
|
||||||
n > u2sz_max ? u2sz_max : n
|
n > u2sz_max ? u2sz_max : n
|
||||||
);
|
);
|
||||||
if (n == u2sz_tgt) sdrop('u2sz'); else swrite('u2sz', n);
|
if (n == u2sz_tgt) sdrop('u2sz'); else swrite('u2sz', n);
|
||||||
|
|
@ -3403,7 +3400,7 @@ function up2k_init(subtle) {
|
||||||
function set_nosubtle(v) {
|
function set_nosubtle(v) {
|
||||||
if (!WebAssembly)
|
if (!WebAssembly)
|
||||||
return toast.err(10, L.u_nowork);
|
return toast.err(10, L.u_nowork);
|
||||||
modal.confirm(L.lang_set, relod, null);
|
modal.confirm(L.lang_set, location.reload.bind(location), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_upnag(en) {
|
function set_upnag(en) {
|
||||||
|
|
@ -3474,9 +3471,6 @@ function up2k_init(subtle) {
|
||||||
|
|
||||||
|
|
||||||
function warn_uploader_busy(e) {
|
function warn_uploader_busy(e) {
|
||||||
if (window.gtfo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.returnValue = '';
|
e.returnValue = '';
|
||||||
return "upload in progress, click abort and use the file-tree to navigate instead";
|
return "upload in progress, click abort and use the file-tree to navigate instead";
|
||||||
|
|
|
||||||
|
|
@ -108,13 +108,6 @@ function qsr(sel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function relod() {
|
|
||||||
crashed = 1;
|
|
||||||
window.gtfo = 1;
|
|
||||||
location.href = location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// error handler for mobile devices
|
// error handler for mobile devices
|
||||||
function esc(txt) {
|
function esc(txt) {
|
||||||
return txt.replace(/[&"<>]/g, function (c) {
|
return txt.replace(/[&"<>]/g, function (c) {
|
||||||
|
|
@ -296,7 +289,7 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
|
||||||
var x = ebi('exh_wipecfg');
|
var x = ebi('exh_wipecfg');
|
||||||
if (x) x.onclick = function () {
|
if (x) x.onclick = function () {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
relod();
|
location.reload();
|
||||||
};
|
};
|
||||||
x = ebi('exh_ignex'); if (x) x.onclick = ignex;
|
x = ebi('exh_ignex'); if (x) x.onclick = ignex;
|
||||||
x = ebi('exh_ignexa'); if (x) x.onclick = ignexa;
|
x = ebi('exh_ignexa'); if (x) x.onclick = ignexa;
|
||||||
|
|
@ -2028,12 +2021,6 @@ var modal = (function () {
|
||||||
q.shift()();
|
q.shift()();
|
||||||
}
|
}
|
||||||
|
|
||||||
r.die = function (html) {
|
|
||||||
crashed = 1;
|
|
||||||
if (r.busy)
|
|
||||||
r.hide();
|
|
||||||
_alert(lf2br(html), relod);
|
|
||||||
};
|
|
||||||
r.alert = function (html, cb, fun) {
|
r.alert = function (html, cb, fun) {
|
||||||
q.push(function () {
|
q.push(function () {
|
||||||
_alert(lf2br(html), cb, fun);
|
_alert(lf2br(html), cb, fun);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ body {
|
||||||
<div style="display: none">
|
<div style="display: none">
|
||||||
<form action="{{ url }}" enctype="multipart/form-data" method="post" target="w" id="submit-form">
|
<form action="{{ url }}" enctype="multipart/form-data" method="post" target="w" id="submit-form">
|
||||||
<input name="access_token" value="{{ atoken }}" type="hidden" id="access-token"/>
|
<input name="access_token" value="{{ atoken }}" type="hidden" id="access-token"/>
|
||||||
<input name="access_token_ttl" value="{{ ttl }}" type="hidden" id="access-token_ttl"/>
|
<input name="access_token_ttl" value="{{ ttl }}000" type="hidden" id="access-token_ttl"/>
|
||||||
<input type="submit" value="" />
|
<input type="submit" value="" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ command -v gsort >/dev/null && {
|
||||||
|
|
||||||
cd ../dist
|
cd ../dist
|
||||||
|
|
||||||
kwds='-bind -accounts -auth -auth-ord -flags -thumb-ex -handlers -hooks -idp -urlform -exp -rlo -ls -dbd -chmod -pwhash -zm'
|
kwds='-bind -accounts -auth -auth-ord -flags -handlers -hooks -idp -urlform -exp -rlo -ls -dbd -chmod -pwhash -zm'
|
||||||
|
|
||||||
export PRTY_FULL_HELP=1
|
export PRTY_FULL_HELP=1
|
||||||
export PRTY_NO_PARAMIKO=1
|
export PRTY_NO_PARAMIKO=1
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ def cnv(src):
|
||||||
continue
|
continue
|
||||||
if '">uuid:' in ln:
|
if '">uuid:' in ln:
|
||||||
ln = re.sub(r">uuid:[0-9a-f-]{36}<", ">autogenerated<", ln)
|
ln = re.sub(r">uuid:[0-9a-f-]{36}<", ">autogenerated<", ln)
|
||||||
if "-salt " in ln and ("-salt SALT" in ln or "-salt TXT" in ln):
|
if "-salt SALT" in ln:
|
||||||
in_salt = 3
|
in_salt = 3
|
||||||
if in_salt:
|
if in_salt:
|
||||||
in_salt -= 1
|
in_salt -= 1
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ command -v gsort >/dev/null && {
|
||||||
( ( HLPTXT=CAT && cat || xsel -ob ) | sed -r '
|
( ( HLPTXT=CAT && cat || xsel -ob ) | sed -r '
|
||||||
s`/home/ed/`~/`;
|
s`/home/ed/`~/`;
|
||||||
s/uuid:[0-9a-f-]{36}/autogenerated/;
|
s/uuid:[0-9a-f-]{36}/autogenerated/;
|
||||||
s/(-salt (SALT|TXT).*default: )[0-9a-zA-Z/+]{24}\)/\124-character-autogenerated)/;
|
s/(-salt SALT.*default: )[0-9a-zA-Z/+]{24}\)/\124-character-autogenerated)/;
|
||||||
s/(-salt (SALT|TXT).*default: )[0-9a-zA-Z/+]{40}\)/\140-character-autogenerated)/;
|
s/(-salt SALT.*default: )[0-9a-zA-Z/+]{40}\)/\140-character-autogenerated)/;
|
||||||
s/(--name TXT.*default: )[^)]+/\1hostname/;
|
s/(--name TXT.*default: )[^)]+/\1hostname/;
|
||||||
s/(--hash-mt CORES.*default: )[0-9]+/\1numCores if 5 or less/;
|
s/(--hash-mt CORES.*default: )[0-9]+/\1numCores if 5 or less/;
|
||||||
s/(--mtag-mt|th-mt)( CORES.*default: )[0-9]+/\1\2numCores/;
|
s/(--mtag-mt|th-mt)( CORES.*default: )[0-9]+/\1\2numCores/;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ uname -s | grep WOW64 && m=64 || m=32
|
||||||
uname -s | grep NT-10 && w10=1 || w7=1
|
uname -s | grep NT-10 && w10=1 || w7=1
|
||||||
[ $w7 ] && [ -e up2k.sh ] && [ ! "$1" ] && ./up2k.sh
|
[ $w7 ] && [ -e up2k.sh ] && [ ! "$1" ] && ./up2k.sh
|
||||||
|
|
||||||
[ $w7 ] && pyv=37 || pyv=314
|
[ $w7 ] && pyv=37 || pyv=313
|
||||||
[ $w7 ] && sfx=en || sfx=sfx
|
[ $w7 ] && sfx=en || sfx=sfx
|
||||||
esuf=
|
esuf=
|
||||||
[ $w7 ] && [ $m = 32 ] && esuf=32
|
[ $w7 ] && [ $m = 32 ] && esuf=32
|
||||||
|
|
@ -100,14 +100,9 @@ excl=(
|
||||||
)
|
)
|
||||||
[ $w10 ] && excl+=(
|
[ $w10 ] && excl+=(
|
||||||
_pyrepl
|
_pyrepl
|
||||||
bz2 # 51k
|
|
||||||
compression.zstd # 195k
|
|
||||||
concurrent.interpreters # 12k
|
|
||||||
distutils
|
distutils
|
||||||
setuptools
|
setuptools
|
||||||
ftplib # 23k
|
|
||||||
PIL._avif
|
PIL._avif
|
||||||
PIL._imagingft # 861k (freetype)
|
|
||||||
PIL.ImageQt
|
PIL.ImageQt
|
||||||
PIL.ImageShow
|
PIL.ImageShow
|
||||||
PIL.ImageTk
|
PIL.ImageTk
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
76e42806c52319081201d9fd9101827d36d9dbdd34e04f8a48736f2e3b37d68e79e8f52e43260d3eaaa46fe149d95b54ef1355af24361d0bf190dced93cd77bb altgraph-0.17.5-py2.py3-none-any.whl
|
f117016b1e6a7d7e745db30d3e67f1acf7957c443a0dd301b6c5e10b8368f2aa4db6be9782d2d3f84beadd139bfeef4982e40f21ca5d9065cb794eeb0e473e82 altgraph-0.17.4-py2.py3-none-any.whl
|
||||||
17ce52ba50692a9d964f57a23ac163fb74c77fdeb2ca988a6d439ae1fe91955ff43730c073af97a7b3223093ffea3479a996b9b50ee7fba0869247a56f74baa6 pefile-2023.2.7-py3-none-any.whl
|
17ce52ba50692a9d964f57a23ac163fb74c77fdeb2ca988a6d439ae1fe91955ff43730c073af97a7b3223093ffea3479a996b9b50ee7fba0869247a56f74baa6 pefile-2023.2.7-py3-none-any.whl
|
||||||
b297ff66ec50cf5a1abcf07d6ac949644c5150ba094ffac974c5d27c81574c3e97ed814a47547f4b03a4c83ea0fb8f026433fca06a3f08e32742dc5c024f3d07 pywin32_ctypes-0.2.3-py3-none-any.whl
|
b297ff66ec50cf5a1abcf07d6ac949644c5150ba094ffac974c5d27c81574c3e97ed814a47547f4b03a4c83ea0fb8f026433fca06a3f08e32742dc5c024f3d07 pywin32_ctypes-0.2.3-py3-none-any.whl
|
||||||
76724b04d6fdfadb46f27b6fd5753429d597642d1035ff7bf52fe1b6f5bc18f129567b738a40436adf03afd3a38708dc268de3c1b5d4ef9a89968335805ead72 upx-5.2.0-win32.zip
|
fd88d00c7231f9fcbe0fb9037217b6ae5dcb5b06a98be56243400542671a32f003d594b2e1852f77d316e9327ad4c643321e1f9f3ea20cc8500ac5bba8ae170e upx-5.0.2-win32.zip
|
||||||
# win7
|
# win7
|
||||||
d9d30ff960365307833425e340bf0a642fd54e35155f18ff1d9746bc1ecf8ecb864aad24948735e8fd994503b659dc8968e6ba337eeb4568217ebdf97dd292dd Git-2.46.2-32-bit.exe
|
d9d30ff960365307833425e340bf0a642fd54e35155f18ff1d9746bc1ecf8ecb864aad24948735e8fd994503b659dc8968e6ba337eeb4568217ebdf97dd292dd Git-2.46.2-32-bit.exe
|
||||||
3253e86471e6f9fa85bfdb7684cd2f964ed6e35c6a4db87f81cca157c049bef43e66dfcae1e037b2fb904567b1e028aaeefe8983ba3255105df787406d2aa71e en_windows_7_professional_with_sp1_x86_dvd_u_677056.iso
|
3253e86471e6f9fa85bfdb7684cd2f964ed6e35c6a4db87f81cca157c049bef43e66dfcae1e037b2fb904567b1e028aaeefe8983ba3255105df787406d2aa71e en_windows_7_professional_with_sp1_x86_dvd_u_677056.iso
|
||||||
|
|
@ -21,15 +21,15 @@ ea73aa54cc6d5db20dfb127e54562dabf890e4cd6171a91b10a51af2bcfc76e1d64cbdce4546df2d
|
||||||
479a63e14586ab2f2228208116fc149ed8ee7b1e4ff360754f5bda4bf765c61af2e04b5ef123976623d04df4976b7886e0445647269da81436bd0a7b5671d361 windows6.1-kb2533623-x86.msu
|
479a63e14586ab2f2228208116fc149ed8ee7b1e4ff360754f5bda4bf765c61af2e04b5ef123976623d04df4976b7886e0445647269da81436bd0a7b5671d361 windows6.1-kb2533623-x86.msu
|
||||||
ac96786e5d35882e0c5b724794329c9125c2b86ae7847f17acfc49f0d294312c6afc1c3f248655de3f0ccb4ca426d7957d02ba702f4a15e9fcd7e2c314e72c19 zipp-3.15.0-py3-none-any.whl
|
ac96786e5d35882e0c5b724794329c9125c2b86ae7847f17acfc49f0d294312c6afc1c3f248655de3f0ccb4ca426d7957d02ba702f4a15e9fcd7e2c314e72c19 zipp-3.15.0-py3-none-any.whl
|
||||||
# win10
|
# win10
|
||||||
ef723f34ce8c0c1f8ef9eb7746f77e4ab6129aa7c7dcf501bee56f522ff2c57ff013f9a69db141ad04c9d1b90b4f1bbd22b6028218e3ae68eb4efec861d63f65 Git-2.55.0.3-64-bit.exe
|
f4b4e330995ebe96c0bd06e16e5b26062ece9473f06d369775aa68eab261dedcf32dfdd159acaa227502bbf9fa2cd8bbe57cddb89fc6f2196fef7a9ed5a80ae9 Git-2.51.0-64-bit.exe
|
||||||
0a2cd4cadf0395f0374974cd2bc2407e5cc65c111275acdffb6ecc5a2026eee9e1bb3da528b35c7f0ff4b64563a74857d5c2149051e281cc09ebd0d1968be9aa en-us_windows_10_enterprise_ltsc_2021_x64_dvd_d289cf96.iso
|
0a2cd4cadf0395f0374974cd2bc2407e5cc65c111275acdffb6ecc5a2026eee9e1bb3da528b35c7f0ff4b64563a74857d5c2149051e281cc09ebd0d1968be9aa en-us_windows_10_enterprise_ltsc_2021_x64_dvd_d289cf96.iso
|
||||||
4f13070cc9241fa342deab4ebfac360565030580ff77b6e5f1951a64627621e5da4abfd30e1e46ca8bae2bb7dd4ff98141aff424142c9629a5876a61283962e5 virtio-win-0.1.285.iso
|
4f13070cc9241fa342deab4ebfac360565030580ff77b6e5f1951a64627621e5da4abfd30e1e46ca8bae2bb7dd4ff98141aff424142c9629a5876a61283962e5 virtio-win-0.1.285.iso
|
||||||
9a7f40edc6f9209a2acd23793f3cbd6213c94f36064048cb8bf6eb04f1bdb2c2fe991cb09f77fe8b13e5cd85c618ef23573e79813b2fef899ab2f290cd129779 jinja2-3.1.6-py3-none-any.whl
|
9a7f40edc6f9209a2acd23793f3cbd6213c94f36064048cb8bf6eb04f1bdb2c2fe991cb09f77fe8b13e5cd85c618ef23573e79813b2fef899ab2f290cd129779 jinja2-3.1.6-py3-none-any.whl
|
||||||
52adad30ac608695a6345468144048e5134696313ab775ef72f41ca082f8fa19953e2b9924fb5970f829bf9188183fe616b3942c4705eeddfe4ce223a5940186 markupsafe-3.0.3-cp314-cp314-win_amd64.whl
|
00731cfdd9d5c12efef04a7161c90c1e5ed1dc4677aa88a1d4054aff836f3430df4da5262ed4289c21637358a9e10e5df16f76743cbf5a29bb3a44b146c19cf3 MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl
|
||||||
c7668214758cb79a6ba0f7dbffb4b1b6f7cbf98d8ab6cbe77ab42c891916de9339bf17e3de3c3f2d20f6065b49f97c6d521419cc0a2b6c6b8940cf4317172d71 mutagen-1.48.1-py3-none-any.whl
|
8a6e2b13a2ec4ef914a5d62aad3db6464d45e525a82e07f6051ed10474eae959069e165dba011aefb8207cdfd55391d73d6f06362c7eb247b08763106709526e mutagen-1.47.0-py3-none-any.whl
|
||||||
e9492eedaac7cfddde6d84389ef7df86c68275e8f29d838fc431d9bf379401bf6d82ec70ac02461995982613c80592cd8de74c16a3654d7d8fdc06f96057d6e7 packaging-26.3-py3-none-any.whl
|
a726fb46cce24f781fc8b55a3e6dea0a884ebc3b2b400ea74aa02333699f4955a5dc1e2ec5927ac72f35a624401f3f3b442882ba1cc4cadaf9c88558b5b8bdae packaging-25.0-py3-none-any.whl
|
||||||
8ea9946d8484a6de833a97d3cd545c2b67475207944856281cffb2c513ab14bf50e2b9d31d7cca8f50a6ca8b6711fb8e45cbadabd566cab28f7d58ee058dc650 pillow-12.3.0-cp314-cp314-win_amd64.whl
|
efcb9da8e6f50cb5ea8e1d41e631e89b6f852b68a2568619a6ec151267e7fac94aba1e36317341c4fc5df822215b7ab9dd6b33cfb738e1b8423d4f0f6cff9525 pillow-12.3.0-cp313-cp313-win_amd64.whl
|
||||||
6f7ed5dc47ade9ad56f6f0499bc5d8eb485bd454d47189133297fa5aa633cf70dad18656cd673318c664f96097c39003d94d9c9703c8337d62840b4564695a04 pyinstaller-6.21.0-py3-none-win_amd64.whl
|
b9b98714dfca6fa80b0b3f222965724d63be9c54d19435d1fe768e07016913d6db8d6e043fcb185b55a9bd6fe370a80cf961814fc096046a5f4640d99ed575ef pyinstaller-6.15.0-py3-none-win_amd64.whl
|
||||||
0a7c1ae7063a2ee46a1c5c057fe73838d7dc5c59800e56037b3fb9dbd1c363915375f989160e44f21436e1071713682bb14473aa8112128beb670f5b110dc8e2 pyinstaller_hooks_contrib-2026.6-py3-none-any.whl
|
cad0f7cf39de691813b1d4abc7d33f8bda99a87d9c5886039b814752e8690364150da26fb61b3e28d5698ff57a90e6dcd619ed2b64b04f72b5aadb75e201bdb0 pyinstaller_hooks_contrib-2025.8-py3-none-any.whl
|
||||||
a4adbefaa216571ade7fda561ed3404c762ff03029696ce1745fd4e23b066cb49b1fef99792ce3a594a04f9260a2f05a9e2f851bcc83ed4404f00ce05709c56a python-3.14.7-amd64.exe
|
d0d23fd4ae8900764df664803844155994b253ed449b9ed54ea020fbfa7aaea8800ca1928e4a7f26b9278613f8bce27ef9a424cfcc4ca15551c7e4e1b78f3991 python-3.13.14-amd64.exe
|
||||||
bfda5996cdf908edf971df38421ed154e2f2c58f38731ad3be22a88e78c933c64efd35fbc6daf82845dc0b59b5211e925038b430749b2c851887096578c68219 setuptools-83.0.0-py3-none-any.whl
|
2a0420f7faaa33d2132b82895a8282688030e939db0225ad8abb95a47bdb87b45318f10985fc3cee271a9121441c1526caa363d7f2e4a4b18b1a674068766e87 setuptools-80.9.0-py3-none-any.whl
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 555 B After Width: | Height: | Size: 554 B |
|
|
@ -29,21 +29,21 @@ uname -s | grep NT-10 && w10=1 || {
|
||||||
w7=1; uname -s | grep WOW64 && w7x64=1 || w7x32=1
|
w7=1; uname -s | grep WOW64 && w7x64=1 || w7x32=1
|
||||||
}
|
}
|
||||||
fns=(
|
fns=(
|
||||||
altgraph-0.17.5-py2.py3-none-any.whl
|
altgraph-0.17.4-py2.py3-none-any.whl
|
||||||
pefile-2023.2.7-py3-none-any.whl
|
pefile-2023.2.7-py3-none-any.whl
|
||||||
pywin32_ctypes-0.2.3-py3-none-any.whl
|
pywin32_ctypes-0.2.3-py3-none-any.whl
|
||||||
upx-5.2.0-win32.zip
|
upx-5.0.2-win32.zip
|
||||||
)
|
)
|
||||||
[ $w10 ] && fns+=(
|
[ $w10 ] && fns+=(
|
||||||
jinja2-3.1.6-py3-none-any.whl
|
jinja2-3.1.6-py3-none-any.whl
|
||||||
markupsafe-3.0.3-cp314-cp314-win_amd64.whl
|
MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl
|
||||||
mutagen-1.48.1-py3-none-any.whl
|
mutagen-1.47.0-py3-none-any.whl
|
||||||
packaging-26.3-py3-none-any.whl
|
packaging-25.0-py3-none-any.whl
|
||||||
pillow-12.3.0-cp314-cp314-win_amd64.whl
|
pillow-12.3.0-cp313-cp313-win_amd64.whl
|
||||||
pyinstaller-6.21.0-py3-none-win_amd64.whl
|
pyinstaller-6.15.0-py3-none-win_amd64.whl
|
||||||
pyinstaller_hooks_contrib-2026.6-py3-none-any.whl
|
pyinstaller_hooks_contrib-2025.8-py3-none-any.whl
|
||||||
python-3.14.7-amd64.exe
|
python-3.13.14-amd64.exe
|
||||||
setuptools-83.0.0-py3-none-any.whl
|
setuptools-80.9.0-py3-none-any.whl
|
||||||
)
|
)
|
||||||
[ $w7 ] && fns+=(
|
[ $w7 ] && fns+=(
|
||||||
future-1.0.0-py3-none-any.whl
|
future-1.0.0-py3-none-any.whl
|
||||||
|
|
@ -83,7 +83,7 @@ close and reopen git-bash so python is in PATH
|
||||||
|
|
||||||
===[ copy-paste into git-bash ]================================
|
===[ copy-paste into git-bash ]================================
|
||||||
uname -s | grep NT-10 && w10=1 || w7=1
|
uname -s | grep NT-10 && w10=1 || w7=1
|
||||||
[ $w7 ] && pyv=37 || pyv=314
|
[ $w7 ] && pyv=37 || pyv=313
|
||||||
appd=$(cygpath.exe "$APPDATA")
|
appd=$(cygpath.exe "$APPDATA")
|
||||||
cd ~/Downloads &&
|
cd ~/Downloads &&
|
||||||
yes | unzip upx-*-win32.zip &&
|
yes | unzip upx-*-win32.zip &&
|
||||||
|
|
@ -91,7 +91,7 @@ mv upx-*/upx.exe . &&
|
||||||
python -m ensurepip &&
|
python -m ensurepip &&
|
||||||
{ [ $w10 ] || python -m pip install --user -U pip-*.whl; } &&
|
{ [ $w10 ] || python -m pip install --user -U pip-*.whl; } &&
|
||||||
python -m pip install --user -U packaging-*.whl &&
|
python -m pip install --user -U packaging-*.whl &&
|
||||||
{ [ $w7 ] || python -m pip install --user -U {setuptools,mutagen,pillow,jinja2,markupsafe}-*.whl; } &&
|
{ [ $w7 ] || python -m pip install --user -U {setuptools,mutagen,pillow,jinja2,MarkupSafe}-*.whl; } &&
|
||||||
{ [ $w10 ] || python -m pip install --user -U future-*.whl importlib_metadata-*.whl typing_extensions-*.whl zipp-*.whl; } &&
|
{ [ $w10 ] || python -m pip install --user -U future-*.whl importlib_metadata-*.whl typing_extensions-*.whl zipp-*.whl; } &&
|
||||||
python -m pip install --user -U pyinstaller-*.whl pefile-*.whl pywin32_ctypes-*.whl pyinstaller_hooks_contrib-*.whl altgraph-*.whl &&
|
python -m pip install --user -U pyinstaller-*.whl pefile-*.whl pywin32_ctypes-*.whl pyinstaller_hooks_contrib-*.whl altgraph-*.whl &&
|
||||||
sed -ri 's/--lzma/--best/' $appd/Python/Python$pyv/site-packages/pyinstaller/building/utils.py &&
|
sed -ri 's/--lzma/--best/' $appd/Python/Python$pyv/site-packages/pyinstaller/building/utils.py &&
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Loading…
Reference in a new issue