def write_tags(f, meta, tag_cfg, cov, ext, embed_cov):
    if ext == ".flac":
        audio = FLAC(f)
        for k, v in meta.items():
            if tag_cfg[k]:
                audio[k] = str(v)
        if embed_cov and cov:
            with open(cov, 'rb') as cov_obj:
                image = Picture()
                image.type = 3
                image.mime = "image/jpeg"
                image.data = cov_obj.read()
                audio.add_picture(image)
        audio.save()
    elif ext == ".mp3":
        try:
            audio = id3.ID3(f)
        except ID3NoHeaderError:
            audio = id3.ID3()
        if tag_cfg['TRACKNUMBER'] and tag_cfg['TRACKTOTAL']:
            audio['TRCK'] = id3.TRCK(encoding=3,
                                     text=str(meta['TRACKNUMBER']) + "/" +
                                     str(meta['TRACKTOTAL']))
        elif tag_cfg['TRACKNUMBER']:
            audio['TRCK'] = id3.TRCK(encoding=3, text=str(meta['TRACKNUMBER']))
        if tag_cfg['DISCNUMBER']:
            audio['TPOS'] = id3.TPOS(encoding=3,
                                     text=str(meta['DISCNUMBER']) + "/" +
                                     str(meta['DISCTOTAL']))
        legend = {
            "ALBUM": id3.TALB,
            "ALBUMARTIST": id3.TPE2,
            "ARTIST": id3.TPE1,
            "COMMENT": id3.COMM,
            "COMPOSER": id3.TCOM,
            "COPYRIGHT": id3.TCOP,
            "DATE": id3.TDAT,
            "GENRE": id3.TCON,
            "ISRC": id3.TSRC,
            "LABEL": id3.TPUB,
            "PERFORMER": id3.TOPE,
            "TITLE": id3.TIT2,
            # Not working.
            "URL": id3.WXXX,
            "YEAR": id3.TYER
        }
        for k, v in meta.items():
            try:
                if tag_cfg[k]:
                    id3tag = legend[k]
                    audio[id3tag.__name__] = id3tag(encoding=3, text=v)
            except KeyError:
                pass
        if embed_cov and cov:
            with open(cov, 'rb') as cov_obj:
                audio.add(id3.APIC(3, 'image/jpeg', 3, '', cov_obj.read()))
        audio.save(f, 'v2_version=3')
Beispiel #2
0
def write_id3(mp3_file, track, cover=None):
    t = mp3.Open(mp3_file)
    if not t.tags:
        t.add_tags()

    album = track['albums'][0]

    t_add = t.tags.add
    t_add(id3.TIT2(encoding=3, text=track['title']))
    t_add(id3.TPE1(encoding=3, text=track['artists']))
    t_add(id3.TCOM(encoding=3, text=track[FLD_COMPOSERS]))
    t_add(id3.TALB(encoding=3, text=album['title']))

    if 'labels' in album:
        t_add(id3.TPUB(encoding=3,
                       text=', '.join(l['name'] for l in album['labels'])))
    if FLD_TRACKNUM in track:
        tnum = '{}/{}'.format(track[FLD_TRACKNUM], album['trackCount'])
        t_add(id3.TRCK(encoding=3, text=tnum))
    if FLD_VOLUMENUM in album:
        t_add(id3.TPOS(encoding=3, text=str(album[FLD_VOLUMENUM])))
    if 'year' in album:
        t_add(id3.TDRC(encoding=3, text=str(album['year'])))
    if args.genre:
        t_add(id3.TCON(encoding=3, text=album['genre'].title()))
    if cover:
        t_add(id3.APIC(encoding=3, desc='', mime=cover.mime,
                       type=3, data=cover.data))

    t.tags.update_to_v23()
#id3.ID3v1SaveOptions.CREATE = 2
    t.save(v1=2, v2_version=3)
Beispiel #3
0
def fix_tags(abs, ext, f_meta):
    """
	:param abs: Path of the file we're tagging
	:param ext: Extension of the file we're tagging
	:param f_meta: Dict containing the metadata of the track we're tagging.
	"""
    if ext == "mp3":
        try:
            audio = id3.ID3(abs)
        except ID3NoHeaderError:
            audio = id3.ID3()
        audio['TRCK'] = id3.TRCK(text=str(audio['TRCK']) + "/" +
                                 str(f_meta['track_total']))
        audio['TPOS'] = id3.TPOS(text=str(audio['TPOS']) + "/" +
                                 str(f_meta['disc_total']))
        audio['TDRC'] = id3.TPOS(text=f_meta['release_date'])
        audio['TPUB'] = id3.TPOS(text=f_meta['planning'])
        audio['TPE1'] = id3.TPE1(text=f_meta['track_artist'])
        audio['TPE2'] = id3.TPE2(text=f_meta['album_artist'])
        audio.save(abs, "v2_version=3")
    else:
        audio = FLAC(abs)
        audio['TRACKTOTAL'] = str(f_meta['track_total'])
        audio['DISCTOTAL'] = str(f_meta['disc_total'])
        audio['DATE'] = f_meta['release_date']
        audio['LABEL'] = f_meta['planning']
        audio['ARTIST'] = f_meta['track_artist']
        audio['ALBUMARTIST'] = f_meta['album_artist']
        audio.save()
Beispiel #4
0
def add_mp3_tags(filename, metadata):
    metadata = metadata.copy()
    try:
        audio = id3.ID3(filename)
    except ID3NoHeaderError:
        audio = id3.ID3()
    # ID3 is weird about the track number and total so we have to set that manually
    audio["TRCK"] = id3.TRCK(
        encoding=3,
        text=f"{metadata.pop('TRACKNUMBER')}/{metadata.pop('TRACKTOTAL')}")
    legend = {
        "ALBUM": id3.TALB,
        "ALBUMARTIST": id3.TPE2,
        "ARTIST": id3.TPE1,
        "COMMENT": id3.COMM,
        "COMPOSER": id3.TCOM,
        "COPYRIGHT": id3.TCOP,
        "GENRE": id3.TCON,
        "ORGANIZATION": id3.TPUB,
        "TITLE": id3.TIT2,
        "ISRC": id3.TSRC,
        "DATE": id3.TYER
    }
    for tag, value in metadata.items():
        if value:
            id3tag = legend[tag]
            audio[id3tag.__name__] = id3tag(encoding=3, text=value)
    audio.save(filename, 'v2_version=3')
Beispiel #5
0
def write_tags(f, meta, cov):
    if f.endswith('.mp3'):
        try:
            audio = id3.ID3(f)
        except ID3NoHeaderError:
            audio = id3.ID3()
        audio['TRCK'] = id3.TRCK(encoding=3,
                                 text=str(meta['TRACK']) + "/" +
                                 str(meta['TRACKTOTAL']))
        legend = {
            "ALBUM": id3.TALB,
            "ALBUMARTIST": id3.TPE2,
            "ARTIST": id3.TPE1,
            "COPYRIGHT": id3.TCOP,
            "TITLE": id3.TIT2,
            "YEAR": id3.TYER
        }
        for tag, value in meta.items():
            if not tag in ['UPC', 'TRACK', 'TRACKTOTAL']:
                id3tag = legend[tag]
                audio[id3tag.__name__] = id3tag(encoding=3, text=value)
        with open(cov, 'rb') as cov_obj:
            audio.add(id3.APIC(3, 'image/jpeg', 3, '', cov_obj.read()))
        audio.save(f, 'v2_version=3')
    else:
        audio = FLAC(f)
        for tag, value in meta.items():
            audio[tag] = str(value)
            image = Picture()
        image.type = 3
        image.mime = "image/jpeg"
        with open(cov, 'rb') as cov_obj:
            image.data = cov_obj.read()
            audio.add_picture(image)
        audio.save()
Beispiel #6
0
        def set_id3_tags(audio):
            # add ID3 tag if it doesn't exist
            audio.add_tags()

            def embed_image(data):
                audio.tags.add(
                    id3.APIC(
                        encoding=3,
                        mime='image/jpeg',
                        type=3,
                        desc='Front Cover',
                        data=data
                    )
                )

            save_cover_image(embed_image)

            if album is not None:
                audio.tags.add(
                    id3.TALB(text=[tag_to_ascii(track.album.name, album)],
                             encoding=3))
            audio.tags.add(
                id3.TIT2(text=[tag_to_ascii(track.name, title)],
                         encoding=3))
            audio.tags.add(
                id3.TPE1(text=[tag_to_ascii(artists, artists_ascii)],
                         encoding=3))
            if album_artist is not None:
                audio.tags.add(
                    id3.TPE2(text=[tag_to_ascii(
                                       track.album.artist.name, album_artist)],
                             encoding=3))
            audio.tags.add(id3.TDRC(text=[str(track.album.year)],
                                    encoding=3))
            audio.tags.add(
                id3.TPOS(text=[idx_of_total_str(track.disc, num_discs)],
                         encoding=3))
            audio.tags.add(
                id3.TRCK(text=[idx_of_total_str(track.index, num_tracks)],
                         encoding=3))
            if args.comment is not None:
                audio.tags.add(
                    id3.COMM(text=[tag_to_ascii(comment, comment_ascii)],
                             encoding=3))
            if args.grouping is not None:
                audio.tags.add(
                    id3.TIT1(text=[tag_to_ascii(grouping, grouping_ascii)],
                             encoding=3))
            if genres is not None and genres:
                tcon_tag = id3.TCON(encoding=3)
                tcon_tag.genres = genres if args.ascii_path_only \
                    else genres_ascii
                audio.tags.add(tcon_tag)

            if args.id3_v23:
                audio.tags.update_to_v23()
                audio.save(v2_version=3, v23_sep='/')
                audio.tags.version = (2, 3, 0)
            else:
                audio.save()
Beispiel #7
0
        def set_id3_tags_raw(audio, audio_file):
            try:
                id3_dict = id3.ID3(audio_file)
            except id3.ID3NoHeaderError:
                id3_dict = id3.ID3()

            def embed_image(data):
                id3_dict.add(
                    id3.APIC(encoding=3,
                             mime='image/jpeg',
                             type=3,
                             desc='Front Cover',
                             data=data))

            save_cover_image(embed_image)

            if album is not None:
                id3_dict.add(
                    id3.TALB(text=[tag_to_ascii(track.album.name, album)],
                             encoding=3))
            id3_dict.add(
                id3.TIT2(text=[tag_to_ascii(track.name, title)], encoding=3))
            id3_dict.add(
                id3.TPE1(text=[tag_to_ascii(artists, artists_ascii)],
                         encoding=3))
            if album_artist is not None:
                id3_dict.add(
                    id3.TPE2(text=[
                        tag_to_ascii(track.album.artist.name, album_artist)
                    ],
                             encoding=3))
            id3_dict.add(id3.TDRC(text=[str(track.album.year)], encoding=3))
            id3_dict.add(
                id3.TPOS(text=[idx_of_total_str(track.disc, num_discs)],
                         encoding=3))
            id3_dict.add(
                id3.TRCK(text=[idx_of_total_str(track.index, num_tracks)],
                         encoding=3))
            if args.comment is not None:
                id3_dict.add(
                    id3.COMM(text=[tag_to_ascii(comment, comment_ascii)],
                             encoding=3))
            if args.grouping is not None:
                audio.tags.add(
                    id3.TIT1(text=[tag_to_ascii(grouping, grouping_ascii)],
                             encoding=3))
            if genres is not None and genres:
                tcon_tag = id3.TCON(encoding=3)
                tcon_tag.genres = genres if args.ascii_path_only \
                    else genres_ascii
                id3_dict.add(tcon_tag)

            if args.id3_v23:
                id3_dict.update_to_v23()
                id3_dict.save(audio_file, v2_version=3, v23_sep='/')
                id3_dict.version = (2, 3, 0)
            else:
                id3_dict.save(audio_file)
            audio.tags = id3_dict
Beispiel #8
0
def write_tags(pre_abs, meta, fmt, cov_abs):
    if fmt == "FLAC":
        audio = FLAC(pre_abs)
        del meta['track_padded']
        for k, v in meta.items():
            if v:
                audio[k] = str(v)
        if cov_abs:
            with open(cov_abs, "rb") as f:
                image = Picture()
                image.type = 3
                image.mime = "image/jpeg"
                image.data = f.read()
                audio.add_picture(image)
    elif fmt == "MP3":
        try:
            audio = id3.ID3(pre_abs)
        except ID3NoHeaderError:
            audio = id3.ID3()
        audio['TRCK'] = id3.TRCK(encoding=3,
                                 text="{}/{}".format(meta['track'],
                                                     meta['tracktotal']))
        legend = {
            "album": id3.TALB,
            "albumartist": id3.TPE2,
            "artist": id3.TPE1,
            #"comment": id3.COMM,
            "copyright": id3.TCOP,
            "isrc": id3.TSRC,
            "label": id3.TPUB,
            "title": id3.TIT2,
            "year": id3.TYER
        }
        for k, v in meta.items():
            id3tag = legend.get(k)
            if v and id3tag:
                audio[id3tag.__name__] = id3tag(encoding=3, text=v)
        if cov_abs:
            with open(cov_abs, "rb") as cov_obj:
                audio.add(id3.APIC(3, "image/jpeg", 3, None, cov_obj.read()))
    else:
        audio = MP4(pre_abs)
        audio['\xa9nam'] = meta['title']
        audio['\xa9alb'] = meta['album']
        audio['aART'] = meta['albumartist']
        audio['\xa9ART'] = meta['artist']
        audio['trkn'] = [(meta['track'], meta['tracktotal'])]
        audio['\xa9day'] = meta['year']
        audio['cprt'] = meta['copyright']
        if cov_abs:
            with open(cov_abs, "rb") as f:
                audio['covr'] = [
                    MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG)
                ]
    audio.save(pre_abs)
Beispiel #9
0
 def setTrackNum(self, _value):
     self.isSave = True
     values = _value.split("/")
     try:
         self.tags["TRCK"] = id3.TRCK(
             encoding=3,
             text=str(int(self.correctValuesForMusicTagType(values[0]))))
         if len(values) > 1:
             self.tags["TPOS"] = id3.TPOS(
                 encoding=3,
                 text=str(int(self.correctValuesForMusicTagType(
                     values[1]))))
         elif len(values) == 1 and self.tags["TPOS"] is not None:
             del self.tags["TPOS"]
     except:
         pass
Beispiel #10
0
    def set_tags(self, audio):
        try:
            id3_dict = id3.ID3(self.audio_file)
        except id3.ID3NoHeaderError:
            id3_dict = id3.ID3()

        def embed_image(data):
            id3_dict.add(
                id3.APIC(encoding=3,
                         mime='image/jpeg',
                         type=3,
                         desc='Front Cover',
                         data=data))

        self.save_cover_image(embed_image)

        if self.album() is not None:
            id3_dict.add(id3.TALB(text=[self.album()], encoding=3))

        id3_dict.add(id3.TIT2(text=[self.title()], encoding=3))
        id3_dict.add(id3.TPE1(text=[self.artists()], encoding=3))

        if self.album_artist() is not None:
            id3_dict.add(id3.TPE2(text=[self.album_artist()], encoding=3))

        id3_dict.add(id3.TDRC(text=[self.year()], encoding=3))
        id3_dict.add(id3.TPOS(text=[self.disc_idx_and_total()], encoding=3))
        id3_dict.add(id3.TRCK(text=[self.track_idx_and_total()], encoding=3))

        if self.comment() is not None:
            id3_dict.add(id3.COMM(text=[self.comment()], encoding=3))

        if self.grouping() is not None:
            id3_dict.add(id3.TIT1(text=[self.grouping()], encoding=3))

        if self.genres() is not None:
            tcon_tag = id3.TCON(encoding=3)
            tcon_tag.genres = self.genres()
            id3_dict.add(tcon_tag)

        if self.args.id3_v23:
            id3_dict.update_to_v23()
            id3_dict.save(self.audio_file, v2_version=3, v23_sep='/')
            id3_dict.version = (2, 3, 0)
        else:
            id3_dict.save(self.audio_file)
        audio.tags = id3_dict
Beispiel #11
0
def compiletracl(tracl):
    rawfile = File("%s.mp3" % tracl['id'])

    rawfile['TIT2'] = id3.TIT2(encoding=3, text=tracl['title'])
    rawfile['TALB'] = id3.TALB(encoding=3, text=tracl['album'])
    rawfile['TPE1'] = id3.TPE1(encoding=3, text=tracl['artist'])
    rawfile['TCON'] = id3.TCON(encoding=3, text=tracl['genre'])
    rawfile['TYER'] = id3.TYER(encoding=3, text=tracl['year'])
    rawfile['TRCK'] = id3.TRCK(encoding=3, text=tracl['len'])
    rawfile['WOAS'] = id3.WOAS(encoding=3, text=tracl['link'])

    rawfile['APIC'] = id3.APIC(encoding=3,
                               type=3,
                               mime='image/jpeg',
                               desc='Cover',
                               data=downloadcover(tracl))

    rawfile.save(v2_version=3)
Beispiel #12
0
        def set_id3_tags_raw(audio, audio_file):
            try:
                id3_dict = id3.ID3(audio_file)
            except id3.ID3NoHeaderError:
                id3_dict = id3.ID3()

            def embed_image():
                id3_dict.add(
                    id3.APIC(encoding=3,
                             mime='image/jpeg',
                             type=3,
                             desc='Front Cover',
                             data=image.data))

            save_cover_image(embed_image)

            if album is not None:
                id3_dict.add(
                    id3.TALB(text=[tag_to_ascii(track.album.name, album)],
                             encoding=3))
            id3_dict.add(
                id3.TIT2(text=[tag_to_ascii(track.name, title)], encoding=3))
            id3_dict.add(
                id3.TPE1(text=[tag_to_ascii(track.artists[0].name, artist)],
                         encoding=3))
            id3_dict.add(id3.TDRC(text=[str(track.album.year)], encoding=3))
            id3_dict.add(
                id3.TPOS(text=[idx_of_total_str(track.disc, num_discs)],
                         encoding=3))
            id3_dict.add(
                id3.TRCK(text=[idx_of_total_str(track.index, num_tracks)],
                         encoding=3))
            if args.comment is not None:
                id3_dict.add(
                    id3.COMM(text=[tag_to_ascii(args.comment[0], comment)],
                             encoding=3))
            if genres is not None and genres:
                tcon_tag = id3.TCON(encoding=3)
                tcon_tag.genres = genres if args.ascii_path_only \
                    else genres_ascii
                id3_dict.add(tcon_tag)

            id3_dict.save(audio_file)
            audio.tags = id3_dict
Beispiel #13
0
    def set_tags(self, audio):
        # add ID3 tag if it doesn't exist
        audio.add_tags()

        def embed_image(data):
            audio.tags.add(
                id3.APIC(encoding=3,
                         mime='image/jpeg',
                         type=3,
                         desc='Front Cover',
                         data=data))

        self.save_cover_image(embed_image)

        if self.album() is not None:
            audio.tags.add(id3.TALB(text=[self.album()], encoding=3))

        audio.tags.add(id3.TIT2(text=[self.title()], encoding=3))
        audio.tags.add(id3.TPE1(text=[self.artists()], encoding=3))

        if self.album_artist() is not None:
            audio.tags.add(id3.TPE2(text=[self.album_artist()], encoding=3))

        audio.tags.add(id3.TDRC(text=[self.year()], encoding=3))
        audio.tags.add(id3.TPOS(text=[self.disc_idx_and_total()], encoding=3))
        audio.tags.add(id3.TRCK(text=[self.track_idx_and_total()], encoding=3))

        if self.comment() is not None:
            audio.tags.add(id3.COMM(text=[self.comment()], encoding=3))

        if self.grouping() is not None:
            audio.tags.add(id3.TIT1(text=[self.grouping()], encoding=3))

        if self.genres() is not None:
            tcon_tag = id3.TCON(encoding=3)
            tcon_tag.genres = self.genres()
            audio.tags.add(tcon_tag)

        if self.args.id3_v23:
            audio.tags.update_to_v23()
            audio.save(v2_version=3, v23_sep='/')
            audio.tags.version = (2, 3, 0)
        else:
            audio.save()
Beispiel #14
0
        def set_id3_tags(audio):
            # add ID3 tag if it doesn't exist
            audio.add_tags()

            def embed_image():
                audio.tags.add(
                    id3.APIC(encoding=3,
                             mime='image/jpeg',
                             type=3,
                             desc='Front Cover',
                             data=image.data))

            save_cover_image(embed_image)

            if album is not None:
                audio.tags.add(
                    id3.TALB(text=[tag_to_ascii(track.album.name, album)],
                             encoding=3))
            audio.tags.add(
                id3.TIT2(text=[tag_to_ascii(track.name, title)], encoding=3))
            audio.tags.add(
                id3.TPE1(text=[tag_to_ascii(track.artists[0].name, artist)],
                         encoding=3))
            audio.tags.add(id3.TDRC(text=[str(track.album.year)], encoding=3))
            audio.tags.add(
                id3.TPOS(text=[idx_of_total_str(track.disc, num_discs)],
                         encoding=3))
            audio.tags.add(
                id3.TRCK(text=[idx_of_total_str(track.index, num_tracks)],
                         encoding=3))
            if args.comment is not None:
                audio.tags.add(
                    id3.COMM(text=[tag_to_ascii(args.comment[0], comment)],
                             encoding=3))
            if genres is not None and genres:
                tcon_tag = id3.TCON(encoding=3)
                tcon_tag.genres = genres if args.ascii_path_only \
                    else genres_ascii
                audio.tags.add(tcon_tag)

            audio.save()
Beispiel #15
0
    def __get_tags(metadata: MetaData) -> id3.ID3:
        tags = id3.ID3()

        if metadata.podcast_title:
            tags.add(
                id3.TPE1(encoding=id3.Encoding.LATIN1,
                         text=metadata.podcast_title))

        if metadata.episode_title:
            tags.add(
                id3.TIT2(encoding=id3.Encoding.LATIN1,
                         text=metadata.episode_title))

        if metadata.episode_number:
            tags.add(
                id3.TRCK(encoding=id3.Encoding.LATIN1,
                         text=str(metadata.episode_number)))

        if metadata.chapters:
            toc: List[str] = [
                f"chp{index}" for index in range(len(metadata.chapters))
            ]
            tags.add(
                id3.CTOC(encoding=id3.Encoding.LATIN1,
                         element_id="toc",
                         flags=id3.CTOCFlags.TOP_LEVEL | id3.CTOCFlags.ORDERED,
                         child_element_ids=toc,
                         sub_frames=[]))

            for idx, chapter in enumerate(metadata.chapters):
                tags.add(
                    id3.CHAP(encoding=id3.Encoding.LATIN1,
                             element_id=f"chp{idx}",
                             start_time=chapter.start,
                             end_time=chapter.end,
                             sub_frames=[
                                 id3.TIT2(encoding=id3.Encoding.LATIN1,
                                          text=chapter.name)
                             ]))

        return tags
Beispiel #16
0
 def _write_id3v2_tag(self, file_name, step, obj):
     song = self.active_class(file_name)
     song.delete()
     song['TPE1'] = id3.TPE1(encoding=3, text=[obj.artist[step]])
     song['TALB'] = id3.TALB(encoding=3, text=[obj.album])
     if obj.genre and not obj.tgenre:
         song['TCON'] = id3.TCON(encoding=3, text=[obj.genre])
     elif obj.tgenre:
         song['TCON'] = id3.TCON(encoding=3, text=[obj.tgenre[step]])
     song['TIT2'] = id3.TIT2(encoding=3, text=[obj.title[step]])
     number = '{0}/{1}'.format(int(obj.track[step]), int(obj.track[-1]))
     song['TRCK'] = id3.TRCK(encoding=3, text=[number])
     if obj.year and not obj.tdate:
         song['TDRC'] = id3.TDRC(encoding=3, text=[obj.year])
     elif obj.tdate:
         song['TDRC'] = id3.TDRC(encoding=3, text=[obj.tdate[step]])
     song['COMM::XXX'] = id3.COMM(encoding=3,
                                  lang='XXX',
                                  desc='',
                                  text=[obj.comment])
     song.save(file_name)
Beispiel #17
0
def tag_mp3(path_audio,path_pic,lrc,title,artist,album,disc,track,**kw):
    '''
    ref:
    http://id3.org/id3v2.3.0
    https://github.com/quodlibet/mutagen/blob/master/mutagen/id3/_frames.py
    http://help.mp3tag.de/main_tags.html
    http://code.activestate.com/recipes/577138-embed-lyrics-into-mp3-files-using-mutagen-uslt-tag/
    '''
    tags=id3.ID3()
    if path_pic:
        with open(path_pic,'rb') as f:
            tags['APIC']=id3.APIC(mime='image/jpeg',type=id3.PictureType.COVER_FRONT,data=f.read())
    for x in lrc:
        tags["USLT::"+x['lang']]=id3.USLT(text=x['text'],lang=x['lang'])
    tags['TIT2']=id3.TIT2(text=title)
    tags['TPE1']=id3.TPE1(text=artist)
    if album!=None:
        tags['TALB']=id3.TALB(text=album)
    tags['TPOS']=id3.TPOS(text=disc)
    tags['TRCK']=id3.TRCK(text=str(track))
    tags.save(path_audio)
Beispiel #18
0
def xx_total_correct(tag_thing):
    """
    id3 tags combine the 'track/disc-number' and 'track/disc-total' fields in one frame (e.g. 3/14).

    :param tag_thing: mutagen.id3.ID3 object (= mp3.MP3.tags) or flac_like dict
    :return: corrected tags
    """
    if type(tag_thing) == id3.ID3:

        if all(x in tag_thing for x in ('TXXX:tracktotal', 'TRCK')):
            track_numb = tag_thing['TRCK'].text[0]
            track_tot = tag_thing['TXXX:tracktotal'].text[0]
            tag_thing.add(id3.TRCK(encoding=3, text=f'{track_numb}/{track_tot}'))
            tag_thing.delall('TXXX:tracktotal')

        if all(x in tag_thing for x in('TXXX:disctotal', 'TPOS')):
            track_numb = tag_thing['TPOS'].text[0]
            track_tot = tag_thing['TXXX:disctotal'].text[0]
            tag_thing.add(id3.TPOS(encoding=3, text=f'{track_numb}/{track_tot}'))
            tag_thing.delall('TXXX:disctotal')
        
        return tag_thing
    
    if type(tag_thing) == dict:

        if 'tracknumber' in tag_thing and '/' in tag_thing['tracknumber'][0]:
            track_numb, track_tot = tag_thing['tracknumber'][0].split('/')
            tag_thing['tracknumber'] = [track_numb]
            tag_thing['tracktotal'] = [track_tot]

        if 'discnumber' in tag_thing and '/' in tag_thing['discnumber'][0]:
            disc_numb, track_tot = tag_thing['discnumber'][0].split('/')
            tag_thing['discnumber'] = [disc_numb]
            tag_thing['disctotal'] = [track_tot]

        return tag_thing

    else:
        raise Exception('What is this thing?')
Beispiel #19
0
    def tag(self, target, track):
        mp3 = MP3(os.path.join(self.workdir, target))

        if not mp3.tags:
            mp3.add_tags()

        tags = mp3.tags
        tags.add(id3.TALB(encoding=id3.Encoding.UTF8, text=self.disc.album))
        tags.add(id3.TPE1(encoding=id3.Encoding.UTF8, text=self.disc.artist))
        tags.add(id3.TIT2(encoding=id3.Encoding.UTF8, text=track.title))
        tags.add(id3.TRCK(encoding=id3.Encoding.UTF8, text=str(track.trackno)))
        tags.add(id3.TDRC(encoding=id3.Encoding.UTF8,
                          text=str(self.disc.year)))

        tpos = str(self.disc.discno)
        if self.disc.set_size > 1:
            tpos = f"{self.disc.discno}/{self.disc.set_size}"
        tags.add(id3.TPOS(encoding=id3.Encoding.UTF8, text=tpos))

        if self.disc.cover_art:
            tags.add(
                id3.APIC(encoding=id3.Encoding.UTF8, data=self.disc.cover_art))

        mp3.save()
Beispiel #20
0
    def save(self):
        if self.clr:
            for file in self.audiofiles:
                tmp = mid3.ID3(file)
                tmp.clear()
                tmp.add(mid3.TIT2(text=""))  # title frame
                tmp.add(mid3.TPE1(text=""))  # artist frame
                tmp.add(mid3.TALB(text=""))  # album frame
                tmp.add(mid3.TPE2(text=""))  # album artist frame
                tmp.add(mid3.TCOM(text=""))  # composer frame
                tmp.add(mid3.TCON(text=""))  # genre frame
                tmp.add(mid3.TDRC(text=""))  # date frame
                tmp.add(mid3.TRCK(text=""))  # tracknumber frame
                tmp.add(mid3.TPOS(text=""))  # discnumber frame
                tmp.add(mid3.TBPM(text=""))  # bpm frame
                tmp.save()

        if self.artwork:
            with open(self.artwork, 'rb') as albumart:
                for file in self.audiofiles:
                    tmp = mid3.ID3(file)
                    tmp['APIC'] = mid3.APIC(
                        encoding=3,
                        mime='image/jpeg',
                        type=3, desc=u'Cover',
                        data=albumart.read()
                    )
                    tmp.save()
                    albumart.seek(0)

        for file in self.audiofiles:
            tmp = EasyID3(file)
            for tag in self.__sets:
                if self.__sets[tag]:
                    tmp[tag] = self.__sets[tag]
                    tmp.save()
Beispiel #21
0
def load_mp3(dir, file, _numtracks = None, _disk = None, _numdisks = None):
    m = id3.ID3(os.path.join(dir, file))
    changed = []
    # Don't want this taking up space
    if t3['encodedby'] in m:
        del(m[t3['encodedby']])
        changed.append('encodedby')
    # Adjust num tracks
    try:
        numtracks = 0
        track = m[t3['track']].text[0]
        if '/' in track:
            (track, numtracks) = track.split('/')
    except:
        track = numtracks = 0
    if numtracks == 0:
        if _numtracks:
            numtracks = _numtracks
            m[t3['track']] = id3.TRCK(0, '{0}/{1}'.format(track,numtracks))
            changed.append('track')
        else:
            print "  no numtracks for {0}".format(file)
            sys.exit(1)
    # Try to detect disk numbers
    try:
        numdisks = 0
        disk = m[t3['disk']].text[0]
        if '/' in disk:
            (disk, numdisks) = disk.split('/')
    except:
        disk = numdisks = 0
    if _disk and _numdisks and not int(disk) and not int(numdisks):
        disk     = str(_disk).zfill(len(str(_numdisks)))
        numdisks = _numdisks
        m[t3['disk']] = id3.TPOS(0, '{0}/{1}'.format(disk,numdisks))
        changed.append('disk')
    elif str(_disk) != '0' and str(disk) != '0' and str(disk) != str(_disk):
        print "  Disknum mismatch {0} != {1} on {2}".format(disk, _disk, file)
        sys.exit(1)
    elif int(disk) and not int(numdisks):
        if _numdisks:
            disk     = str(disk).zfill(len(str(_numdisks)))
            numdisks = _numdisks
            m[t3['disk']] = id3.TPOS(0, '{0}/{1}'.format(disk,numdisks))
            changed.append('disk')
        else:
            print "  disknum but no numdisks on {0}".format(file)
            sys.exit(1)
    # Clean up the album name
    if t3['album'] in m:
        album = fix_album(m[t3['album']].text[0].strip())
        if album != m[t3['album']].text[0]:
            m[t3['album']].text[0] = album
            changed.append('album')
    # Clean up the title
    #print m[t3['title']].text[0]
    if t3['title'] in m:
        title = m[t3['title']].text[0].strip()
        title = fix_title(title)
        if title != m[t3['title']].text[0]:
            m[t3['title']].text = [title]
            changed.append('title')
    else:
        title = ''
        changed.append('title')
    # Generate a new name
    new = fix_name_full(u"{0} {1}.mp3".format(
        str(track).zfill(max(2,len(str(numtracks)))),
        title
        ))
    if int(disk) > 0 and int(numdisks) > 1:
        new = "{0}-{1}".format(
            str(disk).zfill(len(str(numdisks))),
            new)
    try:
        if file.decode("utf-8") == new.decode("utf-8"):
            new = None
    except:
        print "  FILE:  "+os.path.join(dirname, file)
        raise
    # Return
    return (m, new, changed)
def add_episode_number(tags: id3.ID3, episode_number: int) -> None:
    tags.add(id3.TRCK(encoding=id3.Encoding.LATIN1, text=str(episode_number)))
Beispiel #23
0
def tag_mp3(filename,
            root_dir,
            final_name,
            d,
            album,
            istrack=True,
            em_image=False):
    """
    Tag an mp3 file

    :param str filename: mp3 temporary file path
    :param str root_dir: Root dir used to get the cover art
    :param str final_name: Final name of the mp3 file (complete path)
    :param dict d: Track dictionary from Qobuz_client
    :param bool istrack
    :param bool em_image: Embed cover art into file
    """

    try:
        audio = id3.ID3(filename)
    except ID3NoHeaderError:
        audio = id3.ID3()

    # temporarily holds metadata
    tags = dict()
    tags["title"] = _get_title(d)
    try:
        tags["label"] = album["label"]["name"]
    except KeyError:
        pass

    artist_ = d.get("performer", {}).get("name")  # TRACK ARTIST
    if istrack:
        tags["artist"] = artist_ or d["album"]["artist"][
            "name"]  # TRACK ARTIST
    else:
        tags["artist"] = artist_ or album["artist"]["name"]

    if istrack:
        tags["genre"] = _format_genres(d["album"]["genres_list"])
        tags["albumartist"] = d["album"]["artist"]["name"]
        tags["album"] = d["album"]["title"]
        tags["date"] = d["album"]["release_date_original"]
        tags["copyright"] = _format_copyright(d["copyright"])
        tracktotal = str(d["album"]["tracks_count"])
    else:
        tags["genre"] = _format_genres(album["genres_list"])
        tags["albumartist"] = album["artist"]["name"]
        tags["album"] = album["title"]
        tags["date"] = album["release_date_original"]
        tags["copyright"] = _format_copyright(album["copyright"])
        tracktotal = str(album["tracks_count"])

    tags["year"] = tags["date"][:4]

    audio["TRCK"] = id3.TRCK(encoding=3,
                             text=f'{d["track_number"]}/{tracktotal}')
    audio["TPOS"] = id3.TPOS(encoding=3, text=str(d["media_number"]))

    # write metadata in `tags` to file
    for k, v in tags.items():
        id3tag = ID3_LEGEND[k]
        audio[id3tag.__name__] = id3tag(encoding=3, text=v)

    if em_image:
        _embed_id3_img(root_dir, audio)

    audio.save(filename, "v2_version=3")
    os.rename(filename, final_name)
Beispiel #24
0
 def _write_tags(self, tags):
     for tag, value in tags.items():
         if tag == "releaseName" or tag == "release_name" or tag == "TALB":
             self._add_tag(id3.TALB(encoding=UTF_8, text=value))
         elif tag == "front_cover" or tag == "APIC_FRONT":
             mime, desc, data = value
             self._add_tag(id3.APIC(UTF_8, mime, FRONT_COVER, desc, data))
         elif tag == "backCover" or tag == "APIC_BACK":
             mime, desc, data = value
             self._add_tag(id3.APIC(UTF_8, mime, BACK_COVER, desc, data))
         elif tag == "lead_performer" or tag == "TPE1":
             self._add_tag(id3.TPE1(encoding=UTF_8, text=value))
         elif tag == "lead_performer_region" or tag == "TXXX_LEAD_PERFORMER_REGION":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="LEAD-PERFORMER-REGION:UN/LOCODE",
                          text=value))
         elif tag == "lead_performer_date_of_birth" or tag == "TXXX_LEAD_PERFORMER_DATE_OF_BIRTH":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="LEAD-PERFORMER-DATE-OF-BIRTH",
                          text=value))
         elif tag == "guestPerformers" or tag == "TMCL":
             self._add_tag(id3.TMCL(encoding=UTF_8, people=value))
         elif tag == "label_name" or tag == "TOWN":
             self._add_tag(id3.TOWN(encoding=UTF_8, text=value))
         elif tag == "catalogNumber" or tag == "TXXX_CATALOG_NUMBER":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="Catalog Number",
                          text=value))
         elif tag == "upc" or tag == "TXXX_UPC":
             """ Deprecated and replaced with BARCODE """
             self._add_tag(id3.TXXX(encoding=UTF_8, desc="UPC", text=value))
         elif tag == "barcode" or tag == "TXXX_BARCODE":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="BARCODE", text=value))
         elif tag == "recording_time" or tag == "TDRC":
             self._add_tag(
                 id3.TDRC(encoding=UTF_8, text=[id3.ID3TimeStamp(value)]))
         elif tag == "releaseTime" or tag == "TDRL":
             self._add_tag(
                 id3.TDRL(encoding=UTF_8, text=[id3.ID3TimeStamp(value)]))
         elif tag == "originalReleaseTime" or tag == "TDOR":
             self._add_tag(
                 id3.TDOR(encoding=UTF_8, text=[id3.ID3TimeStamp(value)]))
         elif tag == "tagging_time" or tag == "TDTG":
             self._add_tag(
                 id3.TDTG(encoding=UTF_8, text=[id3.ID3TimeStamp(value)]))
         elif tag == "recordingStudios" or tag == "TXXX_RECORDING_STUDIO":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="Recording Studio",
                          text=value))
         elif tag == "TIPL":
             self._add_tag(id3.TIPL(encoding=UTF_8, people=value))
         elif tag == "comments" or tag == "COMM":
             text, lang = value
             self._add_tag(
                 id3.COMM(encoding=UTF_8, text=text, desc="", lang=lang))
         elif tag == "track_title" or tag == "TIT2":
             self._add_tag(id3.TIT2(encoding=UTF_8, text=value))
         elif tag == "version_info" or tag == "TPE4":
             self._add_tag(id3.TPE4(encoding=UTF_8, text=value))
         elif tag == "featured_guest" or tag == "TXXX_FEATURED_GUEST":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="Featured Guest",
                          text=value))
         elif tag == "lyricist" or tag == "TEXT":
             self._add_tag(id3.TEXT(encoding=UTF_8, text=value))
         elif tag == "composer" or tag == "TCOM":
             self._add_tag(id3.TCOM(encoding=UTF_8, text=value))
         elif tag == "publisher" or tag == "TPUB":
             self._add_tag(id3.TPUB(encoding=UTF_8, text=value))
         elif tag == "isrc" or tag == "TSRC":
             self._add_tag(id3.TSRC(encoding=UTF_8, text=value))
         elif tag == "labels" or tag == "TXXX_TAGS":
             self._add_tag(id3.TXXX(encoding=UTF_8, desc="Tags",
                                    text=value))
         elif tag == "isni" or tag == "TXXX_ISNI_Joel_Miller":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="ISNI:Joel Miller",
                          text=value))
         elif tag == "TXXX_ISNI_Rebecca_Ann_Maloy":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="ISNI:Rebecca Ann Maloy",
                          text=value))
         elif tag == "TXXX_IPI_Joel_Miller":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="IPI:Joel Miller",
                          text=value))
         elif tag == "TXXX_IPI_Rebecca_Ann_Maloy":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="IPI:Rebecca Ann Maloy",
                          text=value))
         elif tag == "TXXX_ISNI":
             self._add_tag(id3.TXXX(encoding=UTF_8, desc="ISNI",
                                    text=value))
         elif tag == "iswc" or tag == "TXXX_ISWC":
             self._add_tag(id3.TXXX(encoding=UTF_8, desc="ISWC",
                                    text=value))
         elif tag == "lyrics" or tag == "USLT":
             text, lang = value
             self._add_tag(
                 id3.USLT(encoding=UTF_8, text=text, desc="", lang=lang))
         elif tag == "language" or tag == "TLAN":
             self._add_tag(id3.TLAN(encoding=UTF_8, text=value))
         elif tag == "primary_style" or tag == "TCON":
             self._add_tag(id3.TCON(encoding=UTF_8, text=value))
         elif tag == "compilation" or tag == "TCMP":
             self._add_tag(id3.TCMP(encoding=UTF_8, text=value))
         elif tag == "tagger" or tag == "TXXX_TAGGER":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="TAGGER", text=value))
         elif tag == "TXXX_Tagger":
             """ Deprecated and replaced with separate TAGGER and VERSION tags """
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="Tagger", text=value))
         elif tag == "tagger_version" or tag == "TXXX_TAGGER_VERSION":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="TAGGER_VERSION",
                          text=value))
         elif tag == "TXXX_Tagging_Time":
             """ Deprecated and replaced with TAGGING_TIME """
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="Tagging Time", text=value))
         elif tag == "TXXX_TAGGING_TIME":
             """ Deprecated and replaced with TDTG """
             self._add_tag(
                 id3.TXXX(encoding=UTF_8, desc="TAGGING_TIME", text=value))
         elif tag == "TXXX_PRODUCTION_COMPANY":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="PRODUCTION-COMPANY",
                          text=value))
         elif tag == "TXXX_PRODUCTION_COMPANY_REGION":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="PRODUCTION-COMPANY-REGION:UN/LOCODE",
                          text=value))
         elif tag == "TXXX_RECORDING_STUDIO_REGION":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="RECORDING-STUDIO-REGION:UN/LOCODE",
                          text=value))
         elif tag == "TXXX_RECORDING_STUDIO_ADDRESS":
             self._add_tag(
                 id3.TXXX(encoding=UTF_8,
                          desc="RECORDING-STUDIO-ADDRESS",
                          text=value))
         elif tag == "TRCK":
             self._add_tag(id3.TRCK(encoding=UTF_8, text=value))
         else:
             raise AssertionError("Knows nothing about '{0}'".format(tag))
Beispiel #25
0
                    continue

            if 'TALB' in tags and str(
                    tags['TALB']) and str(tags['TALB']) != 'Unknown Album':
                result['album_title'] = str(tags['TALB'])

            tags['TIT2'] = id3.TIT2(encoding=3, text=u'{0}'.format(music))
            tags['TALB'] = id3.TALB(encoding=3,
                                    text=u'{0}'.format(result['album_title']))
            tags['TPE1'] = id3.TPE1(encoding=3,
                                    text=u'{0}'.format(real_artist))
            tags['TCON'] = id3.TCON(encoding=3,
                                    text=u'{0}'.format(result['genre']))
            tags['TDRC'] = id3.TDRC(encoding=3,
                                    text=u'{0}'.format(result['album_year']))
            tags['TRCK'] = id3.TRCK(encoding=3,
                                    text=u'{0}'.format(result['track_number']))
            if album_art:
                tags['APIC'] = id3.APIC(
                    encoding=3,
                    mime='image/png'
                    if '.png' in result['album_art_url'] else 'image/jpeg',
                    type=3,
                    desc=u'Cover',
                    data=album_art)

            tags.save(music_path)
            print("Artist: {} | Album: {} ({}) | {} Music: {} ({})".format(
                real_artist, result['album_title'], result['album_year'],
                result['track_number'], music, result['genre']))

            if album is not result['album_title']:
Beispiel #26
0
    def _save(self, filename, metadata):
        """Save metadata to the file."""
        log.debug("Saving file %r", filename)
        try:
            tags = compatid3.CompatID3(encode_filename(filename))
        except mutagen.id3.ID3NoHeaderError:
            tags = compatid3.CompatID3()

        if config.setting['clear_existing_tags']:
            tags.clear()
        if config.setting['save_images_to_tags'] and metadata.images:
            tags.delall('APIC')

        if config.setting['write_id3v1']:
            v1 = 2
        else:
            v1 = 0
        encoding = {
            'utf-8': 3,
            'utf-16': 1
        }.get(config.setting['id3v2_encoding'], 0)

        if 'tracknumber' in metadata:
            if 'totaltracks' in metadata:
                text = '%s/%s' % (metadata['tracknumber'],
                                  metadata['totaltracks'])
            else:
                text = metadata['tracknumber']
            tags.add(id3.TRCK(encoding=0, text=text))

        if 'discnumber' in metadata:
            if 'totaldiscs' in metadata:
                text = '%s/%s' % (metadata['discnumber'],
                                  metadata['totaldiscs'])
            else:
                text = metadata['discnumber']
            tags.add(id3.TPOS(encoding=0, text=text))

        if config.setting['save_images_to_tags']:
            # This is necessary because mutagens HashKey for APIC frames only
            # includes the FrameID (APIC) and description - it's basically
            # impossible to save two images, even of different types, without
            # any description.
            counters = defaultdict(lambda: 0)
            for image in metadata.images:
                desc = desctag = image['desc']
                if not save_this_image_to_tags(image):
                    continue
                if counters[desc] > 0:
                    if desc:
                        desctag = "%s (%i)" % (desc, counters[desc])
                    else:
                        desctag = "(%i)" % counters[desc]
                counters[desc] += 1
                tags.add(
                    id3.APIC(encoding=0,
                             mime=image["mime"],
                             type=image_type_as_id3_num(image['type']),
                             desc=desctag,
                             data=image["data"]))

        tmcl = mutagen.id3.TMCL(encoding=encoding, people=[])
        tipl = mutagen.id3.TIPL(encoding=encoding, people=[])

        tags.delall('TCMP')
        for name, values in metadata.rawitems():
            if name.startswith('performer:'):
                role = name.split(':', 1)[1]
                for value in values:
                    tmcl.people.append([role, value])
            elif name.startswith('comment:'):
                desc = name.split(':', 1)[1]
                if desc.lower()[:4] == "itun":
                    tags.delall('COMM:' + desc)
                    tags.add(
                        id3.COMM(encoding=0,
                                 desc=desc,
                                 lang='eng',
                                 text=[v + u'\x00' for v in values]))
                else:
                    tags.add(
                        id3.COMM(encoding=encoding,
                                 desc=desc,
                                 lang='eng',
                                 text=values))
            elif name.startswith('lyrics:') or name == 'lyrics':
                if ':' in name:
                    desc = name.split(':', 1)[1]
                else:
                    desc = ''
                for value in values:
                    tags.add(id3.USLT(encoding=encoding, desc=desc,
                                      text=value))
            elif name in self._rtipl_roles:
                for value in values:
                    tipl.people.append([self._rtipl_roles[name], value])
            elif name == 'musicbrainz_recordingid':
                tags.add(
                    id3.UFID(owner='http://musicbrainz.org',
                             data=str(values[0])))
            elif name == '~rating':
                # Search for an existing POPM frame to get the current playcount
                for frame in tags.values():
                    if frame.FrameID == 'POPM' and frame.email == config.setting[
                            'rating_user_email']:
                        count = getattr(frame, 'count', 0)
                        break
                else:
                    count = 0

                # Convert rating to range between 0 and 255
                rating = int(
                    round(
                        float(values[0]) * 255 /
                        (config.setting['rating_steps'] - 1)))
                tags.add(
                    id3.POPM(email=config.setting['rating_user_email'],
                             rating=rating,
                             count=count))
            elif name in self.__rtranslate:
                frameid = self.__rtranslate[name]
                if frameid.startswith('W'):
                    valid_urls = all([all(urlparse(v)[:2]) for v in values])
                    if frameid == 'WCOP':
                        # Only add WCOP if there is only one license URL, otherwise use TXXX:LICENSE
                        if len(values) > 1 or not valid_urls:
                            tags.add(
                                id3.TXXX(encoding=encoding,
                                         desc=self.__rtranslate_freetext[name],
                                         text=values))
                        else:
                            tags.add(id3.WCOP(url=values[0]))
                    elif frameid == 'WOAR' and valid_urls:
                        for url in values:
                            tags.add(id3.WOAR(url=url))
                elif frameid.startswith('T'):
                    tags.add(
                        getattr(id3, frameid)(encoding=encoding, text=values))
                    if frameid == 'TSOA':
                        tags.delall('XSOA')
                    elif frameid == 'TSOP':
                        tags.delall('XSOP')
                    elif frameid == 'TSO2':
                        tags.delall('TXXX:ALBUMARTISTSORT')
            elif name in self.__rtranslate_freetext:
                tags.add(
                    id3.TXXX(encoding=encoding,
                             desc=self.__rtranslate_freetext[name],
                             text=values))
            elif name.startswith('~id3:'):
                name = name[5:]
                if name.startswith('TXXX:'):
                    tags.add(
                        id3.TXXX(encoding=encoding, desc=name[5:],
                                 text=values))
                else:
                    frameclass = getattr(id3, name[:4], None)
                    if frameclass:
                        tags.add(frameclass(encoding=encoding, text=values))
            # don't save private / already stored tags
            elif not name.startswith(
                    "~") and not name in self.__other_supported_tags:
                tags.add(id3.TXXX(encoding=encoding, desc=name, text=values))

        if tmcl.people:
            tags.add(tmcl)
        if tipl.people:
            tags.add(tipl)

        if config.setting['write_id3v23']:
            tags.update_to_v23(join_with=config.setting['id3v23_join_with'])
            tags.save(encode_filename(filename), v2=3, v1=v1)
        else:
            tags.update_to_v24()
            tags.save(encode_filename(filename), v2=4, v1=v1)

        if self._IsMP3 and config.setting["remove_ape_from_mp3"]:
            try:
                mutagen.apev2.delete(encode_filename(filename))
            except:
                pass
Beispiel #27
0
def tag_mp3(filename, root_dir, final_name, d, album, istrack=True, em_image=False):
    """
    Tag an mp3 file

    :param str filename: mp3 temporary file path
    :param str root_dir: Root dir used to get the cover art
    :param str final_name: Final name of the mp3 file (complete path)
    :param dict d: Track dictionary from Qobuz_client
    :param bool istrack
    :param bool em_image: Embed cover art into file
    """

    id3_legend = {
        "album": id3.TALB,
        "albumartist": id3.TPE2,
        "artist": id3.TPE1,
        "comment": id3.COMM,
        "composer": id3.TCOM,
        "copyright": id3.TCOP,
        "date": id3.TDAT,
        "genre": id3.TCON,
        "isrc": id3.TSRC,
        "label": id3.TPUB,
        "performer": id3.TOPE,
        "title": id3.TIT2,
        "year": id3.TYER,
    }
    try:
        audio = id3.ID3(filename)
    except ID3NoHeaderError:
        audio = id3.ID3()

    # temporarily holds metadata
    tags = dict()
    tags["title"] = get_title(d)
    try:
        tags["label"] = album["label"]["name"]
    except KeyError:
        pass

    try:
        tags["artist"] = d["performer"]["name"]
    except KeyError:
        if istrack:
            tags["artist"] = d["album"]["artist"]["name"]
        else:
            tags["artist"] = album["artist"]["name"]

    if istrack:
        tags["genre"] = _format_genres(d["album"]["genres_list"])
        tags["albumartist"] = d["album"]["artist"]["name"]
        tags["album"] = d["album"]["title"]
        tags["date"] = d["album"]["release_date_original"]
        tags["copyright"] = _format_copyright(d["copyright"])
        tracktotal = str(d["album"]["tracks_count"])
    else:
        tags["genre"] = _format_genres(album["genres_list"])
        tags["albumartist"] = album["artist"]["name"]
        tags["album"] = album["title"]
        tags["date"] = album["release_date_original"]
        tags["copyright"] = _format_copyright(album["copyright"])
        tracktotal = str(album["tracks_count"])

    tags["year"] = tags["date"][:4]

    audio["TRCK"] = id3.TRCK(encoding=3, text=f'{d["track_number"]}/{tracktotal}')
    audio["TPOS"] = id3.TPOS(encoding=3, text=str(d["media_number"]))

    # write metadata in `tags` to file
    for k, v in tags.items():
        id3tag = id3_legend[k]
        audio[id3tag.__name__] = id3tag(encoding=3, text=v)

    if em_image:
        emb_image = os.path.join(root_dir, "cover.jpg")
        multi_emb_image = os.path.join(
            os.path.abspath(os.path.join(root_dir, os.pardir)), "cover.jpg"
        )
        if os.path.isfile(emb_image):
            cover_image = emb_image
        else:
            cover_image = multi_emb_image

        with open(cover_image, "rb") as cover:
            audio.add(id3.APIC(3, "image/jpeg", 3, "", cover.read()))

    audio.save(filename, "v2_version=3")
    os.rename(filename, final_name)
Beispiel #28
0
    def __update_tag(self, download_dir, audio_file, image_file,
                     song_title=None, album_title=None, album_artist=None, album_composer=None,
                     track_number=-1, process_index=-1, process_total=-1):
        """
        The function that update audio metadata for each song.

        :param str download_dir: Download directory
        :param str audio_file: Path to audio file
        :param str image_file: Path to image file
        :param str song_title: Song title
        :param str album_title: Album title to be saved in metadata
        :param str album_artist: Album artist to be saved in metadata
        :param str album_composer: Album composer to be saved in metadata
        :param int track_number: track number to be saved in metadata
        :param int process_index: Current process index displayed in log message
        :param int process_total: Total number of process displayed in log message
        """

        if audio_file is None:
            logger.warning('[Process:{}/{}][Track:{}] Could not update metadata because there is no data found on the playlist. The video may be private or deleted.'.format(process_index, process_total, track_number))
            return

        if process_index > 0 and process_total > 0:

            if track_number > 0:
                log_prefix = '[Process:{}/{}][Track:{}]'.format(process_index, process_total, track_number)

            else:
                log_prefix = '[Process:{}/{}]'.format(process_index, process_total)

        else:
            log_prefix = ''

        audio_filename = os.path.basename(audio_file)

        try:
            # Validate audio data
            if not os.path.isfile(audio_file):
                raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), audio_file)

            audio_mime_type = mimetypes.guess_type(audio_file)

            if contains_at_least(audio_mime_type, ['audio/x-mp4', 'audio/x-m4a', 'audio/mp4a-latm']):

                # For more info about mp4 tag is available at
                # https://github.com/quodlibet/mutagen/blob/cf399dc58940fb1356f672809d763be9e2af0033/mutagen/mp4/__init__.py
                # http://atomicparsley.sourceforge.net/mpeg-4files.html
                mp4_data = mp4.MP4(audio_file)
                # Track Number
                if not self.no_track_number and track_number > 0:
                    mp4_data['trkn'] = [(track_number, 0)]
                # Cover image
                if not self.no_artwork:
                    image_data = self.__get_tag_image(image_file, audio_mime_type)
                    if image_data:
                        mp4_data['covr'] = [image_data]
                # Album title
                if not self.no_album_title and album_title is not None:
                    mp4_data['\xa9alb'] = album_title
                # Album artist
                if not self.no_album_artist and album_artist is not None:
                    mp4_data['aART'] = album_artist
                # Composer
                if not self.no_composer and album_composer is not None:
                    mp4_data['\xa9wrt'] = album_composer
                # Part of compilation
                if not self.no_compilation:
                    mp4_data['cpil'] = True
                # Save
                mp4_data.save()

            elif contains_at_least(audio_mime_type, ['audio/x-mp3', 'audio/mpeg']):

                # For more info about ID3v2 tag is available at
                # https://github.com/quodlibet/mutagen/blob/4a5d7d17f1a611280cc52d229aa70b77ca3c55dd/mutagen/id3/_frames.py
                # https://help.mp3tag.de/main_tags.html
                mp3_data = id3.ID3(audio_file)
                # Cover image
                if not self.no_artwork:
                    image_data = self.__get_tag_image(image_file, audio_mime_type)
                    if image_data:
                        mp3_data['APIC'] = image_data
                # Track number
                if not self.no_track_number and track_number > 0:
                    mp3_data.add(id3.TRCK(encoding=3, text=['{}/{}'.format(track_number, 0)]))
                # Album title
                if not self.no_album_title and album_title is not None:
                    mp3_data["TALB"] = id3.TALB(encoding=0, text=album_title)
                # Album artist
                if not self.no_album_artist and album_artist is not None:
                    mp3_data["TPE2"] = id3.TPE2(encoding=0, text=album_artist)
                # Composer
                if not self.no_composer and album_composer is not None:
                    mp3_data["TCOM"] = id3.TCOM(encoding=0, text=album_composer)
                # Part of compilation
                if not self.no_compilation:
                    mp3_data['TCMP'] = id3.TCMP(encoding=0, text=['1'])
                # Save
                mp3_data.save()

            elif contains_at_least(audio_mime_type, ['audio/x-aac']):

                # TODO: Add AAC support
                pass
                # image_data = __get_tag_image(image_file, audio_mime_type)
                # aac_data = aac.AAC(audio_file)
                # if not self.no_track_number:
                #     if track_number > 0 and track_total > 0:
                #         aac_data.add_tags(id3.TRCK(encoding=3, text=['{}/{}'.format(track_number, track_total)]))
                #         # mp3_data['TRCK'] = id3.TRCK(encoding=3, text=[str(track_number)])
                # if image_data:
                #     mp3_data['APIC'] = image_data
                #     aac_data.save()

            elif contains_at_least(audio_mime_type, ['audio/x-flac']):

                # https://github.com/quodlibet/mutagen/blob/a1db79ece62c4e86259f15825e360d1ce0986a22/mutagen/flac.py
                # https://github.com/quodlibet/mutagen/blob/4a5d7d17f1a611280cc52d229aa70b77ca3c55dd/tests/test_flac.py

                flac_data = flac.FLAC(audio_file)
                # Artwork
                if not self.no_artwork:
                    image_data = self.__get_tag_image(image_file, audio_mime_type)
                    if image_data:
                        flac_data.add_picture(image_data)
                # Save
                flac_data.save()

                flac_data = File(audio_file)
                # Track number
                if not self.no_track_number and track_number > 0:
                    flac_data.tags['tracknumber'] = str(track_number)
                # Album title
                if not self.no_album_title and album_title is not None:
                    flac_data.tags['album'] = album_title
                # Album artist
                if not self.no_album_artist and album_artist is not None:
                    flac_data.tags['albumartist'] = album_artist
                # Composer
                if not self.no_composer and album_composer is not None:
                    flac_data.tags['composer'] = album_composer
                # Part of compilation
                if not self.no_compilation:
                    pass
                # Save
                flac_data.save()
                # audio = File(audio_file, easy=True)

            else:
                raise InvalidMimeTypeException("Invalid audio format.", audio_mime_type)

            # Remove artwork if succeeded
            if os.path.exists(image_file):
                os.remove(image_file)

            # Rename filename from id to title
            dest_audio_file = os.path.join(download_dir, '{}.{}'.format(song_title, self.audio_codec))
            os.rename(audio_file, dest_audio_file)

            dest_audio_filename = os.path.basename(dest_audio_file)
            logger.info('{}[File:{}] Updated.'.format(log_prefix, dest_audio_filename))

        except FileNotFoundError:
            message = 'File not found. Skipped.'
            logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message))

        except InvalidDataException as e:
            message = e.message + ' Skipped.'
            logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message))

        except InvalidMimeTypeException as e:
            message = e.message + ' Skipped.'
            logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message))

        except Exception as e:
            message = 'Error {}: {} Skipped.'.format(type(e), str(e))
            logger.error('{}[File:{}] {}'.format(log_prefix, audio_filename, message))
Beispiel #29
0
    def _save(self, filename, metadata):
        """Save metadata to the file."""
        log.debug("Saving file %r", filename)
        tags = self._get_tags(filename)

        if config.setting['clear_existing_tags']:
            tags.clear()
        if metadata.images_to_be_saved_to_tags:
            tags.delall('APIC')

        encoding = {
            'utf-8': 3,
            'utf-16': 1
        }.get(config.setting['id3v2_encoding'], 0)

        if 'tracknumber' in metadata:
            if 'totaltracks' in metadata:
                text = '%s/%s' % (metadata['tracknumber'],
                                  metadata['totaltracks'])
            else:
                text = metadata['tracknumber']
            tags.add(id3.TRCK(encoding=0, text=id3text(text, 0)))

        if 'discnumber' in metadata:
            if 'totaldiscs' in metadata:
                text = '%s/%s' % (metadata['discnumber'],
                                  metadata['totaldiscs'])
            else:
                text = metadata['discnumber']
            tags.add(id3.TPOS(encoding=0, text=id3text(text, 0)))

        # This is necessary because mutagens HashKey for APIC frames only
        # includes the FrameID (APIC) and description - it's basically
        # impossible to save two images, even of different types, without
        # any description.
        counters = defaultdict(lambda: 0)
        for image in metadata.images_to_be_saved_to_tags:
            desc = desctag = image.comment
            if counters[desc] > 0:
                if desc:
                    desctag = "%s (%i)" % (desc, counters[desc])
                else:
                    desctag = "(%i)" % counters[desc]
            counters[desc] += 1
            tags.add(
                id3.APIC(encoding=0,
                         mime=image.mimetype,
                         type=image_type_as_id3_num(image.maintype),
                         desc=id3text(desctag, 0),
                         data=image.data))

        tmcl = mutagen.id3.TMCL(encoding=encoding, people=[])
        tipl = mutagen.id3.TIPL(encoding=encoding, people=[])

        tags.delall('TCMP')
        for name, values in metadata.rawitems():
            values = [id3text(v, encoding) for v in values]
            name = id3text(name, encoding)

            if name.startswith('performer:'):
                role = name.split(':', 1)[1]
                for value in values:
                    tmcl.people.append([role, value])
            elif name.startswith('comment:'):
                desc = name.split(':', 1)[1]
                if desc.lower()[:4] == 'itun':
                    tags.delall('COMM:' + desc)
                    tags.add(
                        id3.COMM(encoding=0,
                                 desc=desc,
                                 lang='eng',
                                 text=[v + '\x00' for v in values]))
                else:
                    tags.add(
                        id3.COMM(encoding=encoding,
                                 desc=desc,
                                 lang='eng',
                                 text=values))
            elif name.startswith('lyrics:') or name == 'lyrics':
                if ':' in name:
                    desc = name.split(':', 1)[1]
                else:
                    desc = ''
                for value in values:
                    tags.add(id3.USLT(encoding=encoding, desc=desc,
                                      text=value))
            elif name in self._rtipl_roles:
                for value in values:
                    tipl.people.append([self._rtipl_roles[name], value])
            elif name == 'musicbrainz_recordingid':
                tags.add(
                    id3.UFID(owner='http://musicbrainz.org',
                             data=bytes(values[0], 'ascii')))
            elif name == '~rating':
                # Search for an existing POPM frame to get the current playcount
                for frame in tags.values():
                    if frame.FrameID == 'POPM' and frame.email == config.setting[
                            'rating_user_email']:
                        count = getattr(frame, 'count', 0)
                        break
                else:
                    count = 0

                # Convert rating to range between 0 and 255
                rating = int(
                    round(
                        float(values[0]) * 255 /
                        (config.setting['rating_steps'] - 1)))
                tags.add(
                    id3.POPM(email=config.setting['rating_user_email'],
                             rating=rating,
                             count=count))
            elif name == 'grouping':
                if config.setting['itunes_compatible_grouping']:
                    tags.add(id3.GRP1(encoding=encoding, text=values))
                else:
                    tags.add(id3.TIT1(encoding=encoding, text=values))
            elif name == 'work':
                if config.setting['itunes_compatible_grouping']:
                    tags.add(id3.TIT1(encoding=encoding, text=values))
                    tags.delall('TXXX:Work')
                else:
                    tags.add(self.build_TXXX(encoding, 'Work', values))
            elif name in self.__rtranslate:
                frameid = self.__rtranslate[name]
                if frameid.startswith('W'):
                    valid_urls = all([all(urlparse(v)[:2]) for v in values])
                    if frameid == 'WCOP':
                        # Only add WCOP if there is only one license URL, otherwise use TXXX:LICENSE
                        if len(values) > 1 or not valid_urls:
                            tags.add(
                                self.build_TXXX(
                                    encoding, self.__rtranslate_freetext[name],
                                    values))
                        else:
                            tags.add(id3.WCOP(url=values[0]))
                    elif frameid == 'WOAR' and valid_urls:
                        for url in values:
                            tags.add(id3.WOAR(url=url))
                elif frameid.startswith('T'):
                    if config.setting['write_id3v23']:
                        if frameid == 'TMOO':
                            tags.add(self.build_TXXX(encoding, 'mood', values))
                    # No need to care about the TMOO tag being added again as it is
                    # automatically deleted by Mutagen if id2v23 is selected
                    tags.add(
                        getattr(id3, frameid)(encoding=encoding, text=values))
                    if frameid == 'TSOA':
                        tags.delall('XSOA')
                    elif frameid == 'TSOP':
                        tags.delall('XSOP')
                    elif frameid == 'TSO2':
                        tags.delall('TXXX:ALBUMARTISTSORT')
            elif name in self.__rtranslate_freetext:
                tags.add(
                    self.build_TXXX(encoding, self.__rtranslate_freetext[name],
                                    values))
            elif name.startswith('~id3:'):
                name = name[5:]
                if name.startswith('TXXX:'):
                    tags.add(self.build_TXXX(encoding, name[5:], values))
                else:
                    frameclass = getattr(id3, name[:4], None)
                    if frameclass:
                        tags.add(frameclass(encoding=encoding, text=values))
            # don't save private / already stored tags
            elif not name.startswith(
                    "~") and name not in self.__other_supported_tags:
                tags.add(self.build_TXXX(encoding, name, values))

        tags.add(tmcl)
        tags.add(tipl)

        self._remove_deleted_tags(metadata, tags)

        self._save_tags(tags, encode_filename(filename))

        if self._IsMP3 and config.setting["remove_ape_from_mp3"]:
            try:
                mutagen.apev2.delete(encode_filename(filename))
            except:
                pass
Beispiel #30
0
    def _save(self, filename, metadata, settings):
        """Save metadata to the file."""
        self.log.debug("Saving file %r", filename)
        try:
            tags = compatid3.CompatID3(encode_filename(filename))
        except mutagen.id3.ID3NoHeaderError:
            tags = compatid3.CompatID3()

        if settings['clear_existing_tags']:
            tags.clear()
        if settings['save_images_to_tags'] and metadata.images:
            tags.delall('APIC')

        if settings['write_id3v1']:
            v1 = 2
        else:
            v1 = 0
        encoding = {'utf-8': 3, 'utf-16': 1}.get(settings['id3v2_encoding'], 0)

        if 'tracknumber' in metadata:
            if 'totaltracks' in metadata:
                text = '%s/%s' % (metadata['tracknumber'],
                                  metadata['totaltracks'])
            else:
                text = metadata['tracknumber']
            tags.add(id3.TRCK(encoding=0, text=text))

        if 'discnumber' in metadata:
            if 'totaldiscs' in metadata:
                text = '%s/%s' % (metadata['discnumber'],
                                  metadata['totaldiscs'])
            else:
                text = metadata['discnumber']
            tags.add(id3.TPOS(encoding=0, text=text))

        if settings['save_images_to_tags']:
            for mime, data in metadata.images:
                tags.add(
                    id3.APIC(encoding=0, mime=mime, type=3, desc='',
                             data=data))

        tmcl = mutagen.id3.TMCL(encoding=encoding, people=[])
        tipl = mutagen.id3.TIPL(encoding=encoding, people=[])

        id3.TCMP = compatid3.TCMP
        tags.delall('TCMP')
        for name, values in metadata.rawitems():
            if name.startswith('performer:'):
                role = name.split(':', 1)[1]
                for value in values:
                    tmcl.people.append([role, value])
            elif name.startswith('comment:'):
                desc = name.split(':', 1)[1]
                if desc.lower()[:4] == "itun":
                    tags.delall('COMM:' + desc)
                    tags.add(
                        id3.COMM(encoding=0,
                                 desc=desc,
                                 lang='eng',
                                 text=[v + u'\x00' for v in values]))
                else:
                    tags.add(
                        id3.COMM(encoding=encoding,
                                 desc=desc,
                                 lang='eng',
                                 text=values))
            elif name.startswith('lyrics:') or name == 'lyrics':
                if ':' in name:
                    desc = name.split(':', 1)[1]
                else:
                    desc = ''
                for value in values:
                    tags.add(id3.USLT(encoding=encoding, desc=desc,
                                      text=value))
            elif name in self.__rtipl_roles:
                for value in values:
                    tipl.people.append([self.__rtipl_roles[name], value])
            elif name == 'musicbrainz_trackid':
                tags.add(
                    id3.UFID(owner='http://musicbrainz.org',
                             data=str(values[0])))
            elif name == '~rating':
                # Search for an existing POPM frame to get the current playcount
                for frame in tags.values():
                    if frame.FrameID == 'POPM' and frame.email == settings[
                            'rating_user_email']:
                        count = getattr(frame, 'count', 0)
                        break
                else:
                    count = 0

                # Convert rating to range between 0 and 255
                rating = int(
                    round(
                        float(values[0]) * 255 /
                        (settings['rating_steps'] - 1)))
                tags.add(
                    id3.POPM(email=settings['rating_user_email'],
                             rating=rating,
                             count=count))
            elif name in self.__rtranslate:
                frameid = self.__rtranslate[name]
                if frameid.startswith('W'):
                    tags.add(getattr(id3, frameid)(url=values[0]))
                elif frameid.startswith('T'):
                    tags.add(
                        getattr(id3, frameid)(encoding=encoding, text=values))
            elif name in self.__rtranslate_freetext:
                tags.add(
                    id3.TXXX(encoding=encoding,
                             desc=self.__rtranslate_freetext[name],
                             text=values))
            elif name.startswith('~id3:'):
                name = name[5:]
                if name.startswith('TXXX:'):
                    tags.add(
                        id3.TXXX(encoding=encoding, desc=name[5:],
                                 text=values))
                else:
                    frameclass = getattr(id3, name[:4], None)
                    if frameclass:
                        tags.add(frameclass(encoding=encoding, text=values))

        if tmcl.people:
            tags.add(tmcl)
        if tipl.people:
            tags.add(tipl)

        if settings['write_id3v23']:
            tags.update_to_v23()
            tags.save(encode_filename(filename), v2=3, v1=v1)
        else:
            # remove all custom 2.3 frames
            for old in self.__upgrade.keys():
                tags.delall(old)
            tags.update_to_v24()
            tags.save(encode_filename(filename), v2=4, v1=v1)

        if self._IsMP3 and settings["remove_ape_from_mp3"]:
            try:
                mutagen.apev2.delete(encode_filename(filename))
            except:
                pass