#!/usr/bin/env python3
import argparse
import mutagen.id3
import mutagen.mp3
import os
import sys
from nullroute.core import Core

def trace(msg):
    global verbose
    if verbose:
        print(msg, file=sys.stderr)

def usage():
    print("Usage:")
    print("    import: cover -i [-f image_file] audio_file [audio_file ...]")
    print("    export: cover -e [-f image_file] audio_file")
    print("    remove: cover -x audio_file [audio_file ...]")

def fileext_to_type(ext):
    return {
        "jpeg": "image/jpeg",
        "jpg":  "image/jpeg",
        "png":  "image/png",
    }[ext[1:]]

def type_to_fileext(type):
    return {
        "image/jpeg":   ".jpeg",
        "image/png":    ".png",
    }[type]

def export_cover(file, cover_file):
    try:
        filetag = mutagen.mp3.MP3(file)
    except BaseException as e:
        Core.err(e)
        return False

    if "APIC:" not in filetag:
        Core.err("no cover image (APIC frame not found)")
        return False

    buf = filetag["APIC:"].data

    if (not cover_file) and sys.stdout.isatty():
        exit("error: Not writing cover to terminal (%d bytes)" % len(buf))

    with open(cover_file or "/dev/stdout", "wb") as cover_fh:
        trace("exporting image: %s" % cover_file)
        cover_fh.write(buf)

    return True

def import_cover(file, image_data, image_type="image/jpeg"):
    try:
        filetag = mutagen.mp3.MP3(file)
    except BaseException as e:
        Core.err(e)
        return False

    trace("using content type %r" % image_type)

    filetag.tags.add(mutagen.id3.APIC(
        data=image_data,
        mime=image_type,
        type=mutagen.id3.PictureType.COVER_FRONT,
        desc=u"",
        encoding=mutagen.id3.Encoding.UTF8))

    trace("updating tags: %s" % file)
    try:
        filetag.save()
    except BaseException as e:
        Core.err(e)
        return False
    else:
        return True

def remove_cover(file):
    try:
        filetag = mutagen.mp3.MP3(file)
    except BaseException as e:
        Core.err(e)
        return False

    if "APIC:" in filetag:
        del filetag["APIC:"]

    trace("updating tags: %s" % file)
    try:
        filetag.save()
    except BaseException as e:
        Core.err(e)
        return False
    else:
        return True

parser = argparse.ArgumentParser()
parser.add_argument("-e", "-o", "--export",
                    dest="do_export",
                    action="store_true",
                    help="export cover art from ID3 tag to file")
parser.add_argument("-i", "--import",
                    dest="do_import",
                    action="store_true",
                    help="import cover art from file to ID3 tag")
parser.add_argument("-r", "-x", "--remove",
                    dest="do_remove",
                    action="store_true",
                    help="remove cover art from ID3 tags")
parser.add_argument("-f", "--cover-file",
                    help="path to image file")
parser.add_argument("-v", "--verbose",
                    action="store_true",
                    help="print more details")
parser.add_argument("mp3_file", nargs="+")
args = parser.parse_args()

cover_file = args.cover_file
verbose = args.verbose
files = args.mp3_file

if (args.do_export + args.do_import + args.do_remove) > 1:
    exit("error: Conflicting mode options given")

elif args.do_import:
    if cover_file:
        _, ext = os.path.splitext(cover_file)
        image_type = fileext_to_type(ext)
    else:
        cover_file = "/dev/stdin"
        image_type = None #"image/jpeg"
    with open(cover_file, "rb") as fh:
        image_data = fh.read()
    for audiofile in files:
        import_cover(audiofile, image_data, image_type)

elif args.do_export:
    if len(files) > 1:
        exit("error: Cannot export multiple covers to one file")
    ret = export_cover(files[0], cover_file)
    sys.exit(0 if ret else 1)

elif args.do_remove:
    ret = True
    for audiofile in files:
        ret = remove_cover(audiofile) and ret
    sys.exit(0 if ret else 1)

else:
    exit("error: No operation specified")
