copyparty 1.17.2__tar.gz → 1.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {copyparty-1.17.2 → copyparty-1.18.0}/PKG-INFO +30 -4
- {copyparty-1.17.2 → copyparty-1.18.0}/README.md +29 -3
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/__main__.py +14 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/__version__.py +3 -3
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/authsrv.py +32 -14
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/cfg.py +14 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/httpcli.py +170 -7
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/util.py +21 -5
- copyparty-1.18.0/copyparty/web/browser.css.gz +0 -0
- copyparty-1.18.0/copyparty/web/browser.js.gz +0 -0
- copyparty-1.18.0/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/ui.css.gz +0 -0
- copyparty-1.18.0/copyparty/web/util.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/PKG-INFO +30 -4
- copyparty-1.17.2/copyparty/web/browser.css.gz +0 -0
- copyparty-1.17.2/copyparty/web/browser.js.gz +0 -0
- copyparty-1.17.2/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.17.2/copyparty/web/util.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/LICENSE +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/bos/bos.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/bos/path.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/broker_mp.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/broker_thr.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/broker_util.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/cert.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/dxml.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/fsutil.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/ftpd.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/httpconn.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/httpsrv.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/ico.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/mdns.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/metrics.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/mtag.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/multicast.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/pwhash.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/res/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/smbd.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/ssdp.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/star.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/sutil.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/svchub.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/szip.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/tftpd.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/th_cli.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/th_srv.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/u2idx.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/up2k.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/a/u2c.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/browser.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/browser2.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/cf.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/md.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/mde.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/msg.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/rups.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/rups.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/rups.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/shares.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/shares.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/splash.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/svcs.html +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/pyproject.toml +0 -0
- {copyparty-1.17.2 → copyparty-1.18.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.18.0
|
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
|
@@ -66,7 +66,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
66
66
|
* 🔌 protocols: [http](#the-browser) // [webdav](#webdav-server) // [ftp](#ftp-server) // [tftp](#tftp-server) // [smb/cifs](#smb-server)
|
67
67
|
* 📱 [android app](#android-app) // [iPhone shortcuts](#ios-shortcuts)
|
68
68
|
|
69
|
-
👉 **[Get started](#quickstart)!** or visit the **[read-only demo server](https://a.ocv.me/pub/demo/)** 👀 running
|
69
|
+
👉 **[Get started](#quickstart)!** or visit the **[read-only demo server](https://a.ocv.me/pub/demo/)** 👀 running on a nuc in my basement
|
70
70
|
|
71
71
|
📷 **screenshots:** [browser](#the-browser) // [upload](#uploading) // [unpost](#unpost) // [thumbnails](#thumbnails) // [search](#searching) // [fsearch](#file-search) // [zip-DL](#zip-downloads) // [md-viewer](#markdown-viewer)
|
72
72
|
|
@@ -114,6 +114,7 @@ made in Norway 🇳🇴
|
|
114
114
|
* [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
|
115
115
|
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
116
116
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
117
|
+
* [textfile viewer](#textfile-viewer) - with realtime streaming of logfiles and such ([demo](https://a.ocv.me/pub/demo/logtail/))
|
117
118
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
118
119
|
* [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
|
119
120
|
* [other tricks](#other-tricks)
|
@@ -315,7 +316,8 @@ also see [comparison to similar software](./docs/versus.md)
|
|
315
316
|
* ☑ play video files as audio (converted on server)
|
316
317
|
* ☑ create and play [m3u8 playlists](#playlists)
|
317
318
|
* ☑ image gallery with webm player
|
318
|
-
* ☑ textfile browser with syntax hilighting
|
319
|
+
* ☑ [textfile browser](#textfile-viewer) with syntax hilighting
|
320
|
+
* ☑ realtime streaming of growing files (logfiles and such)
|
319
321
|
* ☑ [thumbnails](#thumbnails)
|
320
322
|
* ☑ ...of images using Pillow, pyvips, or FFmpeg
|
321
323
|
* ☑ ...of videos using FFmpeg
|
@@ -619,6 +621,8 @@ a client can request to see dotfiles in directory listings if global option `-ed
|
|
619
621
|
|
620
622
|
dotfiles do not appear in search results unless one of the above is true, **and** the global option / volflag `dotsrch` is set
|
621
623
|
|
624
|
+
> even if user has permission to see dotfiles, they are default-hidden unless `--see-dots` is set, and/or user has enabled the `dotfiles` option in the settings tab
|
625
|
+
|
622
626
|
config file example, where the same permission to see dotfiles is given in two different ways just for reference:
|
623
627
|
|
624
628
|
```yaml
|
@@ -755,7 +759,10 @@ enabling `multiselect` lets you click files to select them, and then shift-click
|
|
755
759
|
* `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking
|
756
760
|
* the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
|
757
761
|
|
758
|
-
to show `/icons/exe.png` as the thumbnail for all
|
762
|
+
to show `/icons/exe.png` and `/icons/elf.gif` as the thumbnail for all `.exe` and `.elf` files respectively, do this: `--ext-th=exe=/icons/exe.png --ext-th=elf=/icons/elf.gif`
|
763
|
+
* optionally as separate volflags for each mapping; see config file example below
|
764
|
+
* the supported image formats are [jpg, png, gif, webp, ico](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types)
|
765
|
+
* be careful with svg; chrome will crash if you have too many unique svg files showing on the same page (the limit is 250 or so) -- showing the same handful of svg files thousands of times is ok however
|
759
766
|
|
760
767
|
config file example:
|
761
768
|
|
@@ -772,6 +779,7 @@ config file example:
|
|
772
779
|
dthumb # disable ALL thumbnails and audio transcoding
|
773
780
|
dvthumb # only disable video thumbnails
|
774
781
|
ext-th: exe=/ico/exe.png # /ico/exe.png is the thumbnail of *.exe
|
782
|
+
ext-th: elf=/ico/elf.gif # ...and /ico/elf.gif is used for *.elf
|
775
783
|
th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default
|
776
784
|
```
|
777
785
|
|
@@ -1179,6 +1187,18 @@ not available on iPhones / iPads because AudioContext currently breaks backgroun
|
|
1179
1187
|
due to phone / app settings, android phones may randomly stop playing music when the power saver kicks in, especially at the end of an album -- you can fix it by [disabling power saving](https://user-images.githubusercontent.com/241032/235262123-c328cca9-3930-4948-bd18-3949b9fd3fcf.png) in the [app settings](https://user-images.githubusercontent.com/241032/235262121-2ffc51ae-7821-4310-a322-c3b7a507890c.png) of the browser you use for music streaming (preferably a dedicated one)
|
1180
1188
|
|
1181
1189
|
|
1190
|
+
## textfile viewer
|
1191
|
+
|
1192
|
+
with realtime streaming of logfiles and such ([demo](https://a.ocv.me/pub/demo/logtail/)) , and terminal colors work too
|
1193
|
+
|
1194
|
+
click `-txt-` next to a textfile to open the viewer, which has the following toolbar buttons:
|
1195
|
+
|
1196
|
+
* `✏️ edit` opens the textfile editor
|
1197
|
+
* `📡 follow` starts monitoring the file for changes, streaming new lines in realtime
|
1198
|
+
* similar to `tail -f`
|
1199
|
+
* [link directly](https://a.ocv.me/pub/demo/logtail/?doc=lipsum.txt&tail) to a file with tailing enabled by adding `&tail` to the textviewer URL
|
1200
|
+
|
1201
|
+
|
1182
1202
|
## markdown viewer
|
1183
1203
|
|
1184
1204
|
and there are *two* editors
|
@@ -2477,6 +2497,9 @@ interact with copyparty using non-browser clients
|
|
2477
2497
|
* and for screenshots on macos, see [./contrib/ishare.iscu](./contrib/#ishareiscu)
|
2478
2498
|
* and for screenshots on linux, see [./contrib/flameshot.sh](./contrib/flameshot.sh)
|
2479
2499
|
|
2500
|
+
* [Custom Uploader](https://f-droid.org/en/packages/com.nyx.custom_uploader/) (an Android app) as an alternative to copyparty's own [PartyUP!](#android-app)
|
2501
|
+
* works if you set UploadURL to `https://your.com/foo/?want=url&pw=hunter2` and FormDataName `f`
|
2502
|
+
|
2480
2503
|
* contextlet (web browser integration); see [contrib contextlet](contrib/#send-to-cppcontextletjson)
|
2481
2504
|
|
2482
2505
|
* [igloo irc](https://iglooirc.com/): Method: `post` Host: `https://you.com/up/?want=url&pw=hunter2` Multipart: `yes` File parameter: `f`
|
@@ -2790,6 +2813,7 @@ set any of the following environment variables to disable its associated optiona
|
|
2790
2813
|
| `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
|
2791
2814
|
| `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
|
2792
2815
|
| `PRTY_NO_FFPROBE` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips, **metadata-scanning** must be handled by mutagen |
|
2816
|
+
| `PRTY_NO_MAGIC` | do not use [magic](https://pypi.org/project/python-magic/) for filetype detection |
|
2793
2817
|
| `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
|
2794
2818
|
| `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
|
2795
2819
|
| `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
|
@@ -2890,5 +2914,7 @@ if there's a wall of base64 in the log (thread stacks) then please include that,
|
|
2890
2914
|
|
2891
2915
|
for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
|
2892
2916
|
|
2917
|
+
specifically you may want to [build the sfx](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#just-the-sfx) or [build from scratch](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#build-from-scratch)
|
2918
|
+
|
2893
2919
|
see [./docs/TODO.md](./docs/TODO.md) for planned features / fixes / changes
|
2894
2920
|
|
@@ -8,7 +8,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
8
8
|
* 🔌 protocols: [http](#the-browser) // [webdav](#webdav-server) // [ftp](#ftp-server) // [tftp](#tftp-server) // [smb/cifs](#smb-server)
|
9
9
|
* 📱 [android app](#android-app) // [iPhone shortcuts](#ios-shortcuts)
|
10
10
|
|
11
|
-
👉 **[Get started](#quickstart)!** or visit the **[read-only demo server](https://a.ocv.me/pub/demo/)** 👀 running
|
11
|
+
👉 **[Get started](#quickstart)!** or visit the **[read-only demo server](https://a.ocv.me/pub/demo/)** 👀 running on a nuc in my basement
|
12
12
|
|
13
13
|
📷 **screenshots:** [browser](#the-browser) // [upload](#uploading) // [unpost](#unpost) // [thumbnails](#thumbnails) // [search](#searching) // [fsearch](#file-search) // [zip-DL](#zip-downloads) // [md-viewer](#markdown-viewer)
|
14
14
|
|
@@ -56,6 +56,7 @@ made in Norway 🇳🇴
|
|
56
56
|
* [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
|
57
57
|
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
58
58
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
59
|
+
* [textfile viewer](#textfile-viewer) - with realtime streaming of logfiles and such ([demo](https://a.ocv.me/pub/demo/logtail/))
|
59
60
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
60
61
|
* [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
|
61
62
|
* [other tricks](#other-tricks)
|
@@ -257,7 +258,8 @@ also see [comparison to similar software](./docs/versus.md)
|
|
257
258
|
* ☑ play video files as audio (converted on server)
|
258
259
|
* ☑ create and play [m3u8 playlists](#playlists)
|
259
260
|
* ☑ image gallery with webm player
|
260
|
-
* ☑ textfile browser with syntax hilighting
|
261
|
+
* ☑ [textfile browser](#textfile-viewer) with syntax hilighting
|
262
|
+
* ☑ realtime streaming of growing files (logfiles and such)
|
261
263
|
* ☑ [thumbnails](#thumbnails)
|
262
264
|
* ☑ ...of images using Pillow, pyvips, or FFmpeg
|
263
265
|
* ☑ ...of videos using FFmpeg
|
@@ -561,6 +563,8 @@ a client can request to see dotfiles in directory listings if global option `-ed
|
|
561
563
|
|
562
564
|
dotfiles do not appear in search results unless one of the above is true, **and** the global option / volflag `dotsrch` is set
|
563
565
|
|
566
|
+
> even if user has permission to see dotfiles, they are default-hidden unless `--see-dots` is set, and/or user has enabled the `dotfiles` option in the settings tab
|
567
|
+
|
564
568
|
config file example, where the same permission to see dotfiles is given in two different ways just for reference:
|
565
569
|
|
566
570
|
```yaml
|
@@ -697,7 +701,10 @@ enabling `multiselect` lets you click files to select them, and then shift-click
|
|
697
701
|
* `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking
|
698
702
|
* the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
|
699
703
|
|
700
|
-
to show `/icons/exe.png` as the thumbnail for all
|
704
|
+
to show `/icons/exe.png` and `/icons/elf.gif` as the thumbnail for all `.exe` and `.elf` files respectively, do this: `--ext-th=exe=/icons/exe.png --ext-th=elf=/icons/elf.gif`
|
705
|
+
* optionally as separate volflags for each mapping; see config file example below
|
706
|
+
* the supported image formats are [jpg, png, gif, webp, ico](https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Image_types)
|
707
|
+
* be careful with svg; chrome will crash if you have too many unique svg files showing on the same page (the limit is 250 or so) -- showing the same handful of svg files thousands of times is ok however
|
701
708
|
|
702
709
|
config file example:
|
703
710
|
|
@@ -714,6 +721,7 @@ config file example:
|
|
714
721
|
dthumb # disable ALL thumbnails and audio transcoding
|
715
722
|
dvthumb # only disable video thumbnails
|
716
723
|
ext-th: exe=/ico/exe.png # /ico/exe.png is the thumbnail of *.exe
|
724
|
+
ext-th: elf=/ico/elf.gif # ...and /ico/elf.gif is used for *.elf
|
717
725
|
th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default
|
718
726
|
```
|
719
727
|
|
@@ -1121,6 +1129,18 @@ not available on iPhones / iPads because AudioContext currently breaks backgroun
|
|
1121
1129
|
due to phone / app settings, android phones may randomly stop playing music when the power saver kicks in, especially at the end of an album -- you can fix it by [disabling power saving](https://user-images.githubusercontent.com/241032/235262123-c328cca9-3930-4948-bd18-3949b9fd3fcf.png) in the [app settings](https://user-images.githubusercontent.com/241032/235262121-2ffc51ae-7821-4310-a322-c3b7a507890c.png) of the browser you use for music streaming (preferably a dedicated one)
|
1122
1130
|
|
1123
1131
|
|
1132
|
+
## textfile viewer
|
1133
|
+
|
1134
|
+
with realtime streaming of logfiles and such ([demo](https://a.ocv.me/pub/demo/logtail/)) , and terminal colors work too
|
1135
|
+
|
1136
|
+
click `-txt-` next to a textfile to open the viewer, which has the following toolbar buttons:
|
1137
|
+
|
1138
|
+
* `✏️ edit` opens the textfile editor
|
1139
|
+
* `📡 follow` starts monitoring the file for changes, streaming new lines in realtime
|
1140
|
+
* similar to `tail -f`
|
1141
|
+
* [link directly](https://a.ocv.me/pub/demo/logtail/?doc=lipsum.txt&tail) to a file with tailing enabled by adding `&tail` to the textviewer URL
|
1142
|
+
|
1143
|
+
|
1124
1144
|
## markdown viewer
|
1125
1145
|
|
1126
1146
|
and there are *two* editors
|
@@ -2419,6 +2439,9 @@ interact with copyparty using non-browser clients
|
|
2419
2439
|
* and for screenshots on macos, see [./contrib/ishare.iscu](./contrib/#ishareiscu)
|
2420
2440
|
* and for screenshots on linux, see [./contrib/flameshot.sh](./contrib/flameshot.sh)
|
2421
2441
|
|
2442
|
+
* [Custom Uploader](https://f-droid.org/en/packages/com.nyx.custom_uploader/) (an Android app) as an alternative to copyparty's own [PartyUP!](#android-app)
|
2443
|
+
* works if you set UploadURL to `https://your.com/foo/?want=url&pw=hunter2` and FormDataName `f`
|
2444
|
+
|
2422
2445
|
* contextlet (web browser integration); see [contrib contextlet](contrib/#send-to-cppcontextletjson)
|
2423
2446
|
|
2424
2447
|
* [igloo irc](https://iglooirc.com/): Method: `post` Host: `https://you.com/up/?want=url&pw=hunter2` Multipart: `yes` File parameter: `f`
|
@@ -2732,6 +2755,7 @@ set any of the following environment variables to disable its associated optiona
|
|
2732
2755
|
| `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
|
2733
2756
|
| `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
|
2734
2757
|
| `PRTY_NO_FFPROBE` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips, **metadata-scanning** must be handled by mutagen |
|
2758
|
+
| `PRTY_NO_MAGIC` | do not use [magic](https://pypi.org/project/python-magic/) for filetype detection |
|
2735
2759
|
| `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
|
2736
2760
|
| `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
|
2737
2761
|
| `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
|
@@ -2832,5 +2856,7 @@ if there's a wall of base64 in the log (thread stacks) then please include that,
|
|
2832
2856
|
|
2833
2857
|
for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
|
2834
2858
|
|
2859
|
+
specifically you may want to [build the sfx](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#just-the-sfx) or [build from scratch](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#build-from-scratch)
|
2860
|
+
|
2835
2861
|
see [./docs/TODO.md](./docs/TODO.md) for planned features / fixes / changes
|
2836
2862
|
|
@@ -956,6 +956,7 @@ def add_general(ap, nc, srvname):
|
|
956
956
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
957
957
|
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
958
958
|
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
959
|
+
ap2.add_argument("--rmagic", action="store_true", help="do expensive analysis to improve accuracy of returned mimetypes; will make file-downloads, rss, and webdav slower (volflag=rmagic)")
|
959
960
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
960
961
|
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
961
962
|
|
@@ -1262,6 +1263,7 @@ def add_optouts(ap):
|
|
1262
1263
|
ap2.add_argument("--no-tarcmp", action="store_true", help="disable download as compressed tar (?tar=gz, ?tar=bz2, ?tar=xz, ?tar=gz:9, ...)")
|
1263
1264
|
ap2.add_argument("--no-lifetime", action="store_true", help="do not allow clients (or server config) to schedule an upload to be deleted after a given time")
|
1264
1265
|
ap2.add_argument("--no-pipe", action="store_true", help="disable race-the-beam (lockstep download of files which are currently being uploaded) (volflag=nopipe)")
|
1266
|
+
ap2.add_argument("--no-tail", action="store_true", help="disable streaming a growing files with ?tail (volflag=notail)")
|
1265
1267
|
ap2.add_argument("--no-db-ip", action="store_true", help="do not write uploader-IP into the database; will also disable unpost, you may want \033[32m--forget-ip\033[0m instead (volflag=no_db_ip)")
|
1266
1268
|
|
1267
1269
|
|
@@ -1391,6 +1393,16 @@ def add_transcoding(ap):
|
|
1391
1393
|
ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
|
1392
1394
|
|
1393
1395
|
|
1396
|
+
def add_tail(ap):
|
1397
|
+
ap2 = ap.add_argument_group('tailing options (realtime streaming of a growing file)')
|
1398
|
+
ap2.add_argument("--tail-who", metavar="LVL", type=int, default=2, help="who can tail? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=authenticated-with-read-access, [\033[32m3\033[0m]=everyone-with-read-access (volflag=tail_who)")
|
1399
|
+
ap2.add_argument("--tail-cmax", metavar="N", type=int, default=64, help="do not allow starting a new tail if more than \033[33mN\033[0m active downloads")
|
1400
|
+
ap2.add_argument("--tail-tmax", metavar="SEC", type=float, default=0, help="terminate connection after \033[33mSEC\033[0m seconds; [\033[32m0\033[0m]=never (volflag=tail_tmax)")
|
1401
|
+
ap2.add_argument("--tail-rate", metavar="SEC", type=float, default=0.2, help="check for new data every \033[33mSEC\033[0m seconds (volflag=tail_rate)")
|
1402
|
+
ap2.add_argument("--tail-ka", metavar="SEC", type=float, default=3.0, help="send a zerobyte if connection is idle for \033[33mSEC\033[0m seconds to prevent disconnect")
|
1403
|
+
ap2.add_argument("--tail-fd", metavar="SEC", type=float, default=1.0, help="check if file was replaced (new fd) if idle for \033[33mSEC\033[0m seconds (volflag=tail_fd)")
|
1404
|
+
|
1405
|
+
|
1394
1406
|
def add_rss(ap):
|
1395
1407
|
ap2 = ap.add_argument_group('RSS options')
|
1396
1408
|
ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)")
|
@@ -1486,6 +1498,7 @@ def add_ui(ap, retry):
|
|
1486
1498
|
ap2.add_argument("--sort", metavar="C,C,C", type=u, default="href", help="default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: \033[32mhref -href ext sz ts tags/Album tags/.tn\033[0m (volflag=sort)")
|
1487
1499
|
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
1488
1500
|
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
1501
|
+
ap2.add_argument("--see-dots", action="store_true", help="default-enable seeing dotfiles; only takes effect if user has the necessary permissions")
|
1489
1502
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
1490
1503
|
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
1491
1504
|
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
|
@@ -1595,6 +1608,7 @@ def run_argparse(
|
|
1595
1608
|
add_hooks(ap)
|
1596
1609
|
add_stats(ap)
|
1597
1610
|
add_txt(ap)
|
1611
|
+
add_tail(ap)
|
1598
1612
|
add_og(ap)
|
1599
1613
|
add_ui(ap, retry)
|
1600
1614
|
add_admin(ap)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2025,
|
3
|
+
VERSION = (1, 18, 0)
|
4
|
+
CODENAME = "logtail"
|
5
|
+
BUILD_DT = (2025, 6, 22)
|
6
6
|
|
7
7
|
S_VERSION = ".".join(map(str, VERSION))
|
8
8
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
@@ -65,7 +65,9 @@ SSEELOG = " ({})".format(SEE_LOG)
|
|
65
65
|
BAD_CFG = "invalid config; {}".format(SEE_LOG)
|
66
66
|
SBADCFG = " ({})".format(BAD_CFG)
|
67
67
|
|
68
|
-
PTN_U_GRP = re.compile(r"\$\{u%
|
68
|
+
PTN_U_GRP = re.compile(r"\$\{u(%[+-][^}]+)\}")
|
69
|
+
PTN_G_GRP = re.compile(r"\$\{g(%[+-][^}]+)\}")
|
70
|
+
PTN_SIGIL = re.compile(r"(\${[ug][}%])")
|
69
71
|
|
70
72
|
|
71
73
|
class CfgEx(Exception):
|
@@ -958,15 +960,27 @@ class AuthSrv(object):
|
|
958
960
|
un_gn = [("", "")]
|
959
961
|
|
960
962
|
for un, gn in un_gn:
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
if req == "+":
|
966
|
-
if not hit:
|
967
|
-
continue
|
968
|
-
elif hit:
|
963
|
+
rejected = False
|
964
|
+
for ptn in [PTN_U_GRP, PTN_G_GRP]:
|
965
|
+
m = ptn.search(dst0)
|
966
|
+
if not m:
|
969
967
|
continue
|
968
|
+
zs = m.group(1)
|
969
|
+
zs = zs.replace(",%+", "\n%+")
|
970
|
+
zs = zs.replace(",%-", "\n%-")
|
971
|
+
for rule in zs.split("\n"):
|
972
|
+
gnc = rule[2:]
|
973
|
+
if ptn == PTN_U_GRP:
|
974
|
+
# is user member of group?
|
975
|
+
hit = gnc in (un_gns.get(un) or [])
|
976
|
+
else:
|
977
|
+
# is it this specific group?
|
978
|
+
hit = gn == gnc
|
979
|
+
|
980
|
+
if rule.startswith("%+") != hit:
|
981
|
+
rejected = True
|
982
|
+
if rejected:
|
983
|
+
continue
|
970
984
|
|
971
985
|
# if ap/vp has a user/group placeholder, make sure to keep
|
972
986
|
# track so the same user/group is mapped when setting perms;
|
@@ -981,6 +995,8 @@ class AuthSrv(object):
|
|
981
995
|
|
982
996
|
src = src1.replace("${g}", gn or "\n")
|
983
997
|
dst = dst1.replace("${g}", gn or "\n")
|
998
|
+
src = PTN_G_GRP.sub(gn or "\n", src)
|
999
|
+
dst = PTN_G_GRP.sub(gn or "\n", dst)
|
984
1000
|
if src == src1 and dst == dst1:
|
985
1001
|
gn = ""
|
986
1002
|
|
@@ -1855,7 +1871,7 @@ class AuthSrv(object):
|
|
1855
1871
|
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1856
1872
|
if histp and not is_shr and histp in rhisttab:
|
1857
1873
|
zv2 = rhisttab[histp]
|
1858
|
-
t = "invalid config; multiple volumes share the same histpath (database+thumbnails location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2:
|
1874
|
+
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]"
|
1859
1875
|
t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1860
1876
|
self.log(t, 1)
|
1861
1877
|
raise Exception(t)
|
@@ -1869,7 +1885,7 @@ class AuthSrv(object):
|
|
1869
1885
|
is_shr = shr and zv.vpath.split("/")[0] == shr
|
1870
1886
|
if dbp and not is_shr and dbp in rdbpaths:
|
1871
1887
|
zv2 = rdbpaths[dbp]
|
1872
|
-
t = "invalid config; multiple volumes share the same dbpath (database location):\n dbpath: %s\n volume 1: /%s [%s]\n volume 2:
|
1888
|
+
t = "invalid config; multiple volumes share the same dbpath (database location):\n dbpath: %s\n volume 1: /%s [%s]\n volume 2: /%s [%s]"
|
1873
1889
|
t = t % (dbp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
|
1874
1890
|
self.log(t, 1)
|
1875
1891
|
raise Exception(t)
|
@@ -2052,12 +2068,13 @@ class AuthSrv(object):
|
|
2052
2068
|
if vf not in vol.flags:
|
2053
2069
|
vol.flags[vf] = getattr(self.args, ga)
|
2054
2070
|
|
2055
|
-
zs = "forget_ip nrand u2abort u2ow ups_who zip_who"
|
2071
|
+
zs = "forget_ip nrand tail_who u2abort u2ow ups_who zip_who"
|
2056
2072
|
for k in zs.split():
|
2057
2073
|
if k in vol.flags:
|
2058
2074
|
vol.flags[k] = int(vol.flags[k])
|
2059
2075
|
|
2060
|
-
|
2076
|
+
zs = "convt tail_fd tail_rate tail_tmax"
|
2077
|
+
for k in zs.split():
|
2061
2078
|
if k in vol.flags:
|
2062
2079
|
vol.flags[k] = float(vol.flags[k])
|
2063
2080
|
|
@@ -2386,7 +2403,7 @@ class AuthSrv(object):
|
|
2386
2403
|
idp_vn, _ = vfs.get(idp_vp, "*", False, False)
|
2387
2404
|
idp_vp0 = idp_vn.vpath0
|
2388
2405
|
|
2389
|
-
sigils = set(
|
2406
|
+
sigils = set(PTN_SIGIL.findall(idp_vp0))
|
2390
2407
|
if len(sigils) > 1:
|
2391
2408
|
t = '\nWARNING: IdP-volume "/%s" created by "/%s" has multiple IdP placeholders: %s'
|
2392
2409
|
self.idp_warn.append(t % (idp_vp, idp_vp0, list(sigils)))
|
@@ -2556,6 +2573,7 @@ class AuthSrv(object):
|
|
2556
2573
|
"txt_ext": self.args.textfiles.replace(",", " "),
|
2557
2574
|
"def_hcols": list(vf.get("mth") or []),
|
2558
2575
|
"unlist0": vf.get("unlist") or "",
|
2576
|
+
"see_dots": self.args.see_dots,
|
2559
2577
|
"dgrid": "grid" in vf,
|
2560
2578
|
"dgsel": "gsel" in vf,
|
2561
2579
|
"dnsort": "nsort" in vf,
|
@@ -22,6 +22,7 @@ def vf_bmap() :
|
|
22
22
|
"no_forget": "noforget",
|
23
23
|
"no_pipe": "nopipe",
|
24
24
|
"no_robots": "norobots",
|
25
|
+
"no_tail": "notail",
|
25
26
|
"no_thumb": "dthumb",
|
26
27
|
"no_vthumb": "dvthumb",
|
27
28
|
"no_athumb": "dathumb",
|
@@ -51,6 +52,7 @@ def vf_bmap() :
|
|
51
52
|
"og_no_head",
|
52
53
|
"og_s_title",
|
53
54
|
"rand",
|
55
|
+
"rmagic",
|
54
56
|
"rss",
|
55
57
|
"wo_up_readme",
|
56
58
|
"xdev",
|
@@ -101,6 +103,10 @@ def vf_vmap() :
|
|
101
103
|
"mv_retry",
|
102
104
|
"rm_retry",
|
103
105
|
"sort",
|
106
|
+
"tail_fd",
|
107
|
+
"tail_rate",
|
108
|
+
"tail_tmax",
|
109
|
+
"tail_who",
|
104
110
|
"tcolor",
|
105
111
|
"unlist",
|
106
112
|
"u2abort",
|
@@ -304,6 +310,13 @@ flagcats = {
|
|
304
310
|
"exp_md": "placeholders to expand in markdown files; see --help",
|
305
311
|
"exp_lg": "placeholders to expand in prologue/epilogue; see --help",
|
306
312
|
},
|
313
|
+
"tailing": {
|
314
|
+
"notail": "disable ?tail (download a growing file continuously)",
|
315
|
+
"tail_fd=1": "check if file was replaced (new fd) every 1 sec",
|
316
|
+
"tail_rate=0.2": "check for new data every 0.2 sec",
|
317
|
+
"tail_tmax=30": "kill connection after 30 sec",
|
318
|
+
"tail_who=2": "restrict ?tail access (1=admins,2=authed,3=everyone)",
|
319
|
+
},
|
307
320
|
"others": {
|
308
321
|
"dots": "allow all users with read-access to\nenable the option to show dotfiles in listings",
|
309
322
|
"fk=8": 'generates per-file accesskeys,\nwhich are then required at the "g" permission;\nkeys are invalidated if filesize or inode changes',
|
@@ -312,6 +325,7 @@ flagcats = {
|
|
312
325
|
"dks": "per-directory accesskeys allow browsing into subdirs",
|
313
326
|
"dky": 'allow seeing files (not folders) inside a specific folder\nwith "g" perm, and does not require a valid dirkey to do so',
|
314
327
|
"rss": "allow '?rss' URL suffix (experimental)",
|
328
|
+
"rmagic": "expensive analysis for mimetype accuracy",
|
315
329
|
"ups_who=2": "restrict viewing the list of recent uploads",
|
316
330
|
"zip_who=2": "restrict access to download-as-zip/tar",
|
317
331
|
"zipmaxn=9k": "reject download-as-zip if more than 9000 files",
|