copyparty 1.13.0__tar.gz → 1.13.2__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 (121) hide show
  1. {copyparty-1.13.0 → copyparty-1.13.2}/PKG-INFO +55 -8
  2. {copyparty-1.13.0 → copyparty-1.13.2}/README.md +54 -7
  3. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/__main__.py +55 -5
  4. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/__version__.py +2 -2
  5. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/authsrv.py +23 -2
  6. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/broker_mp.py +2 -5
  7. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/cfg.py +16 -2
  8. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/fsutil.py +25 -5
  9. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/httpcli.py +262 -20
  10. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/httpsrv.py +1 -4
  11. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/metrics.py +1 -1
  12. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/mtag.py +72 -3
  13. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/smbd.py +1 -1
  14. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/svchub.py +14 -3
  15. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/tcpsrv.py +6 -0
  16. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/th_cli.py +5 -0
  17. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/th_srv.py +32 -5
  18. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/u2idx.py +18 -3
  19. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/up2k.py +27 -9
  20. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/util.py +41 -6
  21. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/a/u2c.py +14 -5
  22. copyparty-1.13.2/copyparty/web/baguettebox.js.gz +0 -0
  23. copyparty-1.13.2/copyparty/web/browser.css.gz +0 -0
  24. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/browser.html +1 -1
  25. copyparty-1.13.2/copyparty/web/browser.js.gz +0 -0
  26. copyparty-1.13.2/copyparty/web/deps/marked.js.gz +0 -0
  27. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/md.html +1 -1
  28. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/mde.html +1 -1
  29. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/msg.html +1 -1
  30. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/splash.html +2 -1
  31. copyparty-1.13.2/copyparty/web/splash.js.gz +0 -0
  32. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/svcs.html +1 -1
  33. copyparty-1.13.2/copyparty/web/util.js.gz +0 -0
  34. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/PKG-INFO +55 -8
  35. copyparty-1.13.0/copyparty/web/baguettebox.js.gz +0 -0
  36. copyparty-1.13.0/copyparty/web/browser.css.gz +0 -0
  37. copyparty-1.13.0/copyparty/web/browser.js.gz +0 -0
  38. copyparty-1.13.0/copyparty/web/deps/marked.js.gz +0 -0
  39. copyparty-1.13.0/copyparty/web/splash.js.gz +0 -0
  40. copyparty-1.13.0/copyparty/web/util.js.gz +0 -0
  41. {copyparty-1.13.0 → copyparty-1.13.2}/LICENSE +0 -0
  42. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/__init__.py +0 -0
  43. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/bos/__init__.py +0 -0
  44. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/bos/bos.py +0 -0
  45. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/bos/path.py +0 -0
  46. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/broker_mpw.py +0 -0
  47. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/broker_thr.py +0 -0
  48. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/broker_util.py +0 -0
  49. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/cert.py +0 -0
  50. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/dxml.py +0 -0
  51. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/ftpd.py +0 -0
  52. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/httpconn.py +0 -0
  53. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/ico.py +0 -0
  54. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/mdns.py +0 -0
  55. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/multicast.py +0 -0
  56. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/pwhash.py +0 -0
  57. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/res/COPYING.txt +0 -0
  58. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/res/__init__.py +0 -0
  59. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/res/insecure.pem +0 -0
  60. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/ssdp.py +0 -0
  61. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/star.py +0 -0
  62. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/__init__.py +0 -0
  63. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/__init__.py +0 -0
  64. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/bimap.py +0 -0
  65. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/bit.py +0 -0
  66. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/buffer.py +0 -0
  67. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/dns.py +0 -0
  68. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/label.py +0 -0
  69. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/lex.py +0 -0
  70. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/dnslib/ranges.py +0 -0
  71. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/ifaddr/__init__.py +0 -0
  72. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/ifaddr/_posix.py +0 -0
  73. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/ifaddr/_shared.py +0 -0
  74. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/ifaddr/_win32.py +0 -0
  75. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/qrcodegen.py +0 -0
  76. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/stolen/surrogateescape.py +0 -0
  77. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/sutil.py +0 -0
  78. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/szip.py +0 -0
  79. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/tftpd.py +0 -0
  80. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/a/__init__.py +0 -0
  81. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/a/partyfuse.py +0 -0
  82. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/a/webdav-cfg.bat +0 -0
  83. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/browser2.html +0 -0
  84. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/cf.html +0 -0
  85. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dbg-audio.js.gz +0 -0
  86. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dd/2.png +0 -0
  87. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dd/3.png +0 -0
  88. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dd/4.png +0 -0
  89. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dd/5.png +0 -0
  90. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/dd/__init__.py +0 -0
  91. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/__init__.py +0 -0
  92. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/busy.mp3.gz +0 -0
  93. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/easymde.css.gz +0 -0
  94. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/easymde.js.gz +0 -0
  95. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/mini-fa.css.gz +0 -0
  96. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/mini-fa.woff +0 -0
  97. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/prism.css.gz +0 -0
  98. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/prism.js.gz +0 -0
  99. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/prismd.css.gz +0 -0
  100. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/scp.woff2 +0 -0
  101. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  102. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  103. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/md.css.gz +0 -0
  104. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/md.js.gz +0 -0
  105. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/md2.css.gz +0 -0
  106. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/md2.js.gz +0 -0
  107. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/mde.css.gz +0 -0
  108. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/mde.js.gz +0 -0
  109. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/msg.css.gz +0 -0
  110. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/splash.css.gz +0 -0
  111. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/svcs.js.gz +0 -0
  112. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/ui.css.gz +0 -0
  113. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/up2k.js.gz +0 -0
  114. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty/web/w.hash.js.gz +0 -0
  115. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/SOURCES.txt +0 -0
  116. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/dependency_links.txt +0 -0
  117. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/entry_points.txt +0 -0
  118. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/requires.txt +0 -0
  119. {copyparty-1.13.0 → copyparty-1.13.2}/copyparty.egg-info/top_level.txt +0 -0
  120. {copyparty-1.13.0 → copyparty-1.13.2}/pyproject.toml +0 -0
  121. {copyparty-1.13.0 → copyparty-1.13.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.13.0
3
+ Version: 1.13.2
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
@@ -101,6 +101,7 @@ turn almost any device into a file server with resumable uploads/downloads using
101
101
  * [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
102
102
  * [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
103
103
  * [markdown viewer](#markdown-viewer) - and there are *two* editors
104
+ * [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
104
105
  * [other tricks](#other-tricks)
105
106
  * [searching](#searching) - search by size, date, path/name, mp3-tags, ...
106
107
  * [server config](#server-config) - using arguments or config files, or a mix of both
@@ -114,6 +115,7 @@ turn almost any device into a file server with resumable uploads/downloads using
114
115
  * [tftp server](#tftp-server) - a TFTP server (read/write) can be started using `--tftp 3969`
115
116
  * [smb server](#smb-server) - unsafe, slow, not recommended for wan
116
117
  * [browser ux](#browser-ux) - tweaking the ui
118
+ * [opengraph](#opengraph) - discord and social-media embeds
117
119
  * [file indexing](#file-indexing) - enables dedup and music search ++
118
120
  * [exclude-patterns](#exclude-patterns) - to save some time
119
121
  * [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
@@ -162,8 +164,9 @@ turn almost any device into a file server with resumable uploads/downloads using
162
164
  * [dependencies](#dependencies) - mandatory deps
163
165
  * [optional dependencies](#optional-dependencies) - install these to enable bonus features
164
166
  * [optional gpl stuff](#optional-gpl-stuff)
165
- * [sfx](#sfx) - the self-contained "binary"
167
+ * [sfx](#sfx) - the self-contained "binary" (recommended!)
166
168
  * [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
169
+ * [zipapp](#zipapp) - another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz)
167
170
  * [install on android](#install-on-android)
168
171
  * [reporting bugs](#reporting-bugs) - ideas for context to include, and where to submit them
169
172
  * [devnotes](#devnotes) - for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
@@ -177,6 +180,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
177
180
  * or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
178
181
  * or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
179
182
  * or if you are on android, [install copyparty in termux](#install-on-android)
183
+ * or if your computer is messed up and nothing else works, [try the pyz](#zipapp)
180
184
  * or if you prefer to [use docker](./scripts/docker/) 🐋 you can do that too
181
185
  * docker has all deps built-in, so skip this step:
182
186
 
@@ -280,6 +284,7 @@ also see [comparison to similar software](./docs/versus.md)
280
284
  * ☑ ...of videos using FFmpeg
281
285
  * ☑ ...of audio (spectrograms) using FFmpeg
282
286
  * ☑ cache eviction (max-age; maybe max-size eventually)
287
+ * ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
283
288
  * ☑ SPA (browse while uploading)
284
289
  * server indexing
285
290
  * ☑ [locate files by contents](#file-search)
@@ -288,9 +293,11 @@ also see [comparison to similar software](./docs/versus.md)
288
293
  * client support
289
294
  * ☑ [folder sync](#folder-sync)
290
295
  * ☑ [curl-friendly](https://user-images.githubusercontent.com/241032/215322619-ea5fd606-3654-40ad-94ee-2bc058647bb2.png)
296
+ * ☑ [opengraph](#opengraph) (discord embeds)
291
297
  * markdown
292
298
  * ☑ [viewer](#markdown-viewer)
293
299
  * ☑ editor (sure why not)
300
+ * ☑ [variables](#markdown-vars)
294
301
 
295
302
  PS: something missing? post any crazy ideas you've got as a [feature request](https://github.com/9001/copyparty/issues/new?assignees=9001&labels=enhancement&template=feature_request.md) or [discussion](https://github.com/9001/copyparty/discussions/new?category=ideas) 🤙
296
303
 
@@ -460,7 +467,7 @@ configuring accounts/volumes with arguments:
460
467
  `-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
461
468
 
462
469
  permissions:
463
- * `r` (read): browse folder contents, download files, download as zip/tar
470
+ * `r` (read): browse folder contents, download files, download as zip/tar, see filekeys/dirkeys
464
471
  * `w` (write): upload files, move files *into* this folder
465
472
  * `m` (move): move files/folders *from* this folder
466
473
  * `d` (delete): delete files/folders
@@ -662,15 +669,21 @@ you can also zip a selection of files or folders by clicking them in the browser
662
669
 
663
670
  cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
664
671
  * super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
665
- * and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
672
+ * and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
666
673
  * can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
667
674
 
668
675
 
669
676
  ## uploading
670
677
 
671
- drag files/folders into the web-browser to upload (or use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy))
678
+ drag files/folders into the web-browser to upload
672
679
 
673
- this initiates an upload using `up2k`; there are two uploaders available:
680
+ dragdrop is the recommended way, but you may also:
681
+
682
+ * select some files (not folders) in your file explorer and press CTRL-V inside the browser window
683
+ * use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy)
684
+ * upload using [curl or sharex](#client-examples)
685
+
686
+ when uploading files through dragdrop or CTRL-V, this initiates an upload using `up2k`; there are two browser-based uploaders available:
674
687
  * `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
675
688
  * `[🚀] up2k`, the good / fancy one
676
689
 
@@ -897,6 +910,13 @@ other notes,
897
910
  * the document preview has a max-width which is the same as an A4 paper when printed
898
911
 
899
912
 
913
+ ### markdown vars
914
+
915
+ dynamic docs with serverside variable expansion to replace stuff like `{{self.ip}}` with the client's IP, or `{{srv.htime}}` with the current time on the server
916
+
917
+ see [./srv/expand/](./srv/expand/) for usage and examples
918
+
919
+
900
920
  ## other tricks
901
921
 
902
922
  * you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&t=1:20` after the `.../#af-c8960dab`
@@ -945,6 +965,8 @@ using arguments or config files, or a mix of both:
945
965
 
946
966
  **NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
947
967
  * if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
968
+ * or see this (probably outdated): https://ocv.me/copyparty/helptext.html
969
+ * or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
948
970
 
949
971
 
950
972
  ## zeroconf
@@ -1121,7 +1143,22 @@ tweaking the ui
1121
1143
  * to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
1122
1144
  * 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`
1123
1145
 
1124
- see [./docs/rice](./docs/rice) for more
1146
+ see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
1147
+
1148
+
1149
+ ## opengraph
1150
+
1151
+ discord and social-media embeds
1152
+
1153
+ can be enabled globally with `--og` or per-volume with volflag `og`
1154
+
1155
+ note that this disables hotlinking because the opengraph spec demands it; to sneak past this intentional limitation, you can enable opengraph selectively by user-agent, for example `--og-ua '(Discord|Twitter|Slack)bot'` (or volflag `og_ua`)
1156
+
1157
+ you can also hotlink files regardless by appending `?raw` to the url
1158
+
1159
+ NOTE: because discord (and maybe others) strip query args such as `?raw` in opengraph tags, any links which require a filekey or dirkey will not work
1160
+
1161
+ if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
1125
1162
 
1126
1163
 
1127
1164
  ## file indexing
@@ -2035,7 +2072,7 @@ these are standalone programs and will never be imported / evaluated by copypart
2035
2072
 
2036
2073
  # sfx
2037
2074
 
2038
- the self-contained "binary" [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
2075
+ the self-contained "binary" (recommended!) [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
2039
2076
 
2040
2077
  you can reduce the sfx size by repacking it; see [./docs/devnotes.md#sfx-repack](./docs/devnotes.md#sfx-repack)
2041
2078
 
@@ -2062,6 +2099,16 @@ meanwhile [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/d
2062
2099
  then again, if you are already into downloading shady binaries from the internet, you may also want my [minimal builds](./scripts/pyinstaller#ffmpeg) of [ffmpeg](https://ocv.me/stuff/bin/ffmpeg.exe) and [ffprobe](https://ocv.me/stuff/bin/ffprobe.exe) which enables copyparty to extract multimedia-info, do audio-transcoding, and thumbnails/spectrograms/waveforms, however it's much better to instead grab a [recent official build](https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z) every once ina while if you can afford the size
2063
2100
 
2064
2101
 
2102
+ ## zipapp
2103
+
2104
+ another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz) has less features, requires python 3.7 or newer, worse compression, and more importantly is unable to benefit from more recent versions of jinja2 and such (which makes it less secure)... lots of drawbacks with this one really -- but it *may* just work if the regular sfx fails to start because the computer is messed up in certain funky ways, so it's worth a shot if all else fails
2105
+
2106
+ run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails
2107
+
2108
+ it is a python [zipapp](https://docs.python.org/3/library/zipapp.html) meaning it doesn't have to unpack its own python code anywhere to run, so if the filesystem is busted it has a better chance of getting somewhere
2109
+ * but note that it currently still needs to extract the web-resources somewhere (they'll land in the default TEMP-folder of your OS)
2110
+
2111
+
2065
2112
  # install on android
2066
2113
 
2067
2114
  install [Termux](https://termux.com/) + its companion app `Termux:API` (see [ocv.me/termux](https://ocv.me/termux/)) and then copy-paste this into Termux (long-tap) all at once:
@@ -47,6 +47,7 @@ turn almost any device into a file server with resumable uploads/downloads using
47
47
  * [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
48
48
  * [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
49
49
  * [markdown viewer](#markdown-viewer) - and there are *two* editors
50
+ * [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
50
51
  * [other tricks](#other-tricks)
51
52
  * [searching](#searching) - search by size, date, path/name, mp3-tags, ...
52
53
  * [server config](#server-config) - using arguments or config files, or a mix of both
@@ -60,6 +61,7 @@ turn almost any device into a file server with resumable uploads/downloads using
60
61
  * [tftp server](#tftp-server) - a TFTP server (read/write) can be started using `--tftp 3969`
61
62
  * [smb server](#smb-server) - unsafe, slow, not recommended for wan
62
63
  * [browser ux](#browser-ux) - tweaking the ui
64
+ * [opengraph](#opengraph) - discord and social-media embeds
63
65
  * [file indexing](#file-indexing) - enables dedup and music search ++
64
66
  * [exclude-patterns](#exclude-patterns) - to save some time
65
67
  * [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
@@ -108,8 +110,9 @@ turn almost any device into a file server with resumable uploads/downloads using
108
110
  * [dependencies](#dependencies) - mandatory deps
109
111
  * [optional dependencies](#optional-dependencies) - install these to enable bonus features
110
112
  * [optional gpl stuff](#optional-gpl-stuff)
111
- * [sfx](#sfx) - the self-contained "binary"
113
+ * [sfx](#sfx) - the self-contained "binary" (recommended!)
112
114
  * [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
115
+ * [zipapp](#zipapp) - another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz)
113
116
  * [install on android](#install-on-android)
114
117
  * [reporting bugs](#reporting-bugs) - ideas for context to include, and where to submit them
115
118
  * [devnotes](#devnotes) - for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
@@ -123,6 +126,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
123
126
  * or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
124
127
  * or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
125
128
  * or if you are on android, [install copyparty in termux](#install-on-android)
129
+ * or if your computer is messed up and nothing else works, [try the pyz](#zipapp)
126
130
  * or if you prefer to [use docker](./scripts/docker/) 🐋 you can do that too
127
131
  * docker has all deps built-in, so skip this step:
128
132
 
@@ -226,6 +230,7 @@ also see [comparison to similar software](./docs/versus.md)
226
230
  * ☑ ...of videos using FFmpeg
227
231
  * ☑ ...of audio (spectrograms) using FFmpeg
228
232
  * ☑ cache eviction (max-age; maybe max-size eventually)
233
+ * ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
229
234
  * ☑ SPA (browse while uploading)
230
235
  * server indexing
231
236
  * ☑ [locate files by contents](#file-search)
@@ -234,9 +239,11 @@ also see [comparison to similar software](./docs/versus.md)
234
239
  * client support
235
240
  * ☑ [folder sync](#folder-sync)
236
241
  * ☑ [curl-friendly](https://user-images.githubusercontent.com/241032/215322619-ea5fd606-3654-40ad-94ee-2bc058647bb2.png)
242
+ * ☑ [opengraph](#opengraph) (discord embeds)
237
243
  * markdown
238
244
  * ☑ [viewer](#markdown-viewer)
239
245
  * ☑ editor (sure why not)
246
+ * ☑ [variables](#markdown-vars)
240
247
 
241
248
  PS: something missing? post any crazy ideas you've got as a [feature request](https://github.com/9001/copyparty/issues/new?assignees=9001&labels=enhancement&template=feature_request.md) or [discussion](https://github.com/9001/copyparty/discussions/new?category=ideas) 🤙
242
249
 
@@ -406,7 +413,7 @@ configuring accounts/volumes with arguments:
406
413
  `-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
407
414
 
408
415
  permissions:
409
- * `r` (read): browse folder contents, download files, download as zip/tar
416
+ * `r` (read): browse folder contents, download files, download as zip/tar, see filekeys/dirkeys
410
417
  * `w` (write): upload files, move files *into* this folder
411
418
  * `m` (move): move files/folders *from* this folder
412
419
  * `d` (delete): delete files/folders
@@ -608,15 +615,21 @@ you can also zip a selection of files or folders by clicking them in the browser
608
615
 
609
616
  cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
610
617
  * super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
611
- * and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
618
+ * and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
612
619
  * can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
613
620
 
614
621
 
615
622
  ## uploading
616
623
 
617
- drag files/folders into the web-browser to upload (or use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy))
624
+ drag files/folders into the web-browser to upload
618
625
 
619
- this initiates an upload using `up2k`; there are two uploaders available:
626
+ dragdrop is the recommended way, but you may also:
627
+
628
+ * select some files (not folders) in your file explorer and press CTRL-V inside the browser window
629
+ * use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy)
630
+ * upload using [curl or sharex](#client-examples)
631
+
632
+ when uploading files through dragdrop or CTRL-V, this initiates an upload using `up2k`; there are two browser-based uploaders available:
620
633
  * `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
621
634
  * `[🚀] up2k`, the good / fancy one
622
635
 
@@ -843,6 +856,13 @@ other notes,
843
856
  * the document preview has a max-width which is the same as an A4 paper when printed
844
857
 
845
858
 
859
+ ### markdown vars
860
+
861
+ dynamic docs with serverside variable expansion to replace stuff like `{{self.ip}}` with the client's IP, or `{{srv.htime}}` with the current time on the server
862
+
863
+ see [./srv/expand/](./srv/expand/) for usage and examples
864
+
865
+
846
866
  ## other tricks
847
867
 
848
868
  * you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&t=1:20` after the `.../#af-c8960dab`
@@ -891,6 +911,8 @@ using arguments or config files, or a mix of both:
891
911
 
892
912
  **NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
893
913
  * if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
914
+ * or see this (probably outdated): https://ocv.me/copyparty/helptext.html
915
+ * or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
894
916
 
895
917
 
896
918
  ## zeroconf
@@ -1067,7 +1089,22 @@ tweaking the ui
1067
1089
  * to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
1068
1090
  * 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`
1069
1091
 
1070
- see [./docs/rice](./docs/rice) for more
1092
+ see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
1093
+
1094
+
1095
+ ## opengraph
1096
+
1097
+ discord and social-media embeds
1098
+
1099
+ can be enabled globally with `--og` or per-volume with volflag `og`
1100
+
1101
+ note that this disables hotlinking because the opengraph spec demands it; to sneak past this intentional limitation, you can enable opengraph selectively by user-agent, for example `--og-ua '(Discord|Twitter|Slack)bot'` (or volflag `og_ua`)
1102
+
1103
+ you can also hotlink files regardless by appending `?raw` to the url
1104
+
1105
+ NOTE: because discord (and maybe others) strip query args such as `?raw` in opengraph tags, any links which require a filekey or dirkey will not work
1106
+
1107
+ if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
1071
1108
 
1072
1109
 
1073
1110
  ## file indexing
@@ -1981,7 +2018,7 @@ these are standalone programs and will never be imported / evaluated by copypart
1981
2018
 
1982
2019
  # sfx
1983
2020
 
1984
- the self-contained "binary" [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
2021
+ the self-contained "binary" (recommended!) [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
1985
2022
 
1986
2023
  you can reduce the sfx size by repacking it; see [./docs/devnotes.md#sfx-repack](./docs/devnotes.md#sfx-repack)
1987
2024
 
@@ -2008,6 +2045,16 @@ meanwhile [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/d
2008
2045
  then again, if you are already into downloading shady binaries from the internet, you may also want my [minimal builds](./scripts/pyinstaller#ffmpeg) of [ffmpeg](https://ocv.me/stuff/bin/ffmpeg.exe) and [ffprobe](https://ocv.me/stuff/bin/ffprobe.exe) which enables copyparty to extract multimedia-info, do audio-transcoding, and thumbnails/spectrograms/waveforms, however it's much better to instead grab a [recent official build](https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z) every once ina while if you can afford the size
2009
2046
 
2010
2047
 
2048
+ ## zipapp
2049
+
2050
+ another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz) has less features, requires python 3.7 or newer, worse compression, and more importantly is unable to benefit from more recent versions of jinja2 and such (which makes it less secure)... lots of drawbacks with this one really -- but it *may* just work if the regular sfx fails to start because the computer is messed up in certain funky ways, so it's worth a shot if all else fails
2051
+
2052
+ run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails
2053
+
2054
+ it is a python [zipapp](https://docs.python.org/3/library/zipapp.html) meaning it doesn't have to unpack its own python code anywhere to run, so if the filesystem is busted it has a better chance of getting somewhere
2055
+ * but note that it currently still needs to extract the web-resources somewhere (they'll land in the default TEMP-folder of your OS)
2056
+
2057
+
2011
2058
  # install on android
2012
2059
 
2013
2060
  install [Termux](https://termux.com/) + its companion app `Termux:API` (see [ocv.me/termux](https://ocv.me/termux/)) and then copy-paste this into Termux (long-tap) all at once:
@@ -43,11 +43,13 @@ from .util import (
43
43
  DEF_MTH,
44
44
  IMPLICATIONS,
45
45
  JINJA_VER,
46
+ MIMES,
46
47
  PARTFTPY_VER,
47
48
  PY_DESC,
48
49
  PYFTPD_VER,
49
50
  SQLITE_VER,
50
51
  UNPLICATIONS,
52
+ Daemon,
51
53
  align_tab,
52
54
  ansi_re,
53
55
  dedent,
@@ -464,6 +466,16 @@ def disable_quickedit() :
464
466
  cmode(True, mode | 4)
465
467
 
466
468
 
469
+ def sfx_tpoke(top ):
470
+ files = [os.path.join(dp, p) for dp, dd, df in os.walk(top) for p in dd + df]
471
+ while True:
472
+ t = int(time.time())
473
+ for f in [top] + files:
474
+ os.utime(f, (t, t))
475
+
476
+ time.sleep(78123)
477
+
478
+
467
479
  def showlic() :
468
480
  p = os.path.join(E.mod, "res", "COPYING.txt")
469
481
  if not os.path.exists(p):
@@ -814,7 +826,7 @@ def build_flags_desc():
814
826
  v = v.replace("\n", "\n ")
815
827
  ret += "\n \033[36m{}\033[35m {}".format(k, v)
816
828
 
817
- return ret + "\033[0m"
829
+ return ret
818
830
 
819
831
 
820
832
  # fmt: off
@@ -832,6 +844,8 @@ def add_general(ap, nc, srvname):
832
844
  ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
833
845
  ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
834
846
  ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
847
+ 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]")
848
+ ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
835
849
  ap2.add_argument("--license", action="store_true", help="show licenses and exit")
836
850
  ap2.add_argument("--version", action="store_true", help="show versions and exit")
837
851
 
@@ -854,6 +868,7 @@ def add_fs(ap):
854
868
  ap2.add_argument("--rm-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be deleted because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=rm_retry)")
855
869
  ap2.add_argument("--mv-retry", metavar="T/R", type=u, default=rm_re_def, help="if a file cannot be renamed because it is busy, continue trying for \033[33mT\033[0m seconds, retry every \033[33mR\033[0m seconds; disable with 0/0 (volflag=mv_retry)")
856
870
  ap2.add_argument("--iobuf", metavar="BYTES", type=int, default=256*1024, help="file I/O buffer-size; if your volumes are on a network drive, try increasing to \033[32m524288\033[0m or even \033[32m4194304\033[0m (and let me know if that improves your performance)")
871
+ ap2.add_argument("--mtab-age", metavar="SEC", type=int, default=60, help="rebuild mountpoint cache every \033[33mSEC\033[0m to keep track of sparse-files support; keep low on servers with removable media")
857
872
 
858
873
 
859
874
  def add_upload(ap):
@@ -1187,7 +1202,8 @@ def add_thumbnail(ap):
1187
1202
  ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
1188
1203
  ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
1189
1204
  ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
1190
- ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,m4a,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,tak,tta,ulaw,wav,wma,wv,xm,xpk", help="audio formats to decode using ffmpeg")
1205
+ ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
1206
+ ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg")
1191
1207
 
1192
1208
 
1193
1209
  def add_transcoding(ap):
@@ -1250,19 +1266,38 @@ def add_txt(ap):
1250
1266
  ap2.add_argument("--exp-lg", metavar="V,V,V", type=u, default=DEF_EXP, help="comma/space-separated list of placeholders to expand in prologue/epilogue files (volflag=exp_lg)")
1251
1267
 
1252
1268
 
1269
+ def add_og(ap):
1270
+ ap2 = ap.add_argument_group('og / open graph / discord-embed options')
1271
+ ap2.add_argument("--og", action="store_true", help="disable hotlinking and return an html document instead; this is required by open-graph, but can also be useful on its own (volflag=og)")
1272
+ ap2.add_argument("--og-ua", metavar="RE", type=u, default="", help="only disable hotlinking / engage OG behavior if the useragent matches regex \033[33mRE\033[0m (volflag=og_ua)")
1273
+ ap2.add_argument("--og-tpl", metavar="PATH", type=u, default="", help="do not return the regular copyparty html, but instead load the jinja2 template at \033[33mPATH\033[0m (if path contains 'EXT' then EXT will be replaced with the requested file's extension) (volflag=og_tpl)")
1274
+ ap2.add_argument("--og-no-head", action="store_true", help="do not automatically add OG entries into <head> (useful if you're doing this yourself in a template or such) (volflag=og_no_head)")
1275
+ ap2.add_argument("--og-th", metavar="FMT", type=u, default="jf3", help="thumbnail format; j=jpeg, jf=jpeg-uncropped, jf3=jpeg-uncropped-large, w=webm, ... (volflag=og_th)")
1276
+ ap2.add_argument("--og-title", metavar="TXT", type=u, default="", help="fallback title if there is nothing in the \033[33m-e2t\033[0m database (volflag=og_title)")
1277
+ ap2.add_argument("--og-title-a", metavar="T", type=u, default="🎵 {{ artist }} - {{ title }}", help="audio title format; takes any metadata key (volflag=og_title_a)")
1278
+ ap2.add_argument("--og-title-v", metavar="T", type=u, default="{{ title }}", help="video title format; takes any metadata key (volflag=og_title_v)")
1279
+ ap2.add_argument("--og-title-i", metavar="T", type=u, default="{{ title }}", help="image title format; takes any metadata key (volflag=og_title_i)")
1280
+ ap2.add_argument("--og-s-title", action="store_true", help="force default title; do not read from tags (volflag=og_s_title)")
1281
+ ap2.add_argument("--og-desc", metavar="TXT", type=u, default="", help="description text; same for all files, disable with [\033[32m-\033[0m] (volflag=og_desc)")
1282
+ ap2.add_argument("--og-site", metavar="TXT", type=u, default="", help="sitename; defaults to \033[33m--name\033[0m, disable with [\033[32m-\033[0m] (volflag=og_site)")
1283
+ ap2.add_argument("--tcolor", metavar="RGB", type=u, default="333", help="accent color (3 or 6 hex digits); may also affect safari and/or android-chrome (volflag=tcolor)")
1284
+ ap2.add_argument("--uqe", action="store_true", help="query-string parceling; translate a request for \033[33m/foo/.uqe/BASE64\033[0m into \033[33m/foo?TEXT\033[0m, or \033[33m/foo/?TEXT\033[0m if the first character in \033[33mTEXT\033[0m is a slash. Automatically enabled for \033[33m--og\033[0m")
1285
+
1286
+
1253
1287
  def add_ui(ap, retry):
1254
1288
  ap2 = ap.add_argument_group('ui options')
1255
1289
  ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)")
1256
1290
  ap2.add_argument("--lang", metavar="LANG", type=u, default="eng", help="language; one of the following: \033[32meng nor\033[0m")
1257
1291
  ap2.add_argument("--theme", metavar="NUM", type=int, default=0, help="default theme to use (0..7)")
1258
1292
  ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
1293
+ ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")
1259
1294
  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)")
1260
1295
  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)")
1261
1296
  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")
1262
1297
  ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
1263
1298
  ap2.add_argument("--js-browser", metavar="L", type=u, help="URL to additional JS to include")
1264
1299
  ap2.add_argument("--css-browser", metavar="L", type=u, help="URL to additional CSS to include")
1265
- ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages")
1300
+ ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages; can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)")
1266
1301
  ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI, or add ?v to URL for override)")
1267
1302
  ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
1268
1303
  ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")
@@ -1350,6 +1385,7 @@ def run_argparse(
1350
1385
  add_hooks(ap)
1351
1386
  add_stats(ap)
1352
1387
  add_txt(ap)
1388
+ add_og(ap)
1353
1389
  add_ui(ap, retry)
1354
1390
  add_admin(ap)
1355
1391
  add_logging(ap)
@@ -1378,18 +1414,22 @@ def run_argparse(
1378
1414
  k2 = "help_" + k.replace("-", "_")
1379
1415
  if vars(ret)[k2]:
1380
1416
  lprint("# %s help page (%s)" % (k, h))
1381
- lprint(t + "\033[0m")
1417
+ lprint(t.rstrip() + "\033[0m")
1382
1418
  sys.exit(0)
1383
1419
 
1384
1420
  return ret
1385
1421
 
1386
1422
 
1387
- def main(argv = None) :
1423
+ def main(argv = None, rsrc = None) :
1388
1424
  time.strptime("19970815", "%Y%m%d") # python#7980
1389
1425
  if WINDOWS:
1390
1426
  os.system("rem") # enables colors
1391
1427
 
1392
1428
  init_E(E)
1429
+
1430
+ if rsrc: # pyz
1431
+ E.mod = rsrc
1432
+
1393
1433
  if argv is None:
1394
1434
  argv = sys.argv
1395
1435
 
@@ -1413,9 +1453,19 @@ def main(argv = None) :
1413
1453
  showlic()
1414
1454
  sys.exit(0)
1415
1455
 
1456
+ if "--mimes" in argv:
1457
+ print("\n".join("%8s %s" % (k, v) for k, v in sorted(MIMES.items())))
1458
+ sys.exit(0)
1459
+
1416
1460
  if EXE:
1417
1461
  print("pybin: {}\n".format(pybin), end="")
1418
1462
 
1463
+ for n, zs in enumerate(argv):
1464
+ if zs.startswith("--sfx-tpoke="):
1465
+ Daemon(sfx_tpoke, "sfx-tpoke", (zs.split("=", 1)[1],))
1466
+ argv.pop(n)
1467
+ break
1468
+
1419
1469
  ensure_locale()
1420
1470
 
1421
1471
  ensure_webdeps()
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 13, 0)
3
+ VERSION = (1, 13, 2)
4
4
  CODENAME = "race the beam"
5
- BUILD_DT = (2024, 4, 20)
5
+ BUILD_DT = (2024, 5, 10)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
@@ -17,7 +17,9 @@ from .bos import bos
17
17
  from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
18
18
  from .pwhash import PWHash
19
19
  from .util import (
20
+ EXTS,
20
21
  IMPLICATIONS,
22
+ MIMES,
21
23
  SQLITE_VER,
22
24
  UNPLICATIONS,
23
25
  UTC,
@@ -1435,6 +1437,7 @@ class AuthSrv(object):
1435
1437
  elif "" not in mount:
1436
1438
  # there's volumes but no root; make root inaccessible
1437
1439
  vfs = VFS(self.log_func, "", "", AXS(), {})
1440
+ vfs.flags["tcolor"] = self.args.tcolor
1438
1441
  vfs.flags["d2d"] = True
1439
1442
 
1440
1443
  maxdepth = 0
@@ -1720,7 +1723,11 @@ class AuthSrv(object):
1720
1723
  if self.args.e2d or "e2ds" in vol.flags:
1721
1724
  vol.flags["e2d"] = True
1722
1725
 
1723
- for ga, vf in [["no_hash", "nohash"], ["no_idx", "noidx"]]:
1726
+ for ga, vf in [
1727
+ ["no_hash", "nohash"],
1728
+ ["no_idx", "noidx"],
1729
+ ["og_ua", "og_ua"],
1730
+ ]:
1724
1731
  if vf in vol.flags:
1725
1732
  ptn = re.compile(vol.flags.pop(vf))
1726
1733
  else:
@@ -1766,6 +1773,13 @@ class AuthSrv(object):
1766
1773
  t = 'volume "/%s" has invalid %stry [%s]'
1767
1774
  raise Exception(t % (vol.vpath, k, vol.flags.get(k + "try")))
1768
1775
 
1776
+ if vol.flags.get("og"):
1777
+ self.args.uqe = True
1778
+
1779
+ zs = str(vol.flags.get("tcolor", "")).lstrip("#")
1780
+ if len(zs) == 3: # fc5 => ffcc55
1781
+ vol.flags["tcolor"] = "".join([x * 2 for x in zs])
1782
+
1769
1783
  for k1, k2 in IMPLICATIONS:
1770
1784
  if k1 in vol.flags:
1771
1785
  vol.flags[k2] = True
@@ -2046,6 +2060,13 @@ class AuthSrv(object):
2046
2060
 
2047
2061
  self.re_pwd = re.compile(zs)
2048
2062
 
2063
+ # to ensure it propagates into tcpsrv with mp on
2064
+ if self.args.mime:
2065
+ for zs in self.args.mime:
2066
+ ext, mime = zs.split("=", 1)
2067
+ MIMES[ext] = mime
2068
+ EXTS.update({v: k for k, v in MIMES.items()})
2069
+
2049
2070
  def setup_pwhash(self, acct ) :
2050
2071
  self.ah = PWHash(self.args)
2051
2072
  if not self.ah.on:
@@ -2403,7 +2424,7 @@ def expand_config_file(
2403
2424
  if not cnames:
2404
2425
  t = "warning: tried to read config-files from folder '%s' but it does not contain any "
2405
2426
  if names:
2406
- t += ".conf files; the following files were ignored: %s"
2427
+ t += ".conf files; the following files/subfolders were ignored: %s"
2407
2428
  t = t % (fp, ", ".join(names[:8]))
2408
2429
  else:
2409
2430
  t += "files at all"
@@ -53,11 +53,8 @@ class BrokerMp(object):
53
53
  def shutdown(self) :
54
54
  self.log("broker", "shutting down")
55
55
  for n, proc in enumerate(self.procs):
56
- thr = threading.Thread(
57
- target=proc.q_pend.put((0, "shutdown", [])),
58
- name="mp-shutdown-{}-{}".format(n, len(self.procs)),
59
- )
60
- thr.start()
56
+ name = "mp-shut-%d-%d" % (n, len(self.procs))
57
+ Daemon(proc.q_pend.put, name, ((0, "shutdown", []),))
61
58
 
62
59
  with self.mutex:
63
60
  procs = self.procs
@@ -39,6 +39,9 @@ def vf_bmap() :
39
39
  "magic",
40
40
  "no_sb_md",
41
41
  "no_sb_lg",
42
+ "og",
43
+ "og_no_head",
44
+ "og_s_title",
42
45
  "rand",
43
46
  "xdev",
44
47
  "xlink",
@@ -61,12 +64,23 @@ def vf_vmap() :
61
64
  }
62
65
  for k in (
63
66
  "dbd",
67
+ "html_head",
64
68
  "lg_sbf",
65
69
  "md_sbf",
66
70
  "nrand",
71
+ "og_desc",
72
+ "og_site",
73
+ "og_th",
74
+ "og_title",
75
+ "og_title_a",
76
+ "og_title_v",
77
+ "og_title_i",
78
+ "og_tpl",
79
+ "og_ua",
67
80
  "mv_retry",
68
81
  "rm_retry",
69
82
  "sort",
83
+ "tcolor",
70
84
  "unlist",
71
85
  "u2abort",
72
86
  "u2ts",
@@ -81,7 +95,6 @@ def vf_cmap() :
81
95
  for k in (
82
96
  "exp_lg",
83
97
  "exp_md",
84
- "html_head",
85
98
  "mte",
86
99
  "mth",
87
100
  "mtp",
@@ -177,6 +190,7 @@ flagcats = {
177
190
  "dvthumb": "disables video thumbnails",
178
191
  "dathumb": "disables audio thumbnails (spectrograms)",
179
192
  "dithumb": "disables image thumbnails",
193
+ "pngquant": "compress audio waveforms 33% better",
180
194
  "thsize": "thumbnail res; WxH",
181
195
  "crop": "center-cropping (y/n/fy/fn)",
182
196
  "th3x": "3x resolution (y/n/fy/fn)",
@@ -201,7 +215,7 @@ flagcats = {
201
215
  "grid": "show grid/thumbnails by default",
202
216
  "sort": "default sort order",
203
217
  "unlist": "dont list files matching REGEX",
204
- "html_head=TXT": "includes TXT in the <head>",
218
+ "html_head=TXT": "includes TXT in the <head>, or @PATH for file at PATH",
205
219
  "robots": "allows indexing by search engines (default)",
206
220
  "norobots": "kindly asks search engines to leave",
207
221
  "no_sb_md": "disable js sandbox for markdown files",