copyparty 1.19.0__py3-none-any.whl → 1.19.2__py3-none-any.whl
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/__main__.py +131 -27
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +33 -7
- copyparty/cfg.py +7 -1
- copyparty/dxml.py +3 -0
- copyparty/ftpd.py +21 -6
- copyparty/httpcli.py +92 -23
- copyparty/httpsrv.py +6 -0
- copyparty/mdns.py +2 -1
- copyparty/mtag.py +88 -6
- copyparty/svchub.py +76 -5
- copyparty/tcpsrv.py +6 -0
- copyparty/th_cli.py +5 -1
- copyparty/th_srv.py +160 -51
- copyparty/u2idx.py +1 -1
- copyparty/up2k.py +80 -39
- copyparty/util.py +25 -1
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/rups.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +8 -1
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/METADATA +39 -3
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/RECORD +33 -33
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/WHEEL +0 -0
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/entry_points.txt +0 -0
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/licenses/LICENSE +0 -0
- {copyparty-1.19.0.dist-info → copyparty-1.19.2.dist-info}/top_level.txt +0 -0
copyparty/th_srv.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
4
|
import hashlib
|
5
|
+
import io
|
5
6
|
import logging
|
6
7
|
import os
|
7
8
|
import re
|
@@ -82,7 +83,10 @@ try:
|
|
82
83
|
if os.environ.get("PRTY_NO_PIL_HEIF"):
|
83
84
|
raise Exception()
|
84
85
|
|
85
|
-
|
86
|
+
try:
|
87
|
+
from pillow_heif import register_heif_opener
|
88
|
+
except ImportError:
|
89
|
+
from pyheif_pillow_opener import register_heif_opener
|
86
90
|
|
87
91
|
register_heif_opener()
|
88
92
|
HAVE_HEIF = True
|
@@ -109,14 +113,28 @@ except:
|
|
109
113
|
|
110
114
|
try:
|
111
115
|
if os.environ.get("PRTY_NO_VIPS"):
|
112
|
-
raise
|
116
|
+
raise ImportError()
|
113
117
|
|
114
118
|
HAVE_VIPS = True
|
115
119
|
import pyvips
|
116
120
|
|
117
121
|
logging.getLogger("pyvips").setLevel(logging.WARNING)
|
118
|
-
except:
|
122
|
+
except Exception as e:
|
119
123
|
HAVE_VIPS = False
|
124
|
+
if not isinstance(e, ImportError):
|
125
|
+
logging.warning("libvips found, but failed to load: " + str(e))
|
126
|
+
|
127
|
+
|
128
|
+
try:
|
129
|
+
if os.environ.get("PRTY_NO_RAW"):
|
130
|
+
raise Exception()
|
131
|
+
|
132
|
+
HAVE_RAW = True
|
133
|
+
import rawpy
|
134
|
+
|
135
|
+
logging.getLogger("rawpy").setLevel(logging.WARNING)
|
136
|
+
except:
|
137
|
+
HAVE_RAW = False
|
120
138
|
|
121
139
|
|
122
140
|
th_dir_cache = {}
|
@@ -202,11 +220,19 @@ class ThumbSrv(object):
|
|
202
220
|
if self.args.th_clean:
|
203
221
|
Daemon(self.cleaner, "thumb.cln")
|
204
222
|
|
205
|
-
|
223
|
+
(
|
224
|
+
self.fmt_pil,
|
225
|
+
self.fmt_vips,
|
226
|
+
self.fmt_raw,
|
227
|
+
self.fmt_ffi,
|
228
|
+
self.fmt_ffv,
|
229
|
+
self.fmt_ffa,
|
230
|
+
) = [
|
206
231
|
set(y.split(","))
|
207
232
|
for y in [
|
208
233
|
self.args.th_r_pil,
|
209
234
|
self.args.th_r_vips,
|
235
|
+
self.args.th_r_raw,
|
210
236
|
self.args.th_r_ffi,
|
211
237
|
self.args.th_r_ffv,
|
212
238
|
self.args.th_r_ffa,
|
@@ -229,6 +255,9 @@ class ThumbSrv(object):
|
|
229
255
|
if "vips" in self.args.th_dec:
|
230
256
|
self.thumbable |= self.fmt_vips
|
231
257
|
|
258
|
+
if "raw" in self.args.th_dec:
|
259
|
+
self.thumbable |= self.fmt_raw
|
260
|
+
|
232
261
|
if "ff" in self.args.th_dec:
|
233
262
|
for zss in [self.fmt_ffi, self.fmt_ffv, self.fmt_ffa]:
|
234
263
|
self.thumbable |= zss
|
@@ -310,6 +339,7 @@ class ThumbSrv(object):
|
|
310
339
|
"thumbable": self.thumbable,
|
311
340
|
"pil": self.fmt_pil,
|
312
341
|
"vips": self.fmt_vips,
|
342
|
+
"raw": self.fmt_raw,
|
313
343
|
"ffi": self.fmt_ffi,
|
314
344
|
"ffv": self.fmt_ffv,
|
315
345
|
"ffa": self.fmt_ffa,
|
@@ -365,6 +395,8 @@ class ThumbSrv(object):
|
|
365
395
|
funs.append(self.conv_pil)
|
366
396
|
elif lib == "vips" and ext in self.fmt_vips:
|
367
397
|
funs.append(self.conv_vips)
|
398
|
+
elif lib == "raw" and ext in self.fmt_raw:
|
399
|
+
funs.append(self.conv_raw)
|
368
400
|
elif can_au and (want_png or want_au):
|
369
401
|
if want_opus:
|
370
402
|
funs.append(self.conv_opus)
|
@@ -477,35 +509,38 @@ class ThumbSrv(object):
|
|
477
509
|
|
478
510
|
return im
|
479
511
|
|
512
|
+
def conv_image_pil(self, im , tpath , fmt , vn ) :
|
513
|
+
try:
|
514
|
+
im = self.fancy_pillow(im, fmt, vn)
|
515
|
+
except Exception as ex:
|
516
|
+
self.log("fancy_pillow {}".format(ex), "90")
|
517
|
+
im.thumbnail(self.getres(vn, fmt))
|
518
|
+
|
519
|
+
fmts = ["RGB", "L"]
|
520
|
+
args = {"quality": 40}
|
521
|
+
|
522
|
+
if tpath.endswith(".webp"):
|
523
|
+
# quality 80 = pillow-default
|
524
|
+
# quality 75 = ffmpeg-default
|
525
|
+
# method 0 = pillow-default, fast
|
526
|
+
# method 4 = ffmpeg-default
|
527
|
+
# method 6 = max, slow
|
528
|
+
fmts.extend(("RGBA", "LA"))
|
529
|
+
args["method"] = 6
|
530
|
+
else:
|
531
|
+
# default q = 75
|
532
|
+
args["progressive"] = True
|
533
|
+
|
534
|
+
if im.mode not in fmts:
|
535
|
+
# print("conv {}".format(im.mode))
|
536
|
+
im = im.convert("RGB")
|
537
|
+
|
538
|
+
im.save(tpath, **args)
|
539
|
+
|
480
540
|
def conv_pil(self, abspath , tpath , fmt , vn ) :
|
481
541
|
self.wait4ram(0.2, tpath)
|
482
542
|
with Image.open(fsenc(abspath)) as im:
|
483
|
-
|
484
|
-
im = self.fancy_pillow(im, fmt, vn)
|
485
|
-
except Exception as ex:
|
486
|
-
self.log("fancy_pillow {}".format(ex), "90")
|
487
|
-
im.thumbnail(self.getres(vn, fmt))
|
488
|
-
|
489
|
-
fmts = ["RGB", "L"]
|
490
|
-
args = {"quality": 40}
|
491
|
-
|
492
|
-
if tpath.endswith(".webp"):
|
493
|
-
# quality 80 = pillow-default
|
494
|
-
# quality 75 = ffmpeg-default
|
495
|
-
# method 0 = pillow-default, fast
|
496
|
-
# method 4 = ffmpeg-default
|
497
|
-
# method 6 = max, slow
|
498
|
-
fmts.extend(("RGBA", "LA"))
|
499
|
-
args["method"] = 6
|
500
|
-
else:
|
501
|
-
# default q = 75
|
502
|
-
args["progressive"] = True
|
503
|
-
|
504
|
-
if im.mode not in fmts:
|
505
|
-
# print("conv {}".format(im.mode))
|
506
|
-
im = im.convert("RGB")
|
507
|
-
|
508
|
-
im.save(tpath, **args)
|
543
|
+
self.conv_image_pil(im, tpath, fmt, vn)
|
509
544
|
|
510
545
|
def conv_vips(self, abspath , tpath , fmt , vn ) :
|
511
546
|
self.wait4ram(0.2, tpath)
|
@@ -527,9 +562,52 @@ class ThumbSrv(object):
|
|
527
562
|
|
528
563
|
img.write_to_file(tpath, Q=40)
|
529
564
|
|
565
|
+
def conv_raw(self, abspath , tpath , fmt , vn ) :
|
566
|
+
self.wait4ram(0.2, tpath)
|
567
|
+
with rawpy.imread(abspath) as raw:
|
568
|
+
thumb = raw.extract_thumb()
|
569
|
+
if thumb.format == rawpy.ThumbFormat.JPEG and tpath.endswith(".jpg"):
|
570
|
+
# if we have a jpg thumbnail and no webp output is available,
|
571
|
+
# just write the jpg directly (it'll be the wrong size, but it's fast)
|
572
|
+
with open(tpath, "wb") as f:
|
573
|
+
f.write(thumb.data)
|
574
|
+
if HAVE_VIPS:
|
575
|
+
crops = ["centre", "none"]
|
576
|
+
if "f" in fmt:
|
577
|
+
crops = ["none"]
|
578
|
+
w, h = self.getres(vn, fmt)
|
579
|
+
kw = {"height": h, "size": "down", "intent": "relative"}
|
580
|
+
|
581
|
+
for c in crops:
|
582
|
+
try:
|
583
|
+
kw["crop"] = c
|
584
|
+
if thumb.format == rawpy.ThumbFormat.BITMAP:
|
585
|
+
img = pyvips.Image.new_from_array(
|
586
|
+
thumb.data, interpretation="rgb"
|
587
|
+
)
|
588
|
+
img = img.thumbnail_image(w, **kw)
|
589
|
+
else:
|
590
|
+
img = pyvips.Image.thumbnail_buffer(thumb.data, w, **kw)
|
591
|
+
break
|
592
|
+
except:
|
593
|
+
if c == crops[-1]:
|
594
|
+
raise
|
595
|
+
|
596
|
+
img.write_to_file(tpath, Q=40)
|
597
|
+
elif HAVE_PIL:
|
598
|
+
if thumb.format == rawpy.ThumbFormat.BITMAP:
|
599
|
+
im = Image.fromarray(thumb.data, "RGB")
|
600
|
+
else:
|
601
|
+
im = Image.open(io.BytesIO(thumb.data))
|
602
|
+
self.conv_image_pil(im, tpath, fmt, vn)
|
603
|
+
else:
|
604
|
+
raise Exception(
|
605
|
+
"either pil or vips is needed to process embedded bitmap thumbnails in raw files"
|
606
|
+
)
|
607
|
+
|
530
608
|
def conv_ffmpeg(self, abspath , tpath , fmt , vn ) :
|
531
609
|
self.wait4ram(0.2, tpath)
|
532
|
-
ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
610
|
+
ret, _, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
533
611
|
if not ret:
|
534
612
|
return
|
535
613
|
|
@@ -540,6 +618,17 @@ class ThumbSrv(object):
|
|
540
618
|
dur = ret[".dur"][1] if ".dur" in ret else 4
|
541
619
|
seek = [b"-ss", "{:.0f}".format(dur / 3).encode("utf-8")]
|
542
620
|
|
621
|
+
self._ffmpeg_im(abspath, tpath, fmt, vn, seek, b"0:v:0")
|
622
|
+
|
623
|
+
def _ffmpeg_im(
|
624
|
+
self,
|
625
|
+
abspath ,
|
626
|
+
tpath ,
|
627
|
+
fmt ,
|
628
|
+
vn ,
|
629
|
+
seek ,
|
630
|
+
imap ,
|
631
|
+
) :
|
543
632
|
scale = "scale={0}:{1}:force_original_aspect_ratio="
|
544
633
|
if "f" in fmt:
|
545
634
|
scale += "decrease,setsar=1:1"
|
@@ -558,7 +647,7 @@ class ThumbSrv(object):
|
|
558
647
|
cmd += seek
|
559
648
|
cmd += [
|
560
649
|
b"-i", fsenc(abspath),
|
561
|
-
b"-map",
|
650
|
+
b"-map", imap,
|
562
651
|
b"-vf", bscale,
|
563
652
|
b"-frames:v", b"1",
|
564
653
|
b"-metadata:s:v:0", b"rotate=0",
|
@@ -579,11 +668,11 @@ class ThumbSrv(object):
|
|
579
668
|
]
|
580
669
|
|
581
670
|
cmd += [fsenc(tpath)]
|
582
|
-
self._run_ff(cmd, vn)
|
671
|
+
self._run_ff(cmd, vn, "convt")
|
583
672
|
|
584
|
-
def _run_ff(self, cmd , vn , oom = 400) :
|
673
|
+
def _run_ff(self, cmd , vn , kto , oom = 400) :
|
585
674
|
# self.log((b" ".join(cmd)).decode("utf-8"))
|
586
|
-
ret, _, serr = runcmd(cmd, timeout=vn.flags[
|
675
|
+
ret, _, serr = runcmd(cmd, timeout=vn.flags[kto], nice=True, oom=oom)
|
587
676
|
if not ret:
|
588
677
|
return
|
589
678
|
|
@@ -627,7 +716,7 @@ class ThumbSrv(object):
|
|
627
716
|
raise sp.CalledProcessError(ret, (cmd[0], b"...", cmd[-1]))
|
628
717
|
|
629
718
|
def conv_waves(self, abspath , tpath , fmt , vn ) :
|
630
|
-
ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
719
|
+
ret, _, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
631
720
|
if "ac" not in ret:
|
632
721
|
raise Exception("not audio")
|
633
722
|
|
@@ -665,7 +754,7 @@ class ThumbSrv(object):
|
|
665
754
|
# fmt: on
|
666
755
|
|
667
756
|
cmd += [fsenc(tpath)]
|
668
|
-
self._run_ff(cmd, vn)
|
757
|
+
self._run_ff(cmd, vn, "convt")
|
669
758
|
|
670
759
|
if "pngquant" in vn.flags:
|
671
760
|
wtpath = tpath + ".png"
|
@@ -686,11 +775,31 @@ class ThumbSrv(object):
|
|
686
775
|
else:
|
687
776
|
atomic_move(self.log, wtpath, tpath, vn.flags)
|
688
777
|
|
778
|
+
def conv_emb_cv(
|
779
|
+
self, abspath , tpath , fmt , vn , strm
|
780
|
+
) :
|
781
|
+
self.wait4ram(0.2, tpath)
|
782
|
+
self._ffmpeg_im(
|
783
|
+
abspath, tpath, fmt, vn, [], b"0:" + strm["index"].encode("ascii")
|
784
|
+
)
|
785
|
+
|
689
786
|
def conv_spec(self, abspath , tpath , fmt , vn ) :
|
690
|
-
ret,
|
787
|
+
ret, raw, strms, ctnr = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
691
788
|
if "ac" not in ret:
|
692
789
|
raise Exception("not audio")
|
693
790
|
|
791
|
+
want_spec = vn.flags.get("th_spec_p", 1)
|
792
|
+
if want_spec < 2:
|
793
|
+
for strm in strms:
|
794
|
+
if (
|
795
|
+
strm.get("codec_type") == "video"
|
796
|
+
and strm.get("DISPOSITION:attached_pic") == "1"
|
797
|
+
):
|
798
|
+
return self.conv_emb_cv(abspath, tpath, fmt, vn, strm)
|
799
|
+
|
800
|
+
if not want_spec:
|
801
|
+
raise Exception("spectrograms forbidden by volflag")
|
802
|
+
|
694
803
|
fext = abspath.split(".")[-1].lower()
|
695
804
|
|
696
805
|
# https://trac.ffmpeg.org/ticket/10797
|
@@ -726,7 +835,7 @@ class ThumbSrv(object):
|
|
726
835
|
b"-y", fsenc(infile),
|
727
836
|
]
|
728
837
|
# fmt: on
|
729
|
-
self._run_ff(cmd, vn)
|
838
|
+
self._run_ff(cmd, vn, "convt")
|
730
839
|
|
731
840
|
fc = "[0:a:0]aresample=48000{},showspectrumpic=s="
|
732
841
|
if "3" in fmt:
|
@@ -768,7 +877,7 @@ class ThumbSrv(object):
|
|
768
877
|
]
|
769
878
|
|
770
879
|
cmd += [fsenc(tpath)]
|
771
|
-
self._run_ff(cmd, vn)
|
880
|
+
self._run_ff(cmd, vn, "convt")
|
772
881
|
|
773
882
|
def conv_mp3(self, abspath , tpath , fmt , vn ) :
|
774
883
|
quality = self.args.q_mp3.lower()
|
@@ -776,7 +885,7 @@ class ThumbSrv(object):
|
|
776
885
|
raise Exception("disabled in server config")
|
777
886
|
|
778
887
|
self.wait4ram(0.2, tpath)
|
779
|
-
tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
888
|
+
tags, rawtags, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
780
889
|
if "ac" not in tags:
|
781
890
|
raise Exception("not audio")
|
782
891
|
|
@@ -807,14 +916,14 @@ class ThumbSrv(object):
|
|
807
916
|
fsenc(tpath)
|
808
917
|
]
|
809
918
|
# fmt: on
|
810
|
-
self._run_ff(cmd, vn, oom=300)
|
919
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
811
920
|
|
812
921
|
def conv_flac(self, abspath , tpath , fmt , vn ) :
|
813
922
|
if self.args.no_acode or not self.args.allow_flac:
|
814
923
|
raise Exception("flac not permitted in server config")
|
815
924
|
|
816
925
|
self.wait4ram(0.2, tpath)
|
817
|
-
tags,
|
926
|
+
tags, _, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
818
927
|
if "ac" not in tags:
|
819
928
|
raise Exception("not audio")
|
820
929
|
|
@@ -832,14 +941,14 @@ class ThumbSrv(object):
|
|
832
941
|
fsenc(tpath)
|
833
942
|
]
|
834
943
|
# fmt: on
|
835
|
-
self._run_ff(cmd, vn, oom=300)
|
944
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
836
945
|
|
837
946
|
def conv_wav(self, abspath , tpath , fmt , vn ) :
|
838
947
|
if self.args.no_acode or not self.args.allow_wav:
|
839
948
|
raise Exception("wav not permitted in server config")
|
840
949
|
|
841
950
|
self.wait4ram(0.2, tpath)
|
842
|
-
tags,
|
951
|
+
tags, _, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
843
952
|
if "ac" not in tags:
|
844
953
|
raise Exception("not audio")
|
845
954
|
|
@@ -867,14 +976,14 @@ class ThumbSrv(object):
|
|
867
976
|
fsenc(tpath)
|
868
977
|
]
|
869
978
|
# fmt: on
|
870
|
-
self._run_ff(cmd, vn, oom=300)
|
979
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
871
980
|
|
872
981
|
def conv_opus(self, abspath , tpath , fmt , vn ) :
|
873
982
|
if self.args.no_acode or not self.args.q_opus:
|
874
983
|
raise Exception("disabled in server config")
|
875
984
|
|
876
985
|
self.wait4ram(0.2, tpath)
|
877
|
-
tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
986
|
+
tags, rawtags, _, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
878
987
|
if "ac" not in tags:
|
879
988
|
raise Exception("not audio")
|
880
989
|
|
@@ -923,7 +1032,7 @@ class ThumbSrv(object):
|
|
923
1032
|
fsenc(tpath)
|
924
1033
|
]
|
925
1034
|
# fmt: on
|
926
|
-
self._run_ff(cmd, vn, oom=300)
|
1035
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
927
1036
|
|
928
1037
|
def _conv_caf(
|
929
1038
|
self,
|
@@ -963,7 +1072,7 @@ class ThumbSrv(object):
|
|
963
1072
|
fsenc(tmp_opus)
|
964
1073
|
]
|
965
1074
|
# fmt: on
|
966
|
-
self._run_ff(cmd, vn, oom=300)
|
1075
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
967
1076
|
|
968
1077
|
# iOS fails to play some "insufficiently complex" files
|
969
1078
|
# (average file shorter than 8 seconds), so of course we
|
@@ -990,7 +1099,7 @@ class ThumbSrv(object):
|
|
990
1099
|
fsenc(tpath)
|
991
1100
|
]
|
992
1101
|
# fmt: on
|
993
|
-
self._run_ff(cmd, vn, oom=300)
|
1102
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
994
1103
|
|
995
1104
|
else:
|
996
1105
|
# simple remux should be safe
|
@@ -1009,7 +1118,7 @@ class ThumbSrv(object):
|
|
1009
1118
|
fsenc(tpath)
|
1010
1119
|
]
|
1011
1120
|
# fmt: on
|
1012
|
-
self._run_ff(cmd, vn, oom=300)
|
1121
|
+
self._run_ff(cmd, vn, "aconvt", oom=300)
|
1013
1122
|
|
1014
1123
|
try:
|
1015
1124
|
wunlink(self.log, tmp_opus, vn.flags)
|
copyparty/u2idx.py
CHANGED
@@ -385,7 +385,7 @@ class U2idx(object):
|
|
385
385
|
fk_alg = 2 if "fka" in flags else 1
|
386
386
|
c = cur.execute(uq, tuple(vuv))
|
387
387
|
for hit in c:
|
388
|
-
w, ts, sz, rd, fn
|
388
|
+
w, ts, sz, rd, fn = hit[:5]
|
389
389
|
|
390
390
|
if rd.startswith("//") or fn.startswith("//"):
|
391
391
|
rd, fn = s3dec(rd, fn)
|