def fix_cover(audio: File):
    """
    Transfers album cover from audio key APIC:XXXX to APIC:
    Example
    audio['APIC: Payday 2.jpg'] = APIC() becomes audio['APIC:'] = APIC()
    """
    restart = False
    for k in audio.keys():
        if k.startswith('APIC:') and k != 'APIC:':
            apic = audio.pop(k)
            apic.desc = ''
            apic.encoding = 0
            audio['APIC:'] = apic
            audio.save()
            restart = True
            break
        elif k == 'APIC:' and audio[k].encoding != 0:
            apic = audio.pop(k)
            apic.desc = ''
            apic.encoding = 0
            audio[k] = apic
            audio.save()
            restart = True
            break
    if restart: fix_cover(audio)
Exemple #2
0
def writeAlbumCover(songPath: str, coverPath: str, picData=None):
    """ 给音频文件写入封面
    Parameters
    ----------
    songPath: 音频文件路径\n
    coverPath: 封面图片路径\n
    picData: 封面图片二进制数据
    """
    id_card = File(songPath)
    # 读取封面数据
    if not picData:
        with open(coverPath, 'rb') as f:
            picData = f.read()
    # 获取音频数据和图片数据后缀名
    audioSuffix = id_card.mime[0].split('/')[-1]
    try:
        picSuffix = imghdr.what(None, picData)
    except:
        picSuffix = 'jpeg'
    mimeType = 'image/' + picSuffix
    # 开始写入封面
    if audioSuffix == 'mp3':
        keyName = 'APIC:'
        keyName_list = []
        # 获取可能已经存在的封面键名
        for key in id_card.tags.keys():
            if key.startswith('APIC'):
                keyName = key
                keyName_list.append(key)
        # 弹出所有旧标签才能写入新数据
        for key in keyName_list:
            id_card.pop(key)
        id_card[keyName] = APIC(encoding=0,
                                mime=mimeType,
                                type=3,
                                desc='',
                                data=picData)
    elif audioSuffix == 'flac':
        # 创建Picture实例
        picture = Picture()
        # 设置属性值
        picture.mime = mimeType
        picture.data = picData
        picture.type = 0
        # 清除原来的图片数据
        id_card.clear_pictures()
        # 添加图片
        id_card.add_picture(picture)
    elif audioSuffix == 'mp4':
        try:
            id_card['covr'][0] = picData
        except:
            id_card['covr'] = [picData]  # 没有键时需要创建一个
    id_card.save()
def fix_cover(audio: File):
    """
    Transfers album cover from audio key APIC:XXXX to APIC:
    Example
    audio['APIC: Payday 2.jpg'] = APIC() becomes audio['APIC:'] = APIC()
     """
    for k in audio.keys():
        if k.startswith('APIC:') and k != 'APIC:':
            audio['APIC:'] = audio.pop(k)
            audio.save()
            break
Exemple #4
0
def main():
    args = sys.argv
    err = 0
    if 'id3help' in args:
        from mutagen.easyid3 import EasyID3
        for key in EasyID3.valid_keys.keys():
            print(key, )

    from optparse import OptionParser as OP

    OP = OP()
    OP.usage = ("%prog [options] filenames")
    OP.epilog = '%s id3help: for help with id3 tags' % os.path.basename(
        args[0])
    OP.add_option('-t',
                  '--tag',
                  dest='tag',
                  action='append',
                  help="set a tag",
                  metavar='tag=value')
    OP.add_option(
        '-a',
        '--add',
        dest='add',
        action='append',
        help='set/add values to a tag, without removing any existing values',
        metavar='tag=value')
    OP.add_option('-p',
                  '--pattern',
                  dest='pattern',
                  action='store',
                  help='substitution pattern from filename',
                  metavar="'%n %t.flac'")
    OP.add_option('--fn2tag',
                  dest='pattern',
                  action='store',
                  help='same as -p | --pattern')
    OP.add_option('-r',
                  '--remove',
                  dest='remove',
                  action='append',
                  help='remove a tag value or entire tag',
                  metavar="'tag' or 'tag=value'")
    OP.add_option('-j',
                  '--justify',
                  dest='justify',
                  action='store_true',
                  help='zero-justify tracknumbers')
    OP.add_option('--clear',
                  dest='clear',
                  action='store_true',
                  help='clear all tags')
    OP.add_option('-n',
                  '--noact',
                  dest='noact',
                  action='store_true',
                  help="just show what changes would be made")
    OP.add_option('-c',
                  '--confirm',
                  dest='confirm',
                  action='store_true',
                  help='show changes and prompt for confirmation to save')
    OP.add_option('-f',
                  '--files',
                  dest='filenames',
                  action='append',
                  help='one or more filenames/globs')
    OP.add_option('-q',
                  '--quiet',
                  dest='quiet',
                  action='store_true',
                  help='no output to stdout')
    OP.add_option('--tag2fn',
                  dest='tag2fn',
                  action='store',
                  help='substitution pattern from tags',
                  metavar="'%n %t.flac'")
    OP.add_option(
        '-s',
        '--filter',
        dest='symbols',
        action='store',
        help=
        'one or more characters to filter from tags used to build filenames',
        metavar="'!@$&*/\?'")
    OP.add_option(
        '-m',
        '--map',
        dest='map',
        action='store',
        help=
        'replace all instances of a char with another char\nin conjunction with --tag2fn',
        metavar="/ -")
    OP.add_option('-i',
                  '--index',
                  dest='idx',
                  action='store_true',
                  help='index files by filename order (persistent file order)')
    OP.add_option('-v',
                  '--version',
                  dest='vers',
                  action='store_true',
                  help='show version')

    argstr = ' '.join(args)

    if len(args) < 2:
        OP.print_usage()
        #        print("version %s" % __version__)
        print('-h|--help for help')
        sys.exit(1)

    p = '(-t|--tag|-a|--add|-p|--pattern|-r|--remove|-f|--files)\ +?\-[^\ ]*'
    mo = re.search(p, argstr)
    if mo:
        print('illegal option combination: ', mo.group())
        sys.exit(1)

    (opt, fnames) = OP.parse_args()
    if opt.vers:
        print('%s %s' % (OP.get_prog_name(), __version__))
    if opt.filenames:
        fnames += opt.filenames

    for fname in fnames:
        if not os.path.exists(fname):
            print('%s: no such file' % fname)
            err += 1
    if err:
        sys.exit(err)

    cfmr = Confirmer(opt)
    fnum = 0
    idx = 0
    if opt.pattern:
        subster = Subster(opt.pattern)
    elif opt.tag2fn:
        subster = Subster(opt.tag2fn, 'tag2fn')
    else:
        subster = Subster('', '')

    modded = any(
        [opt.clear, opt.remove, opt.add, opt.tag, opt.pattern, opt.justify])
    spkr = Speaker(opt.quiet)
    top_length = 0
    for fname in fnames:
        bfname = os.path.basename(fname)
        top_length = len(bfname) if len(bfname) > top_length else top_length

    for fname in fnames:
        fnum += 1
        vals = {}
        keys = []
        origfn = fname

        if os.path.splitext(fname)[1] == '.mp3':
            try:
                mf = MP3(fname)
            except IOError:
                spkr.speak("\ncan't open %s" % fname)
                continue
            spkr.speak("processing %s" % fname)
            if opt.clear:
                mf.clear()
            for action in opt.remove or []:
                k, v = (action.split('=', 1) + [''])[:2]
                vals[k] = mf.pop(k, [])
                if k and not v:
                    vals[k] = []

                elif v and v in vals[k]:
                    vals[k].remove(v)
            for action in opt.tag or []:
                k, v = (action.split('=', 1) + [''])[:2]
                vals[k] = [v]
            for action in opt.add or []:
                k, v = (action.split('=', 1) + [''])[:2]
                if vals.get(k, []):
                    vals[k] += mf.pop(k, [])
                else:
                    vals[k] = mf.pop(k, [])
                vals[k].extend([v])
            if subster.pattern:
                d = subster.getdict(fname)
                for k in d:
                    values = d.get(k, [])
                    if not isinstance(values, list):
                        values = [values]
                    try:
                        vals[k].extend(values)
                    except KeyError:
                        vals[k] = values
            if opt.justify:
                if not vals.get('tracknumber'):
                    vals['tracknumber'] = fnum
                width = len(str(len(fnames)))
                n = width - len(str(vals['tracknumber']))
                vals['tracknumber'] = [n * '0' + str(vals['tracknumber'])]

            if not modded:
                if not opt.quiet:
                    print(mf.pprint())
                    continue

            if opt.noact or opt.confirm:
                for k in vals:
                    print(k + '=' + str(vals[k]))
            if opt.noact:
                continue
            if opt.confirm and not cfmr.confirm():
                continue
            for k in vals:
                try:
                    mf.update({k: vals[k]})
#                mf.save( )
                except ValueError:
                    pass
            mf.save()
        else:
            try:
                #            print(fname)
                mf = File(fname)
            except IOError:
                spkr.speak("can't open %s" % fname)
                continue
            spkr.speak(os.path.basename(fname))

            if opt.idx:
                trn = mf.get('tracknumber', None)
                mf['idx'] = unicode(fnum)
                if trn:
                    mf['idx'] += trn
                mf.save()
                print(' indexed')

            if opt.clear:
                mf.clear()
                spkr.speak('\n\ttags cleared..')
            for action in opt.remove or []:
                k, v = (action.split('=', 1) + [''])[:2]
                t = mf.pop(k, [])
                if v and v in t:
                    t.remove(v)
                    spkr.speak(str(k) + ' removes ' + str(v))
                if v and t:
                    mf.update({k: t})
            for action in opt.tag or []:
                if '=' in action:
                    k, v = action.split('=', 1)
                    if k and v:
                        mf.update({k: [v]})
                        spkr.speak('\t\ttag set: ' + k + '=' + v)
            for action in opt.add or []:
                if '=' in action:
                    k, v = action.split('=', 1)
                    mf.update({k: mf.get(k, []) + [v]})
                    spkr.speak('\n\ttag appended: ' + k + '=' + v)
            if subster.mode == 'fn2tag':
                d = subster.getdict(fname)
                for k in d:
                    mf.update({k: d[k]})
                    spkr.speak('\n\tfrom filename: ' + k + '=' + d[k])

            if subster.mode == 'tag2fn':
                fname = ''
                fnlist = subster.getfnlist()
                if 'tracknumber' in fnlist:
                    tn = 1
                else:
                    tn = 0
                lit = True
                for item in fnlist:
                    lit = not lit
                    if lit:
                        if not tn and item == 'tracknumber':
                            item = 'track'
                        if tn and item == 'track':
                            item = 'tracknumber'
                        if item.startswith('track') and opt.justify:
                            subst = mf[item][0].rjust(2, '0')
                        else:
                            subst = mf[item][0]

                        if opt.symbols:
                            pat = '[' + opt.symbols + ']'
                            subst = re.sub(pat, '', subst)
                            subst = subst.strip()

                        fname += subst
                    else:
                        fname += item

                    if '/' in fname:
                        fname = re.sub('/', '-', fname)

#            if opt.map:
#                fname = map(fname,opt.map)

                if opt.noact or opt.confirm:
                    pass

            if not any([modded, opt.tag2fn, opt.quiet]):
                print(mf.pprint(), )

            if cfmr.confirm():
                if opt.tag2fn:
                    if opt.map:
                        a, b = opt.map.split()
                        fname = re.sub(a, b, fname)

                    pth = os.path.join(os.path.dirname(origfn), fname)
                    second_column = top_length + 2
                    tab = (second_column - len(os.path.basename(origfn))) * ' '
                    try:
                        os.rename(origfn, pth)
                        print(tab + '--> ' + fname),
#                    spkr.speak( 'renamed...   ' + fname )
                    except IOError:
                        raise IOError
                else:
                    mf.save()
                    spkr.speak('\tsaved!')