copyparty 1.17.1__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.
Files changed (128) hide show
  1. {copyparty-1.17.1 → copyparty-1.18.0}/PKG-INFO +37 -4
  2. {copyparty-1.17.1 → copyparty-1.18.0}/README.md +36 -3
  3. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/__main__.py +15 -0
  4. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/__version__.py +3 -3
  5. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/authsrv.py +49 -19
  6. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/cfg.py +14 -0
  7. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/httpcli.py +189 -17
  8. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/util.py +21 -5
  9. copyparty-1.18.0/copyparty/web/browser.css.gz +0 -0
  10. copyparty-1.18.0/copyparty/web/browser.js.gz +0 -0
  11. copyparty-1.18.0/copyparty/web/deps/marked.js.gz +0 -0
  12. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/splash.js.gz +0 -0
  13. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/ui.css.gz +0 -0
  14. copyparty-1.18.0/copyparty/web/up2k.js.gz +0 -0
  15. copyparty-1.18.0/copyparty/web/util.js.gz +0 -0
  16. copyparty-1.18.0/copyparty/web/w.hash.js.gz +0 -0
  17. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/PKG-INFO +37 -4
  18. copyparty-1.17.1/copyparty/web/browser.css.gz +0 -0
  19. copyparty-1.17.1/copyparty/web/browser.js.gz +0 -0
  20. copyparty-1.17.1/copyparty/web/deps/marked.js.gz +0 -0
  21. copyparty-1.17.1/copyparty/web/up2k.js.gz +0 -0
  22. copyparty-1.17.1/copyparty/web/util.js.gz +0 -0
  23. copyparty-1.17.1/copyparty/web/w.hash.js.gz +0 -0
  24. {copyparty-1.17.1 → copyparty-1.18.0}/LICENSE +0 -0
  25. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/__init__.py +0 -0
  26. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/bos/__init__.py +0 -0
  27. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/bos/bos.py +0 -0
  28. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/bos/path.py +0 -0
  29. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/broker_mp.py +0 -0
  30. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/broker_mpw.py +0 -0
  31. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/broker_thr.py +0 -0
  32. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/broker_util.py +0 -0
  33. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/cert.py +0 -0
  34. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/dxml.py +0 -0
  35. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/fsutil.py +0 -0
  36. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/ftpd.py +0 -0
  37. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/httpconn.py +0 -0
  38. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/httpsrv.py +0 -0
  39. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/ico.py +0 -0
  40. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/mdns.py +0 -0
  41. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/metrics.py +0 -0
  42. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/mtag.py +0 -0
  43. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/multicast.py +0 -0
  44. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/pwhash.py +0 -0
  45. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/res/COPYING.txt +0 -0
  46. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/res/__init__.py +0 -0
  47. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/res/insecure.pem +0 -0
  48. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/smbd.py +0 -0
  49. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/ssdp.py +0 -0
  50. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/star.py +0 -0
  51. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/__init__.py +0 -0
  52. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/__init__.py +0 -0
  53. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/bimap.py +0 -0
  54. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/bit.py +0 -0
  55. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/buffer.py +0 -0
  56. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/dns.py +0 -0
  57. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/label.py +0 -0
  58. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/lex.py +0 -0
  59. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/dnslib/ranges.py +0 -0
  60. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/ifaddr/__init__.py +0 -0
  61. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_posix.py +0 -0
  62. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_shared.py +0 -0
  63. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/ifaddr/_win32.py +0 -0
  64. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/qrcodegen.py +0 -0
  65. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/stolen/surrogateescape.py +0 -0
  66. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/sutil.py +0 -0
  67. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/svchub.py +0 -0
  68. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/szip.py +0 -0
  69. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/tcpsrv.py +0 -0
  70. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/tftpd.py +0 -0
  71. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/th_cli.py +0 -0
  72. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/th_srv.py +0 -0
  73. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/u2idx.py +0 -0
  74. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/up2k.py +0 -0
  75. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/a/__init__.py +0 -0
  76. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/a/partyfuse.py +0 -0
  77. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/a/u2c.py +0 -0
  78. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/a/webdav-cfg.bat +0 -0
  79. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/baguettebox.js.gz +0 -0
  80. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/browser.html +0 -0
  81. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/browser2.html +0 -0
  82. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/cf.html +0 -0
  83. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dbg-audio.js.gz +0 -0
  84. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dd/2.png +0 -0
  85. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dd/3.png +0 -0
  86. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dd/4.png +0 -0
  87. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dd/5.png +0 -0
  88. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/dd/__init__.py +0 -0
  89. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/__init__.py +0 -0
  90. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/busy.mp3.gz +0 -0
  91. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/easymde.css.gz +0 -0
  92. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/easymde.js.gz +0 -0
  93. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/fuse.py +0 -0
  94. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/mini-fa.css.gz +0 -0
  95. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/mini-fa.woff +0 -0
  96. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/prism.css.gz +0 -0
  97. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/prism.js.gz +0 -0
  98. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/prismd.css.gz +0 -0
  99. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/scp.woff2 +0 -0
  100. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  101. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  102. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/md.css.gz +0 -0
  103. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/md.html +0 -0
  104. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/md.js.gz +0 -0
  105. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/md2.css.gz +0 -0
  106. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/md2.js.gz +0 -0
  107. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/mde.css.gz +0 -0
  108. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/mde.html +0 -0
  109. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/mde.js.gz +0 -0
  110. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/msg.css.gz +0 -0
  111. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/msg.html +0 -0
  112. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/rups.css.gz +0 -0
  113. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/rups.html +0 -0
  114. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/rups.js.gz +0 -0
  115. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/shares.css.gz +0 -0
  116. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/shares.html +0 -0
  117. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/shares.js.gz +0 -0
  118. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/splash.css.gz +0 -0
  119. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/splash.html +0 -0
  120. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/svcs.html +0 -0
  121. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty/web/svcs.js.gz +0 -0
  122. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/SOURCES.txt +0 -0
  123. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/dependency_links.txt +0 -0
  124. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/entry_points.txt +0 -0
  125. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/requires.txt +0 -0
  126. {copyparty-1.17.1 → copyparty-1.18.0}/copyparty.egg-info/top_level.txt +0 -0
  127. {copyparty-1.17.1 → copyparty-1.18.0}/pyproject.toml +0 -0
  128. {copyparty-1.17.1 → 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.17.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,12 +66,14 @@ 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 from a basement in finland
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
 
73
73
  🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm)
74
74
 
75
+ made in Norway 🇳🇴
76
+
75
77
 
76
78
  ## readme toc
77
79
 
@@ -112,6 +114,7 @@ turn almost any device into a file server with resumable uploads/downloads using
112
114
  * [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
113
115
  * [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
114
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/))
115
118
  * [markdown viewer](#markdown-viewer) - and there are *two* editors
116
119
  * [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
117
120
  * [other tricks](#other-tricks)
@@ -313,7 +316,8 @@ also see [comparison to similar software](./docs/versus.md)
313
316
  * ☑ play video files as audio (converted on server)
314
317
  * ☑ create and play [m3u8 playlists](#playlists)
315
318
  * ☑ image gallery with webm player
316
- * ☑ textfile browser with syntax hilighting
319
+ * ☑ [textfile browser](#textfile-viewer) with syntax hilighting
320
+ * ☑ realtime streaming of growing files (logfiles and such)
317
321
  * ☑ [thumbnails](#thumbnails)
318
322
  * ☑ ...of images using Pillow, pyvips, or FFmpeg
319
323
  * ☑ ...of videos using FFmpeg
@@ -617,6 +621,8 @@ a client can request to see dotfiles in directory listings if global option `-ed
617
621
 
618
622
  dotfiles do not appear in search results unless one of the above is true, **and** the global option / volflag `dotsrch` is set
619
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
+
620
626
  config file example, where the same permission to see dotfiles is given in two different ways just for reference:
621
627
 
622
628
  ```yaml
@@ -753,7 +759,10 @@ enabling `multiselect` lets you click files to select them, and then shift-click
753
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
754
760
  * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
755
761
 
756
- to show `/icons/exe.png` as the thumbnail for all .exe files, `--ext-th=exe=/icons/exe.png` (optionally as a volflag)
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
757
766
 
758
767
  config file example:
759
768
 
@@ -770,6 +779,7 @@ config file example:
770
779
  dthumb # disable ALL thumbnails and audio transcoding
771
780
  dvthumb # only disable video thumbnails
772
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
773
783
  th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default
774
784
  ```
775
785
 
@@ -1177,6 +1187,18 @@ not available on iPhones / iPads because AudioContext currently breaks backgroun
1177
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)
1178
1188
 
1179
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
+
1180
1202
  ## markdown viewer
1181
1203
 
1182
1204
  and there are *two* editors
@@ -2475,6 +2497,9 @@ interact with copyparty using non-browser clients
2475
2497
  * and for screenshots on macos, see [./contrib/ishare.iscu](./contrib/#ishareiscu)
2476
2498
  * and for screenshots on linux, see [./contrib/flameshot.sh](./contrib/flameshot.sh)
2477
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
+
2478
2503
  * contextlet (web browser integration); see [contrib contextlet](contrib/#send-to-cppcontextletjson)
2479
2504
 
2480
2505
  * [igloo irc](https://iglooirc.com/): Method: `post` Host: `https://you.com/up/?want=url&pw=hunter2` Multipart: `yes` File parameter: `f`
@@ -2576,6 +2601,11 @@ below are some tweaks roughly ordered by usefulness:
2576
2601
 
2577
2602
  when uploading files,
2578
2603
 
2604
+ * when uploading from very fast storage (NVMe SSD) with chrome/firefox, enable `[wasm]` in the `[⚙️] settings` tab to more effectively use all CPU-cores for hashing
2605
+ * don't do this on Safari (runs faster without)
2606
+ * don't do this on older browsers; likely to provoke browser-bugs (browser eats all RAM and crashes)
2607
+ * can be made default-enabled serverside with `--nosubtle 137` (chrome v137+) or `--nosubtle 2` (chrome+firefox)
2608
+
2579
2609
  * chrome is recommended (unfortunately), at least compared to firefox:
2580
2610
  * up to 90% faster when hashing, especially on SSDs
2581
2611
  * up to 40% faster when uploading over extremely fast internets
@@ -2783,6 +2813,7 @@ set any of the following environment variables to disable its associated optiona
2783
2813
  | `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
2784
2814
  | `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
2785
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 |
2786
2817
  | `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
2787
2818
  | `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
2788
2819
  | `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
@@ -2883,5 +2914,7 @@ if there's a wall of base64 in the log (thread stacks) then please include that,
2883
2914
 
2884
2915
  for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
2885
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
+
2886
2919
  see [./docs/TODO.md](./docs/TODO.md) for planned features / fixes / changes
2887
2920
 
@@ -8,12 +8,14 @@ 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 from a basement in finland
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
 
15
15
  🎬 **videos:** [upload](https://a.ocv.me/pub/demo/pics-vids/up2k.webm) // [cli-upload](https://a.ocv.me/pub/demo/pics-vids/u2cli.webm) // [race-the-beam](https://a.ocv.me/pub/g/nerd-stuff/cpp/2024-0418-race-the-beam.webm)
16
16
 
17
+ made in Norway 🇳🇴
18
+
17
19
 
18
20
  ## readme toc
19
21
 
@@ -54,6 +56,7 @@ turn almost any device into a file server with resumable uploads/downloads using
54
56
  * [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
55
57
  * [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
56
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/))
57
60
  * [markdown viewer](#markdown-viewer) - and there are *two* editors
58
61
  * [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
59
62
  * [other tricks](#other-tricks)
@@ -255,7 +258,8 @@ also see [comparison to similar software](./docs/versus.md)
255
258
  * ☑ play video files as audio (converted on server)
256
259
  * ☑ create and play [m3u8 playlists](#playlists)
257
260
  * ☑ image gallery with webm player
258
- * ☑ textfile browser with syntax hilighting
261
+ * ☑ [textfile browser](#textfile-viewer) with syntax hilighting
262
+ * ☑ realtime streaming of growing files (logfiles and such)
259
263
  * ☑ [thumbnails](#thumbnails)
260
264
  * ☑ ...of images using Pillow, pyvips, or FFmpeg
261
265
  * ☑ ...of videos using FFmpeg
@@ -559,6 +563,8 @@ a client can request to see dotfiles in directory listings if global option `-ed
559
563
 
560
564
  dotfiles do not appear in search results unless one of the above is true, **and** the global option / volflag `dotsrch` is set
561
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
+
562
568
  config file example, where the same permission to see dotfiles is given in two different ways just for reference:
563
569
 
564
570
  ```yaml
@@ -695,7 +701,10 @@ enabling `multiselect` lets you click files to select them, and then shift-click
695
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
696
702
  * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
697
703
 
698
- to show `/icons/exe.png` as the thumbnail for all .exe files, `--ext-th=exe=/icons/exe.png` (optionally as a volflag)
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
699
708
 
700
709
  config file example:
701
710
 
@@ -712,6 +721,7 @@ config file example:
712
721
  dthumb # disable ALL thumbnails and audio transcoding
713
722
  dvthumb # only disable video thumbnails
714
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
715
725
  th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default
716
726
  ```
717
727
 
@@ -1119,6 +1129,18 @@ not available on iPhones / iPads because AudioContext currently breaks backgroun
1119
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)
1120
1130
 
1121
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
+
1122
1144
  ## markdown viewer
1123
1145
 
1124
1146
  and there are *two* editors
@@ -2417,6 +2439,9 @@ interact with copyparty using non-browser clients
2417
2439
  * and for screenshots on macos, see [./contrib/ishare.iscu](./contrib/#ishareiscu)
2418
2440
  * and for screenshots on linux, see [./contrib/flameshot.sh](./contrib/flameshot.sh)
2419
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
+
2420
2445
  * contextlet (web browser integration); see [contrib contextlet](contrib/#send-to-cppcontextletjson)
2421
2446
 
2422
2447
  * [igloo irc](https://iglooirc.com/): Method: `post` Host: `https://you.com/up/?want=url&pw=hunter2` Multipart: `yes` File parameter: `f`
@@ -2518,6 +2543,11 @@ below are some tweaks roughly ordered by usefulness:
2518
2543
 
2519
2544
  when uploading files,
2520
2545
 
2546
+ * when uploading from very fast storage (NVMe SSD) with chrome/firefox, enable `[wasm]` in the `[⚙️] settings` tab to more effectively use all CPU-cores for hashing
2547
+ * don't do this on Safari (runs faster without)
2548
+ * don't do this on older browsers; likely to provoke browser-bugs (browser eats all RAM and crashes)
2549
+ * can be made default-enabled serverside with `--nosubtle 137` (chrome v137+) or `--nosubtle 2` (chrome+firefox)
2550
+
2521
2551
  * chrome is recommended (unfortunately), at least compared to firefox:
2522
2552
  * up to 90% faster when hashing, especially on SSDs
2523
2553
  * up to 40% faster when uploading over extremely fast internets
@@ -2725,6 +2755,7 @@ set any of the following environment variables to disable its associated optiona
2725
2755
  | `PRTY_NO_CFSSL` | never attempt to generate self-signed certificates using [cfssl](https://github.com/cloudflare/cfssl) |
2726
2756
  | `PRTY_NO_FFMPEG` | **audio transcoding** goes byebye, **thumbnailing** must be handled by Pillow/libvips |
2727
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 |
2728
2759
  | `PRTY_NO_MUTAGEN` | do not use [mutagen](https://pypi.org/project/mutagen/) for reading metadata from media files; will fallback to ffprobe |
2729
2760
  | `PRTY_NO_PIL` | disable all [Pillow](https://pypi.org/project/pillow/)-based thumbnail support; will fallback to libvips or ffmpeg |
2730
2761
  | `PRTY_NO_PILF` | disable Pillow `ImageFont` text rendering, used for folder thumbnails |
@@ -2825,5 +2856,7 @@ if there's a wall of base64 in the log (thread stacks) then please include that,
2825
2856
 
2826
2857
  for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
2827
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
+
2828
2861
  see [./docs/TODO.md](./docs/TODO.md) for planned features / fixes / changes
2829
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
 
@@ -1020,6 +1021,7 @@ def add_upload(ap):
1020
1021
  ap2.add_argument("--df", metavar="GiB", type=u, default="0", help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [\033[32m256m\033[0m], [\033[32m4\033[0m], [\033[32m2T\033[0m] (volflag=df)")
1021
1022
  ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files")
1022
1023
  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")
1024
+ ap2.add_argument("--nosubtle", metavar="N", type=int, default=0, help="when to use a wasm-hasher instead of the browser's builtin; faster on chrome, but buggy in older chrome versions. [\033[32m0\033[0m] = only when necessary (non-https), [\033[32m1\033[0m] = always (all browsers), [\033[32m2\033[0m] = always on chrome/firefox, [\033[32m3\033[0m] = always on chrome, [\033[32mN\033[0m] = chrome-version N and newer (recommendation: 137)")
1023
1025
  ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed")
1024
1026
  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]")
1025
1027
  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)")
@@ -1261,6 +1263,7 @@ def add_optouts(ap):
1261
1263
  ap2.add_argument("--no-tarcmp", action="store_true", help="disable download as compressed tar (?tar=gz, ?tar=bz2, ?tar=xz, ?tar=gz:9, ...)")
1262
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")
1263
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)")
1264
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)")
1265
1268
 
1266
1269
 
@@ -1390,6 +1393,16 @@ def add_transcoding(ap):
1390
1393
  ap2.add_argument("--ac-maxage", metavar="SEC", type=int, default=86400, help="delete cached transcode output after \033[33mSEC\033[0m seconds")
1391
1394
 
1392
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
+
1393
1406
  def add_rss(ap):
1394
1407
  ap2 = ap.add_argument_group('RSS options')
1395
1408
  ap2.add_argument("--rss", action="store_true", help="enable RSS output (experimental) (volflag=rss)")
@@ -1485,6 +1498,7 @@ def add_ui(ap, retry):
1485
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)")
1486
1499
  ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
1487
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")
1488
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)")
1489
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")
1490
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)")
@@ -1594,6 +1608,7 @@ def run_argparse(
1594
1608
  add_hooks(ap)
1595
1609
  add_stats(ap)
1596
1610
  add_txt(ap)
1611
+ add_tail(ap)
1597
1612
  add_og(ap)
1598
1613
  add_ui(ap, retry)
1599
1614
  add_admin(ap)
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 17, 1)
4
- CODENAME = "mixtape.m3u"
5
- BUILD_DT = (2025, 5, 18)
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):
@@ -350,7 +352,6 @@ class VFS(object):
350
352
  self.flags = flags # config options
351
353
  self.root = self
352
354
  self.dev = 0 # st_dev
353
- self.badcfg1 = False
354
355
  self.nodes = {} # child nodes
355
356
  self.histtab = {} # all realpath->histpath
356
357
  self.dbpaths = {} # all realpath->dbpath
@@ -870,6 +871,7 @@ class AuthSrv(object):
870
871
  self.warn_anonwrite = warn_anonwrite
871
872
  self.line_ctr = 0
872
873
  self.indent = ""
874
+ self.is_lxc = args.c == ["/z/initcfg"]
873
875
 
874
876
  # fwd-decl
875
877
  self.vfs = VFS(log_func, "", "", "", AXS(), {})
@@ -880,6 +882,8 @@ class AuthSrv(object):
880
882
  self.defpw = {}
881
883
  self.grps = {}
882
884
  self.re_pwd = None
885
+ self.cfg_files_loaded = []
886
+ self.badcfg1 = False
883
887
 
884
888
  # all volumes observed since last restart
885
889
  self.idp_vols = {} # vpath->abspath
@@ -956,15 +960,27 @@ class AuthSrv(object):
956
960
  un_gn = [("", "")]
957
961
 
958
962
  for un, gn in un_gn:
959
- m = PTN_U_GRP.search(dst0)
960
- if m:
961
- req, gnc = m.groups()
962
- hit = gnc in (un_gns.get(un) or [])
963
- if req == "+":
964
- if not hit:
965
- continue
966
- elif hit:
963
+ rejected = False
964
+ for ptn in [PTN_U_GRP, PTN_G_GRP]:
965
+ m = ptn.search(dst0)
966
+ if not m:
967
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
968
984
 
969
985
  # if ap/vp has a user/group placeholder, make sure to keep
970
986
  # track so the same user/group is mapped when setting perms;
@@ -979,6 +995,8 @@ class AuthSrv(object):
979
995
 
980
996
  src = src1.replace("${g}", gn or "\n")
981
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)
982
1000
  if src == src1 and dst == dst1:
983
1001
  gn = ""
984
1002
 
@@ -1475,8 +1493,10 @@ class AuthSrv(object):
1475
1493
  daxs = {}
1476
1494
  mflags = {} # vpath:flags
1477
1495
  mount = {} # dst:src (vp:(ap,vp0))
1496
+ cfg_files_loaded = []
1478
1497
 
1479
1498
  self.idp_vols = {} # yolo
1499
+ self.badcfg1 = False
1480
1500
 
1481
1501
  if self.args.a:
1482
1502
  # list of username:password
@@ -1537,6 +1557,7 @@ class AuthSrv(object):
1537
1557
  zst = [(max(0, len(x) - 2) * " ") + "└" + x[-1] for x in zstt]
1538
1558
  t = "loaded {} config files:\n{}"
1539
1559
  self.log(t.format(len(zst), "\n".join(zst)))
1560
+ cfg_files_loaded = zst
1540
1561
 
1541
1562
  except:
1542
1563
  lns = lns[: self.line_ctr]
@@ -1561,9 +1582,14 @@ class AuthSrv(object):
1561
1582
  if not mount and not self.args.idp_h_usr:
1562
1583
  # -h says our defaults are CWD at root and read/write for everyone
1563
1584
  axs = AXS(["*"], ["*"], None, None)
1564
- if os.path.exists("/z/initcfg"):
1565
- t = "Read-access has been disabled due to failsafe: Docker detected, but the config does not define any volumes. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw"
1566
- self.log(t, 1)
1585
+ if self.is_lxc:
1586
+ t = "Read-access has been disabled due to failsafe: Docker detected, but %s. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to all of /w/ by adding the following arguments to the docker container: -v .::rw"
1587
+ if len(cfg_files_loaded) == 1:
1588
+ self.log(t % ("no config-file was provided",), 1)
1589
+ t = "it is strongly recommended to add a config-file instead, for example based on https://github.com/9001/copyparty/blob/hovudstraum/docs/examples/docker/basic-docker-compose/copyparty.conf"
1590
+ self.log(t, 3)
1591
+ else:
1592
+ self.log(t % ("the config does not define any volumes",), 1)
1567
1593
  axs = AXS()
1568
1594
  elif self.args.c:
1569
1595
  t = "Read-access has been disabled due to failsafe: No volumes were defined by the config-file. This failsafe is to prevent unintended access if this is due to accidental loss of config. You can override this safeguard and allow read/write to the working-directory by adding the following arguments: -v .::rw"
@@ -1571,7 +1597,7 @@ class AuthSrv(object):
1571
1597
  axs = AXS()
1572
1598
  vfs = VFS(self.log_func, absreal("."), "", "", axs, {})
1573
1599
  if not axs.uread:
1574
- vfs.badcfg1 = True
1600
+ self.badcfg1 = True
1575
1601
  elif "" not in mount:
1576
1602
  # there's volumes but no root; make root inaccessible
1577
1603
  zsd = {"d2d": True, "tcolor": self.args.tcolor}
@@ -1845,7 +1871,7 @@ class AuthSrv(object):
1845
1871
  is_shr = shr and zv.vpath.split("/")[0] == shr
1846
1872
  if histp and not is_shr and histp in rhisttab:
1847
1873
  zv2 = rhisttab[histp]
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]"
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]"
1849
1875
  t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
1850
1876
  self.log(t, 1)
1851
1877
  raise Exception(t)
@@ -1859,7 +1885,7 @@ class AuthSrv(object):
1859
1885
  is_shr = shr and zv.vpath.split("/")[0] == shr
1860
1886
  if dbp and not is_shr and dbp in rdbpaths:
1861
1887
  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]"
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]"
1863
1889
  t = t % (dbp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
1864
1890
  self.log(t, 1)
1865
1891
  raise Exception(t)
@@ -2042,12 +2068,13 @@ class AuthSrv(object):
2042
2068
  if vf not in vol.flags:
2043
2069
  vol.flags[vf] = getattr(self.args, ga)
2044
2070
 
2045
- zs = "forget_ip nrand u2abort u2ow ups_who zip_who"
2071
+ zs = "forget_ip nrand tail_who u2abort u2ow ups_who zip_who"
2046
2072
  for k in zs.split():
2047
2073
  if k in vol.flags:
2048
2074
  vol.flags[k] = int(vol.flags[k])
2049
2075
 
2050
- for k in ("convt",):
2076
+ zs = "convt tail_fd tail_rate tail_tmax"
2077
+ for k in zs.split():
2051
2078
  if k in vol.flags:
2052
2079
  vol.flags[k] = float(vol.flags[k])
2053
2080
 
@@ -2376,7 +2403,7 @@ class AuthSrv(object):
2376
2403
  idp_vn, _ = vfs.get(idp_vp, "*", False, False)
2377
2404
  idp_vp0 = idp_vn.vpath0
2378
2405
 
2379
- sigils = set(re.findall(r"(\${[ug][}%])", idp_vp0))
2406
+ sigils = set(PTN_SIGIL.findall(idp_vp0))
2380
2407
  if len(sigils) > 1:
2381
2408
  t = '\nWARNING: IdP-volume "/%s" created by "/%s" has multiple IdP placeholders: %s'
2382
2409
  self.idp_warn.append(t % (idp_vp, idp_vp0, list(sigils)))
@@ -2426,6 +2453,7 @@ class AuthSrv(object):
2426
2453
  self.defpw = defpw
2427
2454
  self.grps = grps
2428
2455
  self.iacct = {v: k for k, v in acct.items()}
2456
+ self.cfg_files_loaded = cfg_files_loaded
2429
2457
 
2430
2458
  self.load_sessions()
2431
2459
 
@@ -2545,6 +2573,7 @@ class AuthSrv(object):
2545
2573
  "txt_ext": self.args.textfiles.replace(",", " "),
2546
2574
  "def_hcols": list(vf.get("mth") or []),
2547
2575
  "unlist0": vf.get("unlist") or "",
2576
+ "see_dots": self.args.see_dots,
2548
2577
  "dgrid": "grid" in vf,
2549
2578
  "dgsel": "gsel" in vf,
2550
2579
  "dnsort": "nsort" in vf,
@@ -2556,6 +2585,7 @@ class AuthSrv(object):
2556
2585
  "idxh": int(self.args.ih),
2557
2586
  "themes": self.args.themes,
2558
2587
  "turbolvl": self.args.turbo,
2588
+ "nosubtle": self.args.nosubtle,
2559
2589
  "u2j": self.args.u2j,
2560
2590
  "u2sz": self.args.u2sz,
2561
2591
  "u2ts": vf["u2ts"],
@@ -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",