Last active
January 22, 2021 08:08
-
-
Save kkew3/e7051f473eb30ecb2cc8d4eb3f026ee0 to your computer and use it in GitHub Desktop.
Extract cover art using [`mid3v2`](https://github.com/quodlibet/mutagen/blob/master/mutagen/_tools/mid3v2.py)
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 python3 | |
import os | |
import sys | |
import argparse | |
import subprocess | |
import ast | |
HOMEDIR = os.path.normpath(os.environ['HOME']) | |
MUSICDIR = os.path.join(HOMEDIR, 'Music') | |
COVERARTDIR = os.path.join(MUSICDIR, '.cover-arts') | |
OK = 0 | |
ERRNO_MID3V2_NOT_FOUND = 1 | |
ERRNO_MID3V2_TIMEOUT = 2 | |
ERRNO_MID3V2_FAILED = 4 | |
ERRNO_TAGINFO_NO_MIME = 8 | |
ERRNO_TAGINFO_NO_DATA = 16 | |
ERRNO_TAGINFO_NO_APIC = 32 | |
def make_parser(): | |
parser = argparse.ArgumentParser( | |
description=('Extract cover art, if any, from FILEs under ' | |
'~/Music/ and save them to ~/Music/.cover-arts/.')) | |
parser.add_argument('filenames', metavar='FILE', nargs='*') | |
return parser | |
def extract_apic_info(filename): | |
command_s = 'mid3v2 --list-raw "{}"'.format(filename) | |
try: | |
output = subprocess.check_output(['mid3v2', '--list-raw', filename], | |
stderr=subprocess.STDOUT, | |
timeout=5, | |
cwd=MUSICDIR) | |
except FileNotFoundError: | |
print('`mid3v2\' is required to run this script!', file=sys.stderr) | |
return ERRNO_MID3V2_NOT_FOUND | |
except subprocess.TimeoutExpired: | |
print('`{}\' timeout!'.format(command_s), file=sys.stderr) | |
return ERRNO_MID3V2_TIMEOUT | |
except subprocess.CalledProcessError as err: | |
print( | |
'`{}\' failed with error code {}'.format(command_s, | |
err.returncode), | |
file=sys.stderr) | |
return ERRNO_MID3V2_FAILED | |
for line in output.decode('utf-8').split('\n'): | |
if line.startswith('APIC('): | |
try: | |
mime_start_pos = line.index("mime='") | |
except ValueError: | |
print( | |
'failed to find MIME type in `{}\'s output'.format( | |
command_s), | |
file=sys.stderr) | |
return ERRNO_TAGINFO_NO_MIME | |
mime_end_pos = line.index("',", mime_start_pos) | |
mime = line[mime_start_pos + len("mime='"):mime_end_pos] | |
_literal_image, ext = mime.split('/', maxsplit=1) | |
assert _literal_image == 'image', \ | |
'unrecognized MIME {}'.format(mime) | |
try: | |
data_start_pos = line.index('data=', mime_end_pos) | |
except ValueError: | |
print( | |
'failed to find image data in `{}\'s output'.format( | |
command_s), | |
file=sys.stderr) | |
return ERRNO_TAGINFO_NO_DATA | |
data = line[data_start_pos + len('data='):-1] | |
buffer = ast.literal_eval(data) | |
fname = os.path.splitext(os.path.basename(filename))[0] | |
tofile = os.path.join(COVERARTDIR, '.'.join([fname, ext])) | |
with open(tofile, 'wb') as outfile: | |
outfile.write(buffer) | |
return OK | |
print('{}: no cover art found'.format(filename), file=sys.stderr) | |
return ERRNO_TAGINFO_NO_APIC | |
def main(): | |
args = make_parser().parse_args() | |
for filename in args.filenames: | |
returncode = extract_apic_info(filename) | |
if returncode not in [OK, ERRNO_TAGINFO_NO_APIC]: | |
sys.exit(returncode) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment