copyparty 1.9.12__tar.gz → 1.9.14__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.9.12 → copyparty-1.9.14}/PKG-INFO +33 -18
- {copyparty-1.9.12 → copyparty-1.9.14}/README.md +32 -17
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/__main__.py +13 -8
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/__version__.py +2 -2
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/authsrv.py +21 -13
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/cfg.py +29 -2
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/httpcli.py +31 -12
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/sutil.py +2 -2
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/svchub.py +28 -8
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/u2idx.py +5 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/up2k.py +24 -17
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/util.py +50 -2
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/a/partyfuse.py +3 -2
- copyparty-1.9.14/copyparty/web/browser.css.gz +0 -0
- copyparty-1.9.14/copyparty/web/browser.js.gz +0 -0
- copyparty-1.9.14/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/PKG-INFO +33 -18
- copyparty-1.9.12/copyparty/web/browser.css.gz +0 -0
- copyparty-1.9.12/copyparty/web/browser.js.gz +0 -0
- copyparty-1.9.12/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/LICENSE +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/bos/bos.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/bos/path.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/broker_mp.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/broker_thr.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/broker_util.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/cert.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/dxml.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/fsutil.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/ftpd.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/httpconn.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/httpsrv.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/ico.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/mdns.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/metrics.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/mtag.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/multicast.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/pwhash.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/res/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/smbd.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/ssdp.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/star.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/szip.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/th_cli.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/th_srv.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/browser.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/browser2.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/cf.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/md.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/mde.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/msg.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/splash.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/svcs.html +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/util.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/pyproject.toml +0 -0
- {copyparty-1.9.12 → copyparty-1.9.14}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.9.
|
3
|
+
Version: 1.9.14
|
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
|
@@ -71,9 +71,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
71
71
|
* [testimonials](#testimonials) - small collection of user feedback
|
72
72
|
* [motivations](#motivations) - project goals / philosophy
|
73
73
|
* [notes](#notes) - general notes
|
74
|
-
* [bugs](#bugs)
|
75
|
-
* [
|
76
|
-
* [not my bugs](#not-my-bugs)
|
74
|
+
* [bugs](#bugs) - roughly sorted by chance of encounter
|
75
|
+
* [not my bugs](#not-my-bugs) - same order here too
|
77
76
|
* [breaking changes](#breaking-changes) - upgrade notes
|
78
77
|
* [FAQ](#FAQ) - "frequently" asked questions
|
79
78
|
* [accounts and volumes](#accounts-and-volumes) - per-folder, per-user permissions
|
@@ -91,7 +90,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
91
90
|
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
|
92
91
|
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
|
93
92
|
* [media player](#media-player) - plays almost every audio format there is
|
94
|
-
* [audio equalizer](#audio-equalizer) -
|
93
|
+
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
95
94
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
96
95
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
97
96
|
* [other tricks](#other-tricks)
|
@@ -314,20 +313,28 @@ server notes:
|
|
314
313
|
|
315
314
|
# bugs
|
316
315
|
|
317
|
-
|
318
|
-
* Windows: python 2.7 cannot handle filenames with mojibake
|
319
|
-
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
320
|
-
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
316
|
+
roughly sorted by chance of encounter
|
321
317
|
|
322
|
-
|
318
|
+
* general:
|
319
|
+
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
320
|
+
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
321
|
+
* 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
|
322
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db on a local disk instead
|
323
|
+
* all volumes must exist / be available on startup; up2k (mtp especially) gets funky otherwise
|
324
|
+
* probably more, pls let me know
|
323
325
|
|
324
|
-
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
|
326
|
+
* python 3.4 and older (including 2.7):
|
327
|
+
* many rare and exciting edge-cases because [python didn't handle EINTR yet](https://peps.python.org/pep-0475/)
|
328
|
+
* downloads from copyparty may suddenly fail, but uploads *should* be fine
|
329
|
+
|
330
|
+
* python 2.7 on Windows:
|
331
|
+
* cannot index non-ascii filenames with `-e2d`
|
332
|
+
* cannot handle filenames with mojibake
|
328
333
|
|
329
334
|
## not my bugs
|
330
335
|
|
336
|
+
same order here too
|
337
|
+
|
331
338
|
* [Chrome issue 1317069](https://bugs.chromium.org/p/chromium/issues/detail?id=1317069) -- if you try to upload a folder which contains symlinks by dragging it into the browser, the symlinked files will not get uploaded
|
332
339
|
|
333
340
|
* [Chrome issue 1352210](https://bugs.chromium.org/p/chromium/issues/detail?id=1352210) -- plaintext http may be faster at filehashing than https (but also extremely CPU-intensive)
|
@@ -410,7 +417,7 @@ permissions:
|
|
410
417
|
* `g` (get): only download files, cannot see folder contents or zip/tar
|
411
418
|
* `G` (upget): same as `g` except uploaders get to see their own [filekeys](#filekeys) (see `fk` in examples below)
|
412
419
|
* `h` (html): same as `g` except folders return their index.html, and filekeys are not necessary for index.html
|
413
|
-
* `a` (admin): can see uploader IPs, config-reload
|
420
|
+
* `a` (admin): can see upload time, uploader IPs, config-reload
|
414
421
|
|
415
422
|
examples:
|
416
423
|
* add accounts named u1, u2, u3 with passwords p1, p2, p3: `-a u1:p1 -a u2:p2 -a u3:p3`
|
@@ -787,7 +794,7 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
787
794
|
|
788
795
|
### audio equalizer
|
789
796
|
|
790
|
-
|
797
|
+
and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
791
798
|
|
792
799
|
can also boost the volume in general, or increase/decrease stereo width (like [crossfeed](https://www.foobar2000.org/components/view/foo_dsp_meiercf) just worse)
|
793
800
|
|
@@ -998,6 +1005,15 @@ authenticate with one of the following:
|
|
998
1005
|
* username `$password`, password `k`
|
999
1006
|
|
1000
1007
|
|
1008
|
+
## browser ux
|
1009
|
+
|
1010
|
+
tweaking the ui
|
1011
|
+
|
1012
|
+
* set default sort order globally with `--sort` or per-volume with the `sort` volflag; specify one or more comma-separated columns to sort by, and prefix the column name with `-` for reverse sort
|
1013
|
+
* column names are visible as tooltips when hovering over the column headers in the directory listing, for example `href ext sz ts tags/.up_at tags/Cirle tags/.tn tags/Artist tags/Title`
|
1014
|
+
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
1015
|
+
|
1016
|
+
|
1001
1017
|
## file indexing
|
1002
1018
|
|
1003
1019
|
enables dedup and music search ++
|
@@ -1024,6 +1040,7 @@ the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`,
|
|
1024
1040
|
* `-v ~/music::r:c,d2ts` same except only affecting tags
|
1025
1041
|
|
1026
1042
|
note:
|
1043
|
+
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
|
1027
1044
|
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
|
1028
1045
|
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
1029
1046
|
* deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
|
@@ -1687,8 +1704,6 @@ safety profiles:
|
|
1687
1704
|
* `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
|
1688
1705
|
* however note if you edit one file it will also affect the other copies
|
1689
1706
|
* `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
|
1690
|
-
* `--ban-404=50,60,1440` ban client for 1440min (24h) if they hit 50 404's in 60min
|
1691
|
-
* `--turbo=-1` to force-disable turbo-mode in the uploader which could otherwise hit the 404-ban
|
1692
1707
|
* `--nih` removes the server hostname from directory listings
|
1693
1708
|
|
1694
1709
|
* option `-sss` is a shortcut for the above plus:
|
@@ -20,9 +20,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
20
20
|
* [testimonials](#testimonials) - small collection of user feedback
|
21
21
|
* [motivations](#motivations) - project goals / philosophy
|
22
22
|
* [notes](#notes) - general notes
|
23
|
-
* [bugs](#bugs)
|
24
|
-
* [
|
25
|
-
* [not my bugs](#not-my-bugs)
|
23
|
+
* [bugs](#bugs) - roughly sorted by chance of encounter
|
24
|
+
* [not my bugs](#not-my-bugs) - same order here too
|
26
25
|
* [breaking changes](#breaking-changes) - upgrade notes
|
27
26
|
* [FAQ](#FAQ) - "frequently" asked questions
|
28
27
|
* [accounts and volumes](#accounts-and-volumes) - per-folder, per-user permissions
|
@@ -40,7 +39,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
40
39
|
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
|
41
40
|
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
|
42
41
|
* [media player](#media-player) - plays almost every audio format there is
|
43
|
-
* [audio equalizer](#audio-equalizer) -
|
42
|
+
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
44
43
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
45
44
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
46
45
|
* [other tricks](#other-tricks)
|
@@ -263,20 +262,28 @@ server notes:
|
|
263
262
|
|
264
263
|
# bugs
|
265
264
|
|
266
|
-
|
267
|
-
* Windows: python 2.7 cannot handle filenames with mojibake
|
268
|
-
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
269
|
-
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
265
|
+
roughly sorted by chance of encounter
|
270
266
|
|
271
|
-
|
267
|
+
* general:
|
268
|
+
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
269
|
+
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
270
|
+
* 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
|
271
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db on a local disk instead
|
272
|
+
* all volumes must exist / be available on startup; up2k (mtp especially) gets funky otherwise
|
273
|
+
* probably more, pls let me know
|
272
274
|
|
273
|
-
*
|
274
|
-
*
|
275
|
-
*
|
276
|
-
|
275
|
+
* python 3.4 and older (including 2.7):
|
276
|
+
* many rare and exciting edge-cases because [python didn't handle EINTR yet](https://peps.python.org/pep-0475/)
|
277
|
+
* downloads from copyparty may suddenly fail, but uploads *should* be fine
|
278
|
+
|
279
|
+
* python 2.7 on Windows:
|
280
|
+
* cannot index non-ascii filenames with `-e2d`
|
281
|
+
* cannot handle filenames with mojibake
|
277
282
|
|
278
283
|
## not my bugs
|
279
284
|
|
285
|
+
same order here too
|
286
|
+
|
280
287
|
* [Chrome issue 1317069](https://bugs.chromium.org/p/chromium/issues/detail?id=1317069) -- if you try to upload a folder which contains symlinks by dragging it into the browser, the symlinked files will not get uploaded
|
281
288
|
|
282
289
|
* [Chrome issue 1352210](https://bugs.chromium.org/p/chromium/issues/detail?id=1352210) -- plaintext http may be faster at filehashing than https (but also extremely CPU-intensive)
|
@@ -359,7 +366,7 @@ permissions:
|
|
359
366
|
* `g` (get): only download files, cannot see folder contents or zip/tar
|
360
367
|
* `G` (upget): same as `g` except uploaders get to see their own [filekeys](#filekeys) (see `fk` in examples below)
|
361
368
|
* `h` (html): same as `g` except folders return their index.html, and filekeys are not necessary for index.html
|
362
|
-
* `a` (admin): can see uploader IPs, config-reload
|
369
|
+
* `a` (admin): can see upload time, uploader IPs, config-reload
|
363
370
|
|
364
371
|
examples:
|
365
372
|
* add accounts named u1, u2, u3 with passwords p1, p2, p3: `-a u1:p1 -a u2:p2 -a u3:p3`
|
@@ -736,7 +743,7 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
736
743
|
|
737
744
|
### audio equalizer
|
738
745
|
|
739
|
-
|
746
|
+
and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
740
747
|
|
741
748
|
can also boost the volume in general, or increase/decrease stereo width (like [crossfeed](https://www.foobar2000.org/components/view/foo_dsp_meiercf) just worse)
|
742
749
|
|
@@ -947,6 +954,15 @@ authenticate with one of the following:
|
|
947
954
|
* username `$password`, password `k`
|
948
955
|
|
949
956
|
|
957
|
+
## browser ux
|
958
|
+
|
959
|
+
tweaking the ui
|
960
|
+
|
961
|
+
* set default sort order globally with `--sort` or per-volume with the `sort` volflag; specify one or more comma-separated columns to sort by, and prefix the column name with `-` for reverse sort
|
962
|
+
* column names are visible as tooltips when hovering over the column headers in the directory listing, for example `href ext sz ts tags/.up_at tags/Cirle tags/.tn tags/Artist tags/Title`
|
963
|
+
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
964
|
+
|
965
|
+
|
950
966
|
## file indexing
|
951
967
|
|
952
968
|
enables dedup and music search ++
|
@@ -973,6 +989,7 @@ the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`,
|
|
973
989
|
* `-v ~/music::r:c,d2ts` same except only affecting tags
|
974
990
|
|
975
991
|
note:
|
992
|
+
* upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
|
976
993
|
* `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
|
977
994
|
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
978
995
|
* deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
|
@@ -1636,8 +1653,6 @@ safety profiles:
|
|
1636
1653
|
* `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
|
1637
1654
|
* however note if you edit one file it will also affect the other copies
|
1638
1655
|
* `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
|
1639
|
-
* `--ban-404=50,60,1440` ban client for 1440min (24h) if they hit 50 404's in 60min
|
1640
|
-
* `--turbo=-1` to force-disable turbo-mode in the uploader which could otherwise hit the 404-ban
|
1641
1656
|
* `--nih` removes the server hostname from directory listings
|
1642
1657
|
|
1643
1658
|
* option `-sss` is a shortcut for the above plus:
|
@@ -27,6 +27,8 @@ from .authsrv import expand_config_file, re_vol, split_cfg_ln, upgrade_cfg_fmt
|
|
27
27
|
from .cfg import flagcats, onedash
|
28
28
|
from .svchub import SvcHub
|
29
29
|
from .util import (
|
30
|
+
DEF_MTE,
|
31
|
+
DEF_MTH,
|
30
32
|
IMPLICATIONS,
|
31
33
|
JINJA_VER,
|
32
34
|
PYFTPD_VER,
|
@@ -178,7 +180,10 @@ def init_E(E ) :
|
|
178
180
|
|
179
181
|
with open_binary("copyparty", "z.tar") as tgz:
|
180
182
|
with tarfile.open(fileobj=tgz) as tf:
|
181
|
-
|
183
|
+
try:
|
184
|
+
tf.extractall(tdn, filter="tar")
|
185
|
+
except TypeError:
|
186
|
+
tf.extractall(tdn) # nosec (archive is safe)
|
182
187
|
|
183
188
|
return tdn
|
184
189
|
|
@@ -800,6 +805,8 @@ def add_upload(ap):
|
|
800
805
|
ap2.add_argument("--no-dedup", action="store_true", help="disable symlink/hardlink creation; copy file contents instead (volflag=copydupes)")
|
801
806
|
ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
|
802
807
|
ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
|
808
|
+
ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every SEC seconds; allows resuming incomplete uploads after a server crash")
|
809
|
+
ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440, help="forget unfinished uploads after MIN minutes; impossible to resume them after that (360=6h, 1440=24h)")
|
803
810
|
ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)")
|
804
811
|
ap2.add_argument("--rand", action="store_true", help="force randomized filenames, --nrand chars long (volflag=rand)")
|
805
812
|
ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
|
@@ -990,7 +997,7 @@ def add_optouts(ap):
|
|
990
997
|
def add_safety(ap):
|
991
998
|
ap2 = ap.add_argument_group('safety options')
|
992
999
|
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
993
|
-
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403
|
1000
|
+
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih")
|
994
1001
|
ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r")
|
995
1002
|
ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m; example [\033[32m**,*,ln,p,r\033[0m]")
|
996
1003
|
ap2.add_argument("--xvol", action="store_true", help="never follow symlinks leaving the volume root, unless the link is into another volume where the user has similar access (volflag=xvol)")
|
@@ -1004,10 +1011,10 @@ def add_safety(ap):
|
|
1004
1011
|
ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
|
1005
1012
|
ap2.add_argument("--logout", metavar="H", type=float, default="8086", help="logout clients after H hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
|
1006
1013
|
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
1007
|
-
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="
|
1014
|
+
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
|
1008
1015
|
ap2.add_argument("--ban-403", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 403's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; [\033[32m1440\033[0m]=day, [\033[32m10080\033[0m]=week, [\033[32m43200\033[0m]=month")
|
1009
1016
|
ap2.add_argument("--ban-422", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 422's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (422 is server fuzzing, invalid POSTs and so)")
|
1010
|
-
ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (decent replacement for --ban-404 if that can't be used)")
|
1017
|
+
ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; applies only to access g/G/h (decent replacement for --ban-404 if that can't be used)")
|
1011
1018
|
ap2.add_argument("--sus-urls", metavar="R", type=u, default=r"\.php$|(^|/)wp-(admin|content|includes)/", help="URLs which are considered sus / eligible for banning; disable with blank or [\033[32mno\033[0m]")
|
1012
1019
|
ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon\.ico|robots\.txt)$|^apple-touch-icon|^\.well-known", help="harmless URLs ignored from 404-bans; disable with blank or [\033[32mno\033[0m]")
|
1013
1020
|
ap2.add_argument("--aclose", metavar="MIN", type=int, default=10, help="if a client maxes out the server connection limit, downgrade it from connection:keep-alive to connection:close for MIN minutes (and also kill its active connections) -- disable with 0")
|
@@ -1126,10 +1133,8 @@ def add_db_metadata(ap):
|
|
1126
1133
|
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
1127
1134
|
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/ffprobe parsers")
|
1128
1135
|
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
1129
|
-
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.)",
|
1130
|
-
|
1131
|
-
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.)",
|
1132
|
-
default=".vq,.aq,vc,ac,fmt,res,.fps")
|
1136
|
+
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE)
|
1137
|
+
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as -mte", default=DEF_MTH)
|
1133
1138
|
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag M using program BIN to parse the file")
|
1134
1139
|
|
1135
1140
|
|
@@ -21,11 +21,14 @@ from .util import (
|
|
21
21
|
META_NOBOTS,
|
22
22
|
SQLITE_VER,
|
23
23
|
UNPLICATIONS,
|
24
|
+
ODict,
|
24
25
|
Pebkac,
|
26
|
+
UTC,
|
25
27
|
absreal,
|
26
28
|
afsenc,
|
27
29
|
get_df,
|
28
30
|
humansize,
|
31
|
+
odfusion,
|
29
32
|
relchk,
|
30
33
|
statdir,
|
31
34
|
uncyg,
|
@@ -206,7 +209,7 @@ class Lim(object):
|
|
206
209
|
if self.rot_re.search(path.replace("\\", "/")):
|
207
210
|
return path, ""
|
208
211
|
|
209
|
-
suf = datetime.
|
212
|
+
suf = datetime.now(UTC).strftime(self.rotf)
|
210
213
|
if path:
|
211
214
|
path += "/"
|
212
215
|
|
@@ -1419,12 +1422,12 @@ class AuthSrv(object):
|
|
1419
1422
|
|
1420
1423
|
for ga, vf in [["no_hash", "nohash"], ["no_idx", "noidx"]]:
|
1421
1424
|
if vf in vol.flags:
|
1422
|
-
ptn = vol.flags.pop(vf)
|
1425
|
+
ptn = re.compile(vol.flags.pop(vf))
|
1423
1426
|
else:
|
1424
1427
|
ptn = getattr(self.args, ga)
|
1425
1428
|
|
1426
1429
|
if ptn:
|
1427
|
-
vol.flags[vf] =
|
1430
|
+
vol.flags[vf] = ptn
|
1428
1431
|
|
1429
1432
|
for ga, vf in vf_bmap().items():
|
1430
1433
|
if getattr(self.args, ga):
|
@@ -1470,13 +1473,14 @@ class AuthSrv(object):
|
|
1470
1473
|
|
1471
1474
|
# default tag cfgs if unset
|
1472
1475
|
if "mte" not in vol.flags:
|
1473
|
-
vol.flags["mte"] = self.args.mte
|
1474
|
-
|
1475
|
-
vol.flags["mte"] =
|
1476
|
-
|
1477
|
-
)
|
1476
|
+
vol.flags["mte"] = self.args.mte.copy()
|
1477
|
+
else:
|
1478
|
+
vol.flags["mte"] = odfusion(self.args.mte, vol.flags["mte"])
|
1479
|
+
|
1478
1480
|
if "mth" not in vol.flags:
|
1479
|
-
vol.flags["mth"] = self.args.mth
|
1481
|
+
vol.flags["mth"] = self.args.mth.copy()
|
1482
|
+
else:
|
1483
|
+
vol.flags["mth"] = odfusion(self.args.mth, vol.flags["mth"])
|
1480
1484
|
|
1481
1485
|
# append additive args from argv to volflags
|
1482
1486
|
hooks = "xbu xau xiu xbr xar xbd xad xm xban".split()
|
@@ -1530,7 +1534,11 @@ class AuthSrv(object):
|
|
1530
1534
|
if vol.flags.get(grp, False):
|
1531
1535
|
continue
|
1532
1536
|
|
1533
|
-
vol.flags = {
|
1537
|
+
vol.flags = {
|
1538
|
+
k: v
|
1539
|
+
for k, v in vol.flags.items()
|
1540
|
+
if not k.startswith(rm) or k == "mte"
|
1541
|
+
}
|
1534
1542
|
|
1535
1543
|
for grp, rm in [["d2v", "e2v"]]:
|
1536
1544
|
if not vol.flags.get(grp, False):
|
@@ -1577,12 +1585,12 @@ class AuthSrv(object):
|
|
1577
1585
|
if local:
|
1578
1586
|
local_only_mtp[a] = True
|
1579
1587
|
|
1580
|
-
local_mte =
|
1581
|
-
for a in vol.flags.get("mte",
|
1588
|
+
local_mte = ODict()
|
1589
|
+
for a in vol.flags.get("mte", {}).keys():
|
1582
1590
|
local = True
|
1583
1591
|
all_mte[a] = True
|
1584
1592
|
local_mte[a] = True
|
1585
|
-
for b in self.args.mte.
|
1593
|
+
for b in self.args.mte.keys():
|
1586
1594
|
if not a or not b:
|
1587
1595
|
continue
|
1588
1596
|
|
@@ -13,12 +13,20 @@ def vf_bmap() :
|
|
13
13
|
"no_dedup": "copydupes",
|
14
14
|
"no_dupe": "nodupe",
|
15
15
|
"no_forget": "noforget",
|
16
|
+
"no_robots": "norobots",
|
17
|
+
"no_thumb": "dthumb",
|
18
|
+
"no_vthumb": "dvthumb",
|
19
|
+
"no_athumb": "dathumb",
|
20
|
+
"re_maxage": "scan",
|
16
21
|
"th_no_crop": "nocrop",
|
17
22
|
"dav_auth": "davauth",
|
18
23
|
"dav_rt": "davrt",
|
19
24
|
}
|
20
25
|
for k in (
|
21
26
|
"dotsrch",
|
27
|
+
"e2d",
|
28
|
+
"e2ds",
|
29
|
+
"e2dsa",
|
22
30
|
"e2t",
|
23
31
|
"e2ts",
|
24
32
|
"e2tsr",
|
@@ -41,7 +49,12 @@ def vf_bmap() :
|
|
41
49
|
|
42
50
|
def vf_vmap() :
|
43
51
|
"""argv-to-volflag: simple values"""
|
44
|
-
ret = {
|
52
|
+
ret = {
|
53
|
+
"no_hash": "nohash",
|
54
|
+
"no_idx": "noidx",
|
55
|
+
"th_convt": "convt",
|
56
|
+
"th_size": "thsize",
|
57
|
+
}
|
45
58
|
for k in ("dbd", "lg_sbf", "md_sbf", "nrand", "sort", "unlist", "u2ts"):
|
46
59
|
ret[k] = k
|
47
60
|
return ret
|
@@ -50,7 +63,21 @@ def vf_vmap() :
|
|
50
63
|
def vf_cmap() :
|
51
64
|
"""argv-to-volflag: complex/lists"""
|
52
65
|
ret = {}
|
53
|
-
for k in (
|
66
|
+
for k in (
|
67
|
+
"html_head",
|
68
|
+
"mte",
|
69
|
+
"mth",
|
70
|
+
"mtp",
|
71
|
+
"xad",
|
72
|
+
"xar",
|
73
|
+
"xau",
|
74
|
+
"xban",
|
75
|
+
"xbd",
|
76
|
+
"xbr",
|
77
|
+
"xbu",
|
78
|
+
"xiu",
|
79
|
+
"xm",
|
80
|
+
):
|
54
81
|
ret[k] = k
|
55
82
|
return ret
|
56
83
|
|
@@ -40,7 +40,9 @@ from .util import (
|
|
40
40
|
HTTPCODE,
|
41
41
|
META_NOBOTS,
|
42
42
|
MultipartParser,
|
43
|
+
ODict,
|
43
44
|
Pebkac,
|
45
|
+
UTC,
|
44
46
|
UnrecvEOF,
|
45
47
|
absreal,
|
46
48
|
alltrace,
|
@@ -650,6 +652,7 @@ class HttpCli(object):
|
|
650
652
|
and not body.startswith(b"<pre>source file busy")
|
651
653
|
)
|
652
654
|
)
|
655
|
+
and (status != 404 or (self.can_get and not self.can_read))
|
653
656
|
):
|
654
657
|
if status == 404:
|
655
658
|
g = self.conn.hsrv.g404
|
@@ -1967,8 +1970,7 @@ class HttpCli(object):
|
|
1967
1970
|
self.log("q#: {} ({:.2f}s)".format(msg, idx.p_dur))
|
1968
1971
|
|
1969
1972
|
order = []
|
1970
|
-
|
1971
|
-
for t in cfg:
|
1973
|
+
for t in self.args.mte:
|
1972
1974
|
if t in taglist:
|
1973
1975
|
order.append(t)
|
1974
1976
|
for t in taglist:
|
@@ -3987,7 +3989,7 @@ class HttpCli(object):
|
|
3987
3989
|
margin = "-"
|
3988
3990
|
|
3989
3991
|
sz = inf.st_size
|
3990
|
-
zd = datetime.
|
3992
|
+
zd = datetime.fromtimestamp(linf.st_mtime, UTC)
|
3991
3993
|
dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
|
3992
3994
|
zd.year,
|
3993
3995
|
zd.month,
|
@@ -4047,6 +4049,9 @@ class HttpCli(object):
|
|
4047
4049
|
ap = vn.canonical(rem)
|
4048
4050
|
return self.tx_file(ap) # is no-cache
|
4049
4051
|
|
4052
|
+
mte = vn.flags.get("mte", {})
|
4053
|
+
add_up_at = ".up_at" in mte
|
4054
|
+
is_admin = self.can_admin
|
4050
4055
|
tagset = set()
|
4051
4056
|
for fe in files:
|
4052
4057
|
fn = fe["name"]
|
@@ -4074,24 +4079,38 @@ class HttpCli(object):
|
|
4074
4079
|
self.log(t.format(rd, fn, min_ex()))
|
4075
4080
|
break
|
4076
4081
|
|
4077
|
-
|
4082
|
+
tags = {k: v for k, v in r}
|
4078
4083
|
|
4079
|
-
if
|
4084
|
+
if is_admin:
|
4080
4085
|
q = "select ip, at from up where rd=? and fn=?"
|
4081
4086
|
try:
|
4082
4087
|
zs1, zs2 = icur.execute(q, erd_efn).fetchone()
|
4083
|
-
|
4084
|
-
|
4088
|
+
if zs1:
|
4089
|
+
tags["up_ip"] = zs1
|
4090
|
+
if zs2:
|
4091
|
+
tags[".up_at"] = zs2
|
4092
|
+
except:
|
4093
|
+
pass
|
4094
|
+
elif add_up_at:
|
4095
|
+
q = "select at from up where rd=? and fn=?"
|
4096
|
+
try:
|
4097
|
+
(zs1,) = icur.execute(q, erd_efn).fetchone()
|
4098
|
+
if zs1:
|
4099
|
+
tags[".up_at"] = zs1
|
4085
4100
|
except:
|
4086
4101
|
pass
|
4087
4102
|
|
4088
|
-
_ = [tagset.add(k) for k in
|
4103
|
+
_ = [tagset.add(k) for k in tags]
|
4104
|
+
fe["tags"] = tags
|
4089
4105
|
|
4090
4106
|
if icur:
|
4091
|
-
|
4092
|
-
|
4107
|
+
lmte = list(mte)
|
4108
|
+
if self.can_admin:
|
4109
|
+
lmte += ["up_ip", ".up_at"]
|
4110
|
+
|
4111
|
+
taglist = [k for k in lmte if k in tagset]
|
4093
4112
|
for fe in dirs:
|
4094
|
-
fe["tags"] =
|
4113
|
+
fe["tags"] = ODict()
|
4095
4114
|
else:
|
4096
4115
|
taglist = list(tagset)
|
4097
4116
|
|
@@ -4138,7 +4157,7 @@ class HttpCli(object):
|
|
4138
4157
|
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
4139
4158
|
|
4140
4159
|
if "mth" in vn.flags:
|
4141
|
-
j2a["def_hcols"] = vn.flags["mth"]
|
4160
|
+
j2a["def_hcols"] = list(vn.flags["mth"])
|
4142
4161
|
|
4143
4162
|
html = self.j2s(tpl, **j2a)
|
4144
4163
|
self.reply(html.encode("utf-8", "replace"))
|
@@ -8,7 +8,7 @@ from datetime import datetime
|
|
8
8
|
from .__init__ import CORES
|
9
9
|
from .bos import bos
|
10
10
|
from .th_cli import ThumbCli
|
11
|
-
from .util import vjoin
|
11
|
+
from .util import UTC, vjoin
|
12
12
|
|
13
13
|
class StreamArc(object):
|
14
14
|
def __init__(
|
@@ -102,7 +102,7 @@ def errdesc(errors ) :
|
|
102
102
|
tf_path = tf.name
|
103
103
|
tf.write("\r\n".join(report).encode("utf-8", "replace"))
|
104
104
|
|
105
|
-
dt = datetime.
|
105
|
+
dt = datetime.now(UTC).strftime("%Y-%m%d-%H%M%S")
|
106
106
|
|
107
107
|
bos.chmod(tf_path, 0o444)
|
108
108
|
return {
|