mirror of
https://github.com/9001/copyparty.git
synced 2025-08-18 09:22:31 -06:00
add audio transcoder
This commit is contained in:
parent
26c8589399
commit
f6f9fc5a45
|
@ -416,6 +416,9 @@ def run_argparse(argv, formatter):
|
||||||
ap2.add_argument("--th-maxage", metavar="SEC", type=int, default=604800, help="max folder age")
|
ap2.add_argument("--th-maxage", metavar="SEC", type=int, default=604800, help="max folder age")
|
||||||
ap2.add_argument("--th-covers", metavar="N,N", type=u, default="folder.png,folder.jpg,cover.png,cover.jpg", help="folder thumbnails to stat for")
|
ap2.add_argument("--th-covers", metavar="N,N", type=u, default="folder.png,folder.jpg,cover.png,cover.jpg", help="folder thumbnails to stat for")
|
||||||
|
|
||||||
|
ap2 = ap.add_argument_group('transcoding options')
|
||||||
|
ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding")
|
||||||
|
|
||||||
ap2 = ap.add_argument_group('general db options')
|
ap2 = ap.add_argument_group('general db options')
|
||||||
ap2.add_argument("-e2d", action="store_true", help="enable up2k database")
|
ap2.add_argument("-e2d", action="store_true", help="enable up2k database")
|
||||||
ap2.add_argument("-e2ds", action="store_true", help="enable up2k db-scanner, sets -e2d")
|
ap2.add_argument("-e2ds", action="store_true", help="enable up2k db-scanner, sets -e2d")
|
||||||
|
|
|
@ -2072,6 +2072,7 @@ class HttpCli(object):
|
||||||
"def_hcols": [],
|
"def_hcols": [],
|
||||||
"have_up2k_idx": ("e2d" in vn.flags),
|
"have_up2k_idx": ("e2d" in vn.flags),
|
||||||
"have_tags_idx": ("e2t" in vn.flags),
|
"have_tags_idx": ("e2t" in vn.flags),
|
||||||
|
"have_acode": (not self.args.no_acode),
|
||||||
"have_mv": (not self.args.no_mv),
|
"have_mv": (not self.args.no_mv),
|
||||||
"have_del": (not self.args.no_del),
|
"have_del": (not self.args.no_del),
|
||||||
"have_zip": (not self.args.no_zip),
|
"have_zip": (not self.args.no_zip),
|
||||||
|
|
|
@ -26,8 +26,16 @@ class ThumbCli(object):
|
||||||
if is_vid and self.args.no_vthumb:
|
if is_vid and self.args.no_vthumb:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
want_opus = fmt == "opus"
|
||||||
is_au = ext in FMT_FFA
|
is_au = ext in FMT_FFA
|
||||||
if is_au and self.args.no_athumb:
|
if is_au:
|
||||||
|
if want_opus:
|
||||||
|
if self.args.no_acode:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
if self.args.no_athumb:
|
||||||
|
return None
|
||||||
|
elif want_opus:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if rem.startswith(".hist/th/") and rem.split(".")[-1] in ["webp", "jpg"]:
|
if rem.startswith(".hist/th/") and rem.split(".")[-1] in ["webp", "jpg"]:
|
||||||
|
|
|
@ -51,7 +51,7 @@ except:
|
||||||
# ffmpeg -formats
|
# ffmpeg -formats
|
||||||
FMT_PIL = "bmp dib gif icns ico jpg jpeg jp2 jpx pcx png pbm pgm ppm pnm sgi tga tif tiff webp xbm dds xpm"
|
FMT_PIL = "bmp dib gif icns ico jpg jpeg jp2 jpx pcx png pbm pgm ppm pnm sgi tga tif tiff webp xbm dds xpm"
|
||||||
FMT_FFV = "av1 asf avi flv m4v mkv mjpeg mjpg mpg mpeg mpg2 mpeg2 h264 avc mts h265 hevc mov 3gp mp4 ts mpegts nut ogv ogm rm vob webm wmv"
|
FMT_FFV = "av1 asf avi flv m4v mkv mjpeg mjpg mpg mpeg mpg2 mpeg2 h264 avc mts h265 hevc mov 3gp mp4 ts mpegts nut ogv ogm rm vob webm wmv"
|
||||||
FMT_FFA = "aac m4a ogg opus flac alac mp3 mp2 ac3 dts wma wav aif aiff au amr gsm ape tak tta wv"
|
FMT_FFA = "aac m4a ogg opus flac alac mp3 mp2 ac3 dts wma ra wav aif aiff au amr gsm ape tak tta wv"
|
||||||
|
|
||||||
if HAVE_HEIF:
|
if HAVE_HEIF:
|
||||||
FMT_PIL += " heif heifs heic heics"
|
FMT_PIL += " heif heifs heic heics"
|
||||||
|
@ -90,9 +90,10 @@ def thumb_path(histpath, rem, mtime, fmt):
|
||||||
h = hashlib.sha512(fsenc(fn)).digest()
|
h = hashlib.sha512(fsenc(fn)).digest()
|
||||||
fn = base64.urlsafe_b64encode(h).decode("ascii")[:24]
|
fn = base64.urlsafe_b64encode(h).decode("ascii")[:24]
|
||||||
|
|
||||||
return "{}/th/{}/{}.{:x}.{}".format(
|
if fmt != "opus":
|
||||||
histpath, rd, fn, int(mtime), "webp" if fmt == "w" else "jpg"
|
fmt = "webp" if fmt == "w" else "jpg"
|
||||||
)
|
|
||||||
|
return "{}/th/{}/{}.{:x}.{}".format(histpath, rd, fn, int(mtime), fmt)
|
||||||
|
|
||||||
|
|
||||||
class ThumbSrv(object):
|
class ThumbSrv(object):
|
||||||
|
@ -207,6 +208,9 @@ class ThumbSrv(object):
|
||||||
elif ext in FMT_FFV:
|
elif ext in FMT_FFV:
|
||||||
fun = self.conv_ffmpeg
|
fun = self.conv_ffmpeg
|
||||||
elif ext in FMT_FFA:
|
elif ext in FMT_FFA:
|
||||||
|
if tpath.endswith(".opus"):
|
||||||
|
fun = self.conv_opus
|
||||||
|
else:
|
||||||
fun = self.conv_spec
|
fun = self.conv_spec
|
||||||
|
|
||||||
if fun:
|
if fun:
|
||||||
|
@ -346,7 +350,6 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
def conv_spec(self, abspath, tpath):
|
def conv_spec(self, abspath, tpath):
|
||||||
ret, _ = ffprobe(abspath)
|
ret, _ = ffprobe(abspath)
|
||||||
|
|
||||||
if "ac" not in ret:
|
if "ac" not in ret:
|
||||||
raise Exception("not audio")
|
raise Exception("not audio")
|
||||||
|
|
||||||
|
@ -381,6 +384,30 @@ class ThumbSrv(object):
|
||||||
cmd += [fsenc(tpath)]
|
cmd += [fsenc(tpath)]
|
||||||
self._run_ff(cmd)
|
self._run_ff(cmd)
|
||||||
|
|
||||||
|
def conv_opus(self, abspath, tpath):
|
||||||
|
if self.args.no_acode:
|
||||||
|
raise Exception("disabled in server config")
|
||||||
|
|
||||||
|
ret, _ = ffprobe(abspath)
|
||||||
|
if "ac" not in ret:
|
||||||
|
raise Exception("not audio")
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
cmd = [
|
||||||
|
b"ffmpeg",
|
||||||
|
b"-nostdin",
|
||||||
|
b"-v", b"error",
|
||||||
|
b"-hide_banner",
|
||||||
|
b"-i", fsenc(abspath),
|
||||||
|
b"-map", b"0:a:0",
|
||||||
|
b"-c:a", b"libopus",
|
||||||
|
b"-b:a", b"128k",
|
||||||
|
fsenc(tpath)
|
||||||
|
]
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
self._run_ff(cmd)
|
||||||
|
|
||||||
def poke(self, tdir):
|
def poke(self, tdir):
|
||||||
if not self.poke_cd.poke(tdir):
|
if not self.poke_cd.poke(tdir):
|
||||||
return
|
return
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
def_hcols = {{ def_hcols|tojson }},
|
def_hcols = {{ def_hcols|tojson }},
|
||||||
have_up2k_idx = {{ have_up2k_idx|tojson }},
|
have_up2k_idx = {{ have_up2k_idx|tojson }},
|
||||||
have_tags_idx = {{ have_tags_idx|tojson }},
|
have_tags_idx = {{ have_tags_idx|tojson }},
|
||||||
|
have_acode = {{ have_acode|tojson }},
|
||||||
have_mv = {{ have_mv|tojson }},
|
have_mv = {{ have_mv|tojson }},
|
||||||
have_del = {{ have_del|tojson }},
|
have_del = {{ have_del|tojson }},
|
||||||
have_unpost = {{ have_unpost|tojson }},
|
have_unpost = {{ have_unpost|tojson }},
|
||||||
|
|
|
@ -320,6 +320,14 @@ var mpl = (function () {
|
||||||
'<a href="#" class="tgl btn" tt="load the next folder and continue">📂 next-folder</a>' +
|
'<a href="#" class="tgl btn" tt="load the next folder and continue">📂 next-folder</a>' +
|
||||||
'</div></div>' +
|
'</div></div>' +
|
||||||
|
|
||||||
|
(have_acode ? (
|
||||||
|
'<div><h3>transcode</h3><div>' +
|
||||||
|
'<a href="#" id="ac_flac" class="tgl btn" tt="convert flac to opus">flac</a>' +
|
||||||
|
'<a href="#" id="ac_aac" class="tgl btn" tt="convert aac/m4a to opus">aac</a>' +
|
||||||
|
'<a href="#" id="ac_oth" class="tgl btn" tt="convert all others (not mp3) to opus">oth</a>' +
|
||||||
|
'</div></div>'
|
||||||
|
) : '') +
|
||||||
|
|
||||||
'<div><h3>tint</h3><div>' +
|
'<div><h3>tint</h3><div>' +
|
||||||
'<input type="text" id="pb_tint" size="3" value="0" tt="background level (0-100) on the seekbar$Nto make buffering less distracting" />' +
|
'<input type="text" id="pb_tint" size="3" value="0" tt="background level (0-100) on the seekbar$Nto make buffering less distracting" />' +
|
||||||
'</div></div>' +
|
'</div></div>' +
|
||||||
|
@ -335,6 +343,9 @@ var mpl = (function () {
|
||||||
bcfg_bind(r, 'clip', 'au_npclip', false, function (v) {
|
bcfg_bind(r, 'clip', 'au_npclip', false, function (v) {
|
||||||
clmod(ebi('wtoggle'), 'np', v && mp.au);
|
clmod(ebi('wtoggle'), 'np', v && mp.au);
|
||||||
});
|
});
|
||||||
|
bcfg_bind(r, 'ac_flac', 'ac_flac', true);
|
||||||
|
bcfg_bind(r, 'ac_aac', 'ac_aac', false);
|
||||||
|
bcfg_bind(r, 'ac_oth', 'ac_oth', true, reload_mp);
|
||||||
|
|
||||||
ebi('au_os_ctl').onclick = function (e) {
|
ebi('au_os_ctl').onclick = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
|
@ -373,6 +384,23 @@ var mpl = (function () {
|
||||||
};
|
};
|
||||||
set_tint();
|
set_tint();
|
||||||
|
|
||||||
|
r.acode = function (url) {
|
||||||
|
var c = true;
|
||||||
|
if (!have_acode)
|
||||||
|
c = false;
|
||||||
|
else if (/\.flac$/i.exec(url))
|
||||||
|
c = r.ac_flac;
|
||||||
|
else if (/\.(aac|m4a)$/i.exec(url))
|
||||||
|
c = r.ac_aac;
|
||||||
|
else if (re_au_native.exec(url))
|
||||||
|
c = false;
|
||||||
|
|
||||||
|
if (!c)
|
||||||
|
return url;
|
||||||
|
|
||||||
|
return url + (url.indexOf('?') < 0 ? '?' : '&') + 'th=opus';
|
||||||
|
};
|
||||||
|
|
||||||
r.pp = function () {
|
r.pp = function () {
|
||||||
if (!r.os_ctl)
|
if (!r.os_ctl)
|
||||||
return;
|
return;
|
||||||
|
@ -441,6 +469,10 @@ var mpl = (function () {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
var re_au_native = /\.(opus|ogg|m4a|aac|mp3|wav|flac)$/i,
|
||||||
|
re_au_all = /\.(aac|m4a|ogg|opus|flac|alac|mp3|mp2|ac3|dts|wma|ra|wav|aif|aiff|au|amr|gsm|ape|tak|tta|wv)$/i;
|
||||||
|
|
||||||
|
|
||||||
// extract songs + add play column
|
// extract songs + add play column
|
||||||
function MPlayer() {
|
function MPlayer() {
|
||||||
var r = this;
|
var r = this;
|
||||||
|
@ -454,7 +486,7 @@ function MPlayer() {
|
||||||
r.tracks = {};
|
r.tracks = {};
|
||||||
r.order = [];
|
r.order = [];
|
||||||
|
|
||||||
var re_audio = /\.(opus|ogg|m4a|aac|mp3|wav|flac)$/i,
|
var re_audio = mpl.ac_oth ? re_au_all : re_au_native,
|
||||||
trs = QSA('#files tbody tr');
|
trs = QSA('#files tbody tr');
|
||||||
|
|
||||||
for (var a = 0, aa = trs.length; a < aa; a++) {
|
for (var a = 0, aa = trs.length; a < aa; a++) {
|
||||||
|
@ -552,6 +584,7 @@ function MPlayer() {
|
||||||
|
|
||||||
r.preload = function (url) {
|
r.preload = function (url) {
|
||||||
var au = null;
|
var au = null;
|
||||||
|
url = mpl.acode(url);
|
||||||
if (need_ogv_for(url)) {
|
if (need_ogv_for(url)) {
|
||||||
au = mp.au_ogvjs2;
|
au = mp.au_ogvjs2;
|
||||||
if (!au && window['OGVPlayer']) {
|
if (!au && window['OGVPlayer']) {
|
||||||
|
@ -1033,7 +1066,7 @@ var mpui = (function () {
|
||||||
if (pos > 0 && pos > len - 10) {
|
if (pos > 0 && pos > len - 10) {
|
||||||
preloaded = mp.au.src;
|
preloaded = mp.au.src;
|
||||||
try {
|
try {
|
||||||
mp.preload(ebi(mp.order[mp.order.indexOf(mp.au.tid) + 1]).href);
|
mp.preload(mp.tracks[mp.order[mp.order.indexOf(mp.au.tid) + 1]]);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
console.log("preload failed", ex);
|
console.log("preload failed", ex);
|
||||||
|
@ -1078,7 +1111,7 @@ catch (ex) { }
|
||||||
|
|
||||||
|
|
||||||
function need_ogv_for(url) {
|
function need_ogv_for(url) {
|
||||||
return need_ogv && /\.(ogg|opus)$/i.test(url);
|
return need_ogv && /\.(ogg|opus)|\?th=opus/i.test(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1378,7 +1411,7 @@ function play(tid, is_ev, seek, call_depth) {
|
||||||
// ogv.js breaks on .play() unless directly user-triggered
|
// ogv.js breaks on .play() unless directly user-triggered
|
||||||
var attempt_play = true;
|
var attempt_play = true;
|
||||||
|
|
||||||
var url = mp.tracks[tid];
|
var url = mpl.acode(mp.tracks[tid]);
|
||||||
if (need_ogv_for(url)) {
|
if (need_ogv_for(url)) {
|
||||||
var m = /.* Version\/([0-9]+)\.[0-9\.]+ Mobile\/[^ ]+ Safari\/[0-9\.]+$/.exec(navigator.userAgent),
|
var m = /.* Version\/([0-9]+)\.[0-9\.]+ Mobile\/[^ ]+ Safari\/[0-9\.]+$/.exec(navigator.userAgent),
|
||||||
safari = m ? parseInt(m[1]) : 99;
|
safari = m ? parseInt(m[1]) : 99;
|
||||||
|
@ -1435,7 +1468,7 @@ function play(tid, is_ev, seek, call_depth) {
|
||||||
|
|
||||||
audio_eq.apply();
|
audio_eq.apply();
|
||||||
|
|
||||||
url += (url.indexOf('?') < 0 ? '?cache' : '&cache');
|
url += (url.indexOf('?') < 0 ? '?' : '&') + 'cache';
|
||||||
if (mp.au.src == url)
|
if (mp.au.src == url)
|
||||||
mp.au.currentTime = 0;
|
mp.au.currentTime = 0;
|
||||||
else {
|
else {
|
||||||
|
@ -4450,6 +4483,10 @@ function reload_mp() {
|
||||||
}
|
}
|
||||||
mpl.stop();
|
mpl.stop();
|
||||||
widget.close();
|
widget.close();
|
||||||
|
var plays = QSA('tr>td:first-child>a.play');
|
||||||
|
for (var a = plays.length - 1; a >= 0; a--)
|
||||||
|
plays[a].parentNode.innerHTML = '-';
|
||||||
|
|
||||||
mp = new MPlayer();
|
mp = new MPlayer();
|
||||||
setTimeout(pbar.onresize, 1);
|
setTimeout(pbar.onresize, 1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue