mirror of
https://github.com/9001/copyparty.git
synced 2026-06-18 20:22:27 -06:00
ffmpeg bwrap sandbox
This commit is contained in:
parent
90639de984
commit
efa43f891b
|
|
@ -28,6 +28,7 @@ from .__init__ import (
|
||||||
MACOS,
|
MACOS,
|
||||||
PY2,
|
PY2,
|
||||||
PY36,
|
PY36,
|
||||||
|
UNIX,
|
||||||
VT100,
|
VT100,
|
||||||
WINDOWS,
|
WINDOWS,
|
||||||
E,
|
E,
|
||||||
|
|
@ -45,6 +46,7 @@ from .util import (
|
||||||
DEF_EXP,
|
DEF_EXP,
|
||||||
DEF_MTE,
|
DEF_MTE,
|
||||||
DEF_MTH,
|
DEF_MTH,
|
||||||
|
HAVE_BWRAP,
|
||||||
HAVE_IPV6,
|
HAVE_IPV6,
|
||||||
IMPLICATIONS,
|
IMPLICATIONS,
|
||||||
JINJA_VER,
|
JINJA_VER,
|
||||||
|
|
@ -1643,6 +1645,29 @@ def add_optouts(ap):
|
||||||
|
|
||||||
|
|
||||||
def add_safety(ap):
|
def add_safety(ap):
|
||||||
|
th_bwrap = ""
|
||||||
|
if HAVE_BWRAP:
|
||||||
|
zsl = [
|
||||||
|
"bwrap",
|
||||||
|
"--proc /proc",
|
||||||
|
"--tmpfs /tmp",
|
||||||
|
"--tmpfs /var",
|
||||||
|
"--tmpfs /run",
|
||||||
|
"--dev-bind /dev/null /dev/null",
|
||||||
|
"--dev-bind /dev/random /dev/random",
|
||||||
|
"--dev-bind /dev/urandom /dev/urandom",
|
||||||
|
"--chdir /tmp",
|
||||||
|
"--clearenv",
|
||||||
|
"--unshare-all",
|
||||||
|
"--cap-drop ALL",
|
||||||
|
"--die-with-parent",
|
||||||
|
"--new-session",
|
||||||
|
]
|
||||||
|
for d in ("/lib", "/lib64", "/usr/lib", "/usr/lib64"):
|
||||||
|
if os.path.isdir(d):
|
||||||
|
zsl.append(" --ro-bind %s %s" % (d, d))
|
||||||
|
th_bwrap = " ".join(zsl)
|
||||||
|
|
||||||
ap2 = ap.add_argument_group("safety options")
|
ap2 = ap.add_argument_group("safety options")
|
||||||
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
||||||
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav requires login, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --no-html --no-readme --no-logues --unpost=0 --no-del --no-mv --reflink --dav-auth --vague-403 -nih")
|
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav requires login, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --no-html --no-readme --no-logues --unpost=0 --no-del --no-mv --reflink --dav-auth --vague-403 -nih")
|
||||||
|
|
@ -1679,6 +1704,8 @@ def add_safety(ap):
|
||||||
ap2.add_argument("--loris", metavar="B", type=int, default=60, help="if a client maxes out the server connection limit without sending headers, ban it for \033[33mB\033[0m minutes; disable with [\033[32m0\033[0m]")
|
ap2.add_argument("--loris", metavar="B", type=int, default=60, help="if a client maxes out the server connection limit without sending headers, ban it for \033[33mB\033[0m minutes; disable with [\033[32m0\033[0m]")
|
||||||
ap2.add_argument("--acao", metavar="V[,V]", type=u, default="*", help="Access-Control-Allow-Origin; list of origins (domains/IPs without port) to accept requests from; [\033[32mhttps://1.2.3.4\033[0m]. Default [\033[32m*\033[0m] allows requests from all sites but removes cookies and http-auth; only ?pw=hunter2 survives")
|
ap2.add_argument("--acao", metavar="V[,V]", type=u, default="*", help="Access-Control-Allow-Origin; list of origins (domains/IPs without port) to accept requests from; [\033[32mhttps://1.2.3.4\033[0m]. Default [\033[32m*\033[0m] allows requests from all sites but removes cookies and http-auth; only ?pw=hunter2 survives")
|
||||||
ap2.add_argument("--acam", metavar="V[,V]", type=u, default="GET,HEAD", help="Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like \033[33m--acao\033[0m's description)")
|
ap2.add_argument("--acam", metavar="V[,V]", type=u, default="GET,HEAD", help="Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like \033[33m--acao\033[0m's description)")
|
||||||
|
if not ANYWIN and not UNIX:
|
||||||
|
ap2.add_argument("--th-bwrap", metavar="CMD", type=u, default=th_bwrap, help="optional bwrap sandbox command for FFmpeg and dcraw (Linux-only)")
|
||||||
|
|
||||||
|
|
||||||
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
def add_salt(ap, fk_salt, dk_salt, ah_salt):
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ def have_ff(name: str) -> bytes:
|
||||||
|
|
||||||
HAVE_FFMPEG = have_ff("ffmpeg")
|
HAVE_FFMPEG = have_ff("ffmpeg")
|
||||||
HAVE_FFPROBE = have_ff("ffprobe")
|
HAVE_FFPROBE = have_ff("ffprobe")
|
||||||
|
TH_BWRAP = []
|
||||||
|
|
||||||
CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif jxl".split())
|
CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif jxl".split())
|
||||||
CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b")
|
CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b")
|
||||||
|
|
@ -224,17 +225,28 @@ def au_unpk(
|
||||||
return abspath
|
return abspath
|
||||||
|
|
||||||
|
|
||||||
|
def bwrap(prog: bytes, ap_in: bytes, ap_out: bytes) -> list[bytes]:
|
||||||
|
if not TH_BWRAP:
|
||||||
|
return [prog]
|
||||||
|
ret = TH_BWRAP + [b"--ro-bind", prog, prog, b"--ro-bind", ap_in, ap_in]
|
||||||
|
if ap_out:
|
||||||
|
zs = ap_out.rsplit(b"/", 1)[0]
|
||||||
|
ret += [b"--bind", zs, zs]
|
||||||
|
ret.append(prog)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def ffprobe(
|
def ffprobe(
|
||||||
abspath: str, timeout: int = 60
|
abspath: str, timeout: int = 60
|
||||||
) -> tuple[dict[str, tuple[int, Any]], dict[str, list[Any]], list[Any], dict[str, Any]]:
|
) -> tuple[dict[str, tuple[int, Any]], dict[str, list[Any]], list[Any], dict[str, Any]]:
|
||||||
# ffprobe -hide_banner -show_streams -show_format --
|
# ffprobe -hide_banner -show_streams -show_format --
|
||||||
cmd = [
|
bap = fsenc(abspath)
|
||||||
HAVE_FFPROBE,
|
cmd = bwrap(HAVE_FFPROBE, bap, b"") + [
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-show_streams",
|
b"-show_streams",
|
||||||
b"-show_format",
|
b"-show_format",
|
||||||
b"--",
|
b"--",
|
||||||
fsenc(abspath),
|
bap,
|
||||||
]
|
]
|
||||||
rc, so, se = runcmd(cmd, timeout=timeout, nice=True, oom=200)
|
rc, so, se = runcmd(cmd, timeout=timeout, nice=True, oom=200)
|
||||||
retchk(rc, cmd, se)
|
retchk(rc, cmd, se)
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,23 @@ if True: # pylint: disable=using-constant-test
|
||||||
import typing
|
import typing
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, E, EnvParams, unicode
|
from .__init__ import (
|
||||||
|
ANYWIN,
|
||||||
|
EXE,
|
||||||
|
MACOS,
|
||||||
|
PY2,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
UNIX,
|
||||||
|
E,
|
||||||
|
EnvParams,
|
||||||
|
unicode,
|
||||||
|
)
|
||||||
from .__version__ import S_VERSION, VERSION
|
from .__version__ import S_VERSION, VERSION
|
||||||
from .authsrv import BAD_CFG, AuthSrv, derive_args, n_du_who, n_ver_who
|
from .authsrv import BAD_CFG, AuthSrv, derive_args, n_du_who, n_ver_who
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .cert import ensure_cert
|
from .cert import ensure_cert
|
||||||
from .fsutil import ramdisk_chk
|
from .fsutil import ramdisk_chk
|
||||||
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, HAVE_MUTAGEN, TH_BWRAP
|
||||||
from .pwhash import HAVE_ARGON2
|
from .pwhash import HAVE_ARGON2
|
||||||
from .sutil import close_pools as sutil_close_pools
|
from .sutil import close_pools as sutil_close_pools
|
||||||
from .tcpsrv import TcpSrv
|
from .tcpsrv import TcpSrv
|
||||||
|
|
@ -42,8 +52,6 @@ from .th_srv import (
|
||||||
H_PIL_HEIF,
|
H_PIL_HEIF,
|
||||||
H_PIL_WEBP,
|
H_PIL_WEBP,
|
||||||
HAVE_DCRAW,
|
HAVE_DCRAW,
|
||||||
HAVE_FFMPEG,
|
|
||||||
HAVE_FFPROBE,
|
|
||||||
HAVE_PIL,
|
HAVE_PIL,
|
||||||
HAVE_RAWPY,
|
HAVE_RAWPY,
|
||||||
HAVE_VIPS,
|
HAVE_VIPS,
|
||||||
|
|
@ -56,6 +64,7 @@ from .util import (
|
||||||
DEF_MTE,
|
DEF_MTE,
|
||||||
DEF_MTH,
|
DEF_MTH,
|
||||||
FFMPEG_URL,
|
FFMPEG_URL,
|
||||||
|
HAVE_BWRAP,
|
||||||
HAVE_PSUTIL,
|
HAVE_PSUTIL,
|
||||||
HAVE_SQLITE3,
|
HAVE_SQLITE3,
|
||||||
HAVE_ZMQ,
|
HAVE_ZMQ,
|
||||||
|
|
@ -1013,6 +1022,8 @@ class SvcHub(object):
|
||||||
fok = []
|
fok = []
|
||||||
fng = []
|
fng = []
|
||||||
t_ff = "transcode audio, create spectrograms, video thumbnails"
|
t_ff = "transcode audio, create spectrograms, video thumbnails"
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
to_check = [
|
to_check = [
|
||||||
(HAVE_SQLITE3, "sqlite", "sessions and file/media indexing"),
|
(HAVE_SQLITE3, "sqlite", "sessions and file/media indexing"),
|
||||||
(HAVE_PIL, "pillow", "image thumbnails (plenty fast)"),
|
(HAVE_PIL, "pillow", "image thumbnails (plenty fast)"),
|
||||||
|
|
@ -1020,6 +1031,7 @@ class SvcHub(object):
|
||||||
(H_PIL_WEBP, "pillow-webp", "create thumbnails as webp files"),
|
(H_PIL_WEBP, "pillow-webp", "create thumbnails as webp files"),
|
||||||
(HAVE_FFMPEG, "ffmpeg", t_ff + ", good-but-slow image thumbnails"),
|
(HAVE_FFMPEG, "ffmpeg", t_ff + ", good-but-slow image thumbnails"),
|
||||||
(HAVE_FFPROBE, "ffprobe", t_ff + ", read audio/media tags"),
|
(HAVE_FFPROBE, "ffprobe", t_ff + ", read audio/media tags"),
|
||||||
|
(HAVE_BWRAP, "bwrap", "sandbox to make ffmpeg less dangerous", not ANYWIN and not UNIX),
|
||||||
(HAVE_MUTAGEN, "mutagen", "read audio tags (ffprobe is better but slower)"),
|
(HAVE_MUTAGEN, "mutagen", "read audio tags (ffprobe is better but slower)"),
|
||||||
(HAVE_ARGON2, "argon2", "secure password hashing (advanced users only)"),
|
(HAVE_ARGON2, "argon2", "secure password hashing (advanced users only)"),
|
||||||
(HAVE_ZMQ, "pyzmq", "send zeromq messages from event-hooks"),
|
(HAVE_ZMQ, "pyzmq", "send zeromq messages from event-hooks"),
|
||||||
|
|
@ -1027,17 +1039,21 @@ class SvcHub(object):
|
||||||
(H_PIL_AVIF, "pillow-avif", "read .avif pics with pillow (rarely useful)"),
|
(H_PIL_AVIF, "pillow-avif", "read .avif pics with pillow (rarely useful)"),
|
||||||
(HAVE_RAWPY, "rawpy", "read RAW images"),
|
(HAVE_RAWPY, "rawpy", "read RAW images"),
|
||||||
(HAVE_DCRAW, "libraw", "read RAW images"),
|
(HAVE_DCRAW, "libraw", "read RAW images"),
|
||||||
|
(HAVE_PSUTIL, "psutil", "improved plugin cleanup (rarely useful)", ANYWIN),
|
||||||
]
|
]
|
||||||
if ANYWIN:
|
# fmt: on
|
||||||
to_check += [
|
|
||||||
(HAVE_PSUTIL, "psutil", "improved plugin cleanup (rarely useful)")
|
|
||||||
]
|
|
||||||
|
|
||||||
verbose = self.args.deps
|
verbose = self.args.deps
|
||||||
if verbose:
|
if verbose:
|
||||||
self.log("dependencies", "")
|
self.log("dependencies", "")
|
||||||
|
|
||||||
for have, feat, what in to_check:
|
for zc in to_check:
|
||||||
|
try:
|
||||||
|
have, feat, what = zc
|
||||||
|
except:
|
||||||
|
have, feat, what, zb = zc
|
||||||
|
if not zb:
|
||||||
|
continue
|
||||||
lst = fok if have else fng
|
lst = fok if have else fng
|
||||||
lst.append((feat, what))
|
lst.append((feat, what))
|
||||||
if verbose:
|
if verbose:
|
||||||
|
|
@ -1204,6 +1220,15 @@ class SvcHub(object):
|
||||||
vsa = [x.upper() for x in vsa if x]
|
vsa = [x.upper() for x in vsa if x]
|
||||||
setattr(al, k + "_set", set(vsa))
|
setattr(al, k + "_set", set(vsa))
|
||||||
|
|
||||||
|
zs = "th_bwrap"
|
||||||
|
for k in zs.split(" "):
|
||||||
|
zsl = [x for x in str(getattr(al, k)).split(" ") if x]
|
||||||
|
zbl = [x.encode("ascii", "replace") for x in zsl]
|
||||||
|
setattr(al, k + "_s", zsl)
|
||||||
|
setattr(al, k + "_b", zbl)
|
||||||
|
|
||||||
|
TH_BWRAP[:] = al.th_bwrap_b
|
||||||
|
|
||||||
zs = "dav_ua1 lf_url sus_urls nonsus_urls ua_nodav ua_nodoc ua_nozip"
|
zs = "dav_ua1 lf_url sus_urls nonsus_urls ua_nodav ua_nodoc ua_nozip"
|
||||||
for k in zs.split(" "):
|
for k in zs.split(" "):
|
||||||
vs = getattr(al, k)
|
vs = getattr(al, k)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ from queue import Queue
|
||||||
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
|
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
|
||||||
from .authsrv import VFS
|
from .authsrv import VFS
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, ffprobe, have_ff
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, bwrap, ffprobe, have_ff
|
||||||
from .util import BytesIO # type: ignore
|
from .util import BytesIO # type: ignore
|
||||||
from .util import (
|
from .util import (
|
||||||
FFMPEG_URL,
|
FFMPEG_URL,
|
||||||
|
|
@ -763,14 +763,14 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
def _conv_dcraw(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
def _conv_dcraw(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
||||||
self.wait4ram(0.6, tpath)
|
self.wait4ram(0.6, tpath)
|
||||||
|
bap = fsenc(abspath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_DCRAW, bap, b"") + [
|
||||||
b"dcraw_emu",
|
|
||||||
b"-h", # halfsize
|
b"-h", # halfsize
|
||||||
b"-o", b"1", # srgb
|
b"-o", b"1", # srgb
|
||||||
b"-s", b"0", # first frame
|
b"-s", b"0", # first frame
|
||||||
b"-Z", b"-", # to stdout
|
b"-Z", b"-", # to stdout
|
||||||
fsenc(abspath),
|
bap,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
p = sp.Popen(cmd, stdout=sp.PIPE)
|
p = sp.Popen(cmd, stdout=sp.PIPE)
|
||||||
|
|
@ -858,16 +858,15 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
res = self.getres(vn, fmt)
|
res = self.getres(vn, fmt)
|
||||||
bscale = scale.format(*list(res)).encode("utf-8")
|
bscale = scale.format(*list(res)).encode("utf-8")
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner"
|
b"-hide_banner"
|
||||||
]
|
] + seek + [
|
||||||
cmd += seek
|
b"-i", bap_in,
|
||||||
cmd += [
|
|
||||||
b"-i", fsenc(abspath),
|
|
||||||
b"-map", imap,
|
b"-map", imap,
|
||||||
b"-vf", bscale,
|
b"-vf", bscale,
|
||||||
b"-frames:v", b"1",
|
b"-frames:v", b"1",
|
||||||
|
|
@ -875,15 +874,15 @@ class ThumbSrv(object):
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
self._ffmpeg_im_o(tpath, vn, cmd)
|
self._ffmpeg_im_o(bap_out, vn, cmd)
|
||||||
|
|
||||||
def _ffmpeg_im_o(self, tpath: str, vn: VFS, cmd: list[bytes]) -> None:
|
def _ffmpeg_im_o(self, tpath: bytes, vn: VFS, cmd: list[bytes]) -> None:
|
||||||
if tpath.endswith(".jpg"):
|
if tpath.endswith(b".jpg"):
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
|
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
|
||||||
]
|
]
|
||||||
elif tpath.endswith(".jxl"):
|
elif tpath.endswith(b".jxl"):
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
unicode(vn.flags["th_qvx"]).encode("ascii"), # default=??
|
unicode(vn.flags["th_qvx"]).encode("ascii"), # default=??
|
||||||
|
|
@ -898,7 +897,7 @@ class ThumbSrv(object):
|
||||||
b"6", # default=4, 0=fast, 6=max
|
b"6", # default=4, 0=fast, 6=max
|
||||||
]
|
]
|
||||||
|
|
||||||
cmd += [fsenc(tpath)]
|
cmd.append(tpath)
|
||||||
self._run_ff(cmd, vn, "convt")
|
self._run_ff(cmd, vn, "convt")
|
||||||
|
|
||||||
def _run_ff(self, cmd: list[bytes], vn: VFS, kto: str, oom: int = 400) -> None:
|
def _run_ff(self, cmd: list[bytes], vn: VFS, kto: str, oom: int = 400) -> None:
|
||||||
|
|
@ -998,20 +997,21 @@ class ThumbSrv(object):
|
||||||
b",showwavespic=s=2048x64:colors=white"
|
b",showwavespic=s=2048x64:colors=white"
|
||||||
b",convolution=1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 -1 1 -1 5 -1 1 -1 1" # idk what im doing but it looks ok
|
b",convolution=1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 -1 1 -1 5 -1 1 -1 1" # idk what im doing but it looks ok
|
||||||
)
|
)
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-filter_complex", flt,
|
b"-filter_complex", flt,
|
||||||
b"-frames:v", b"1",
|
b"-frames:v", b"1",
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
cmd += [fsenc(tpath)]
|
cmd.append(bap_out)
|
||||||
self._run_ff(cmd, vn, "convt")
|
self._run_ff(cmd, vn, "convt")
|
||||||
|
|
||||||
if "pngquant" in vn.flags:
|
if "pngquant" in vn.flags:
|
||||||
|
|
@ -1078,19 +1078,21 @@ class ThumbSrv(object):
|
||||||
except:
|
except:
|
||||||
self.untemp[tpath] = [infile]
|
self.untemp[tpath] = [infile]
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(infile)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-ac", b"1",
|
b"-ac", b"1",
|
||||||
b"-ar", b"48000",
|
b"-ar", b"48000",
|
||||||
b"-sample_fmt", b"s16",
|
b"-sample_fmt", b"s16",
|
||||||
b"-t", b"900",
|
b"-t", b"900",
|
||||||
b"-y", fsenc(infile),
|
b"-y", bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "convt")
|
self._run_ff(cmd, vn, "convt")
|
||||||
|
|
@ -1110,20 +1112,22 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
fc = fc.format(fco)
|
fc = fc.format(fco)
|
||||||
|
|
||||||
|
bap_in = fsenc(infile)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(infile),
|
b"-i", bap_in,
|
||||||
b"-filter_complex", fc.encode("utf-8"),
|
b"-filter_complex", fc.encode("utf-8"),
|
||||||
b"-map", b"[o]",
|
b"-map", b"[o]",
|
||||||
b"-frames:v", b"1",
|
b"-frames:v", b"1",
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
self._ffmpeg_im_o(tpath, vn, cmd)
|
self._ffmpeg_im_o(bap_out, vn, cmd)
|
||||||
|
|
||||||
def conv_mp3(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
def conv_mp3(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
||||||
quality = self.args.q_mp3.lower()
|
quality = self.args.q_mp3.lower()
|
||||||
|
|
@ -1142,24 +1146,26 @@ class ThumbSrv(object):
|
||||||
qk = b"-q:a"
|
qk = b"-q:a"
|
||||||
qv = quality[1:].encode("ascii")
|
qv = quality[1:].encode("ascii")
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# extremely conservative choices for output format
|
# extremely conservative choices for output format
|
||||||
# (always 2ch 44k1) because if a device is old enough
|
# (always 2ch 44k1) because if a device is old enough
|
||||||
# to not support opus then it's probably also super picky
|
# to not support opus then it's probably also super picky
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
] + self.big_tags(rawtags) + [
|
] + self.big_tags(rawtags) + [
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-ar", b"44100",
|
b"-ar", b"44100",
|
||||||
b"-ac", b"2",
|
b"-ac", b"2",
|
||||||
b"-c:a", b"libmp3lame",
|
b"-c:a", b"libmp3lame",
|
||||||
qk, qv,
|
qk, qv,
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1175,16 +1181,18 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
self.log("conv2 flac", 6)
|
self.log("conv2 flac", 6)
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-c:a", b"flac",
|
b"-c:a", b"flac",
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1210,16 +1218,18 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
self.log("conv2 wav", 6)
|
self.log("conv2 wav", 6)
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-c:a", codec,
|
b"-c:a", codec,
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1271,19 +1281,21 @@ class ThumbSrv(object):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
] + tagset + [
|
] + tagset + [
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-ac", ac,
|
b"-ac", ac,
|
||||||
] + benc + [
|
] + benc + [
|
||||||
b"-f", container,
|
b"-f", container,
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1312,19 +1324,21 @@ class ThumbSrv(object):
|
||||||
self.log("conv2 caf-tmp [%s]" % (enc,), 6)
|
self.log("conv2 caf-tmp [%s]" % (enc,), 6)
|
||||||
benc = enc.encode("ascii").split(b" ")
|
benc = enc.encode("ascii").split(b" ")
|
||||||
|
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tmp_opus)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-map_metadata", b"-1",
|
b"-map_metadata", b"-1",
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-ac", b"2",
|
b"-ac", b"2",
|
||||||
] + benc + [
|
] + benc + [
|
||||||
b"-f", b"opus",
|
b"-f", b"opus",
|
||||||
fsenc(tmp_opus)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1338,20 +1352,21 @@ class ThumbSrv(object):
|
||||||
if dur < 20 or sz < 256 * 1024:
|
if dur < 20 or sz < 256 * 1024:
|
||||||
zs = bq.decode("ascii")
|
zs = bq.decode("ascii")
|
||||||
self.log("conv2 caf-transcode; dur=%d sz=%d q=%s" % (dur, sz, zs), 6)
|
self.log("conv2 caf-transcode; dur=%d sz=%d q=%s" % (dur, sz, zs), 6)
|
||||||
|
bap_in = fsenc(abspath)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(abspath),
|
b"-i", bap_in,
|
||||||
b"-filter_complex", b"anoisesrc=a=0.001:d=7:c=pink,asplit[l][r]; [l][r]amerge[s]; [0:a:0][s]amix",
|
b"-filter_complex", b"anoisesrc=a=0.001:d=7:c=pink,asplit[l][r]; [l][r]amerge[s]; [0:a:0][s]amix",
|
||||||
b"-map_metadata", b"-1",
|
b"-map_metadata", b"-1",
|
||||||
b"-ac", b"2",
|
b"-ac", b"2",
|
||||||
b"-c:a", b"libopus",
|
b"-c:a", b"libopus",
|
||||||
b"-b:a", bq,
|
b"-b:a", bq,
|
||||||
b"-f", b"caf",
|
b"-f", b"caf",
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
@ -1359,18 +1374,19 @@ class ThumbSrv(object):
|
||||||
else:
|
else:
|
||||||
# simple remux should be safe
|
# simple remux should be safe
|
||||||
self.log("conv2 caf-remux; dur=%d sz=%d" % (dur, sz), 6)
|
self.log("conv2 caf-remux; dur=%d sz=%d" % (dur, sz), 6)
|
||||||
|
bap_in = fsenc(tmp_opus)
|
||||||
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = [
|
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
||||||
HAVE_FFMPEG,
|
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-i", fsenc(tmp_opus),
|
b"-i", bap_in,
|
||||||
b"-map_metadata", b"-1",
|
b"-map_metadata", b"-1",
|
||||||
b"-map", b"0:a:0",
|
b"-map", b"0:a:0",
|
||||||
b"-c:a", b"copy",
|
b"-c:a", b"copy",
|
||||||
b"-f", b"caf",
|
b"-f", b"caf",
|
||||||
fsenc(tpath)
|
bap_out,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
self._run_ff(cmd, vn, "aconvt", oom=300)
|
self._run_ff(cmd, vn, "aconvt", oom=300)
|
||||||
|
|
|
||||||
|
|
@ -657,6 +657,14 @@ if EXE:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
if PY2 or ANYWIN:
|
||||||
|
raise Exception()
|
||||||
|
HAVE_BWRAP = shutil.which("bwrap")
|
||||||
|
except:
|
||||||
|
HAVE_BWRAP = ""
|
||||||
|
|
||||||
|
|
||||||
def py_desc() -> str:
|
def py_desc() -> str:
|
||||||
interp = platform.python_implementation()
|
interp = platform.python_implementation()
|
||||||
py_ver = ".".join([str(x) for x in sys.version_info])
|
py_ver = ".".join([str(x) for x in sys.version_info])
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ ENV XDG_CONFIG_HOME=/cfg
|
||||||
ARG ADD_PKG=""
|
ARG ADD_PKG=""
|
||||||
|
|
||||||
RUN apk --no-cache add !pyc ${ADD_PKG} \
|
RUN apk --no-cache add !pyc ${ADD_PKG} \
|
||||||
tzdata wget mimalloc2 mimalloc2-insecure \
|
tzdata wget mimalloc2 mimalloc2-insecure bubblewrap \
|
||||||
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
||||||
py3-openssl py3-paramiko py3-pillow
|
py3-openssl py3-paramiko py3-pillow
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ COPY i/bin/mtag/install-deps.sh ./
|
||||||
COPY i/bin/mtag/audio-bpm.py /mtag/
|
COPY i/bin/mtag/audio-bpm.py /mtag/
|
||||||
COPY i/bin/mtag/audio-key.py /mtag/
|
COPY i/bin/mtag/audio-key.py /mtag/
|
||||||
RUN apk add -U !pyc ${ADD_PKG} \
|
RUN apk add -U !pyc ${ADD_PKG} \
|
||||||
tzdata wget mimalloc2 mimalloc2-insecure \
|
tzdata wget mimalloc2 mimalloc2-insecure bubblewrap \
|
||||||
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
||||||
py3-openssl py3-paramiko py3-pillow \
|
py3-openssl py3-paramiko py3-pillow \
|
||||||
py3-pip \
|
py3-pip \
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ ENV XDG_CONFIG_HOME=/cfg
|
||||||
ARG ADD_PKG=""
|
ARG ADD_PKG=""
|
||||||
|
|
||||||
RUN apk add -U !pyc ${ADD_PKG} \
|
RUN apk add -U !pyc ${ADD_PKG} \
|
||||||
tzdata wget mimalloc2 mimalloc2-insecure \
|
tzdata wget mimalloc2 mimalloc2-insecure bubblewrap \
|
||||||
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
py3-jinja2 py3-argon2-cffi py3-pyzmq \
|
||||||
py3-openssl py3-paramiko py3-pillow \
|
py3-openssl py3-paramiko py3-pillow \
|
||||||
py3-pip \
|
py3-pip \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue