Last active
April 28, 2020 08:43
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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