78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
"""
|
|
script audiogenerator: uses an external program to generate audio URIs
|
|
|
|
a script can be any valid executable in
|
|
$XDG_CONFIG_DIR/larigira/scripts/<name>; for security reasons, it must be
|
|
executable and owned by the current user. The audiospec can specify arguments
|
|
to the script, while the environment cannot be customized (again, this is for
|
|
security reasons).
|
|
|
|
The script should assume a minimal environment, and being run from /. It must
|
|
output one URI per line; please remember that URI must be understood from mpd,
|
|
so file paths are not valid; file:///file/path.ogg is a valid URI instead.
|
|
The output MUST be UTF-8-encoded.
|
|
Empty lines will be skipped. stderr will be logged, so please be careful. any
|
|
non-zero exit code will result in no files being added.and an exception being
|
|
logged.
|
|
"""
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
|
|
from .config import get_conf
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def generate(spec):
|
|
"""
|
|
Recognized arguments (fields in spec):
|
|
- name [mandatory] script name
|
|
- args [default=empty] arguments, colon-separated
|
|
"""
|
|
conf = get_conf()
|
|
spec.setdefault("args", "")
|
|
if type(spec["args"]) is str:
|
|
args = spec["args"].split(";")
|
|
args = list(spec["args"])
|
|
for attr in ("name",):
|
|
if attr not in spec:
|
|
raise ValueError("Malformed audiospec: missing '%s'" % attr)
|
|
|
|
if "/" in spec["name"]:
|
|
raise ValueError(
|
|
"Script name is a filename, not a path ({} provided)".format(spec["name"])
|
|
)
|
|
scriptpath = os.path.join(conf["SCRIPTS_PATH"], spec["name"])
|
|
if not os.path.exists(scriptpath):
|
|
raise ValueError("Script %s not found", spec["name"])
|
|
if not os.access(scriptpath, os.R_OK | os.X_OK):
|
|
raise ValueError("Insufficient privileges for script %s" % scriptpath)
|
|
|
|
if os.stat(scriptpath).st_uid != os.getuid():
|
|
raise ValueError(
|
|
"Script %s owned by %d, should be owned by %d"
|
|
% (spec["name"], os.stat(scriptpath).st_uid, os.getuid())
|
|
)
|
|
try:
|
|
log.info("Going to run %s", [scriptpath] + args)
|
|
env = dict(
|
|
HOME=os.environ["HOME"],
|
|
PATH=os.environ["PATH"],
|
|
MPD_HOST=conf["MPD_HOST"],
|
|
MPD_PORT=str(conf["MPD_PORT"]),
|
|
)
|
|
if "TMPDIR" in os.environ:
|
|
env["TMPDIR"] = os.environ["TMPDIR"]
|
|
out = subprocess.check_output([scriptpath] + args, env=env, cwd="/")
|
|
except subprocess.CalledProcessError as exc:
|
|
log.error("Error %d when running script %s", exc.returncode, spec["name"])
|
|
return []
|
|
|
|
out = out.decode("utf-8")
|
|
out = [p for p in out.split("\n") if p]
|
|
logging.debug("Script %s produced %d files", spec["name"], len(out))
|
|
return out
|
|
|
|
|
|
generate.description = "Generate audio through an external script. " "Experts only."
|