diff --git a/README.md b/README.md
index 8535bea5..786244d7 100644
--- a/README.md
+++ b/README.md
@@ -225,6 +225,7 @@ also see [comparison to similar software](./docs/versus.md)
* ☑ [navpane](#navpane) (directory tree sidebar)
* ☑ file manager (cut/paste, delete, [batch-rename](#batch-rename))
* ☑ audio player (with [OS media controls](https://user-images.githubusercontent.com/241032/215347492-b4250797-6c90-4e09-9a4c-721edf2fb15c.png) and opus/mp3 transcoding)
+ * ☑ play video files as audio (converted on server)
* ☑ image gallery with webm player
* ☑ textfile browser with syntax hilighting
* ☑ [thumbnails](#thumbnails)
@@ -801,6 +802,7 @@ some hilights:
* 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))
* shows the audio waveform in the seekbar
* not perfectly gapless but can get really close (see settings + eq below); good enough to enjoy gapless albums as intended
+* videos can be played as audio, without wasting bandwidth on the video
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)
diff --git a/copyparty/th_cli.py b/copyparty/th_cli.py
index 0c69be5f..6bebd3de 100644
--- a/copyparty/th_cli.py
+++ b/copyparty/th_cli.py
@@ -59,7 +59,8 @@ class ThumbCli(object):
want_opus = fmt in ("opus", "caf", "mp3")
is_au = ext in self.fmt_ffa
- if is_au:
+ is_vau = want_opus and ext in self.fmt_ffv
+ if is_au or is_vau:
if want_opus:
if self.args.no_acode:
return None
@@ -107,7 +108,7 @@ class ThumbCli(object):
fmt = sfmt
- elif fmt[:1] == "p" and not is_au:
+ elif fmt[:1] == "p" and not is_au and not is_vid:
t = "cannot thumbnail [%s]: png only allowed for waveforms"
self.log(t % (rem), 6)
return None
diff --git a/copyparty/th_srv.py b/copyparty/th_srv.py
index 88d03395..0f9dcf1f 100644
--- a/copyparty/th_srv.py
+++ b/copyparty/th_srv.py
@@ -304,23 +304,29 @@ class ThumbSrv(object):
ap_unpk = abspath
if not bos.path.exists(tpath):
+ want_mp3 = tpath.endswith(".mp3")
+ want_opus = tpath.endswith(".opus") or tpath.endswith(".caf")
+ want_png = tpath.endswith(".png")
+ want_au = want_mp3 or want_opus
for lib in self.args.th_dec:
+ can_au = lib == "ff" and (ext in self.fmt_ffa or ext in self.fmt_ffv)
+
if lib == "pil" and ext in self.fmt_pil:
funs.append(self.conv_pil)
elif lib == "vips" and ext in self.fmt_vips:
funs.append(self.conv_vips)
- elif lib == "ff" and ext in self.fmt_ffi or ext in self.fmt_ffv:
- funs.append(self.conv_ffmpeg)
- elif lib == "ff" and ext in self.fmt_ffa:
- if tpath.endswith(".opus") or tpath.endswith(".caf"):
+ elif can_au and (want_png or want_au):
+ if want_opus:
funs.append(self.conv_opus)
- elif tpath.endswith(".mp3"):
+ elif want_mp3:
funs.append(self.conv_mp3)
- elif tpath.endswith(".png"):
+ elif want_png:
funs.append(self.conv_waves)
png_ok = True
- else:
- funs.append(self.conv_spec)
+ elif lib == "ff" and (ext in self.fmt_ffi or ext in self.fmt_ffv):
+ funs.append(self.conv_ffmpeg)
+ elif lib == "ff" and ext in self.fmt_ffa and not want_au:
+ funs.append(self.conv_spec)
tdir, tfn = os.path.split(tpath)
ttpath = os.path.join(tdir, "w", tfn)
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index d4f54be8..99aa7b68 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -360,6 +360,7 @@ var Ls = {
"tvt_sel": "select file ( for cut / delete / ... )$NHotkey: S\">sel",
"tvt_edit": "open file in text editor$NHotkey: E\">✏️ edit",
+ "gt_vau": "don't show videos, just play the audio\">🎧",
"gt_msel": "enable file selection; ctrl-click a file to override$N$N<em>when active: doubleclick a file / folder to open it</em>$N$NHotkey: S\">multiselect",
"gt_crop": "center-crop thumbnails\">crop",
"gt_3x": "hi-res thumbnails\">3x",
@@ -874,6 +875,7 @@ var Ls = {
"tvt_sel": "markér filen ( for utklipp / sletting / ... )$NSnarvei: S\">merk",
"tvt_edit": "redigér filen$NSnarvei: E\">✏️ endre",
+ "gt_vau": "ikke vis videofiler, bare spill lyden\">🎧",
"gt_msel": "markér filer istedenfor å åpne dem; ctrl-klikk filer for å overstyre$N$N<em>når aktiv: dobbelklikk en fil / mappe for å åpne</em>$N$NSnarvei: S\">markering",
"gt_crop": "beskjær ikonene så de passer bedre\">✂",
"gt_3x": "høyere oppløsning på ikoner\">3x",
@@ -1709,7 +1711,7 @@ catch (ex) { }
var re_au_native = (can_ogg || have_acode) ? /\.(aac|flac|m4a|mp3|ogg|opus|wav)$/i : /\.(aac|flac|m4a|mp3|wav)$/i,
- re_au_all = /\.(aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|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)$/i;
+ re_au_all = /\.(aac|ac3|aif|aiff|alac|alaw|amr|ape|au|dfpwm|dts|flac|gsm|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|3gp|asf|avi|flv|m4v|mkv|mov|mp4|mpeg|mpeg2|mpegts|mpg|mpg2|nut|ogm|ogv|rm|ts|vob|webm|wmv)$/i;
// extract songs + add play column
@@ -4410,7 +4412,7 @@ var showfile = (function () {
var td = ebi(link.id).closest('tr').getElementsByTagName('td')[0];
- if (lang == 'md' && td.textContent != '-')
+ if (lang == 'ts' || (lang == 'md' && td.textContent != '-'))
continue;
td.innerHTML = '' +
+ '