1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- '''
- 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('audioscript')
- 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 {}'.format([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.'
|