Skip to content

Instantly share code, notes, and snippets.

@halloleo
Last active April 28, 2020 08:43
Show Gist options
  • Save halloleo/8ab33c7f98eb76a3930803596d10c641 to your computer and use it in GitHub Desktop.
Save halloleo/8ab33c7f98eb76a3930803596d10c641 to your computer and use it in GitHub Desktop.
Extract and unify the tracks of a Zeit Audio archive so that the tracks appear as part of one book (in audiobook players like Bound)
#!/usr/bin/env xonsh
"""
Extract and unify the tracks of a Zeit Audio archive
so that the tracks appear as part of one book
(in audiobook players like Bound)
"""
import re
import sys
import os
from pathlib import Path
import logging
try:
import click
import click_log
except ModuleNotFoundError:
print(f"ERROR: Starting up {$ARG0} failed. - Click or click_log module not " +
f"found. Please install into xonsh environment via xpip.")
sys.exit(99)
log = logging.getLogger(__name__)
click_log.basic_config(log)
def click_command(name=None, cls=None, **attrs):
"""
click.command with the option to reference the module doc string
in the function doc string.
Reference the module doc string with '{__doc__}' (without the backticks)
"""
if cls is None:
cls = click.Command
def decorator(f):
import inspect
doc = inspect.getdoc(f)
attrs['help'] = doc.replace('{__doc__}',__doc__)
cmd = click.decorators._make_command(f, name, attrs, cls)
cmd.__doc__ = f.__doc__
return cmd
return decorator
def click_option(*args, **kwargs):
"""
click.option with show_default set to True
If envvar is set show the default from the env var
"""
if not 'show_default' in kwargs:
# Make surethat it is not a flag
if not kwargs.get('is_flag', False):
show_default_val = True
if 'envvar' in kwargs:
envvar_name = kwargs['envvar']
envvar_val = os.getenv(envvar_name)
if envvar_val:
show_default_val = f"'{envvar_val}' from ${envvar_name}"
kwargs.update({'show_default': show_default_val})
return click.option(*args, **kwargs)
class ExpandedPath(click.Path):
def convert(self, value, *args, **kwargs):
value = os.path.expanduser(value)
return super(ExpandedPath, self).convert(value, *args, **kwargs)
@click_command()
@click_log.simple_verbosity_option(log)
@click_option('-f', '--force', is_flag=True, help='Force creation of output folder')
@click_option('-l', '--location', default='.', type=ExpandedPath(
exists=True, file_okay=False), envvar='EXTRACT_ZEIT_LOCATION',
help='Where to write the export folder to')
@click_option('-u', '--unmodified', is_flag=True, help='No modification of extracted '
'files')
@click.argument('zipfile', type=click.Path(exists=True))
def main(zipfile, force, location, unmodified):
"""
{__doc__}
The audio tracks are exported into a output folder ZIPFIlE (without extension) in the current directory
ZIPFILE should have a name like DZ_2020-17.zip containing a sub string <YEAR>-<WEEK>
"""
zip_stem = Path(zipfile).stem
outdir = Path(location).joinpath(zip_stem)
if outdir.exists():
if force:
rm -r @(outdir)
if outdir.exists():
raise click.UsageError(f"Out directory '{outdir}' already exists. - Abort.")
log.info(f"Extract archive to {outdir}")
res = !(unzip -d @(outdir) @(zipfile))
if res.rtn != 0:
raise click.Abort()
if unmodified:
return
album_numbers = re.sub(r'^.*?(20[0-9]{2})-([0-9]{1,2}).*',r'\2/\1',zip_stem)
album_name = f"Zeit {album_numbers}"
log.debug(f"Set album to {album_name}")
artist_name = "Various authors"
for f in outdir.glob('*'):
try:
log.debug(f"Working on {f}")
res = !(eyeD3 -Q --no-color --no-config -P display -p "%t% - %a%" @(str(f)))
if res.rtn == 0:
new_title = res.output.strip()
log.debug(f"Set title to {new_title}")
res = !(eyeD3 -Q --no-color --no-config -t @(new_title) -A @(album_name) -a @(artist_name) @(str(f)))
if res.rtn == 0:
cut_title_max = 15
cut_title = new_title if len(new_title) <= cut_title_max else (new_title[:cut_title_max] + '..')
log.info(f"Modified {f.name}: '{cut_title}' ({album_name} - {artist_name})")
else:
log.debug(f"Error modifying {f} ('{res.output}')")
else:
log.debug(f"Error reading {f} ('{res.output}')")
except AttributeError as e:
log.warning("Error: Couldn't find eyeD3 command. Please install eyeD3 (probably via pipx")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment