copyparty 1.16.21__tar.gz → 1.17.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {copyparty-1.16.21 → copyparty-1.17.1}/PKG-INFO +46 -4
- {copyparty-1.16.21 → copyparty-1.17.1}/README.md +45 -3
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/__main__.py +10 -4
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/__version__.py +3 -3
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/authsrv.py +4 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/cert.py +3 -5
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/cfg.py +6 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/httpcli.py +35 -36
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/sutil.py +4 -3
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/svchub.py +8 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/tftpd.py +2 -1
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/th_srv.py +3 -3
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/up2k.py +15 -8
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/util.py +19 -9
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/a/u2c.py +3 -3
- copyparty-1.17.1/copyparty/web/browser.css.gz +0 -0
- copyparty-1.17.1/copyparty/web/browser.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/svcs.html +1 -0
- copyparty-1.17.1/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/PKG-INFO +46 -4
- copyparty-1.16.21/copyparty/web/browser.css.gz +0 -0
- copyparty-1.16.21/copyparty/web/browser.js.gz +0 -0
- copyparty-1.16.21/copyparty/web/util.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/LICENSE +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/bos/bos.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/bos/path.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/broker_mp.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/broker_thr.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/broker_util.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/dxml.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/fsutil.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/ftpd.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/httpconn.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/httpsrv.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/ico.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/mdns.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/metrics.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/mtag.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/multicast.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/pwhash.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/res/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/smbd.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/ssdp.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/star.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/szip.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/th_cli.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/u2idx.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/baguettebox.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/browser.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/browser2.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/cf.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/fuse.py +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/md.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/mde.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/msg.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/rups.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/rups.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/rups.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/shares.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/shares.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/shares.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/splash.html +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/pyproject.toml +0 -0
- {copyparty-1.16.21 → copyparty-1.17.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.17.1
|
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
|
@@ -108,6 +108,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
108
108
|
* [rss feeds](#rss-feeds) - monitor a folder with your RSS reader
|
109
109
|
* [recent uploads](#recent-uploads) - list all recent uploads
|
110
110
|
* [media player](#media-player) - plays almost every audio format there is
|
111
|
+
* [playlists](#playlists) - create and play [m3u8](https://en.wikipedia.org/wiki/M3U) playlists
|
112
|
+
* [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
|
111
113
|
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
112
114
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
113
115
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
@@ -160,7 +162,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
160
162
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
161
163
|
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
162
164
|
* [packages](#packages) - the party might be closer than you think
|
163
|
-
* [arch package](#arch-package) -
|
165
|
+
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
164
166
|
* [fedora package](#fedora-package) - does not exist yet
|
165
167
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
166
168
|
* [nixos module](#nixos-module)
|
@@ -309,6 +311,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
309
311
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
310
312
|
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
311
313
|
* ☑ play video files as audio (converted on server)
|
314
|
+
* ☑ create and play [m3u8 playlists](#playlists)
|
312
315
|
* ☑ image gallery with webm player
|
313
316
|
* ☑ textfile browser with syntax hilighting
|
314
317
|
* ☑ [thumbnails](#thumbnails)
|
@@ -472,6 +475,9 @@ upgrade notes
|
|
472
475
|
|
473
476
|
"frequently" asked questions
|
474
477
|
|
478
|
+
* CopyParty?
|
479
|
+
* nope! the name is either copyparty (all-lowercase) or Copyparty -- it's [one word](https://en.wiktionary.org/wiki/copyparty) after all :>
|
480
|
+
|
475
481
|
* can I change the 🌲 spinning pine-tree loading animation?
|
476
482
|
* [yeah...](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#boring-loader-spinner) :-(
|
477
483
|
|
@@ -970,6 +976,7 @@ semi-intentional limitations:
|
|
970
976
|
|
971
977
|
* cleanup of expired shares only works when global option `e2d` is set, and/or at least one volume on the server has volflag `e2d`
|
972
978
|
* only folders from the same volume are shared; if you are sharing a folder which contains other volumes, then the contents of those volumes will not be available
|
979
|
+
* if you change [password hashing](#password-hashing) settings after creating a password-protected share, then that share will stop working
|
973
980
|
* related to [IdP volumes being forgotten on shutdown](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#idp-volumes-are-forgotten-on-shutdown), any shares pointing into a user's IdP volume will be unavailable until that user makes their first request after a restart
|
974
981
|
* no option to "delete after first access" because tricky
|
975
982
|
* when linking something to discord (for example) it'll get accessed by their scraper and that would count as a hit
|
@@ -1102,6 +1109,7 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
1102
1109
|
* `[full]` does a full preload by downloading the entire next file; good for unreliable connections, bad for slow connections
|
1103
1110
|
* `[~s]` toggles the seekbar waveform display
|
1104
1111
|
* `[/np]` enables buttons to copy the now-playing info as an irc message
|
1112
|
+
* `[📻]` enables buttons to create an [m3u playlist](#playlists) with the selected songs
|
1105
1113
|
* `[os-ctl]` makes it possible to control audio playback from the lockscreen of your device (enables [mediasession](https://developer.mozilla.org/en-US/docs/Web/API/MediaSession))
|
1106
1114
|
* `[seek]` allows seeking with lockscreen controls (buggy on some devices)
|
1107
1115
|
* `[art]` shows album art on the lockscreen
|
@@ -1120,11 +1128,39 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
1120
1128
|
* "transcode to":
|
1121
1129
|
* `[opus]` produces an `opus` whenever transcoding is necessary (the best choice on Android and PCs)
|
1122
1130
|
* `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1
|
1123
|
-
* `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the
|
1131
|
+
* `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the most part
|
1124
1132
|
* `[mp3]` -- the myth, the legend, the undying master of mediocre sound quality that definitely works everywhere
|
1125
1133
|
* "tint" reduces the contrast of the playback bar
|
1126
1134
|
|
1127
1135
|
|
1136
|
+
### playlists
|
1137
|
+
|
1138
|
+
create and play [m3u8](https://en.wikipedia.org/wiki/M3U) playlists -- see example [text](https://a.ocv.me/pub/demo/music/?doc=example-playlist.m3u) and [player](https://a.ocv.me/pub/demo/music/#m3u=example-playlist.m3u)
|
1139
|
+
|
1140
|
+
click a file with the extension `m3u` or `m3u8` (for example `mixtape.m3u` or `touhou.m3u8` ) and you get two choices: Play / Edit
|
1141
|
+
|
1142
|
+
playlists can include songs across folders anywhere on the server, but filekeys/dirkeys are NOT supported, so the listener must have read-access or get-access to the files
|
1143
|
+
|
1144
|
+
|
1145
|
+
### creating a playlist
|
1146
|
+
|
1147
|
+
with a standalone mediaplayer or copyparty
|
1148
|
+
|
1149
|
+
you can use foobar2000, deadbeef, just about any standalone player should work -- but you might need to edit the filepaths in the playlist so they fit with the server-URLs
|
1150
|
+
|
1151
|
+
alternatively, you can create the playlist using copyparty itself:
|
1152
|
+
|
1153
|
+
* open the `[🎺]` media-player-settings tab and enable the `[📻]` create-playlist feature -- this adds two new buttons in the bottom-right tray, `[📻add]` and `[📻copy]` which appear when you listen to music, or when you select a few audiofiles
|
1154
|
+
|
1155
|
+
* click the `📻add` button while a song is playing (or when you've selected some songs) and they'll be added to "the list" (you can't see it yet)
|
1156
|
+
|
1157
|
+
* at any time, click `📻copy` to send the playlist to your clipboard
|
1158
|
+
* you can then continue adding more songs if you'd like
|
1159
|
+
* if you want to wipe the playlist and start from scratch, just refresh the page
|
1160
|
+
|
1161
|
+
* create a new textfile, name it `something.m3u` and paste the playlist there
|
1162
|
+
|
1163
|
+
|
1128
1164
|
### audio equalizer
|
1129
1165
|
|
1130
1166
|
and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
@@ -2229,10 +2265,14 @@ if your distro/OS is not mentioned below, there might be some hints in the [«on
|
|
2229
2265
|
|
2230
2266
|
## arch package
|
2231
2267
|
|
2232
|
-
|
2268
|
+
`pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
2233
2269
|
|
2234
2270
|
it comes with a [systemd service](./contrib/package/arch/copyparty.service) and expects to find one or more [config files](./docs/example.conf) in `/etc/copyparty.d/`
|
2235
2271
|
|
2272
|
+
after installing it, you may want to `cp /usr/lib/systemd/system/copyparty.service /etc/systemd/system/` and then `vim /etc/systemd/system/copyparty.service` to change what user/group it is running as (you only need to do this once)
|
2273
|
+
|
2274
|
+
NOTE: there used to be an aur package; this evaporated when copyparty was adopted by the official archlinux repos. If you're still using the aur package, please move
|
2275
|
+
|
2236
2276
|
|
2237
2277
|
## fedora package
|
2238
2278
|
|
@@ -2446,6 +2486,8 @@ copyparty returns a truncated sha512sum of your PUT/POST as base64; you can gene
|
|
2446
2486
|
|
2447
2487
|
you can provide passwords using header `PW: hunter2`, cookie `cppwd=hunter2`, url-param `?pw=hunter2`, or with basic-authentication (either as the username or password)
|
2448
2488
|
|
2489
|
+
> for basic-authentication, all of the following are accepted: `password` / `whatever:password` / `password:whatever` (the username is ignored)
|
2490
|
+
|
2449
2491
|
NOTE: curl will not send the original filename if you use `-T` combined with url-params! Also, make sure to always leave a trailing slash in URLs unless you want to override the filename
|
2450
2492
|
|
2451
2493
|
|
@@ -50,6 +50,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
50
50
|
* [rss feeds](#rss-feeds) - monitor a folder with your RSS reader
|
51
51
|
* [recent uploads](#recent-uploads) - list all recent uploads
|
52
52
|
* [media player](#media-player) - plays almost every audio format there is
|
53
|
+
* [playlists](#playlists) - create and play [m3u8](https://en.wikipedia.org/wiki/M3U) playlists
|
54
|
+
* [creating a playlist](#creating-a-playlist) - with a standalone mediaplayer or copyparty
|
53
55
|
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
54
56
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
55
57
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
@@ -102,7 +104,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
102
104
|
* [feature chickenbits](#feature-chickenbits) - buggy feature? rip it out
|
103
105
|
* [feature beefybits](#feature-beefybits) - force-enable features with known issues on your OS/env
|
104
106
|
* [packages](#packages) - the party might be closer than you think
|
105
|
-
* [arch package](#arch-package) -
|
107
|
+
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
106
108
|
* [fedora package](#fedora-package) - does not exist yet
|
107
109
|
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
|
108
110
|
* [nixos module](#nixos-module)
|
@@ -251,6 +253,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
251
253
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
252
254
|
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
253
255
|
* ☑ play video files as audio (converted on server)
|
256
|
+
* ☑ create and play [m3u8 playlists](#playlists)
|
254
257
|
* ☑ image gallery with webm player
|
255
258
|
* ☑ textfile browser with syntax hilighting
|
256
259
|
* ☑ [thumbnails](#thumbnails)
|
@@ -414,6 +417,9 @@ upgrade notes
|
|
414
417
|
|
415
418
|
"frequently" asked questions
|
416
419
|
|
420
|
+
* CopyParty?
|
421
|
+
* nope! the name is either copyparty (all-lowercase) or Copyparty -- it's [one word](https://en.wiktionary.org/wiki/copyparty) after all :>
|
422
|
+
|
417
423
|
* can I change the 🌲 spinning pine-tree loading animation?
|
418
424
|
* [yeah...](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#boring-loader-spinner) :-(
|
419
425
|
|
@@ -912,6 +918,7 @@ semi-intentional limitations:
|
|
912
918
|
|
913
919
|
* cleanup of expired shares only works when global option `e2d` is set, and/or at least one volume on the server has volflag `e2d`
|
914
920
|
* only folders from the same volume are shared; if you are sharing a folder which contains other volumes, then the contents of those volumes will not be available
|
921
|
+
* if you change [password hashing](#password-hashing) settings after creating a password-protected share, then that share will stop working
|
915
922
|
* related to [IdP volumes being forgotten on shutdown](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#idp-volumes-are-forgotten-on-shutdown), any shares pointing into a user's IdP volume will be unavailable until that user makes their first request after a restart
|
916
923
|
* no option to "delete after first access" because tricky
|
917
924
|
* when linking something to discord (for example) it'll get accessed by their scraper and that would count as a hit
|
@@ -1044,6 +1051,7 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
1044
1051
|
* `[full]` does a full preload by downloading the entire next file; good for unreliable connections, bad for slow connections
|
1045
1052
|
* `[~s]` toggles the seekbar waveform display
|
1046
1053
|
* `[/np]` enables buttons to copy the now-playing info as an irc message
|
1054
|
+
* `[📻]` enables buttons to create an [m3u playlist](#playlists) with the selected songs
|
1047
1055
|
* `[os-ctl]` makes it possible to control audio playback from the lockscreen of your device (enables [mediasession](https://developer.mozilla.org/en-US/docs/Web/API/MediaSession))
|
1048
1056
|
* `[seek]` allows seeking with lockscreen controls (buggy on some devices)
|
1049
1057
|
* `[art]` shows album art on the lockscreen
|
@@ -1062,11 +1070,39 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
1062
1070
|
* "transcode to":
|
1063
1071
|
* `[opus]` produces an `opus` whenever transcoding is necessary (the best choice on Android and PCs)
|
1064
1072
|
* `[awo]` is `opus` in a `weba` file, good for iPhones (iOS 17.5 and newer) but Apple is still fixing some state-confusion bugs as of iOS 18.2.1
|
1065
|
-
* `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the
|
1073
|
+
* `[caf]` is `opus` in a `caf` file, good for iPhones (iOS 11 through 17), technically unsupported by Apple but works for the most part
|
1066
1074
|
* `[mp3]` -- the myth, the legend, the undying master of mediocre sound quality that definitely works everywhere
|
1067
1075
|
* "tint" reduces the contrast of the playback bar
|
1068
1076
|
|
1069
1077
|
|
1078
|
+
### playlists
|
1079
|
+
|
1080
|
+
create and play [m3u8](https://en.wikipedia.org/wiki/M3U) playlists -- see example [text](https://a.ocv.me/pub/demo/music/?doc=example-playlist.m3u) and [player](https://a.ocv.me/pub/demo/music/#m3u=example-playlist.m3u)
|
1081
|
+
|
1082
|
+
click a file with the extension `m3u` or `m3u8` (for example `mixtape.m3u` or `touhou.m3u8` ) and you get two choices: Play / Edit
|
1083
|
+
|
1084
|
+
playlists can include songs across folders anywhere on the server, but filekeys/dirkeys are NOT supported, so the listener must have read-access or get-access to the files
|
1085
|
+
|
1086
|
+
|
1087
|
+
### creating a playlist
|
1088
|
+
|
1089
|
+
with a standalone mediaplayer or copyparty
|
1090
|
+
|
1091
|
+
you can use foobar2000, deadbeef, just about any standalone player should work -- but you might need to edit the filepaths in the playlist so they fit with the server-URLs
|
1092
|
+
|
1093
|
+
alternatively, you can create the playlist using copyparty itself:
|
1094
|
+
|
1095
|
+
* open the `[🎺]` media-player-settings tab and enable the `[📻]` create-playlist feature -- this adds two new buttons in the bottom-right tray, `[📻add]` and `[📻copy]` which appear when you listen to music, or when you select a few audiofiles
|
1096
|
+
|
1097
|
+
* click the `📻add` button while a song is playing (or when you've selected some songs) and they'll be added to "the list" (you can't see it yet)
|
1098
|
+
|
1099
|
+
* at any time, click `📻copy` to send the playlist to your clipboard
|
1100
|
+
* you can then continue adding more songs if you'd like
|
1101
|
+
* if you want to wipe the playlist and start from scratch, just refresh the page
|
1102
|
+
|
1103
|
+
* create a new textfile, name it `something.m3u` and paste the playlist there
|
1104
|
+
|
1105
|
+
|
1070
1106
|
### audio equalizer
|
1071
1107
|
|
1072
1108
|
and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
@@ -2171,10 +2207,14 @@ if your distro/OS is not mentioned below, there might be some hints in the [«on
|
|
2171
2207
|
|
2172
2208
|
## arch package
|
2173
2209
|
|
2174
|
-
|
2210
|
+
`pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
|
2175
2211
|
|
2176
2212
|
it comes with a [systemd service](./contrib/package/arch/copyparty.service) and expects to find one or more [config files](./docs/example.conf) in `/etc/copyparty.d/`
|
2177
2213
|
|
2214
|
+
after installing it, you may want to `cp /usr/lib/systemd/system/copyparty.service /etc/systemd/system/` and then `vim /etc/systemd/system/copyparty.service` to change what user/group it is running as (you only need to do this once)
|
2215
|
+
|
2216
|
+
NOTE: there used to be an aur package; this evaporated when copyparty was adopted by the official archlinux repos. If you're still using the aur package, please move
|
2217
|
+
|
2178
2218
|
|
2179
2219
|
## fedora package
|
2180
2220
|
|
@@ -2388,6 +2428,8 @@ copyparty returns a truncated sha512sum of your PUT/POST as base64; you can gene
|
|
2388
2428
|
|
2389
2429
|
you can provide passwords using header `PW: hunter2`, cookie `cppwd=hunter2`, url-param `?pw=hunter2`, or with basic-authentication (either as the username or password)
|
2390
2430
|
|
2431
|
+
> for basic-authentication, all of the following are accepted: `password` / `whatever:password` / `password:whatever` (the username is ignored)
|
2432
|
+
|
2391
2433
|
NOTE: curl will not send the original filename if you use `-T` combined with url-params! Also, make sure to always leave a trailing slash in URLs unless you want to override the filename
|
2392
2434
|
|
2393
2435
|
|
@@ -995,6 +995,9 @@ def add_upload(ap):
|
|
995
995
|
ap2 = ap.add_argument_group('upload options')
|
996
996
|
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless \033[33m-ed\033[0m")
|
997
997
|
ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip")
|
998
|
+
ap2.add_argument("--put-name", metavar="TXT", type=u, default="put-{now.6f}-{cip}.bin", help="filename for nameless uploads (when uploader doesn't provide a name); default is [\033[32mput-UNIXTIME-IP.bin\033[0m] (the \033[32m.6f\033[0m means six decimal places) (volflag=put_name)")
|
999
|
+
ap2.add_argument("--put-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for PUT/WebDAV uploads: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=put_ck)")
|
1000
|
+
ap2.add_argument("--bup-ck", metavar="ALG", type=u, default="sha512", help="default checksum-hasher for bup/basic-uploader: no / md5 / sha1 / sha256 / sha512 / b2 / blake2 / b2s / blake2s (volflag=bup_ck)")
|
998
1001
|
ap2.add_argument("--unpost", metavar="SEC", type=int, default=3600*12, help="grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled, default=12h")
|
999
1002
|
ap2.add_argument("--u2abort", metavar="NUM", type=int, default=1, help="clients can abort incomplete uploads by using the unpost tab (requires \033[33m-e2d\033[0m). [\033[32m0\033[0m] = never allowed (disable feature), [\033[32m1\033[0m] = allow if client has the same IP as the upload AND is using the same account, [\033[32m2\033[0m] = just check the IP, [\033[32m3\033[0m] = just check account-name (volflag=u2abort)")
|
1000
1003
|
ap2.add_argument("--blank-wt", metavar="SEC", type=int, default=300, help="file write grace period (any client can write to a blank file last-modified more recently than \033[33mSEC\033[0m seconds ago)")
|
@@ -1017,7 +1020,7 @@ def add_upload(ap):
|
|
1017
1020
|
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)")
|
1018
1021
|
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")
|
1019
1022
|
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")
|
1020
|
-
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
|
1023
|
+
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good when latency is low (same-country), 2~4 for android-clients, 2~6 for cross-atlantic. Max is 6 in most browsers. Big values increase network-speed but may reduce HDD-speed")
|
1021
1024
|
ap2.add_argument("--u2sz", metavar="N,N,N", type=u, default="1,64,96", help="web-client: default upload chunksize (MiB); sets \033[33mmin,default,max\033[0m in the settings gui. Each HTTP POST will aim for \033[33mdefault\033[0m, and never exceed \033[33mmax\033[0m. Cloudflare max is 96. Big values are good for cross-atlantic but may increase HDD fragmentation on some FS. Disable this optimization with [\033[32m1,1,1\033[0m]")
|
1022
1025
|
ap2.add_argument("--u2ow", metavar="NUM", type=int, default=0, help="web-client: default setting for when to replace/overwrite existing files; [\033[32m0\033[0m]=never, [\033[32m1\033[0m]=if-client-newer, [\033[32m2\033[0m]=always (volflag=u2ow)")
|
1023
1026
|
ap2.add_argument("--u2sort", metavar="TXT", type=u, default="s", help="upload order; [\033[32ms\033[0m]=smallest-first, [\033[32mn\033[0m]=alphabetical, [\033[32mfs\033[0m]=force-s, [\033[32mfn\033[0m]=force-n -- alphabetical is a bit slower on fiber/LAN but makes it easier to eyeball if everything went fine")
|
@@ -1300,6 +1303,9 @@ def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
|
1300
1303
|
ap2.add_argument("--fk-salt", metavar="SALT", type=u, default=fk_salt, help="per-file accesskey salt; used to generate unpredictable URLs for hidden files")
|
1301
1304
|
ap2.add_argument("--dk-salt", metavar="SALT", type=u, default=dk_salt, help="per-directory accesskey salt; used to generate unpredictable URLs to share folders with users who only have the 'get' permission")
|
1302
1305
|
ap2.add_argument("--warksalt", metavar="SALT", type=u, default="hunter2", help="up2k file-hash salt; serves no purpose, no reason to change this (but delete all databases if you do)")
|
1306
|
+
ap2.add_argument("--show-ah-salt", action="store_true", help="on startup, print the effective value of \033[33m--ah-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
1307
|
+
ap2.add_argument("--show-fk-salt", action="store_true", help="on startup, print the effective value of \033[33m--fk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
1308
|
+
ap2.add_argument("--show-dk-salt", action="store_true", help="on startup, print the effective value of \033[33m--dk-salt\033[0m (the autogenerated value in $XDG_CONFIG_HOME unless otherwise specified)")
|
1303
1309
|
|
1304
1310
|
|
1305
1311
|
def add_shutdown(ap):
|
@@ -1341,7 +1347,7 @@ def add_admin(ap):
|
|
1341
1347
|
|
1342
1348
|
def add_thumbnail(ap):
|
1343
1349
|
th_ram = (RAM_AVAIL or RAM_TOTAL or 9) * 0.6
|
1344
|
-
th_ram = int(max(min(th_ram, 6),
|
1350
|
+
th_ram = int(max(min(th_ram, 6), 0.3) * 10) / 10
|
1345
1351
|
ap2 = ap.add_argument_group('thumbnail options')
|
1346
1352
|
ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails (volflag=dthumb)")
|
1347
1353
|
ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails (volflag=dvthumb)")
|
@@ -1368,8 +1374,8 @@ def add_thumbnail(ap):
|
|
1368
1374
|
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")
|
1369
1375
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,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")
|
1370
1376
|
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")
|
1371
|
-
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")
|
1372
|
-
ap2.add_argument("--th-spec-cnv", metavar="T
|
1377
|
+
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,oga,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")
|
1378
|
+
ap2.add_argument("--th-spec-cnv", metavar="T", type=u, default="it,itgz,itxz,itz,mdgz,mdxz,mdz,mo3,mod,s3m,s3gz,s3xz,s3z,xm,xmgz,xmxz,xmz,xpk", help="audio formats which provoke https://trac.ffmpeg.org/ticket/10797 (huge ram usage for s3xmodit spectrograms)")
|
1373
1379
|
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, cbz=jpg.cbz", help="audio/image formats to decompress before passing to ffmpeg")
|
1374
1380
|
|
1375
1381
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2025,
|
3
|
+
VERSION = (1, 17, 1)
|
4
|
+
CODENAME = "mixtape.m3u"
|
5
|
+
BUILD_DT = (2025, 5, 18)
|
6
6
|
|
7
7
|
S_VERSION = ".".join(map(str, VERSION))
|
8
8
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
@@ -2067,6 +2067,10 @@ class AuthSrv(object):
|
|
2067
2067
|
if len(zs) == 3: # fc5 => ffcc55
|
2068
2068
|
vol.flags["tcolor"] = "".join([x * 2 for x in zs])
|
2069
2069
|
|
2070
|
+
# volflag syntax currently doesn't allow for ':' in value
|
2071
|
+
zs = vol.flags["put_name"]
|
2072
|
+
vol.flags["put_name2"] = zs.replace("{now.", "{now:.")
|
2073
|
+
|
2070
2074
|
if vol.flags.get("neversymlink"):
|
2071
2075
|
vol.flags["hardlinkonly"] = True # was renamed
|
2072
2076
|
if vol.flags.get("hardlinkonly"):
|
@@ -1,13 +1,11 @@
|
|
1
1
|
import calendar
|
2
2
|
import errno
|
3
|
-
import filecmp
|
4
3
|
import json
|
5
4
|
import os
|
6
|
-
import shutil
|
7
5
|
import time
|
8
6
|
|
9
7
|
from .__init__ import ANYWIN
|
10
|
-
from .util import Netdev, load_resource, runcmd,
|
8
|
+
from .util import Netdev, atomic_move, load_resource, runcmd, wunlink
|
11
9
|
|
12
10
|
HAVE_CFSSL = not os.environ.get("PRTY_NO_CFSSL")
|
13
11
|
|
@@ -118,7 +116,7 @@ def _gen_ca(log , args):
|
|
118
116
|
wunlink(nlog, bname + ".key", VF)
|
119
117
|
except:
|
120
118
|
pass
|
121
|
-
|
119
|
+
atomic_move(nlog, bname + "-key.pem", bname + ".key", VF)
|
122
120
|
wunlink(nlog, bname + ".csr", VF)
|
123
121
|
|
124
122
|
log("cert", "new ca OK", 2)
|
@@ -211,7 +209,7 @@ def _gen_srv(log , args, netdevs ):
|
|
211
209
|
wunlink(nlog, bname + ".key", VF)
|
212
210
|
except:
|
213
211
|
pass
|
214
|
-
|
212
|
+
atomic_move(nlog, bname + "-key.pem", bname + ".key", VF)
|
215
213
|
wunlink(nlog, bname + ".csr", VF)
|
216
214
|
|
217
215
|
with open(os.path.join(args.crt_dir, "ca.pem"), "rb") as f:
|
@@ -75,6 +75,7 @@ def vf_vmap() :
|
|
75
75
|
"th_x3": "th3x",
|
76
76
|
}
|
77
77
|
for k in (
|
78
|
+
"bup_ck",
|
78
79
|
"dbd",
|
79
80
|
"forget_ip",
|
80
81
|
"hsortn",
|
@@ -95,6 +96,8 @@ def vf_vmap() :
|
|
95
96
|
"og_title_i",
|
96
97
|
"og_tpl",
|
97
98
|
"og_ua",
|
99
|
+
"put_ck",
|
100
|
+
"put_name",
|
98
101
|
"mv_retry",
|
99
102
|
"rm_retry",
|
100
103
|
"sort",
|
@@ -165,6 +168,9 @@ flagcats = {
|
|
165
168
|
"daw": "enable full WebDAV write support (dangerous);\nPUT-operations will now \033[1;31mOVERWRITE\033[0;35m existing files",
|
166
169
|
"nosub": "forces all uploads into the top folder of the vfs",
|
167
170
|
"magic": "enables filetype detection for nameless uploads",
|
171
|
+
"put_name": "fallback filename for nameless uploads",
|
172
|
+
"put_ck": "default checksum-hasher for PUT/WebDAV uploads",
|
173
|
+
"bup_ck": "default checksum-hasher for bup/basic uploads",
|
168
174
|
"gz": "allows server-side gzip compression of uploads with ?gz",
|
169
175
|
"xz": "allows server-side lzma compression of uploads with ?xz",
|
170
176
|
"pk": "forces server-side compression, optional arg: xz,9",
|
@@ -113,7 +113,6 @@ from .util import (
|
|
113
113
|
vol_san,
|
114
114
|
vroots,
|
115
115
|
vsplit,
|
116
|
-
wrename,
|
117
116
|
wunlink,
|
118
117
|
yieldfile,
|
119
118
|
)
|
@@ -1408,7 +1407,7 @@ class HttpCli(object):
|
|
1408
1407
|
desc = "%s - %s" % (tag_a, tag_t) if tag_t and tag_a else (tag_t or tag_a)
|
1409
1408
|
desc = html_escape(desc, True, True) if desc else title
|
1410
1409
|
mime = html_escape(guess_mime(title))
|
1411
|
-
lmod = formatdate(i["ts"])
|
1410
|
+
lmod = formatdate(max(0, i["ts"]))
|
1412
1411
|
zsa = (iurl, iurl, title, desc, lmod, iurl, mime, i["sz"])
|
1413
1412
|
zs = (
|
1414
1413
|
"""\
|
@@ -1565,7 +1564,7 @@ class HttpCli(object):
|
|
1565
1564
|
for x in fgen:
|
1566
1565
|
rp = vjoin(vtop, x["vp"])
|
1567
1566
|
st = x["st"]
|
1568
|
-
mtime = st.st_mtime
|
1567
|
+
mtime = max(0, st.st_mtime)
|
1569
1568
|
if stat.S_ISLNK(st.st_mode):
|
1570
1569
|
try:
|
1571
1570
|
st = bos.stat(os.path.join(tap, x["vp"]))
|
@@ -2091,8 +2090,7 @@ class HttpCli(object):
|
|
2091
2090
|
suffix = "-{:.6f}-{}".format(time.time(), self.dip())
|
2092
2091
|
nameless = not fn
|
2093
2092
|
if nameless:
|
2094
|
-
|
2095
|
-
fn = "put" + suffix
|
2093
|
+
fn = vfs.flags["put_name2"].format(now=time.time(), cip=self.dip())
|
2096
2094
|
|
2097
2095
|
params = {"suffix": suffix, "fdir": fdir}
|
2098
2096
|
if self.args.nw:
|
@@ -2171,28 +2169,26 @@ class HttpCli(object):
|
|
2171
2169
|
# small toctou, but better than clobbering a hardlink
|
2172
2170
|
wunlink(self.log, path, vfs.flags)
|
2173
2171
|
|
2174
|
-
halg = "sha512"
|
2175
2172
|
hasher = None
|
2176
2173
|
copier = hashcopy
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
raise Pebkac(500, "unknown hash alg")
|
2174
|
+
halg = self.ouparam.get("ck") or self.headers.get("ck") or vfs.flags["put_ck"]
|
2175
|
+
if halg == "sha512":
|
2176
|
+
pass
|
2177
|
+
elif halg == "no":
|
2178
|
+
copier = justcopy
|
2179
|
+
halg = ""
|
2180
|
+
elif halg == "md5":
|
2181
|
+
hasher = hashlib.md5(**USED4SEC)
|
2182
|
+
elif halg == "sha1":
|
2183
|
+
hasher = hashlib.sha1(**USED4SEC)
|
2184
|
+
elif halg == "sha256":
|
2185
|
+
hasher = hashlib.sha256(**USED4SEC)
|
2186
|
+
elif halg in ("blake2", "b2"):
|
2187
|
+
hasher = hashlib.blake2b(**USED4SEC)
|
2188
|
+
elif halg in ("blake2s", "b2s"):
|
2189
|
+
hasher = hashlib.blake2s(**USED4SEC)
|
2190
|
+
else:
|
2191
|
+
raise Pebkac(500, "unknown hash alg")
|
2196
2192
|
|
2197
2193
|
f, fn = ren_open(fn, *open_a, **params)
|
2198
2194
|
try:
|
@@ -2917,7 +2913,8 @@ class HttpCli(object):
|
|
2917
2913
|
self.parser.drop()
|
2918
2914
|
|
2919
2915
|
self.log("logout " + self.uname)
|
2920
|
-
self.
|
2916
|
+
if not self.uname.startswith("s_"):
|
2917
|
+
self.asrv.forget_session(self.conn.hsrv.broker, self.uname)
|
2921
2918
|
self.get_pwd_cookie("x")
|
2922
2919
|
|
2923
2920
|
dst = self.args.SRS + "?h"
|
@@ -3068,15 +3065,18 @@ class HttpCli(object):
|
|
3068
3065
|
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
3069
3066
|
self._assert_safe_rem(rem)
|
3070
3067
|
|
3071
|
-
halg = "sha512"
|
3072
3068
|
hasher = None
|
3073
|
-
copier = hashcopy
|
3074
3069
|
if nohash:
|
3075
3070
|
halg = ""
|
3076
3071
|
copier = justcopy
|
3077
|
-
|
3078
|
-
|
3079
|
-
|
3072
|
+
else:
|
3073
|
+
copier = hashcopy
|
3074
|
+
halg = (
|
3075
|
+
self.ouparam.get("ck") or self.headers.get("ck") or vfs.flags["bup_ck"]
|
3076
|
+
)
|
3077
|
+
if halg == "sha512":
|
3078
|
+
pass
|
3079
|
+
elif halg == "no":
|
3080
3080
|
copier = justcopy
|
3081
3081
|
halg = ""
|
3082
3082
|
elif halg == "md5":
|
@@ -3089,8 +3089,6 @@ class HttpCli(object):
|
|
3089
3089
|
hasher = hashlib.blake2b(**USED4SEC)
|
3090
3090
|
elif halg in ("blake2s", "b2s"):
|
3091
3091
|
hasher = hashlib.blake2s(**USED4SEC)
|
3092
|
-
elif halg == "sha512":
|
3093
|
-
pass
|
3094
3092
|
else:
|
3095
3093
|
raise Pebkac(500, "unknown hash alg")
|
3096
3094
|
|
@@ -3552,7 +3550,7 @@ class HttpCli(object):
|
|
3552
3550
|
except:
|
3553
3551
|
pass
|
3554
3552
|
if dp:
|
3555
|
-
|
3553
|
+
atomic_move(self.log, fp, os.path.join(dp, mfile2), vfs.flags)
|
3556
3554
|
|
3557
3555
|
p_field, _, p_data = next(self.parser.gen)
|
3558
3556
|
if p_field != "body":
|
@@ -3961,7 +3959,7 @@ class HttpCli(object):
|
|
3961
3959
|
for ext in ("", ".gz"):
|
3962
3960
|
if ptop is not None:
|
3963
3961
|
sz = job["size"]
|
3964
|
-
file_ts = job["lmod"]
|
3962
|
+
file_ts = max(0, job["lmod"])
|
3965
3963
|
editions["plain"] = (ap_data, sz)
|
3966
3964
|
break
|
3967
3965
|
|
@@ -5482,6 +5480,7 @@ class HttpCli(object):
|
|
5482
5480
|
raise Pebkac(400, "selected file not found on disk: [%s]" % (fn,))
|
5483
5481
|
|
5484
5482
|
pw = req.get("pw") or ""
|
5483
|
+
pw = self.asrv.ah.hash(pw)
|
5485
5484
|
now = int(time.time())
|
5486
5485
|
sexp = req["exp"]
|
5487
5486
|
exp = int(sexp) if sexp else 0
|
@@ -6099,7 +6098,7 @@ class HttpCli(object):
|
|
6099
6098
|
margin = "-"
|
6100
6099
|
|
6101
6100
|
sz = inf.st_size
|
6102
|
-
zd = datetime.fromtimestamp(linf.st_mtime, UTC)
|
6101
|
+
zd = datetime.fromtimestamp(max(0, linf.st_mtime), UTC)
|
6103
6102
|
dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
|
6104
6103
|
zd.year,
|
6105
6104
|
zd.month,
|
@@ -11,6 +11,9 @@ from .bos import bos
|
|
11
11
|
from .th_cli import ThumbCli
|
12
12
|
from .util import UTC, vjoin, vol_san
|
13
13
|
|
14
|
+
TAR_NO_OPUS = set("aac|m4a|mp3|oga|ogg|opus|wma".split("|"))
|
15
|
+
|
16
|
+
|
14
17
|
class StreamArc(object):
|
15
18
|
def __init__(
|
16
19
|
self,
|
@@ -76,9 +79,7 @@ def enthumb(
|
|
76
79
|
) :
|
77
80
|
rem = f["vp"]
|
78
81
|
ext = rem.rsplit(".", 1)[-1].lower()
|
79
|
-
if (fmt == "mp3" and ext == "mp3") or (
|
80
|
-
fmt == "opus" and ext in "aac|m4a|mp3|ogg|opus|wma".split("|")
|
81
|
-
):
|
82
|
+
if (fmt == "mp3" and ext == "mp3") or (fmt == "opus" and ext in TAR_NO_OPUS):
|
82
83
|
raise Exception()
|
83
84
|
|
84
85
|
vp = vjoin(vtop, rem.split("/", 1)[1])
|
@@ -247,6 +247,14 @@ class SvcHub(object):
|
|
247
247
|
setattr(args, "ipu_iu", iu)
|
248
248
|
setattr(args, "ipu_nm", nm)
|
249
249
|
|
250
|
+
for zs in "ah_salt fk_salt dk_salt".split():
|
251
|
+
if getattr(args, "show_%s" % (zs,)):
|
252
|
+
self.log("root", "effective %s is %s" % (zs, getattr(args, zs)))
|
253
|
+
|
254
|
+
if args.ah_cli or args.ah_gen:
|
255
|
+
args.no_ses = True
|
256
|
+
args.shr = ""
|
257
|
+
|
250
258
|
if not self.args.no_ses:
|
251
259
|
self.setup_session_db()
|
252
260
|
|
@@ -281,6 +281,7 @@ class Tftpd(object):
|
|
281
281
|
if not ptn or not ptn.match(fn.lower()):
|
282
282
|
return None
|
283
283
|
|
284
|
+
tsdt = datetime.fromtimestamp
|
284
285
|
vn, rem = self.asrv.vfs.get(vpath, "*", True, False)
|
285
286
|
fsroot, vfs_ls, vfs_virt = vn.ls(
|
286
287
|
rem,
|
@@ -293,7 +294,7 @@ class Tftpd(object):
|
|
293
294
|
dirs1 = [(v.st_mtime, v.st_size, k + "/") for k, v in vfs_ls if k in dnames]
|
294
295
|
fils1 = [(v.st_mtime, v.st_size, k) for k, v in vfs_ls if k not in dnames]
|
295
296
|
real1 = dirs1 + fils1
|
296
|
-
realt = [(
|
297
|
+
realt = [(tsdt(max(0, mt), UTC), sz, fn) for mt, sz, fn in real1]
|
297
298
|
reals = [
|
298
299
|
(
|
299
300
|
"%04d-%02d-%02d %02d:%02d:%02d"
|
@@ -24,13 +24,13 @@ from .util import (
|
|
24
24
|
Cooldown,
|
25
25
|
Daemon,
|
26
26
|
afsenc,
|
27
|
+
atomic_move,
|
27
28
|
fsenc,
|
28
29
|
min_ex,
|
29
30
|
runcmd,
|
30
31
|
statdir,
|
31
32
|
ub64enc,
|
32
33
|
vsplit,
|
33
|
-
wrename,
|
34
34
|
wunlink,
|
35
35
|
)
|
36
36
|
|
@@ -409,7 +409,7 @@ class ThumbSrv(object):
|
|
409
409
|
wunlink(self.log, ap_unpk, vn.flags)
|
410
410
|
|
411
411
|
try:
|
412
|
-
|
412
|
+
atomic_move(self.log, ttpath, tpath, vn.flags)
|
413
413
|
except Exception as ex:
|
414
414
|
if not os.path.exists(tpath):
|
415
415
|
t = "failed to move [%s] to [%s]: %r"
|
@@ -673,7 +673,7 @@ class ThumbSrv(object):
|
|
673
673
|
except:
|
674
674
|
pass
|
675
675
|
else:
|
676
|
-
|
676
|
+
atomic_move(self.log, wtpath, tpath, vn.flags)
|
677
677
|
|
678
678
|
def conv_spec(self, abspath , tpath , fmt , vn ) :
|
679
679
|
ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|