copyparty 1.13.2__tar.gz → 1.13.4__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 (122) hide show
  1. {copyparty-1.13.2 → copyparty-1.13.4}/PKG-INFO +39 -7
  2. {copyparty-1.13.2 → copyparty-1.13.4}/README.md +37 -5
  3. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/__main__.py +94 -43
  4. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/__version__.py +2 -2
  5. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/authsrv.py +75 -13
  6. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/cert.py +10 -6
  7. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/cfg.py +3 -0
  8. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/ftpd.py +44 -7
  9. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/httpcli.py +188 -64
  10. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/httpsrv.py +3 -3
  11. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/mdns.py +24 -3
  12. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/mtag.py +6 -1
  13. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/smbd.py +1 -1
  14. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/ssdp.py +23 -3
  15. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/star.py +4 -4
  16. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/sutil.py +12 -6
  17. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/svchub.py +4 -2
  18. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/szip.py +4 -4
  19. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/tcpsrv.py +4 -1
  20. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/tftpd.py +5 -10
  21. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/th_cli.py +1 -1
  22. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/th_srv.py +22 -11
  23. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/up2k.py +84 -16
  24. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/util.py +69 -22
  25. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/a/u2c.py +14 -6
  26. copyparty-1.13.4/copyparty/web/baguettebox.js.gz +0 -0
  27. copyparty-1.13.4/copyparty/web/browser.css.gz +0 -0
  28. copyparty-1.13.4/copyparty/web/browser.js.gz +0 -0
  29. copyparty-1.13.4/copyparty/web/deps/marked.js.gz +0 -0
  30. copyparty-1.13.4/copyparty/web/md2.js.gz +0 -0
  31. copyparty-1.13.4/copyparty/web/ui.css.gz +0 -0
  32. copyparty-1.13.4/copyparty/web/util.js.gz +0 -0
  33. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/PKG-INFO +39 -7
  34. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/requires.txt +1 -1
  35. {copyparty-1.13.2 → copyparty-1.13.4}/pyproject.toml +1 -1
  36. copyparty-1.13.2/copyparty/web/baguettebox.js.gz +0 -0
  37. copyparty-1.13.2/copyparty/web/browser.css.gz +0 -0
  38. copyparty-1.13.2/copyparty/web/browser.js.gz +0 -0
  39. copyparty-1.13.2/copyparty/web/deps/marked.js.gz +0 -0
  40. copyparty-1.13.2/copyparty/web/md2.js.gz +0 -0
  41. copyparty-1.13.2/copyparty/web/ui.css.gz +0 -0
  42. copyparty-1.13.2/copyparty/web/util.js.gz +0 -0
  43. {copyparty-1.13.2 → copyparty-1.13.4}/LICENSE +0 -0
  44. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/__init__.py +0 -0
  45. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/bos/__init__.py +0 -0
  46. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/bos/bos.py +0 -0
  47. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/bos/path.py +0 -0
  48. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/broker_mp.py +0 -0
  49. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/broker_mpw.py +0 -0
  50. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/broker_thr.py +0 -0
  51. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/broker_util.py +0 -0
  52. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/dxml.py +0 -0
  53. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/fsutil.py +0 -0
  54. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/httpconn.py +0 -0
  55. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/ico.py +0 -0
  56. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/metrics.py +0 -0
  57. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/multicast.py +0 -0
  58. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/pwhash.py +0 -0
  59. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/res/COPYING.txt +0 -0
  60. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/res/__init__.py +0 -0
  61. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/res/insecure.pem +0 -0
  62. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/__init__.py +0 -0
  63. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/__init__.py +0 -0
  64. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/bimap.py +0 -0
  65. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/bit.py +0 -0
  66. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/buffer.py +0 -0
  67. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/dns.py +0 -0
  68. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/label.py +0 -0
  69. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/lex.py +0 -0
  70. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/dnslib/ranges.py +0 -0
  71. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/ifaddr/__init__.py +0 -0
  72. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/ifaddr/_posix.py +0 -0
  73. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/ifaddr/_shared.py +0 -0
  74. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/ifaddr/_win32.py +0 -0
  75. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/qrcodegen.py +0 -0
  76. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/stolen/surrogateescape.py +0 -0
  77. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/u2idx.py +0 -0
  78. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/a/__init__.py +0 -0
  79. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/a/partyfuse.py +0 -0
  80. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/a/webdav-cfg.bat +0 -0
  81. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/browser.html +0 -0
  82. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/browser2.html +0 -0
  83. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/cf.html +0 -0
  84. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dbg-audio.js.gz +0 -0
  85. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dd/2.png +0 -0
  86. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dd/3.png +0 -0
  87. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dd/4.png +0 -0
  88. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dd/5.png +0 -0
  89. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/dd/__init__.py +0 -0
  90. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/__init__.py +0 -0
  91. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/busy.mp3.gz +0 -0
  92. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/easymde.css.gz +0 -0
  93. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/easymde.js.gz +0 -0
  94. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/mini-fa.css.gz +0 -0
  95. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/mini-fa.woff +0 -0
  96. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/prism.css.gz +0 -0
  97. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/prism.js.gz +0 -0
  98. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/prismd.css.gz +0 -0
  99. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/scp.woff2 +0 -0
  100. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  101. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  102. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/md.css.gz +0 -0
  103. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/md.html +0 -0
  104. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/md.js.gz +0 -0
  105. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/md2.css.gz +0 -0
  106. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/mde.css.gz +0 -0
  107. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/mde.html +0 -0
  108. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/mde.js.gz +0 -0
  109. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/msg.css.gz +0 -0
  110. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/msg.html +0 -0
  111. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/splash.css.gz +0 -0
  112. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/splash.html +0 -0
  113. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/splash.js.gz +0 -0
  114. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/svcs.html +0 -0
  115. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/svcs.js.gz +0 -0
  116. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/up2k.js.gz +0 -0
  117. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty/web/w.hash.js.gz +0 -0
  118. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/SOURCES.txt +0 -0
  119. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/dependency_links.txt +0 -0
  120. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/entry_points.txt +0 -0
  121. {copyparty-1.13.2 → copyparty-1.13.4}/copyparty.egg-info/top_level.txt +0 -0
  122. {copyparty-1.13.2 → copyparty-1.13.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.13.2
3
+ Version: 1.13.4
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
@@ -48,7 +48,7 @@ Provides-Extra: ftps
48
48
  Requires-Dist: pyftpdlib; extra == "ftps"
49
49
  Requires-Dist: pyopenssl; extra == "ftps"
50
50
  Provides-Extra: tftpd
51
- Requires-Dist: partftpy>=0.3.1; extra == "tftpd"
51
+ Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
52
52
  Provides-Extra: pwhash
53
53
  Requires-Dist: argon2-cffi; extra == "pwhash"
54
54
 
@@ -137,6 +137,8 @@ turn almost any device into a file server with resumable uploads/downloads using
137
137
  * [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
138
138
  * [real-ip](#real-ip) - teaching copyparty how to see client IPs
139
139
  * [prometheus](#prometheus) - metrics/stats can be enabled
140
+ * [other extremely specific features](#other-extremely-specific-features) - you'll never find a use for these
141
+ * [custom mimetypes](#custom-mimetypes) - change the association of a file extension
140
142
  * [packages](#packages) - the party might be closer than you think
141
143
  * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
142
144
  * [fedora package](#fedora-package) - does not exist yet
@@ -627,6 +629,7 @@ it does static images with Pillow / pyvips / FFmpeg, and uses FFmpeg for video f
627
629
  audio files are covnerted into spectrograms using FFmpeg unless you `--no-athumb` (and some FFmpeg builds may need `--th-ff-swr`)
628
630
 
629
631
  images with the following names (see `--th-covers`) become the thumbnail of the folder they're in: `folder.png`, `folder.jpg`, `cover.png`, `cover.jpg`
632
+ * the order is significant, so if both `cover.png` and `folder.jpg` exist in a folder, it will pick the first matching `--th-covers` entry (`folder.jpg`)
630
633
  * and, if you enable [file indexing](#file-indexing), it will also try those names as dotfiles (`.folder.jpg` and so), and then fallback on the first picture in the folder (if it has any pictures at all)
631
634
 
632
635
  in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked
@@ -634,6 +637,7 @@ in the grid/thumbnail view, if the audio player panel is open, songs will start
634
637
 
635
638
  enabling `multiselect` lets you click files to select them, and then shift-click another file for range-select
636
639
  * `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
640
+ * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
637
641
 
638
642
 
639
643
  ## zip downloads
@@ -763,7 +767,7 @@ uploads can be given a lifetime, afer which they expire / self-destruct
763
767
 
764
768
  the feature must be enabled per-volume with the `lifetime` [upload rule](#upload-rules) which sets the upper limit for how long a file gets to stay on the server
765
769
 
766
- clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](#write)
770
+ clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](./docs/devnotes.md#write)
767
771
 
768
772
  specifying a custom expiration time client-side will affect the timespan in which unposts are permitted, so keep an eye on the estimates in the up2k ui
769
773
 
@@ -931,6 +935,8 @@ see [./srv/expand/](./srv/expand/) for usage and examples
931
935
 
932
936
  * files named `.prologue.html` / `.epilogue.html` will be rendered before/after directory listings unless `--no-logues`
933
937
 
938
+ * files named `descript.ion` / `DESCRIPT.ION` are parsed and displayed in the file listing, or as the epilogue if nonstandard
939
+
934
940
  * files named `README.md` / `readme.md` will be rendered after directory listings unless `--no-readme` (but `.epilogue.html` takes precedence)
935
941
 
936
942
  * `README.md` and `*logue.html` can contain placeholder values which are replaced server-side before embedding into directory listings; see `--help-exp`
@@ -1499,8 +1505,9 @@ you can either:
1499
1505
  * or do location-based proxying, using `--rp-loc=/stuff` to tell copyparty where it is mounted -- has a slight performance cost and higher chance of bugs
1500
1506
  * if copyparty says `incorrect --rp-loc or webserver config; expected vpath starting with [...]` it's likely because the webserver is stripping away the proxy location from the request URLs -- see the `ProxyPass` in the apache example below
1501
1507
 
1502
- some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which could be a nice speed boost
1503
- * **warning:** nginx-QUIC is still experimental and can make uploads much slower, so HTTP/2 is recommended for now
1508
+ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which *could* be a nice speed boost, depending on a lot of factors
1509
+ * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
1510
+ * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
1504
1511
 
1505
1512
  example webserver configs:
1506
1513
 
@@ -1580,6 +1587,28 @@ the following options are available to disable some of the metrics:
1580
1587
  note: the following metrics are counted incorrectly if multiprocessing is enabled with `-j`: `cpp_http_conns`, `cpp_http_reqs`, `cpp_sus_reqs`, `cpp_active_bans`, `cpp_total_bans`
1581
1588
 
1582
1589
 
1590
+ ## other extremely specific features
1591
+
1592
+ you'll never find a use for these:
1593
+
1594
+
1595
+ ### custom mimetypes
1596
+
1597
+ change the association of a file extension
1598
+
1599
+ using commandline args, you can do something like `--mime gif=image/jif` and `--mime ts=text/x.typescript` (can be specified multiple times)
1600
+
1601
+ in a config-file, this is the same as:
1602
+
1603
+ ```yaml
1604
+ [global]
1605
+ mime: gif=image/jif
1606
+ mime: ts=text/x.typescript
1607
+ ```
1608
+
1609
+ run copyparty with `--mimes` to list all the default mappings
1610
+
1611
+
1583
1612
  # packages
1584
1613
 
1585
1614
  the party might be closer than you think
@@ -1829,6 +1858,8 @@ alternatively, some alternatives roughly sorted by speed (unreproducible benchma
1829
1858
 
1830
1859
  most clients will fail to mount the root of a copyparty server unless there is a root volume (so you get the admin-panel instead of a browser when accessing it) -- in that case, mount a specific volume instead
1831
1860
 
1861
+ if you have volumes that are accessible without a password, then some webdav clients (such as davfs2) require the global-option `--dav-auth` to access any password-protected areas
1862
+
1832
1863
 
1833
1864
  # android app
1834
1865
 
@@ -1857,6 +1888,7 @@ defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
1857
1888
 
1858
1889
  below are some tweaks roughly ordered by usefulness:
1859
1890
 
1891
+ * disabling HTTP/2 and HTTP/3 can make uploads 5x faster, depending on server/client software
1860
1892
  * `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
1861
1893
  * `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
1862
1894
  * and also makes thumbnails load faster, regardless of e2d/e2t
@@ -1972,7 +2004,7 @@ volflag `dk` generates dirkeys (per-directory accesskeys) for all folders, grant
1972
2004
 
1973
2005
  volflag `dky` disables the actual key-check, meaning anyone can see the contents of a folder where they have `g` access, but not its subdirectories
1974
2006
 
1975
- * `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
2007
+ * `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (as if their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
1976
2008
 
1977
2009
  volflag `dks` lets people enter subfolders as well, and also enables download-as-zip/tar
1978
2010
 
@@ -1997,7 +2029,7 @@ the default configs take about 0.4 sec and 256 MiB RAM to process a new password
1997
2029
 
1998
2030
  both HTTP and HTTPS are accepted by default, but letting a [reverse proxy](#reverse-proxy) handle the https/tls/ssl would be better (probably more secure by default)
1999
2031
 
2000
- copyparty doesn't speak HTTP/2 or QUIC, so using a reverse proxy would solve that as well
2032
+ copyparty doesn't speak HTTP/2 or QUIC, so using a reverse proxy would solve that as well -- but note that HTTP/1 is usually faster than both HTTP/2 and HTTP/3
2001
2033
 
2002
2034
  if [cfssl](https://github.com/cloudflare/cfssl/releases/latest) is installed, copyparty will automatically create a CA and server-cert on startup
2003
2035
  * the certs are written to `--crt-dir` for distribution, see `--help` for the other `--crt` options
@@ -83,6 +83,8 @@ turn almost any device into a file server with resumable uploads/downloads using
83
83
  * [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
84
84
  * [real-ip](#real-ip) - teaching copyparty how to see client IPs
85
85
  * [prometheus](#prometheus) - metrics/stats can be enabled
86
+ * [other extremely specific features](#other-extremely-specific-features) - you'll never find a use for these
87
+ * [custom mimetypes](#custom-mimetypes) - change the association of a file extension
86
88
  * [packages](#packages) - the party might be closer than you think
87
89
  * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
88
90
  * [fedora package](#fedora-package) - does not exist yet
@@ -573,6 +575,7 @@ it does static images with Pillow / pyvips / FFmpeg, and uses FFmpeg for video f
573
575
  audio files are covnerted into spectrograms using FFmpeg unless you `--no-athumb` (and some FFmpeg builds may need `--th-ff-swr`)
574
576
 
575
577
  images with the following names (see `--th-covers`) become the thumbnail of the folder they're in: `folder.png`, `folder.jpg`, `cover.png`, `cover.jpg`
578
+ * the order is significant, so if both `cover.png` and `folder.jpg` exist in a folder, it will pick the first matching `--th-covers` entry (`folder.jpg`)
576
579
  * and, if you enable [file indexing](#file-indexing), it will also try those names as dotfiles (`.folder.jpg` and so), and then fallback on the first picture in the folder (if it has any pictures at all)
577
580
 
578
581
  in the grid/thumbnail view, if the audio player panel is open, songs will start playing when clicked
@@ -580,6 +583,7 @@ in the grid/thumbnail view, if the audio player panel is open, songs will start
580
583
 
581
584
  enabling `multiselect` lets you click files to select them, and then shift-click another file for range-select
582
585
  * `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
586
+ * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
583
587
 
584
588
 
585
589
  ## zip downloads
@@ -709,7 +713,7 @@ uploads can be given a lifetime, afer which they expire / self-destruct
709
713
 
710
714
  the feature must be enabled per-volume with the `lifetime` [upload rule](#upload-rules) which sets the upper limit for how long a file gets to stay on the server
711
715
 
712
- clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](#write)
716
+ clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](./docs/devnotes.md#write)
713
717
 
714
718
  specifying a custom expiration time client-side will affect the timespan in which unposts are permitted, so keep an eye on the estimates in the up2k ui
715
719
 
@@ -877,6 +881,8 @@ see [./srv/expand/](./srv/expand/) for usage and examples
877
881
 
878
882
  * files named `.prologue.html` / `.epilogue.html` will be rendered before/after directory listings unless `--no-logues`
879
883
 
884
+ * files named `descript.ion` / `DESCRIPT.ION` are parsed and displayed in the file listing, or as the epilogue if nonstandard
885
+
880
886
  * files named `README.md` / `readme.md` will be rendered after directory listings unless `--no-readme` (but `.epilogue.html` takes precedence)
881
887
 
882
888
  * `README.md` and `*logue.html` can contain placeholder values which are replaced server-side before embedding into directory listings; see `--help-exp`
@@ -1445,8 +1451,9 @@ you can either:
1445
1451
  * or do location-based proxying, using `--rp-loc=/stuff` to tell copyparty where it is mounted -- has a slight performance cost and higher chance of bugs
1446
1452
  * if copyparty says `incorrect --rp-loc or webserver config; expected vpath starting with [...]` it's likely because the webserver is stripping away the proxy location from the request URLs -- see the `ProxyPass` in the apache example below
1447
1453
 
1448
- some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which could be a nice speed boost
1449
- * **warning:** nginx-QUIC is still experimental and can make uploads much slower, so HTTP/2 is recommended for now
1454
+ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatically obtain a valid https/tls certificate for you, and some support HTTP/2 and QUIC which *could* be a nice speed boost, depending on a lot of factors
1455
+ * **warning:** nginx-QUIC (HTTP/3) is still experimental and can make uploads much slower, so HTTP/1.1 is recommended for now
1456
+ * depending on server/client, HTTP/1.1 can also be 5x faster than HTTP/2
1450
1457
 
1451
1458
  example webserver configs:
1452
1459
 
@@ -1526,6 +1533,28 @@ the following options are available to disable some of the metrics:
1526
1533
  note: the following metrics are counted incorrectly if multiprocessing is enabled with `-j`: `cpp_http_conns`, `cpp_http_reqs`, `cpp_sus_reqs`, `cpp_active_bans`, `cpp_total_bans`
1527
1534
 
1528
1535
 
1536
+ ## other extremely specific features
1537
+
1538
+ you'll never find a use for these:
1539
+
1540
+
1541
+ ### custom mimetypes
1542
+
1543
+ change the association of a file extension
1544
+
1545
+ using commandline args, you can do something like `--mime gif=image/jif` and `--mime ts=text/x.typescript` (can be specified multiple times)
1546
+
1547
+ in a config-file, this is the same as:
1548
+
1549
+ ```yaml
1550
+ [global]
1551
+ mime: gif=image/jif
1552
+ mime: ts=text/x.typescript
1553
+ ```
1554
+
1555
+ run copyparty with `--mimes` to list all the default mappings
1556
+
1557
+
1529
1558
  # packages
1530
1559
 
1531
1560
  the party might be closer than you think
@@ -1775,6 +1804,8 @@ alternatively, some alternatives roughly sorted by speed (unreproducible benchma
1775
1804
 
1776
1805
  most clients will fail to mount the root of a copyparty server unless there is a root volume (so you get the admin-panel instead of a browser when accessing it) -- in that case, mount a specific volume instead
1777
1806
 
1807
+ if you have volumes that are accessible without a password, then some webdav clients (such as davfs2) require the global-option `--dav-auth` to access any password-protected areas
1808
+
1778
1809
 
1779
1810
  # android app
1780
1811
 
@@ -1803,6 +1834,7 @@ defaults are usually fine - expect `8 GiB/s` download, `1 GiB/s` upload
1803
1834
 
1804
1835
  below are some tweaks roughly ordered by usefulness:
1805
1836
 
1837
+ * disabling HTTP/2 and HTTP/3 can make uploads 5x faster, depending on server/client software
1806
1838
  * `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
1807
1839
  * `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
1808
1840
  * and also makes thumbnails load faster, regardless of e2d/e2t
@@ -1918,7 +1950,7 @@ volflag `dk` generates dirkeys (per-directory accesskeys) for all folders, grant
1918
1950
 
1919
1951
  volflag `dky` disables the actual key-check, meaning anyone can see the contents of a folder where they have `g` access, but not its subdirectories
1920
1952
 
1921
- * `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
1953
+ * `dk` + `dky` gives the same behavior as if all users with `g` access have full read-access, but subfolders are hidden files (as if their names start with a dot), so `dky` is an alternative to renaming all the folders for that purpose, maybe just for some users
1922
1954
 
1923
1955
  volflag `dks` lets people enter subfolders as well, and also enables download-as-zip/tar
1924
1956
 
@@ -1943,7 +1975,7 @@ the default configs take about 0.4 sec and 256 MiB RAM to process a new password
1943
1975
 
1944
1976
  both HTTP and HTTPS are accepted by default, but letting a [reverse proxy](#reverse-proxy) handle the https/tls/ssl would be better (probably more secure by default)
1945
1977
 
1946
- copyparty doesn't speak HTTP/2 or QUIC, so using a reverse proxy would solve that as well
1978
+ copyparty doesn't speak HTTP/2 or QUIC, so using a reverse proxy would solve that as well -- but note that HTTP/1 is usually faster than both HTTP/2 and HTTP/3
1947
1979
 
1948
1980
  if [cfssl](https://github.com/cloudflare/cfssl/releases/latest) is installed, copyparty will automatically create a CA and server-cert on startup
1949
1981
  * the certs are written to `--crt-dir` for distribution, see `--help` for the other `--crt` options
@@ -13,6 +13,7 @@ import base64
13
13
  import locale
14
14
  import os
15
15
  import re
16
+ import select
16
17
  import socket
17
18
  import sys
18
19
  import threading
@@ -41,6 +42,7 @@ from .util import (
41
42
  DEF_EXP,
42
43
  DEF_MTE,
43
44
  DEF_MTH,
45
+ HAVE_IPV6,
44
46
  IMPLICATIONS,
45
47
  JINJA_VER,
46
48
  MIMES,
@@ -167,8 +169,10 @@ def init_E(EE ) :
167
169
  (os.environ.get, "TMP"),
168
170
  (unicode, "/tmp"),
169
171
  ]
172
+ errs = []
170
173
  for chk in [os.listdir, os.mkdir]:
171
- for pf, pa in paths:
174
+ for npath, (pf, pa) in enumerate(paths):
175
+ p = ""
172
176
  try:
173
177
  p = pf(pa)
174
178
  # print(chk.__name__, p, pa)
@@ -181,9 +185,20 @@ def init_E(EE ) :
181
185
  if not os.path.isdir(p):
182
186
  os.mkdir(p)
183
187
 
188
+ if npath > 1:
189
+ t = "Using [%s] for config; filekeys/dirkeys will change on every restart. Consider setting XDG_CONFIG_HOME or giving the unix-user a ~/.config/"
190
+ errs.append(t % (p,))
191
+ elif errs:
192
+ errs.append("Using [%s] instead" % (p,))
193
+
194
+ if errs:
195
+ print("WARNING: " + ". ".join(errs))
196
+
184
197
  return p # type: ignore
185
- except:
186
- pass
198
+ except Exception as ex:
199
+ if p and npath < 2:
200
+ t = "Unable to store config in [%s] due to %r"
201
+ errs.append(t % (p, ex))
187
202
 
188
203
  raise Exception("could not find a writable path for config")
189
204
 
@@ -273,6 +288,9 @@ def get_ah_salt() :
273
288
 
274
289
 
275
290
  def ensure_locale() :
291
+ if ANYWIN and PY2:
292
+ return # maybe XP, so busted 65001
293
+
276
294
  safe = "en_US.UTF-8"
277
295
  for x in [
278
296
  safe,
@@ -610,12 +628,12 @@ def get_sects():
610
628
  \033[36mxban\033[35m executes CMD if someone gets banned
611
629
  \033[0m
612
630
  can be defined as --args or volflags; for example \033[36m
613
- --xau notify-send
614
- -v .::r:c,xau=notify-send
631
+ --xau foo.py
632
+ -v .::r:c,xau=bar.py
615
633
  \033[0m
616
- commands specified as --args are appended to volflags;
617
- each --arg and volflag can be specified multiple times,
618
- each command will execute in order unless one returns non-zero
634
+ hooks specified as commandline --args are appended to volflags;
635
+ each commandline --arg and volflag can be specified multiple times,
636
+ each hook will execute in order unless one returns non-zero
619
637
 
620
638
  optionally prefix the command with comma-sep. flags similar to -mtp:
621
639
 
@@ -626,6 +644,10 @@ def get_sects():
626
644
  \033[36mtN\033[35m sets an N sec timeout before the command is abandoned
627
645
  \033[36miN\033[35m xiu only: volume must be idle for N sec (default = 5)
628
646
 
647
+ \033[36mar\033[35m only run hook if user has read-access
648
+ \033[36marw\033[35m only run hook if user has read-write-access
649
+ \033[36marwmd\033[35m ...and so on... (doesn't work for xiu or xban)
650
+
629
651
  \033[36mkt\033[35m kills the entire process tree on timeout (default),
630
652
  \033[36mkm\033[35m kills just the main process
631
653
  \033[36mkn\033[35m lets it continue running until copyparty is terminated
@@ -635,6 +657,21 @@ def get_sects():
635
657
  \033[36mc2\033[35m show only stdout
636
658
  \033[36mc3\033[35m mute all process otput
637
659
  \033[0m
660
+ examples:
661
+
662
+ \033[36m--xm some.py\033[35m runs \033[33msome.py msgtxt\033[35m on each 📟 message;
663
+ \033[33mmsgtxt\033[35m is the message that was written into the web-ui
664
+
665
+ \033[36m--xm j,some.py\033[35m runs \033[33msome.py jsontext\033[35m on each 📟 message;
666
+ \033[33mjsontext\033[35m is the message info (ip, user, ..., msg-text)
667
+
668
+ \033[36m--xm aw,j,some.py\033[35m requires user to have write-access
669
+
670
+ \033[36m--xm aw,,notify-send,hey,--\033[35m shows an OS alert on linux;
671
+ the \033[33m,,\033[35m stops copyparty from reading the rest as flags and
672
+ the \033[33m--\033[35m stops notify-send from reading the message as args
673
+ and the alert will be "hey" followed by the messagetext
674
+ \033[0m
638
675
  each hook is executed once for each event, except for \033[36mxiu\033[0m
639
676
  which builds up a backlog of uploads, running the hook just once
640
677
  as soon as the volume has been idle for iN seconds (5 by default)
@@ -661,7 +698,10 @@ def get_sects():
661
698
  \033[36mstash\033[35m dumps the data to file and returns length + checksum
662
699
  \033[36msave,get\033[35m dumps to file and returns the page like a GET
663
700
  \033[36mprint,get\033[35m prints the data in the log and returns GET
664
- (leave out the ",get" to return an error instead)
701
+ (leave out the ",get" to return an error instead)\033[0m
702
+
703
+ note that the \033[35m--xm\033[0m hook will only run if \033[35m--urlform\033[0m
704
+ is either \033[36mprint\033[0m or the default \033[36mprint,get\033[0m
665
705
  """
666
706
  ),
667
707
  ],
@@ -887,12 +927,12 @@ def add_upload(ap):
887
927
  ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
888
928
  ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
889
929
  ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every \033[33mSEC\033[0m seconds; allows resuming incomplete uploads after a server crash")
890
- ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440, help="forget unfinished uploads after \033[33mMIN\033[0m minutes; impossible to resume them after that (360=6h, 1440=24h)")
930
+ ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440.0, help="forget unfinished uploads after \033[33mMIN\033[0m minutes; impossible to resume them after that (360=6h, 1440=24h)")
891
931
  ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)")
892
932
  ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)")
893
933
  ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
894
934
  ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)")
895
- ap2.add_argument("--df", metavar="GiB", type=float, default=0, help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests")
935
+ 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)")
896
936
  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")
897
937
  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")
898
938
  ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good for low-latency (same-country) connections, 4-8 for android clients, 16 for cross-atlantic (max=64)")
@@ -915,12 +955,12 @@ def add_network(ap):
915
955
  else:
916
956
  ap2.add_argument("--freebind", action="store_true", help="allow listening on IPs which do not yet exist, for example if the network interfaces haven't finished going up. Only makes sense for IPs other than '0.0.0.0', '127.0.0.1', '::', and '::1'. May require running as root (unless net.ipv6.ip_nonlocal_bind)")
917
957
  ap2.add_argument("--s-thead", metavar="SEC", type=int, default=120, help="socket timeout (read request header)")
918
- ap2.add_argument("--s-tbody", metavar="SEC", type=float, default=186, help="socket timeout (read/write request/response bodies). Use 60 on fast servers (default is extremely safe). Disable with 0 if reverse-proxied for a 2%% speed boost")
958
+ ap2.add_argument("--s-tbody", metavar="SEC", type=float, default=186.0, help="socket timeout (read/write request/response bodies). Use 60 on fast servers (default is extremely safe). Disable with 0 if reverse-proxied for a 2%% speed boost")
919
959
  ap2.add_argument("--s-rd-sz", metavar="B", type=int, default=256*1024, help="socket read size in bytes (indirectly affects filesystem writes; recommendation: keep equal-to or lower-than \033[33m--iobuf\033[0m)")
920
960
  ap2.add_argument("--s-wr-sz", metavar="B", type=int, default=256*1024, help="socket write size in bytes")
921
- ap2.add_argument("--s-wr-slp", metavar="SEC", type=float, default=0, help="debug: socket write delay in seconds")
922
- ap2.add_argument("--rsp-slp", metavar="SEC", type=float, default=0, help="debug: response delay in seconds")
923
- ap2.add_argument("--rsp-jtr", metavar="SEC", type=float, default=0, help="debug: response delay, random duration 0..\033[33mSEC\033[0m")
961
+ ap2.add_argument("--s-wr-slp", metavar="SEC", type=float, default=0.0, help="debug: socket write delay in seconds")
962
+ ap2.add_argument("--rsp-slp", metavar="SEC", type=float, default=0.0, help="debug: response delay in seconds")
963
+ ap2.add_argument("--rsp-jtr", metavar="SEC", type=float, default=0.0, help="debug: response delay, random duration 0..\033[33mSEC\033[0m")
924
964
 
925
965
 
926
966
  def add_tls(ap, cert_path):
@@ -928,10 +968,10 @@ def add_tls(ap, cert_path):
928
968
  ap2.add_argument("--http-only", action="store_true", help="disable ssl/tls -- force plaintext")
929
969
  ap2.add_argument("--https-only", action="store_true", help="disable plaintext -- force tls")
930
970
  ap2.add_argument("--cert", metavar="PATH", type=u, default=cert_path, help="path to TLS certificate")
931
- ap2.add_argument("--ssl-ver", metavar="LIST", type=u, help="set allowed ssl/tls versions; [\033[32mhelp\033[0m] shows available versions; default is what your python version considers safe")
932
- ap2.add_argument("--ciphers", metavar="LIST", type=u, help="set allowed ssl/tls ciphers; [\033[32mhelp\033[0m] shows available ciphers")
971
+ ap2.add_argument("--ssl-ver", metavar="LIST", type=u, default="", help="set allowed ssl/tls versions; [\033[32mhelp\033[0m] shows available versions; default is what your python version considers safe")
972
+ ap2.add_argument("--ciphers", metavar="LIST", type=u, default="", help="set allowed ssl/tls ciphers; [\033[32mhelp\033[0m] shows available ciphers")
933
973
  ap2.add_argument("--ssl-dbg", action="store_true", help="dump some tls info")
934
- ap2.add_argument("--ssl-log", metavar="PATH", type=u, help="log master secrets for later decryption in wireshark")
974
+ ap2.add_argument("--ssl-log", metavar="PATH", type=u, default="", help="log master secrets for later decryption in wireshark")
935
975
 
936
976
 
937
977
  def add_cert(ap, cert_path):
@@ -944,12 +984,12 @@ def add_cert(ap, cert_path):
944
984
  ap2.add_argument("--crt-nolo", action="store_true", help="do not add 127.0.0.1 / localhost into cert")
945
985
  ap2.add_argument("--crt-nohn", action="store_true", help="do not add mDNS names / hostname into cert")
946
986
  ap2.add_argument("--crt-dir", metavar="PATH", default=cert_dir, help="where to save the CA cert")
947
- ap2.add_argument("--crt-cdays", metavar="D", type=float, default=3650, help="ca-certificate expiration time in days")
948
- ap2.add_argument("--crt-sdays", metavar="D", type=float, default=365, help="server-cert expiration time in days")
987
+ ap2.add_argument("--crt-cdays", metavar="D", type=float, default=3650.0, help="ca-certificate expiration time in days")
988
+ ap2.add_argument("--crt-sdays", metavar="D", type=float, default=365.0, help="server-cert expiration time in days")
949
989
  ap2.add_argument("--crt-cn", metavar="TXT", type=u, default="partyco", help="CA/server-cert common-name")
950
990
  ap2.add_argument("--crt-cnc", metavar="TXT", type=u, default="--crt-cn", help="override CA name")
951
991
  ap2.add_argument("--crt-cns", metavar="TXT", type=u, default="--crt-cn cpp", help="override server-cert name")
952
- ap2.add_argument("--crt-back", metavar="HRS", type=float, default=72, help="backdate in hours")
992
+ ap2.add_argument("--crt-back", metavar="HRS", type=float, default=72.0, help="backdate in hours")
953
993
  ap2.add_argument("--crt-alg", metavar="S-N", type=u, default="ecdsa-256", help="algorithm and keysize; one of these: \033[32mecdsa-256 rsa-4096 rsa-2048\033[0m")
954
994
 
955
995
 
@@ -990,7 +1030,7 @@ def add_zc_mdns(ap):
990
1030
  ap2.add_argument("--zm-mnic", action="store_true", help="merge NICs which share subnets; assume that same subnet means same network")
991
1031
  ap2.add_argument("--zm-msub", action="store_true", help="merge subnets on each NIC -- always enabled for ipv6 -- reduces network load, but gnome-gvfs clients may stop working, and clients cannot be in subnets that the server is not")
992
1032
  ap2.add_argument("--zm-noneg", action="store_true", help="disable NSEC replies -- try this if some clients don't see copyparty")
993
- ap2.add_argument("--zm-spam", metavar="SEC", type=float, default=0, help="send unsolicited announce every \033[33mSEC\033[0m; useful if clients have IPs in a subnet which doesn't overlap with the server, or to avoid some firewall issues")
1033
+ ap2.add_argument("--zm-spam", metavar="SEC", type=float, default=0.0, help="send unsolicited announce every \033[33mSEC\033[0m; useful if clients have IPs in a subnet which doesn't overlap with the server, or to avoid some firewall issues")
994
1034
 
995
1035
 
996
1036
  def add_zc_ssdp(ap):
@@ -1005,14 +1045,15 @@ def add_zc_ssdp(ap):
1005
1045
 
1006
1046
  def add_ftp(ap):
1007
1047
  ap2 = ap.add_argument_group('FTP options (TCP only)')
1008
- ap2.add_argument("--ftp", metavar="PORT", type=int, help="enable FTP server on \033[33mPORT\033[0m, for example \033[32m3921")
1009
- ap2.add_argument("--ftps", metavar="PORT", type=int, help="enable FTPS server on \033[33mPORT\033[0m, for example \033[32m3990")
1048
+ ap2.add_argument("--ftp", metavar="PORT", type=int, default=0, help="enable FTP server on \033[33mPORT\033[0m, for example \033[32m3921")
1049
+ ap2.add_argument("--ftps", metavar="PORT", type=int, default=0, help="enable FTPS server on \033[33mPORT\033[0m, for example \033[32m3990")
1010
1050
  ap2.add_argument("--ftpv", action="store_true", help="verbose")
1011
1051
  ap2.add_argument("--ftp4", action="store_true", help="only listen on IPv4")
1012
1052
  ap2.add_argument("--ftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
1053
+ ap2.add_argument("--ftp-no-ow", action="store_true", help="if target file exists, reject upload instead of overwrite")
1013
1054
  ap2.add_argument("--ftp-wt", metavar="SEC", type=int, default=7, help="grace period for resuming interrupted uploads (any client can write to any file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
1014
- ap2.add_argument("--ftp-nat", metavar="ADDR", type=u, help="the NAT address to use for passive connections")
1015
- ap2.add_argument("--ftp-pr", metavar="P-P", type=u, help="the range of TCP ports to use for passive connections, for example \033[32m12000-13000")
1055
+ ap2.add_argument("--ftp-nat", metavar="ADDR", type=u, default="", help="the NAT address to use for passive connections")
1056
+ ap2.add_argument("--ftp-pr", metavar="P-P", type=u, default="", help="the range of TCP ports to use for passive connections, for example \033[32m12000-13000")
1016
1057
 
1017
1058
 
1018
1059
  def add_webdav(ap):
@@ -1026,14 +1067,15 @@ def add_webdav(ap):
1026
1067
 
1027
1068
  def add_tftp(ap):
1028
1069
  ap2 = ap.add_argument_group('TFTP options (UDP only)')
1029
- ap2.add_argument("--tftp", metavar="PORT", type=int, help="enable TFTP server on \033[33mPORT\033[0m, for example \033[32m69 \033[0mor \033[32m3969")
1070
+ ap2.add_argument("--tftp", metavar="PORT", type=int, default=0, help="enable TFTP server on \033[33mPORT\033[0m, for example \033[32m69 \033[0mor \033[32m3969")
1071
+ ap2.add_argument("--tftp4", action="store_true", help="only listen on IPv4")
1030
1072
  ap2.add_argument("--tftpv", action="store_true", help="verbose")
1031
1073
  ap2.add_argument("--tftpvv", action="store_true", help="verboser")
1032
1074
  ap2.add_argument("--tftp-no-fast", action="store_true", help="debug: disable optimizations")
1033
1075
  ap2.add_argument("--tftp-lsf", metavar="PTN", type=u, default="\\.?(dir|ls)(\\.txt)?", help="return a directory listing if a file with this name is requested and it does not exist; defaults matches .ls, dir, .dir.txt, ls.txt, ...")
1034
1076
  ap2.add_argument("--tftp-nols", action="store_true", help="if someone tries to download a directory, return an error instead of showing its directory listing")
1035
1077
  ap2.add_argument("--tftp-ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m; specify [\033[32many\033[0m] to disable inheriting \033[33m--ipa\033[0m. Examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
1036
- ap2.add_argument("--tftp-pr", metavar="P-P", type=u, help="the range of UDP ports to use for data transfer, for example \033[32m12000-13000")
1078
+ ap2.add_argument("--tftp-pr", metavar="P-P", type=u, default="", help="the range of UDP ports to use for data transfer, for example \033[32m12000-13000")
1037
1079
 
1038
1080
 
1039
1081
  def add_smb(ap):
@@ -1109,7 +1151,7 @@ def add_safety(ap):
1109
1151
  ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
1110
1152
  ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih")
1111
1153
  ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r")
1112
- ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m (see \033[33m--help-ls\033[0m); example [\033[32m**,*,ln,p,r\033[0m]")
1154
+ ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, default="", help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m (see \033[33m--help-ls\033[0m); example [\033[32m**,*,ln,p,r\033[0m]")
1113
1155
  ap2.add_argument("--xvol", action="store_true", help="never follow symlinks leaving the volume root, unless the link is into another volume where the user has similar access (volflag=xvol)")
1114
1156
  ap2.add_argument("--xdev", action="store_true", help="stay within the filesystem of the volume root; do not descend into other devices (symlink or bind-mount to another HDD, ...) (volflag=xdev)")
1115
1157
  ap2.add_argument("--no-dot-mv", action="store_true", help="disallow moving dotfiles; makes it impossible to move folders containing dotfiles")
@@ -1119,7 +1161,7 @@ def add_safety(ap):
1119
1161
  ap2.add_argument("--vague-403", action="store_true", help="send 404 instead of 403 (security through ambiguity, very enterprise)")
1120
1162
  ap2.add_argument("--force-js", action="store_true", help="don't send folder listings as HTML, force clients to use the embedded json instead -- slight protection against misbehaving search engines which ignore \033[33m--no-robots\033[0m")
1121
1163
  ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
1122
- ap2.add_argument("--logout", metavar="H", type=float, default="8086", help="logout clients after \033[33mH\033[0m hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
1164
+ ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
1123
1165
  ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
1124
1166
  ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
1125
1167
  ap2.add_argument("--ban-403", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 403's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; [\033[32m1440\033[0m]=day, [\033[32m10080\033[0m]=week, [\033[32m43200\033[0m]=month")
@@ -1155,7 +1197,7 @@ def add_shutdown(ap):
1155
1197
  def add_logging(ap):
1156
1198
  ap2 = ap.add_argument_group('logging options')
1157
1199
  ap2.add_argument("-q", action="store_true", help="quiet; disable most STDOUT messages")
1158
- ap2.add_argument("-lo", metavar="PATH", type=u, help="logfile, example: \033[32mcpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz\033[0m (NB: some errors may appear on STDOUT only)")
1200
+ ap2.add_argument("-lo", metavar="PATH", type=u, default="", help="logfile, example: \033[32mcpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz\033[0m (NB: some errors may appear on STDOUT only)")
1159
1201
  ap2.add_argument("--no-ansi", action="store_true", default=not VT100, help="disable colors; same as environment-variable NO_COLOR")
1160
1202
  ap2.add_argument("--ansi", action="store_true", help="force colors; overrides environment-variable NO_COLOR")
1161
1203
  ap2.add_argument("--no-logflush", action="store_true", help="don't flush the logfile after each write; tiny bit faster")
@@ -1182,10 +1224,10 @@ def add_thumbnail(ap):
1182
1224
  ap2.add_argument("--no-athumb", action="store_true", help="disable audio thumbnails (spectrograms) (volflag=dathumb)")
1183
1225
  ap2.add_argument("--th-size", metavar="WxH", default="320x256", help="thumbnail res (volflag=thsize)")
1184
1226
  ap2.add_argument("--th-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for generating thumbnails")
1185
- ap2.add_argument("--th-convt", metavar="SEC", type=float, default=60, help="conversion timeout in seconds (volflag=convt)")
1186
- ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=6, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
1187
- ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32mfy\033[0m]=crop, [\033[32mfn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
1188
- ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32mfy\033[0m]=yes, [\033[32mfn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
1227
+ ap2.add_argument("--th-convt", metavar="SEC", type=float, default=60.0, help="conversion timeout in seconds (volflag=convt)")
1228
+ ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=6.0, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
1229
+ ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32my\033[0m]=crop, [\033[32mn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
1230
+ ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32my\033[0m]=yes, [\033[32mn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
1189
1231
  ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,ff", help="image decoders, in order of preference")
1190
1232
  ap2.add_argument("--th-no-jpg", action="store_true", help="disable jpg output")
1191
1233
  ap2.add_argument("--th-no-webp", action="store_true", help="disable webp output")
@@ -1224,8 +1266,8 @@ def add_db_general(ap, hcores):
1224
1266
  ap2.add_argument("-e2v", action="store_true", help="verify file integrity; rehash all files and compare with db")
1225
1267
  ap2.add_argument("-e2vu", action="store_true", help="on hash mismatch: update the database with the new hash")
1226
1268
  ap2.add_argument("-e2vp", action="store_true", help="on hash mismatch: panic and quit copyparty")
1227
- ap2.add_argument("--hist", metavar="PATH", type=u, help="where to store volume data (db, thumbs) (volflag=hist)")
1228
- ap2.add_argument("--no-hash", metavar="PTN", type=u, help="regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans (volflag=nohash)")
1269
+ ap2.add_argument("--hist", metavar="PATH", type=u, default="", help="where to store volume data (db, thumbs); default is a folder named \".hist\" inside each volume (volflag=hist)")
1270
+ ap2.add_argument("--no-hash", metavar="PTN", type=u, default="", help="regex: disable hashing of matching absolute-filesystem-paths during e2ds folder scans (volflag=nohash)")
1229
1271
  ap2.add_argument("--no-idx", metavar="PTN", type=u, default=noidx, help="regex: disable indexing of matching absolute-filesystem-paths during e2ds folder scans (volflag=noidx)")
1230
1272
  ap2.add_argument("--no-dhash", action="store_true", help="disable rescan acceleration; do full database integrity check -- makes the db ~5%% smaller and bootup/rescans 3~10x slower")
1231
1273
  ap2.add_argument("--re-dhash", action="store_true", help="force a cache rebuild on startup; enable this once if it gets out of sync (should never be necessary)")
@@ -1234,7 +1276,7 @@ def add_db_general(ap, hcores):
1234
1276
  ap2.add_argument("--xlink", action="store_true", help="on upload: check all volumes for dupes, not just the target volume (volflag=xlink)")
1235
1277
  ap2.add_argument("--hash-mt", metavar="CORES", type=int, default=hcores, help="num cpu cores to use for file hashing; set 0 or 1 for single-core hashing")
1236
1278
  ap2.add_argument("--re-maxage", metavar="SEC", type=int, default=0, help="rescan filesystem for changes every \033[33mSEC\033[0m seconds; 0=off (volflag=scan)")
1237
- ap2.add_argument("--db-act", metavar="SEC", type=float, default=10, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
1279
+ ap2.add_argument("--db-act", metavar="SEC", type=float, default=10.0, help="defer any scheduled volume reindexing until \033[33mSEC\033[0m seconds after last db write (uploads, renames, ...)")
1238
1280
  ap2.add_argument("--srch-time", metavar="SEC", type=int, default=45, help="search deadline -- terminate searches running for more than \033[33mSEC\033[0m seconds")
1239
1281
  ap2.add_argument("--srch-hits", metavar="N", type=int, default=7999, help="max search results to allow clients to fetch; 125 results will be shown initially")
1240
1282
  ap2.add_argument("--dotsrch", action="store_true", help="show dotfiles in search results (volflags: dotsrch | nodotsrch)")
@@ -1287,6 +1329,7 @@ def add_og(ap):
1287
1329
  def add_ui(ap, retry):
1288
1330
  ap2 = ap.add_argument_group('ui options')
1289
1331
  ap2.add_argument("--grid", action="store_true", help="show grid/thumbnails by default (volflag=grid)")
1332
+ ap2.add_argument("--gsel", action="store_true", help="select files in grid by ctrl-click (volflag=gsel)")
1290
1333
  ap2.add_argument("--lang", metavar="LANG", type=u, default="eng", help="language; one of the following: \033[32meng nor\033[0m")
1291
1334
  ap2.add_argument("--theme", metavar="NUM", type=int, default=0, help="default theme to use (0..7)")
1292
1335
  ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
@@ -1295,8 +1338,8 @@ def add_ui(ap, retry):
1295
1338
  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)")
1296
1339
  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")
1297
1340
  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])")
1298
- ap2.add_argument("--js-browser", metavar="L", type=u, help="URL to additional JS to include")
1299
- ap2.add_argument("--css-browser", metavar="L", type=u, help="URL to additional CSS to include")
1341
+ ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include")
1342
+ ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include")
1300
1343
  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)")
1301
1344
  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)")
1302
1345
  ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
@@ -1316,14 +1359,16 @@ def add_debug(ap):
1316
1359
  ap2 = ap.add_argument_group('debug options')
1317
1360
  ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
1318
1361
  ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
1362
+ if hasattr(select, "poll"):
1363
+ ap2.add_argument("--no-poll", action="store_true", help="kernel-bug workaround: disable poll; use select instead (limits max num clients to ~700)")
1319
1364
  ap2.add_argument("--no-sendfile", action="store_true", help="kernel-bug workaround: disable sendfile; do a safe and slow read-send-loop instead")
1320
1365
  ap2.add_argument("--no-scandir", action="store_true", help="kernel-bug workaround: disable scandir; do a listdir + stat on each file instead")
1321
1366
  ap2.add_argument("--no-fastboot", action="store_true", help="wait for initial filesystem indexing before accepting client requests")
1322
1367
  ap2.add_argument("--no-htp", action="store_true", help="disable httpserver threadpool, create threads as-needed instead")
1323
1368
  ap2.add_argument("--srch-dbg", action="store_true", help="explain search processing, and do some extra expensive sanity checks")
1324
1369
  ap2.add_argument("--rclone-mdns", action="store_true", help="use mdns-domain instead of server-ip on /?hc")
1325
- ap2.add_argument("--stackmon", metavar="P,S", type=u, help="write stacktrace to \033[33mP\033[0math every \033[33mS\033[0m second, for example --stackmon=\033[32m./st/%%Y-%%m/%%d/%%H%%M.xz,60")
1326
- ap2.add_argument("--log-thrs", metavar="SEC", type=float, help="list active threads every \033[33mSEC\033[0m")
1370
+ ap2.add_argument("--stackmon", metavar="P,S", type=u, default="", help="write stacktrace to \033[33mP\033[0math every \033[33mS\033[0m second, for example --stackmon=\033[32m./st/%%Y-%%m/%%d/%%H%%M.xz,60")
1371
+ ap2.add_argument("--log-thrs", metavar="SEC", type=float, default=0.0, help="list active threads every \033[33mSEC\033[0m")
1327
1372
  ap2.add_argument("--log-fk", metavar="REGEX", type=u, default="", help="log filekey params for files where path matches \033[33mREGEX\033[0m; [\033[32m.\033[0m] (a single dot) = all files")
1328
1373
  ap2.add_argument("--bak-flips", action="store_true", help="[up2k] if a client uploads a bitflipped/corrupted chunk, store a copy according to \033[33m--bf-nc\033[0m and \033[33m--bf-dir\033[0m")
1329
1374
  ap2.add_argument("--bf-nc", metavar="NUM", type=int, default=200, help="bak-flips: stop if there's more than \033[33mNUM\033[0m files at \033[33m--kf-dir\033[0m already; default: 6.3 GiB max (200*32M)")
@@ -1526,7 +1571,7 @@ def main(argv = None, rsrc = None) :
1526
1571
  if hard > 0: # -1 == infinite
1527
1572
  nc = min(nc, int(hard / 4))
1528
1573
  except:
1529
- nc = 512
1574
+ nc = 486 # mdns/ssdp restart headroom; select() maxfd is 512 on windows
1530
1575
 
1531
1576
  retry = False
1532
1577
  for fmtr in [RiceFormatter, RiceFormatter, Dodge11874, BasicDodge11874]:
@@ -1571,6 +1616,9 @@ def main(argv = None, rsrc = None) :
1571
1616
  if getattr(al, k1):
1572
1617
  setattr(al, k2, False)
1573
1618
 
1619
+ if not HAVE_IPV6 and al.i == "::":
1620
+ al.i = "0.0.0.0"
1621
+
1574
1622
  al.i = al.i.split(",")
1575
1623
  try:
1576
1624
  if "-" in al.p:
@@ -1619,6 +1667,9 @@ def main(argv = None, rsrc = None) :
1619
1667
  if not hasattr(os, "sendfile"):
1620
1668
  al.no_sendfile = True
1621
1669
 
1670
+ if not hasattr(select, "poll"):
1671
+ al.no_poll = True
1672
+
1622
1673
  # signal.signal(signal.SIGINT, sighandler)
1623
1674
 
1624
1675
  SvcHub(al, dal, argv, "".join(printed)).run()