copyparty 1.16.18__tar.gz → 1.16.20__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.
- {copyparty-1.16.18 → copyparty-1.16.20}/PKG-INFO +15 -3
- {copyparty-1.16.18 → copyparty-1.16.20}/README.md +14 -2
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/__init__.py +1 -1
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/__main__.py +21 -2
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/__version__.py +2 -2
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/authsrv.py +62 -9
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/cfg.py +3 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/httpcli.py +44 -24
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/ico.py +13 -2
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/pwhash.py +1 -1
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/svchub.py +164 -61
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/tcpsrv.py +1 -1
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/th_cli.py +23 -4
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/th_srv.py +62 -7
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/u2idx.py +2 -2
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/up2k.py +7 -4
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/util.py +81 -3
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/browser.css.gz +0 -0
- copyparty-1.16.20/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.20/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/splash.html +1 -1
- copyparty-1.16.20/copyparty/web/ui.css.gz +0 -0
- copyparty-1.16.20/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.16.20/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/PKG-INFO +15 -3
- copyparty-1.16.18/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.18/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.16.18/copyparty/web/ui.css.gz +0 -0
- copyparty-1.16.18/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.16.18/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/LICENSE +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/bos/bos.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/bos/path.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/broker_mp.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/broker_thr.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/broker_util.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/cert.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/dxml.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/fsutil.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/ftpd.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/httpconn.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/httpsrv.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/mdns.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/metrics.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/mtag.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/multicast.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/res/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/smbd.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/ssdp.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/star.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/sutil.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/szip.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/tftpd.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/browser.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/browser2.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/cf.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/md.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/mde.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/msg.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/rups.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/rups.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/rups.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/shares.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/shares.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/svcs.html +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/pyproject.toml +0 -0
- {copyparty-1.16.18 → copyparty-1.16.20}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.16.
|
3
|
+
Version: 1.16.20
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
6
6
|
License: MIT
|
@@ -339,6 +339,8 @@ small collection of user feedback
|
|
339
339
|
|
340
340
|
`good enough`, `surprisingly correct`, `certified good software`, `just works`, `why`, `wow this is better than nextcloud`
|
341
341
|
|
342
|
+
* UI просто ужасно. Если буду описывать детально не смогу удержаться в рамках приличий
|
343
|
+
|
342
344
|
|
343
345
|
# motivations
|
344
346
|
|
@@ -387,7 +389,8 @@ roughly sorted by chance of encounter
|
|
387
389
|
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
388
390
|
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
389
391
|
* if the `up2k.db` (filesystem index) is on a samba-share or network disk, you'll get unpredictable behavior if the share is disconnected for a bit
|
390
|
-
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db on a local disk instead
|
392
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db and thumbnails on a local disk instead
|
393
|
+
* or, if you only want to move the db (and not the thumbnails), then use `--dbpath` or the `dbpath` volflag
|
391
394
|
* all volumes must exist / be available on startup; up2k (mtp especially) gets funky otherwise
|
392
395
|
* probably more, pls let me know
|
393
396
|
|
@@ -440,7 +443,8 @@ same order here too
|
|
440
443
|
* this is an msys2 bug, the regular windows edition of python is fine
|
441
444
|
|
442
445
|
* VirtualBox: sqlite throws `Disk I/O Error` when running in a VM and the up2k database is in a vboxsf
|
443
|
-
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db inside the vm instead
|
446
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db and thumbnails inside the vm instead
|
447
|
+
* or, if you only want to move the db (and not the thumbnails), then use `--dbpath` or the `dbpath` volflag
|
444
448
|
* also happens on mergerfs, so put the db elsewhere
|
445
449
|
|
446
450
|
* Ubuntu: dragging files from certain folders into firefox or chrome is impossible
|
@@ -862,6 +866,8 @@ if you are resuming a massive upload and want to skip hashing the files which al
|
|
862
866
|
|
863
867
|
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)
|
864
868
|
|
869
|
+
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)
|
870
|
+
|
865
871
|
|
866
872
|
### file-search
|
867
873
|
|
@@ -1650,6 +1656,8 @@ copyparty creates a subfolder named `.hist` inside each volume where it stores t
|
|
1650
1656
|
this can instead be kept in a single place using the `--hist` argument, or the `hist=` volflag, or a mix of both:
|
1651
1657
|
* `--hist ~/.cache/copyparty -v ~/music::r:c,hist=-` sets `~/.cache/copyparty` as the default place to put volume info, but `~/music` gets the regular `.hist` subfolder (`-` restores default behavior)
|
1652
1658
|
|
1659
|
+
by default, the per-volume `up2k.db` sqlite3-database for `-e2d` and `-e2t` is stored next to the thumbnails according to the `--hist` option, but the global-option `--dbpath` and/or volflag `dbpath` can be used to put the database somewhere else
|
1660
|
+
|
1653
1661
|
note:
|
1654
1662
|
* putting the hist-folders on an SSD is strongly recommended for performance
|
1655
1663
|
* markdown edits are always stored in a local `.hist` subdirectory
|
@@ -2185,7 +2193,9 @@ buggy feature? rip it out by setting any of the following environment variables
|
|
2185
2193
|
|
2186
2194
|
| env-var | what it does |
|
2187
2195
|
| -------------------- | ------------ |
|
2196
|
+
| `PRTY_NO_DB_LOCK` | do not lock session/shares-databases for exclusive access |
|
2188
2197
|
| `PRTY_NO_IFADDR` | disable ip/nic discovery by poking into your OS with ctypes |
|
2198
|
+
| `PRTY_NO_IMPRESO` | do not try to load js/css files using `importlib.resources` |
|
2189
2199
|
| `PRTY_NO_IPV6` | disable some ipv6 support (should not be necessary since windows 2000) |
|
2190
2200
|
| `PRTY_NO_LZMA` | disable streaming xz compression of incoming uploads |
|
2191
2201
|
| `PRTY_NO_MP` | disable all use of the python `multiprocessing` module (actual multithreading, cpu-count for parsers/thumbnailers) |
|
@@ -2503,6 +2513,8 @@ below are some tweaks roughly ordered by usefulness:
|
|
2503
2513
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
2504
2514
|
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
2505
2515
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
2516
|
+
* when running on AlpineLinux or other musl-based distro, try mimalloc for higher performance (and twice as much RAM usage); `apk add mimalloc2` and run copyparty with env-var `LD_PRELOAD=/usr/lib/libmimalloc-secure.so.2`
|
2517
|
+
* note that mimalloc requires special care when combined with prisonparty and/or bubbleparty/bubblewrap; you must give it access to `/proc` and `/sys` otherwise you'll encounter issues with FFmpeg (audio transcoding, thumbnails)
|
2506
2518
|
* `-j0` enables multiprocessing (actual multithreading), can reduce latency to `20+80/numCores` percent and generally improve performance in cpu-intensive workloads, for example:
|
2507
2519
|
* lots of connections (many users or heavy clients)
|
2508
2520
|
* simultaneous downloads and uploads saturating a 20gbps connection
|
@@ -281,6 +281,8 @@ small collection of user feedback
|
|
281
281
|
|
282
282
|
`good enough`, `surprisingly correct`, `certified good software`, `just works`, `why`, `wow this is better than nextcloud`
|
283
283
|
|
284
|
+
* UI просто ужасно. Если буду описывать детально не смогу удержаться в рамках приличий
|
285
|
+
|
284
286
|
|
285
287
|
# motivations
|
286
288
|
|
@@ -329,7 +331,8 @@ roughly sorted by chance of encounter
|
|
329
331
|
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
330
332
|
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
331
333
|
* if the `up2k.db` (filesystem index) is on a samba-share or network disk, you'll get unpredictable behavior if the share is disconnected for a bit
|
332
|
-
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db on a local disk instead
|
334
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db and thumbnails on a local disk instead
|
335
|
+
* or, if you only want to move the db (and not the thumbnails), then use `--dbpath` or the `dbpath` volflag
|
333
336
|
* all volumes must exist / be available on startup; up2k (mtp especially) gets funky otherwise
|
334
337
|
* probably more, pls let me know
|
335
338
|
|
@@ -382,7 +385,8 @@ same order here too
|
|
382
385
|
* this is an msys2 bug, the regular windows edition of python is fine
|
383
386
|
|
384
387
|
* VirtualBox: sqlite throws `Disk I/O Error` when running in a VM and the up2k database is in a vboxsf
|
385
|
-
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db inside the vm instead
|
388
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db and thumbnails inside the vm instead
|
389
|
+
* or, if you only want to move the db (and not the thumbnails), then use `--dbpath` or the `dbpath` volflag
|
386
390
|
* also happens on mergerfs, so put the db elsewhere
|
387
391
|
|
388
392
|
* Ubuntu: dragging files from certain folders into firefox or chrome is impossible
|
@@ -804,6 +808,8 @@ if you are resuming a massive upload and want to skip hashing the files which al
|
|
804
808
|
|
805
809
|
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)
|
806
810
|
|
811
|
+
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)
|
812
|
+
|
807
813
|
|
808
814
|
### file-search
|
809
815
|
|
@@ -1592,6 +1598,8 @@ copyparty creates a subfolder named `.hist` inside each volume where it stores t
|
|
1592
1598
|
this can instead be kept in a single place using the `--hist` argument, or the `hist=` volflag, or a mix of both:
|
1593
1599
|
* `--hist ~/.cache/copyparty -v ~/music::r:c,hist=-` sets `~/.cache/copyparty` as the default place to put volume info, but `~/music` gets the regular `.hist` subfolder (`-` restores default behavior)
|
1594
1600
|
|
1601
|
+
by default, the per-volume `up2k.db` sqlite3-database for `-e2d` and `-e2t` is stored next to the thumbnails according to the `--hist` option, but the global-option `--dbpath` and/or volflag `dbpath` can be used to put the database somewhere else
|
1602
|
+
|
1595
1603
|
note:
|
1596
1604
|
* putting the hist-folders on an SSD is strongly recommended for performance
|
1597
1605
|
* markdown edits are always stored in a local `.hist` subdirectory
|
@@ -2127,7 +2135,9 @@ buggy feature? rip it out by setting any of the following environment variables
|
|
2127
2135
|
|
2128
2136
|
| env-var | what it does |
|
2129
2137
|
| -------------------- | ------------ |
|
2138
|
+
| `PRTY_NO_DB_LOCK` | do not lock session/shares-databases for exclusive access |
|
2130
2139
|
| `PRTY_NO_IFADDR` | disable ip/nic discovery by poking into your OS with ctypes |
|
2140
|
+
| `PRTY_NO_IMPRESO` | do not try to load js/css files using `importlib.resources` |
|
2131
2141
|
| `PRTY_NO_IPV6` | disable some ipv6 support (should not be necessary since windows 2000) |
|
2132
2142
|
| `PRTY_NO_LZMA` | disable streaming xz compression of incoming uploads |
|
2133
2143
|
| `PRTY_NO_MP` | disable all use of the python `multiprocessing` module (actual multithreading, cpu-count for parsers/thumbnailers) |
|
@@ -2445,6 +2455,8 @@ below are some tweaks roughly ordered by usefulness:
|
|
2445
2455
|
* `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
|
2446
2456
|
* if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
|
2447
2457
|
* `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
|
2458
|
+
* when running on AlpineLinux or other musl-based distro, try mimalloc for higher performance (and twice as much RAM usage); `apk add mimalloc2` and run copyparty with env-var `LD_PRELOAD=/usr/lib/libmimalloc-secure.so.2`
|
2459
|
+
* note that mimalloc requires special care when combined with prisonparty and/or bubbleparty/bubblewrap; you must give it access to `/proc` and `/sys` otherwise you'll encounter issues with FFmpeg (audio transcoding, thumbnails)
|
2448
2460
|
* `-j0` enables multiprocessing (actual multithreading), can reduce latency to `20+80/numCores` percent and generally improve performance in cpu-intensive workloads, for example:
|
2449
2461
|
* lots of connections (many users or heavy clients)
|
2450
2462
|
* simultaneous downloads and uploads saturating a 20gbps connection
|
@@ -222,7 +222,23 @@ def init_E(EE ) :
|
|
222
222
|
if E.mod.endswith("__init__"):
|
223
223
|
E.mod = os.path.dirname(E.mod)
|
224
224
|
|
225
|
-
|
225
|
+
try:
|
226
|
+
p = os.environ.get("XDG_CONFIG_HOME")
|
227
|
+
if not p:
|
228
|
+
raise Exception()
|
229
|
+
if p.startswith("~"):
|
230
|
+
p = os.path.expanduser(p)
|
231
|
+
p = os.path.abspath(os.path.realpath(p))
|
232
|
+
p = os.path.join(p, "copyparty")
|
233
|
+
if not os.path.isdir(p):
|
234
|
+
os.mkdir(p)
|
235
|
+
os.listdir(p)
|
236
|
+
except:
|
237
|
+
p = ""
|
238
|
+
|
239
|
+
if p:
|
240
|
+
E.cfg = p
|
241
|
+
elif sys.platform == "win32":
|
226
242
|
bdir = os.environ.get("APPDATA") or os.environ.get("TEMP") or "."
|
227
243
|
E.cfg = os.path.normpath(bdir + "/copyparty")
|
228
244
|
elif sys.platform == "darwin":
|
@@ -1003,7 +1019,7 @@ def add_upload(ap):
|
|
1003
1019
|
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")
|
1004
1020
|
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 for low-latency (same-country) connections, 4-8 for android clients, 16 for cross-atlantic (max=64)")
|
1005
1021
|
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]")
|
1006
|
-
ap2.add_argument("--u2ow", metavar="NUM", type=int, default=0, help="web-client: default setting for when to overwrite existing files; [\033[32m0\033[0m]=never, [\033[32m1\033[0m]=if-client-newer, [\033[32m2\033[0m]=always (volflag=u2ow)")
|
1022
|
+
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)")
|
1007
1023
|
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")
|
1008
1024
|
ap2.add_argument("--write-uplog", action="store_true", help="write POST reports to textfiles in working-directory")
|
1009
1025
|
|
@@ -1353,6 +1369,7 @@ def add_thumbnail(ap):
|
|
1353
1369
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1354
1370
|
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")
|
1355
1371
|
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,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")
|
1372
|
+
ap2.add_argument("--th-spec-cnv", metavar="T,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)")
|
1356
1373
|
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", help="audio/image formats to decompress before passing to ffmpeg")
|
1357
1374
|
|
1358
1375
|
|
@@ -1385,6 +1402,7 @@ def add_db_general(ap, hcores):
|
|
1385
1402
|
ap2.add_argument("-e2vu", action="store_true", help="on hash mismatch: update the database with the new hash")
|
1386
1403
|
ap2.add_argument("-e2vp", action="store_true", help="on hash mismatch: panic and quit copyparty")
|
1387
1404
|
ap2.add_argument("--hist", metavar="PATH", type=u, default="", help="where to store volume data (db, thumbs); default is a folder named \".hist\" inside each volume (volflag=hist)")
|
1405
|
+
ap2.add_argument("--dbpath", metavar="PATH", type=u, default="", help="override where the volume databases are to be placed; default is the same as \033[33m--hist\033[0m (volflag=dbpath)")
|
1388
1406
|
ap2.add_argument("--no-hash", metavar="PTN", type=u, default="", help="regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans (volflag=nohash)")
|
1389
1407
|
ap2.add_argument("--no-idx", metavar="PTN", type=u, default=noidx, help="regex: disable indexing of matching absolute-filesystem-paths during e2ds folder scans (volflag=noidx)")
|
1390
1408
|
ap2.add_argument("--no-dirsz", action="store_true", help="do not show total recursive size of folders in listings, show inode size instead; slightly faster (volflag=nodirsz)")
|
@@ -1423,6 +1441,7 @@ def add_db_metadata(ap):
|
|
1423
1441
|
|
1424
1442
|
def add_txt(ap):
|
1425
1443
|
ap2 = ap.add_argument_group('textfile options')
|
1444
|
+
ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)")
|
1426
1445
|
ap2.add_argument("-mcr", metavar="SEC", type=int, default=60, help="the textfile editor will check for serverside changes every \033[33mSEC\033[0m seconds")
|
1427
1446
|
ap2.add_argument("-emp", action="store_true", help="enable markdown plugins -- neat but dangerous, big XSS risk")
|
1428
1447
|
ap2.add_argument("--exp", action="store_true", help="enable textfile expansion -- replace {{self.ip}} and such; see \033[33m--help-exp\033[0m (volflag=exp)")
|
@@ -353,6 +353,7 @@ class VFS(object):
|
|
353
353
|
self.badcfg1 = False
|
354
354
|
self.nodes = {} # child nodes
|
355
355
|
self.histtab = {} # all realpath->histpath
|
356
|
+
self.dbpaths = {} # all realpath->dbpath
|
356
357
|
self.dbv = None # closest full/non-jump parent
|
357
358
|
self.lim = None # upload limits; only set for dbv
|
358
359
|
self.shr_src = None # source vfs+rem of a share
|
@@ -374,12 +375,13 @@ class VFS(object):
|
|
374
375
|
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
375
376
|
vp = vpath + ("/" if vpath else "")
|
376
377
|
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
378
|
+
self.dbpath = self.histpath
|
377
379
|
self.all_vols = {vpath: self} # flattened recursive
|
378
380
|
self.all_nodes = {vpath: self} # also jumpvols/shares
|
379
381
|
self.all_aps = [(rp, self)]
|
380
382
|
self.all_vps = [(vp, self)]
|
381
383
|
else:
|
382
|
-
self.histpath = ""
|
384
|
+
self.histpath = self.dbpath = ""
|
383
385
|
self.all_vols = {}
|
384
386
|
self.all_nodes = {}
|
385
387
|
self.all_aps = []
|
@@ -454,17 +456,23 @@ class VFS(object):
|
|
454
456
|
|
455
457
|
def _copy_flags(self, name ) :
|
456
458
|
flags = {k: v for k, v in self.flags.items()}
|
459
|
+
|
457
460
|
hist = flags.get("hist")
|
458
461
|
if hist and hist != "-":
|
459
462
|
zs = "{}/{}".format(hist.rstrip("/"), name)
|
460
463
|
flags["hist"] = os.path.expandvars(os.path.expanduser(zs))
|
461
464
|
|
465
|
+
dbp = flags.get("dbpath")
|
466
|
+
if dbp and dbp != "-":
|
467
|
+
zs = "{}/{}".format(dbp.rstrip("/"), name)
|
468
|
+
flags["dbpath"] = os.path.expandvars(os.path.expanduser(zs))
|
469
|
+
|
462
470
|
return flags
|
463
471
|
|
464
472
|
def bubble_flags(self) :
|
465
473
|
if self.dbv:
|
466
474
|
for k, v in self.dbv.flags.items():
|
467
|
-
if k not in
|
475
|
+
if k not in ("hist", "dbpath"):
|
468
476
|
self.flags[k] = v
|
469
477
|
|
470
478
|
for n in self.nodes.values():
|
@@ -1752,7 +1760,7 @@ class AuthSrv(object):
|
|
1752
1760
|
pass
|
1753
1761
|
elif vflag:
|
1754
1762
|
vflag = os.path.expandvars(os.path.expanduser(vflag))
|
1755
|
-
vol.histpath = uncyg(vflag) if WINDOWS else vflag
|
1763
|
+
vol.histpath = vol.dbpath = uncyg(vflag) if WINDOWS else vflag
|
1756
1764
|
elif self.args.hist:
|
1757
1765
|
for nch in range(len(hid)):
|
1758
1766
|
hpath = os.path.join(self.args.hist, hid[: nch + 1])
|
@@ -1773,12 +1781,45 @@ class AuthSrv(object):
|
|
1773
1781
|
with open(powner, "wb") as f:
|
1774
1782
|
f.write(me)
|
1775
1783
|
|
1776
|
-
vol.histpath = hpath
|
1784
|
+
vol.histpath = vol.dbpath = hpath
|
1777
1785
|
break
|
1778
1786
|
|
1779
1787
|
vol.histpath = absreal(vol.histpath)
|
1788
|
+
|
1789
|
+
for vol in vfs.all_vols.values():
|
1790
|
+
hid = self.hid_cache[vol.realpath]
|
1791
|
+
vflag = vol.flags.get("dbpath")
|
1792
|
+
if vflag == "-":
|
1793
|
+
pass
|
1794
|
+
elif vflag:
|
1795
|
+
vflag = os.path.expandvars(os.path.expanduser(vflag))
|
1796
|
+
vol.dbpath = uncyg(vflag) if WINDOWS else vflag
|
1797
|
+
elif self.args.dbpath:
|
1798
|
+
for nch in range(len(hid)):
|
1799
|
+
hpath = os.path.join(self.args.dbpath, hid[: nch + 1])
|
1800
|
+
bos.makedirs(hpath)
|
1801
|
+
|
1802
|
+
powner = os.path.join(hpath, "owner.txt")
|
1803
|
+
try:
|
1804
|
+
with open(powner, "rb") as f:
|
1805
|
+
owner = f.read().rstrip()
|
1806
|
+
except:
|
1807
|
+
owner = None
|
1808
|
+
|
1809
|
+
me = afsenc(vol.realpath).rstrip()
|
1810
|
+
if owner not in [None, me]:
|
1811
|
+
continue
|
1812
|
+
|
1813
|
+
if owner is None:
|
1814
|
+
with open(powner, "wb") as f:
|
1815
|
+
f.write(me)
|
1816
|
+
|
1817
|
+
vol.dbpath = hpath
|
1818
|
+
break
|
1819
|
+
|
1820
|
+
vol.dbpath = absreal(vol.dbpath)
|
1780
1821
|
if vol.dbv:
|
1781
|
-
if bos.path.exists(os.path.join(vol.
|
1822
|
+
if bos.path.exists(os.path.join(vol.dbpath, "up2k.db")):
|
1782
1823
|
promote.append(vol)
|
1783
1824
|
vol.dbv = None
|
1784
1825
|
else:
|
@@ -1793,9 +1834,7 @@ class AuthSrv(object):
|
|
1793
1834
|
"\n the following jump-volumes were generated to assist the vfs.\n As they contain a database (probably from v0.11.11 or older),\n they are promoted to full volumes:"
|
1794
1835
|
]
|
1795
1836
|
for vol in promote:
|
1796
|
-
ta.append(
|
1797
|
-
" /{} ({}) ({})".format(vol.vpath, vol.realpath, vol.histpath)
|
1798
|
-
)
|
1837
|
+
ta.append(" /%s (%s) (%s)" % (vol.vpath, vol.realpath, vol.dbpath))
|
1799
1838
|
|
1800
1839
|
self.log("\n\n".join(ta) + "\n", c=3)
|
1801
1840
|
|
@@ -1806,13 +1845,27 @@ class AuthSrv(object):
|
|
1806
1845
|
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1807
1846
|
if histp and not is_shr and histp in rhisttab:
|
1808
1847
|
zv2 = rhisttab[histp]
|
1809
|
-
t = "invalid config; multiple volumes share the same histpath (database location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2: %s [%s]"
|
1848
|
+
t = "invalid config; multiple volumes share the same histpath (database+thumbnails location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2: %s [%s]"
|
1810
1849
|
t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1811
1850
|
self.log(t, 1)
|
1812
1851
|
raise Exception(t)
|
1813
1852
|
rhisttab[histp] = zv
|
1814
1853
|
vfs.histtab[zv.realpath] = histp
|
1815
1854
|
|
1855
|
+
rdbpaths = {}
|
1856
|
+
vfs.dbpaths = {}
|
1857
|
+
for zv in vfs.all_vols.values():
|
1858
|
+
dbp = zv.dbpath
|
1859
|
+
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1860
|
+
if dbp and not is_shr and dbp in rdbpaths:
|
1861
|
+
zv2 = rdbpaths[dbp]
|
1862
|
+
t = "invalid config; multiple volumes share the same dbpath (database location):\n dbpath: %s\n volume 1: /%s [%s]\n volume 2: %s [%s]"
|
1863
|
+
t = t % (dbp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1864
|
+
self.log(t, 1)
|
1865
|
+
raise Exception(t)
|
1866
|
+
rdbpaths[dbp] = zv
|
1867
|
+
vfs.dbpaths[zv.realpath] = dbp
|
1868
|
+
|
1816
1869
|
for vol in vfs.all_vols.values():
|
1817
1870
|
use = False
|
1818
1871
|
for k in ["zipmaxn", "zipmaxs"]:
|
@@ -83,6 +83,7 @@ def vf_vmap() :
|
|
83
83
|
"md_sbf",
|
84
84
|
"lg_sba",
|
85
85
|
"md_sba",
|
86
|
+
"md_hist",
|
86
87
|
"nrand",
|
87
88
|
"u2ow",
|
88
89
|
"og_desc",
|
@@ -204,6 +205,7 @@ flagcats = {
|
|
204
205
|
"d2v": "disables file verification, overrides -e2v*",
|
205
206
|
"d2d": "disables all database stuff, overrides -e2*",
|
206
207
|
"hist=/tmp/cdb": "puts thumbnails and indexes at that location",
|
208
|
+
"dbpath=/tmp/cdb": "puts indexes at that location",
|
207
209
|
"scan=60": "scan for new files every 60sec, same as --re-maxage",
|
208
210
|
"nohash=\\.iso$": "skips hashing file contents if path matches *.iso",
|
209
211
|
"noidx=\\.iso$": "fully ignores the contents at paths matching *.iso",
|
@@ -291,6 +293,7 @@ flagcats = {
|
|
291
293
|
"og_ua": "if defined: only send OG html if useragent matches this regex",
|
292
294
|
},
|
293
295
|
"textfiles": {
|
296
|
+
"md_hist": "where to put markdown backups; s=subfolder, v=volHist, n=nope",
|
294
297
|
"exp": "enable textfile expansion; see --help-exp",
|
295
298
|
"exp_md": "placeholders to expand in markdown files; see --help",
|
296
299
|
"exp_lg": "placeholders to expand in prologue/epilogue; see --help",
|
@@ -57,6 +57,7 @@ from .util import (
|
|
57
57
|
UnrecvEOF,
|
58
58
|
WrongPostKey,
|
59
59
|
absreal,
|
60
|
+
afsenc,
|
60
61
|
alltrace,
|
61
62
|
atomic_move,
|
62
63
|
b64dec,
|
@@ -1200,11 +1201,6 @@ class HttpCli(object):
|
|
1200
1201
|
else:
|
1201
1202
|
return self.tx_res(res_path)
|
1202
1203
|
|
1203
|
-
if res_path != undot(res_path):
|
1204
|
-
t = "malicious user; attempted path traversal; req(%r) vp(%r) => %r"
|
1205
|
-
self.log(t % (self.req, "/" + self.vpath, res_path), 1)
|
1206
|
-
self.cbonk(self.conn.hsrv.gmal, self.req, "trav", "path traversal")
|
1207
|
-
|
1208
1204
|
self.tx_404()
|
1209
1205
|
return False
|
1210
1206
|
|
@@ -2983,9 +2979,6 @@ class HttpCli(object):
|
|
2983
2979
|
vfs, rem = self.asrv.vfs.get(vpath, self.uname, False, True)
|
2984
2980
|
rem = sanitize_vpath(rem, "/")
|
2985
2981
|
fn = vfs.canonical(rem)
|
2986
|
-
if not fn.startswith(vfs.realpath):
|
2987
|
-
self.log("invalid mkdir %r %r" % (self.gctx, vpath), 1)
|
2988
|
-
raise Pebkac(422)
|
2989
2982
|
|
2990
2983
|
if not nullwrite:
|
2991
2984
|
fdir = os.path.dirname(fn)
|
@@ -3484,6 +3477,7 @@ class HttpCli(object):
|
|
3484
3477
|
|
3485
3478
|
fp = os.path.join(fp, fn)
|
3486
3479
|
rem = "{}/{}".format(rp, fn).strip("/")
|
3480
|
+
dbv, vrem = vfs.get_dbv(rem)
|
3487
3481
|
|
3488
3482
|
if not rem.endswith(".md") and not self.can_delete:
|
3489
3483
|
raise Pebkac(400, "only markdown pls")
|
@@ -3538,13 +3532,27 @@ class HttpCli(object):
|
|
3538
3532
|
mdir, mfile = os.path.split(fp)
|
3539
3533
|
fname, fext = mfile.rsplit(".", 1) if "." in mfile else (mfile, "md")
|
3540
3534
|
mfile2 = "{}.{:.3f}.{}".format(fname, srv_lastmod, fext)
|
3541
|
-
|
3535
|
+
|
3536
|
+
dp = ""
|
3537
|
+
hist_cfg = dbv.flags["md_hist"]
|
3538
|
+
if hist_cfg == "v":
|
3539
|
+
vrd = vsplit(vrem)[0]
|
3540
|
+
zb = hashlib.sha512(afsenc(vrd)).digest()
|
3541
|
+
zs = ub64enc(zb).decode("ascii")[:24].lower()
|
3542
|
+
dp = "%s/md/%s/%s/%s" % (dbv.histpath, zs[:2], zs[2:4], zs)
|
3543
|
+
self.log("moving old version to %s/%s" % (dp, mfile2))
|
3544
|
+
if bos.makedirs(dp):
|
3545
|
+
with open(os.path.join(dp, "dir.txt"), "wb") as f:
|
3546
|
+
f.write(afsenc(vrd))
|
3547
|
+
elif hist_cfg == "s":
|
3542
3548
|
dp = os.path.join(mdir, ".hist")
|
3543
|
-
|
3544
|
-
|
3545
|
-
|
3546
|
-
|
3547
|
-
|
3549
|
+
try:
|
3550
|
+
bos.mkdir(dp)
|
3551
|
+
hidedir(dp)
|
3552
|
+
except:
|
3553
|
+
pass
|
3554
|
+
if dp:
|
3555
|
+
wrename(self.log, fp, os.path.join(dp, mfile2), vfs.flags)
|
3548
3556
|
|
3549
3557
|
p_field, _, p_data = next(self.parser.gen)
|
3550
3558
|
if p_field != "body":
|
@@ -3616,13 +3624,12 @@ class HttpCli(object):
|
|
3616
3624
|
wunlink(self.log, fp, vfs.flags)
|
3617
3625
|
raise Pebkac(403, t)
|
3618
3626
|
|
3619
|
-
vfs, rem = vfs.get_dbv(rem)
|
3620
3627
|
self.conn.hsrv.broker.say(
|
3621
3628
|
"up2k.hash_file",
|
3622
|
-
|
3623
|
-
|
3624
|
-
|
3625
|
-
vsplit(
|
3629
|
+
dbv.realpath,
|
3630
|
+
dbv.vpath,
|
3631
|
+
dbv.flags,
|
3632
|
+
vsplit(vrem)[0],
|
3626
3633
|
fn,
|
3627
3634
|
self.ip,
|
3628
3635
|
new_lastmod,
|
@@ -4219,6 +4226,7 @@ class HttpCli(object):
|
|
4219
4226
|
self.log(t % (data_end / M, lower / M, upper / M), 6)
|
4220
4227
|
with self.u2mutex:
|
4221
4228
|
if data_end > self.u2fh.aps.get(ap_data, data_end):
|
4229
|
+
fhs = None
|
4222
4230
|
try:
|
4223
4231
|
fhs = self.u2fh.cache[ap_data].all_fhs
|
4224
4232
|
for fh in fhs:
|
@@ -4226,7 +4234,11 @@ class HttpCli(object):
|
|
4226
4234
|
self.u2fh.aps[ap_data] = data_end
|
4227
4235
|
self.log("pipe: flushed %d up2k-FDs" % (len(fhs),))
|
4228
4236
|
except Exception as ex:
|
4229
|
-
|
4237
|
+
if fhs is None:
|
4238
|
+
err = "file is not being written to right now"
|
4239
|
+
else:
|
4240
|
+
err = repr(ex)
|
4241
|
+
self.log("pipe: u2fh flush failed: " + err)
|
4230
4242
|
|
4231
4243
|
if lower >= data_end:
|
4232
4244
|
if data_end:
|
@@ -4849,7 +4861,7 @@ class HttpCli(object):
|
|
4849
4861
|
self.reply(pt.encode("utf-8"), status=rc)
|
4850
4862
|
return True
|
4851
4863
|
|
4852
|
-
if "th" in self.ouparam:
|
4864
|
+
if "th" in self.ouparam and str(self.ouparam["th"])[:1] in "jw":
|
4853
4865
|
return self.tx_svg("e" + pt[:3])
|
4854
4866
|
|
4855
4867
|
# most webdav clients will not send credentials until they
|
@@ -5776,7 +5788,13 @@ class HttpCli(object):
|
|
5776
5788
|
|
5777
5789
|
thp = None
|
5778
5790
|
if self.thumbcli and not nothumb:
|
5779
|
-
|
5791
|
+
try:
|
5792
|
+
thp = self.thumbcli.get(dbv, vrem, int(st.st_mtime), th_fmt)
|
5793
|
+
except Pebkac as ex:
|
5794
|
+
if ex.code == 500 and th_fmt[:1] in "jw":
|
5795
|
+
self.log("failed to convert [%s]:\n%s" % (abspath, ex), 3)
|
5796
|
+
return self.tx_svg("--error--\ncheck\nserver\nlog")
|
5797
|
+
raise
|
5780
5798
|
|
5781
5799
|
if thp:
|
5782
5800
|
return self.tx_file(thp)
|
@@ -5998,9 +6016,11 @@ class HttpCli(object):
|
|
5998
6016
|
# check for old versions of files,
|
5999
6017
|
# [num-backups, most-recent, hist-path]
|
6000
6018
|
hist = {}
|
6001
|
-
histdir = os.path.join(fsroot, ".hist")
|
6002
|
-
ptn = RE_MDV
|
6003
6019
|
try:
|
6020
|
+
if vf["md_hist"] != "s":
|
6021
|
+
raise Exception()
|
6022
|
+
histdir = os.path.join(fsroot, ".hist")
|
6023
|
+
ptn = RE_MDV
|
6004
6024
|
for hfn in bos.listdir(histdir):
|
6005
6025
|
m = ptn.match(hfn)
|
6006
6026
|
if not m:
|
@@ -94,10 +94,21 @@ class Ico(object):
|
|
94
94
|
<?xml version="1.0" encoding="UTF-8"?>
|
95
95
|
<svg version="1.1" viewBox="0 0 100 {}" xmlns="http://www.w3.org/2000/svg"><g>
|
96
96
|
<rect width="100%" height="100%" fill="#{}" />
|
97
|
-
<text x="50%" y="
|
97
|
+
<text x="50%" y="{}" dominant-baseline="middle" text-anchor="middle" xml:space="preserve"
|
98
98
|
fill="#{}" font-family="monospace" font-size="14px" style="letter-spacing:.5px">{}</text>
|
99
99
|
</g></svg>
|
100
100
|
"""
|
101
|
-
|
101
|
+
|
102
|
+
txt = html_escape(ext, True)
|
103
|
+
if "\n" in txt:
|
104
|
+
lines = txt.split("\n")
|
105
|
+
n = len(lines)
|
106
|
+
y = "20%" if n == 2 else "10%" if n == 3 else "0"
|
107
|
+
zs = '<tspan x="50%%" dy="1.2em">%s</tspan>'
|
108
|
+
txt = "".join([zs % (x,) for x in lines])
|
109
|
+
else:
|
110
|
+
y = "50%"
|
111
|
+
|
112
|
+
svg = svg.format(h, c[:6], y, c[6:], txt)
|
102
113
|
|
103
114
|
return "image/svg+xml", svg.encode("utf-8")
|