copyparty 1.13.4__tar.gz → 1.13.6__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.13.4 → copyparty-1.13.6}/PKG-INFO +9 -4
- {copyparty-1.13.4 → copyparty-1.13.6}/README.md +8 -3
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/__main__.py +10 -3
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/__version__.py +2 -2
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/broker_util.py +3 -3
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/httpcli.py +52 -42
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/th_cli.py +3 -2
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/th_srv.py +16 -8
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/up2k.py +44 -28
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/util.py +1 -1
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/a/u2c.py +123 -38
- copyparty-1.13.6/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.13.6/copyparty/web/browser.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/svcs.html +13 -12
- copyparty-1.13.6/copyparty/web/ui.css.gz +0 -0
- copyparty-1.13.6/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.13.6/copyparty/web/util.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/PKG-INFO +9 -4
- copyparty-1.13.4/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.13.4/copyparty/web/browser.js.gz +0 -0
- copyparty-1.13.4/copyparty/web/ui.css.gz +0 -0
- copyparty-1.13.4/copyparty/web/up2k.js.gz +0 -0
- copyparty-1.13.4/copyparty/web/util.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/LICENSE +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/authsrv.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/bos/bos.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/bos/path.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/broker_mp.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/broker_thr.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/cert.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/cfg.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/dxml.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/fsutil.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/ftpd.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/httpconn.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/httpsrv.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/ico.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/mdns.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/metrics.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/mtag.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/multicast.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/pwhash.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/res/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/smbd.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/ssdp.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/star.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/sutil.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/svchub.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/szip.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/tftpd.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/u2idx.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/browser.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/browser.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/browser2.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/cf.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/marked.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/md.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/md2.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/mde.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/msg.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/splash.html +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/pyproject.toml +0 -0
- {copyparty-1.13.4 → copyparty-1.13.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.13.
|
3
|
+
Version: 1.13.6
|
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
|
@@ -263,7 +263,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
263
263
|
* upload
|
264
264
|
* ☑ basic: plain multipart, ie6 support
|
265
265
|
* ☑ [up2k](#uploading): js, resumable, multithreaded
|
266
|
-
*
|
266
|
+
* **no filesize limit!** ...unless you use Cloudflare, then it's 383.9 GiB
|
267
267
|
* ☑ stash: simple PUT filedropper
|
268
268
|
* ☑ filename randomizer
|
269
269
|
* ☑ write-only folders
|
@@ -279,6 +279,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
279
279
|
* ☑ [navpane](#navpane) (directory tree sidebar)
|
280
280
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
281
281
|
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
282
|
+
* ☑ play video files as audio (converted on server)
|
282
283
|
* ☑ image gallery with webm player
|
283
284
|
* ☑ textfile browser with syntax hilighting
|
284
285
|
* ☑ [thumbnails](#thumbnails)
|
@@ -700,6 +701,7 @@ up2k has several advantages:
|
|
700
701
|
* uploads resume if you reboot your browser or pc, just upload the same files again
|
701
702
|
* server detects any corruption; the client reuploads affected chunks
|
702
703
|
* the client doesn't upload anything that already exists on the server
|
704
|
+
* no filesize limit unless imposed by a proxy, for example Cloudflare, which blocks uploads over 383.9 GiB
|
703
705
|
* much higher speeds than ftp/scp/tarpipe on some internet connections (mainly american ones) thanks to parallel connections
|
704
706
|
* the last-modified timestamp of the file is preserved
|
705
707
|
|
@@ -854,6 +856,7 @@ some hilights:
|
|
854
856
|
* OS integration; control playback from your phone's lockscreen ([windows](https://user-images.githubusercontent.com/241032/233213022-298a98ba-721a-4cf1-a3d4-f62634bc53d5.png) // [iOS](https://user-images.githubusercontent.com/241032/142711926-0700be6c-3e31-47b3-9928-53722221f722.png) // [android](https://user-images.githubusercontent.com/241032/233212311-a7368590-08c7-4f9f-a1af-48ccf3f36fad.png))
|
855
857
|
* shows the audio waveform in the seekbar
|
856
858
|
* not perfectly gapless but can get really close (see settings + eq below); good enough to enjoy gapless albums as intended
|
859
|
+
* videos can be played as audio, without wasting bandwidth on the video
|
857
860
|
|
858
861
|
click the `play` link next to an audio file, or copy the link target to [share it](https://a.ocv.me/pub/demo/music/Ubiktune%20-%20SOUNDSHOCK%202%20-%20FM%20FUNK%20TERRROR!!/#af-1fbfba61&t=18) (optionally with a timestamp to start playing from, like that example does)
|
859
862
|
|
@@ -1041,7 +1044,7 @@ some recommended FTP / FTPS clients; `wark` = example password:
|
|
1041
1044
|
|
1042
1045
|
## webdav server
|
1043
1046
|
|
1044
|
-
with read-write support, supports winXP and later, macos, nautilus/gvfs
|
1047
|
+
with read-write support, supports winXP and later, macos, nautilus/gvfs ... a greay way to [access copyparty straight from the file explorer in your OS](#mount-as-drive)
|
1045
1048
|
|
1046
1049
|
click the [connect](http://127.0.0.1:3923/?hc) button in the control-panel to see connection instructions for windows, linux, macos
|
1047
1050
|
|
@@ -1365,6 +1368,8 @@ you can set hooks before and/or after an event happens, and currently you can ho
|
|
1365
1368
|
|
1366
1369
|
there's a bunch of flags and stuff, see `--help-hooks`
|
1367
1370
|
|
1371
|
+
if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
|
1372
|
+
|
1368
1373
|
|
1369
1374
|
### upload events
|
1370
1375
|
|
@@ -1852,7 +1857,7 @@ alternatively, some alternatives roughly sorted by speed (unreproducible benchma
|
|
1852
1857
|
* [rclone-http](./docs/rclone.md) (26s), read-only
|
1853
1858
|
* [partyfuse.py](./bin/#partyfusepy) (35s), read-only
|
1854
1859
|
* [rclone-ftp](./docs/rclone.md) (47s), read/WRITE
|
1855
|
-
* davfs2 (103s), read/WRITE
|
1860
|
+
* davfs2 (103s), read/WRITE
|
1856
1861
|
* [win10-webdav](#webdav-server) (138s), read/WRITE
|
1857
1862
|
* [win10-smb2](#smb-server) (387s), read/WRITE
|
1858
1863
|
|
@@ -209,7 +209,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
209
209
|
* upload
|
210
210
|
* ☑ basic: plain multipart, ie6 support
|
211
211
|
* ☑ [up2k](#uploading): js, resumable, multithreaded
|
212
|
-
*
|
212
|
+
* **no filesize limit!** ...unless you use Cloudflare, then it's 383.9 GiB
|
213
213
|
* ☑ stash: simple PUT filedropper
|
214
214
|
* ☑ filename randomizer
|
215
215
|
* ☑ write-only folders
|
@@ -225,6 +225,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
225
225
|
* ☑ [navpane](#navpane) (directory tree sidebar)
|
226
226
|
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
|
227
227
|
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
|
228
|
+
* ☑ play video files as audio (converted on server)
|
228
229
|
* ☑ image gallery with webm player
|
229
230
|
* ☑ textfile browser with syntax hilighting
|
230
231
|
* ☑ [thumbnails](#thumbnails)
|
@@ -646,6 +647,7 @@ up2k has several advantages:
|
|
646
647
|
* uploads resume if you reboot your browser or pc, just upload the same files again
|
647
648
|
* server detects any corruption; the client reuploads affected chunks
|
648
649
|
* the client doesn't upload anything that already exists on the server
|
650
|
+
* no filesize limit unless imposed by a proxy, for example Cloudflare, which blocks uploads over 383.9 GiB
|
649
651
|
* much higher speeds than ftp/scp/tarpipe on some internet connections (mainly american ones) thanks to parallel connections
|
650
652
|
* the last-modified timestamp of the file is preserved
|
651
653
|
|
@@ -800,6 +802,7 @@ some hilights:
|
|
800
802
|
* OS integration; control playback from your phone's lockscreen ([windows](https://user-images.githubusercontent.com/241032/233213022-298a98ba-721a-4cf1-a3d4-f62634bc53d5.png) // [iOS](https://user-images.githubusercontent.com/241032/142711926-0700be6c-3e31-47b3-9928-53722221f722.png) // [android](https://user-images.githubusercontent.com/241032/233212311-a7368590-08c7-4f9f-a1af-48ccf3f36fad.png))
|
801
803
|
* shows the audio waveform in the seekbar
|
802
804
|
* not perfectly gapless but can get really close (see settings + eq below); good enough to enjoy gapless albums as intended
|
805
|
+
* videos can be played as audio, without wasting bandwidth on the video
|
803
806
|
|
804
807
|
click the `play` link next to an audio file, or copy the link target to [share it](https://a.ocv.me/pub/demo/music/Ubiktune%20-%20SOUNDSHOCK%202%20-%20FM%20FUNK%20TERRROR!!/#af-1fbfba61&t=18) (optionally with a timestamp to start playing from, like that example does)
|
805
808
|
|
@@ -987,7 +990,7 @@ some recommended FTP / FTPS clients; `wark` = example password:
|
|
987
990
|
|
988
991
|
## webdav server
|
989
992
|
|
990
|
-
with read-write support, supports winXP and later, macos, nautilus/gvfs
|
993
|
+
with read-write support, supports winXP and later, macos, nautilus/gvfs ... a greay way to [access copyparty straight from the file explorer in your OS](#mount-as-drive)
|
991
994
|
|
992
995
|
click the [connect](http://127.0.0.1:3923/?hc) button in the control-panel to see connection instructions for windows, linux, macos
|
993
996
|
|
@@ -1311,6 +1314,8 @@ you can set hooks before and/or after an event happens, and currently you can ho
|
|
1311
1314
|
|
1312
1315
|
there's a bunch of flags and stuff, see `--help-hooks`
|
1313
1316
|
|
1317
|
+
if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
|
1318
|
+
|
1314
1319
|
|
1315
1320
|
### upload events
|
1316
1321
|
|
@@ -1798,7 +1803,7 @@ alternatively, some alternatives roughly sorted by speed (unreproducible benchma
|
|
1798
1803
|
* [rclone-http](./docs/rclone.md) (26s), read-only
|
1799
1804
|
* [partyfuse.py](./bin/#partyfusepy) (35s), read-only
|
1800
1805
|
* [rclone-ftp](./docs/rclone.md) (47s), read/WRITE
|
1801
|
-
* davfs2 (103s), read/WRITE
|
1806
|
+
* davfs2 (103s), read/WRITE
|
1802
1807
|
* [win10-webdav](#webdav-server) (138s), read/WRITE
|
1803
1808
|
* [win10-smb2](#smb-server) (387s), read/WRITE
|
1804
1809
|
|
@@ -485,11 +485,17 @@ def disable_quickedit() :
|
|
485
485
|
|
486
486
|
|
487
487
|
def sfx_tpoke(top ):
|
488
|
-
files = [
|
488
|
+
files = [top] + [
|
489
|
+
os.path.join(dp, p) for dp, dd, df in os.walk(top) for p in dd + df
|
490
|
+
]
|
489
491
|
while True:
|
490
492
|
t = int(time.time())
|
491
|
-
for f in
|
492
|
-
|
493
|
+
for f in list(files):
|
494
|
+
try:
|
495
|
+
os.utime(f, (t, t))
|
496
|
+
except Exception as ex:
|
497
|
+
lprint("<TPOKE> [%s] %r" % (f, ex))
|
498
|
+
files.remove(f)
|
493
499
|
|
494
500
|
time.sleep(78123)
|
495
501
|
|
@@ -936,6 +942,7 @@ def add_upload(ap):
|
|
936
942
|
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")
|
937
943
|
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")
|
938
944
|
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)")
|
945
|
+
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 this size. 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]")
|
939
946
|
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")
|
940
947
|
ap2.add_argument("--write-uplog", action="store_true", help="write POST reports to textfiles in working-directory")
|
941
948
|
|
@@ -23,7 +23,7 @@ class ExceptionalQueue(Queue, object):
|
|
23
23
|
if rv[1] == "pebkac":
|
24
24
|
raise Pebkac(*rv[2:])
|
25
25
|
else:
|
26
|
-
raise
|
26
|
+
raise rv[2]
|
27
27
|
|
28
28
|
return rv
|
29
29
|
|
@@ -60,8 +60,8 @@ def try_exec(want_retval , func , *args ) :
|
|
60
60
|
|
61
61
|
return ["exception", "pebkac", ex.code, str(ex)]
|
62
62
|
|
63
|
-
except:
|
63
|
+
except Exception as ex:
|
64
64
|
if not want_retval:
|
65
65
|
raise
|
66
66
|
|
67
|
-
return ["exception", "stack",
|
67
|
+
return ["exception", "stack", ex]
|
@@ -642,11 +642,8 @@ class HttpCli(object):
|
|
642
642
|
if not self._check_nonfatal(pex, post):
|
643
643
|
self.keepalive = False
|
644
644
|
|
645
|
-
|
646
|
-
|
647
|
-
else:
|
648
|
-
em = repr(ex)
|
649
|
-
msg = min_ex()
|
645
|
+
em = str(ex)
|
646
|
+
msg = em if pex is ex else min_ex()
|
650
647
|
|
651
648
|
if pex.code != 404 or self.do_log:
|
652
649
|
self.log(
|
@@ -2198,33 +2195,39 @@ class HttpCli(object):
|
|
2198
2195
|
|
2199
2196
|
def handle_post_binary(self) :
|
2200
2197
|
try:
|
2201
|
-
remains = int(self.headers["content-length"])
|
2198
|
+
postsize = remains = int(self.headers["content-length"])
|
2202
2199
|
except:
|
2203
2200
|
raise Pebkac(400, "you must supply a content-length for binary POST")
|
2204
2201
|
|
2205
2202
|
try:
|
2206
|
-
|
2203
|
+
chashes = self.headers["x-up2k-hash"].split(",")
|
2207
2204
|
wark = self.headers["x-up2k-wark"]
|
2208
2205
|
except KeyError:
|
2209
2206
|
raise Pebkac(400, "need hash and wark headers for binary POST")
|
2210
2207
|
|
2208
|
+
chashes = [x.strip() for x in chashes]
|
2209
|
+
|
2211
2210
|
vfs, _ = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2212
2211
|
ptop = (vfs.dbv or vfs).realpath
|
2213
2212
|
|
2214
|
-
x = self.conn.hsrv.broker.ask("up2k.
|
2213
|
+
x = self.conn.hsrv.broker.ask("up2k.handle_chunks", ptop, wark, chashes)
|
2215
2214
|
response = x.get()
|
2216
|
-
chunksize,
|
2215
|
+
chunksize, cstarts, path, lastmod, sprs = response
|
2216
|
+
maxsize = chunksize * len(chashes)
|
2217
|
+
cstart0 = cstarts[0]
|
2217
2218
|
|
2218
2219
|
try:
|
2219
2220
|
if self.args.nw:
|
2220
2221
|
path = os.devnull
|
2221
2222
|
|
2222
|
-
if remains >
|
2223
|
-
|
2224
|
-
|
2225
|
-
self.log("writing {} #{} @{} len {}".format(path, chash, cstart, remains))
|
2223
|
+
if remains > maxsize:
|
2224
|
+
t = "your client is sending %d bytes which is too much (server expected %d bytes at most)"
|
2225
|
+
raise Pebkac(400, t % (remains, maxsize))
|
2226
2226
|
|
2227
|
-
|
2227
|
+
t = "writing %s %s+%d #%d+%d %s"
|
2228
|
+
chunkno = cstart0[0] // chunksize
|
2229
|
+
zs = " ".join([chashes[0][:15]] + [x[:9] for x in chashes[1:]])
|
2230
|
+
self.log(t % (path, cstart0, remains, chunkno, len(chashes), zs))
|
2228
2231
|
|
2229
2232
|
f = None
|
2230
2233
|
fpool = not self.args.no_fpool and sprs
|
@@ -2238,37 +2241,43 @@ class HttpCli(object):
|
|
2238
2241
|
f = f or open(fsenc(path), "rb+", self.args.iobuf)
|
2239
2242
|
|
2240
2243
|
try:
|
2241
|
-
|
2242
|
-
|
2244
|
+
for chash, cstart in zip(chashes, cstarts):
|
2245
|
+
f.seek(cstart[0])
|
2246
|
+
reader = read_socket(
|
2247
|
+
self.sr, self.args.s_rd_sz, min(remains, chunksize)
|
2248
|
+
)
|
2249
|
+
post_sz, _, sha_b64 = hashcopy(reader, f, self.args.s_wr_slp)
|
2243
2250
|
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
|
2248
|
-
|
2251
|
+
if sha_b64 != chash:
|
2252
|
+
try:
|
2253
|
+
self.bakflip(f, cstart[0], post_sz, sha_b64, vfs.flags)
|
2254
|
+
except:
|
2255
|
+
self.log("bakflip failed: " + min_ex())
|
2249
2256
|
|
2250
|
-
|
2251
|
-
|
2257
|
+
t = "your chunk got corrupted somehow (received {} bytes); expected vs received hash:\n{}\n{}"
|
2258
|
+
raise Pebkac(400, t.format(post_sz, chash, sha_b64))
|
2252
2259
|
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2260
|
+
remains -= chunksize
|
2261
|
+
|
2262
|
+
if len(cstart) > 1 and path != os.devnull:
|
2263
|
+
self.log(
|
2264
|
+
"clone {} to {}".format(
|
2265
|
+
cstart[0], " & ".join(unicode(x) for x in cstart[1:])
|
2266
|
+
)
|
2257
2267
|
)
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
f.write(buf)
|
2268
|
+
ofs = 0
|
2269
|
+
while ofs < chunksize:
|
2270
|
+
bufsz = max(4 * 1024 * 1024, self.args.iobuf)
|
2271
|
+
bufsz = min(chunksize - ofs, bufsz)
|
2272
|
+
f.seek(cstart[0] + ofs)
|
2273
|
+
buf = f.read(bufsz)
|
2274
|
+
for wofs in cstart[1:]:
|
2275
|
+
f.seek(wofs + ofs)
|
2276
|
+
f.write(buf)
|
2268
2277
|
|
2269
|
-
|
2278
|
+
ofs += len(buf)
|
2270
2279
|
|
2271
|
-
|
2280
|
+
self.log("clone {} done".format(cstart[0]))
|
2272
2281
|
|
2273
2282
|
if not fpool:
|
2274
2283
|
f.close()
|
@@ -2280,10 +2289,10 @@ class HttpCli(object):
|
|
2280
2289
|
f.close()
|
2281
2290
|
raise
|
2282
2291
|
finally:
|
2283
|
-
x = self.conn.hsrv.broker.ask("up2k.
|
2292
|
+
x = self.conn.hsrv.broker.ask("up2k.release_chunks", ptop, wark, chashes)
|
2284
2293
|
x.get() # block client until released
|
2285
2294
|
|
2286
|
-
x = self.conn.hsrv.broker.ask("up2k.
|
2295
|
+
x = self.conn.hsrv.broker.ask("up2k.confirm_chunks", ptop, wark, chashes)
|
2287
2296
|
ztis = x.get()
|
2288
2297
|
try:
|
2289
2298
|
num_left, fin_path = ztis
|
@@ -2302,7 +2311,7 @@ class HttpCli(object):
|
|
2302
2311
|
|
2303
2312
|
cinf = self.headers.get("x-up2k-stat", "")
|
2304
2313
|
|
2305
|
-
spd = self._spd(
|
2314
|
+
spd = self._spd(postsize)
|
2306
2315
|
self.log("{:70} thank {}".format(spd, cinf))
|
2307
2316
|
self.reply(b"thank")
|
2308
2317
|
return True
|
@@ -4499,6 +4508,7 @@ class HttpCli(object):
|
|
4499
4508
|
"themes": self.args.themes,
|
4500
4509
|
"turbolvl": self.args.turbo,
|
4501
4510
|
"u2j": self.args.u2j,
|
4511
|
+
"u2sz": self.args.u2sz,
|
4502
4512
|
"idxh": int(self.args.ih),
|
4503
4513
|
"u2sort": self.args.u2sort,
|
4504
4514
|
}
|
@@ -56,7 +56,8 @@ class ThumbCli(object):
|
|
56
56
|
|
57
57
|
want_opus = fmt in ("opus", "caf", "mp3")
|
58
58
|
is_au = ext in self.fmt_ffa
|
59
|
-
|
59
|
+
is_vau = want_opus and ext in self.fmt_ffv
|
60
|
+
if is_au or is_vau:
|
60
61
|
if want_opus:
|
61
62
|
if self.args.no_acode:
|
62
63
|
return None
|
@@ -104,7 +105,7 @@ class ThumbCli(object):
|
|
104
105
|
|
105
106
|
fmt = sfmt
|
106
107
|
|
107
|
-
elif fmt[:1] == "p" and not is_au:
|
108
|
+
elif fmt[:1] == "p" and not is_au and not is_vid:
|
108
109
|
t = "cannot thumbnail [%s]: png only allowed for waveforms"
|
109
110
|
self.log(t % (rem), 6)
|
110
111
|
return None
|
@@ -301,23 +301,31 @@ class ThumbSrv(object):
|
|
301
301
|
ap_unpk = abspath
|
302
302
|
|
303
303
|
if not bos.path.exists(tpath):
|
304
|
+
want_mp3 = tpath.endswith(".mp3")
|
305
|
+
want_opus = tpath.endswith(".opus") or tpath.endswith(".caf")
|
306
|
+
want_png = tpath.endswith(".png")
|
307
|
+
want_au = want_mp3 or want_opus
|
304
308
|
for lib in self.args.th_dec:
|
309
|
+
can_au = lib == "ff" and (
|
310
|
+
ext in self.fmt_ffa or ext in self.fmt_ffv
|
311
|
+
)
|
312
|
+
|
305
313
|
if lib == "pil" and ext in self.fmt_pil:
|
306
314
|
funs.append(self.conv_pil)
|
307
315
|
elif lib == "vips" and ext in self.fmt_vips:
|
308
316
|
funs.append(self.conv_vips)
|
309
|
-
elif
|
310
|
-
|
311
|
-
elif lib == "ff" and ext in self.fmt_ffa:
|
312
|
-
if tpath.endswith(".opus") or tpath.endswith(".caf"):
|
317
|
+
elif can_au and (want_png or want_au):
|
318
|
+
if want_opus:
|
313
319
|
funs.append(self.conv_opus)
|
314
|
-
elif
|
320
|
+
elif want_mp3:
|
315
321
|
funs.append(self.conv_mp3)
|
316
|
-
elif
|
322
|
+
elif want_png:
|
317
323
|
funs.append(self.conv_waves)
|
318
324
|
png_ok = True
|
319
|
-
|
320
|
-
|
325
|
+
elif lib == "ff" and (ext in self.fmt_ffi or ext in self.fmt_ffv):
|
326
|
+
funs.append(self.conv_ffmpeg)
|
327
|
+
elif lib == "ff" and ext in self.fmt_ffa and not want_au:
|
328
|
+
funs.append(self.conv_spec)
|
321
329
|
|
322
330
|
tdir, tfn = os.path.split(tpath)
|
323
331
|
ttpath = os.path.join(tdir, "w", tfn)
|
@@ -542,7 +542,7 @@ class Up2k(object):
|
|
542
542
|
nrm += 1
|
543
543
|
|
544
544
|
if nrm:
|
545
|
-
self.log("
|
545
|
+
self.log("%d files graduated in /%s" % (nrm, vp))
|
546
546
|
|
547
547
|
if timeout < 10:
|
548
548
|
continue
|
@@ -1293,7 +1293,7 @@ class Up2k(object):
|
|
1293
1293
|
not cv
|
1294
1294
|
or liname not in th_cvds
|
1295
1295
|
or cv.lower() not in th_cvds
|
1296
|
-
or th_cvd.index(
|
1296
|
+
or th_cvd.index(liname) < th_cvd.index(cv.lower())
|
1297
1297
|
)
|
1298
1298
|
):
|
1299
1299
|
cv = iname
|
@@ -3010,8 +3010,8 @@ class Up2k(object):
|
|
3010
3010
|
times = (int(time.time()), int(lmod))
|
3011
3011
|
bos.utime(dst, times, False)
|
3012
3012
|
|
3013
|
-
def
|
3014
|
-
self, ptop , wark ,
|
3013
|
+
def handle_chunks(
|
3014
|
+
self, ptop , wark , chashes
|
3015
3015
|
) :
|
3016
3016
|
with self.mutex, self.reg_mutex:
|
3017
3017
|
self.db_act = self.vol_act[ptop] = time.time()
|
@@ -3021,26 +3021,37 @@ class Up2k(object):
|
|
3021
3021
|
self.log("unknown wark [{}], known: {}".format(wark, known))
|
3022
3022
|
raise Pebkac(400, "unknown wark" + SSEELOG)
|
3023
3023
|
|
3024
|
-
|
3025
|
-
|
3026
|
-
|
3027
|
-
|
3028
|
-
|
3024
|
+
for chash in chashes:
|
3025
|
+
if chash not in job["need"]:
|
3026
|
+
msg = "chash = {} , need:\n".format(chash)
|
3027
|
+
msg += "\n".join(job["need"])
|
3028
|
+
self.log(msg)
|
3029
|
+
raise Pebkac(400, "already got that (%s) but thanks??" % (chash,))
|
3029
3030
|
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3031
|
+
if chash in job["busy"]:
|
3032
|
+
nh = len(job["hash"])
|
3033
|
+
idx = job["hash"].index(chash)
|
3034
|
+
t = "that chunk is already being written to:\n {}\n {} {}/{}\n {}"
|
3035
|
+
raise Pebkac(400, t.format(wark, chash, idx, nh, job["name"]))
|
3033
3036
|
|
3034
|
-
|
3035
|
-
nh = len(job["hash"])
|
3036
|
-
idx = job["hash"].index(chash)
|
3037
|
-
t = "that chunk is already being written to:\n {}\n {} {}/{}\n {}"
|
3038
|
-
raise Pebkac(400, t.format(wark, chash, idx, nh, job["name"]))
|
3037
|
+
chunksize = up2k_chunksize(job["size"])
|
3039
3038
|
|
3040
|
-
|
3039
|
+
coffsets = []
|
3040
|
+
for chash in chashes:
|
3041
|
+
nchunk = [n for n, v in enumerate(job["hash"]) if v == chash]
|
3042
|
+
if not nchunk:
|
3043
|
+
raise Pebkac(400, "unknown chunk %s" % (chash))
|
3041
3044
|
|
3042
|
-
|
3043
|
-
|
3045
|
+
ofs = [chunksize * x for x in nchunk]
|
3046
|
+
coffsets.append(ofs)
|
3047
|
+
|
3048
|
+
for ofs1, ofs2 in zip(coffsets, coffsets[1:]):
|
3049
|
+
gap = (ofs2[0] - ofs1[0]) - chunksize
|
3050
|
+
if gap:
|
3051
|
+
t = "only sibling chunks can be stitched; gap of %d bytes between offsets %d and %d in %s"
|
3052
|
+
raise Pebkac(400, t % (gap, ofs1[0], ofs2[0], job["name"]))
|
3053
|
+
|
3054
|
+
path = djoin(job["ptop"], job["prel"], job["tnam"])
|
3044
3055
|
|
3045
3056
|
if not job["sprs"]:
|
3046
3057
|
cur_sz = bos.path.getsize(path)
|
@@ -3053,17 +3064,20 @@ class Up2k(object):
|
|
3053
3064
|
|
3054
3065
|
job["poke"] = time.time()
|
3055
3066
|
|
3056
|
-
return chunksize,
|
3067
|
+
return chunksize, coffsets, path, job["lmod"], job["sprs"]
|
3057
3068
|
|
3058
|
-
def
|
3069
|
+
def release_chunks(self, ptop , wark , chashes ) :
|
3059
3070
|
with self.reg_mutex:
|
3060
3071
|
job = self.registry[ptop].get(wark)
|
3061
3072
|
if job:
|
3062
|
-
|
3073
|
+
for chash in chashes:
|
3074
|
+
job["busy"].pop(chash, None)
|
3063
3075
|
|
3064
3076
|
return True
|
3065
3077
|
|
3066
|
-
def
|
3078
|
+
def confirm_chunks(
|
3079
|
+
self, ptop , wark , chashes
|
3080
|
+
) :
|
3067
3081
|
with self.mutex, self.reg_mutex:
|
3068
3082
|
self.db_act = self.vol_act[ptop] = time.time()
|
3069
3083
|
try:
|
@@ -3072,14 +3086,16 @@ class Up2k(object):
|
|
3072
3086
|
src = djoin(pdir, job["tnam"])
|
3073
3087
|
dst = djoin(pdir, job["name"])
|
3074
3088
|
except Exception as ex:
|
3075
|
-
return "confirm_chunk, wark
|
3089
|
+
return "confirm_chunk, wark(%r)" % (ex,) # type: ignore
|
3076
3090
|
|
3077
|
-
|
3091
|
+
for chash in chashes:
|
3092
|
+
job["busy"].pop(chash, None)
|
3078
3093
|
|
3079
3094
|
try:
|
3080
|
-
|
3095
|
+
for chash in chashes:
|
3096
|
+
job["need"].remove(chash)
|
3081
3097
|
except Exception as ex:
|
3082
|
-
return "confirm_chunk, chash
|
3098
|
+
return "confirm_chunk, chash(%s) %r" % (chash, ex) # type: ignore
|
3083
3099
|
|
3084
3100
|
ret = len(job["need"])
|
3085
3101
|
if ret > 0:
|
@@ -1356,7 +1356,7 @@ def vol_san(vols , txt ) :
|
|
1356
1356
|
def min_ex(max_lines = 8, reverse = False) :
|
1357
1357
|
et, ev, tb = sys.exc_info()
|
1358
1358
|
stb = traceback.extract_tb(tb) if tb else traceback.extract_stack()[:-1]
|
1359
|
-
fmt = "%s
|
1359
|
+
fmt = "%s:%d <%s>: %s"
|
1360
1360
|
ex = [fmt % (fp.split(os.sep)[-1], ln, fun, txt) for fp, ln, fun, txt in stb]
|
1361
1361
|
if et or ev or tb:
|
1362
1362
|
ex.append("[%s] %s" % (et.__name__ if et else "(anonymous)", ev))
|