Пример #1
0
async def yt_download(event: events.newmessage.NewMessage.Event,
                      yt: YouTube) -> None:
    video = io.BytesIO()
    type_ = None
    for stream in yt.streams:
        if stream.audio_codec == 'opus':
            type_ = stream.mime_type.replace('audio/', '')
            break
        else:
            type_ = 'mp4'
    mess_id = await event.reply(f'__Downloading {yt.title}__')
    yt.streams.get_audio_only(subtype=type_).stream_to_buffer(buffer=video)
    file = io.BytesIO(video.getvalue())
    process = (ffmpeg.input('pipe:').output('pipe:', format='opus').run_async(
        pipe_stdin=True, pipe_stdout=True, pipe_stderr=True))
    out, err = process.communicate(input=file.read())
    out_file = io.BytesIO(out)
    mutagen_file = oggopus.OggOpus(out_file)
    metas = await generate_names(yt)
    mutagen_file['Artist'] = metas['Artist']
    mutagen_file['Title'] = metas['Title']
    mutagen_file['Album'] = metas['Album']
    mutagen_file.save(out_file)
    out_file = io.BytesIO(out_file.getvalue())
    out_file.name = f"{metas['Artist']} - {metas['Title']}.ogg"
    await client.edit_message(mess_id, f'__Uploading {yt.title}__')
    async with client.action(event.sender_id, 'file'):
        await event.reply(file=out_file)
        await client.delete_messages(event.sender_id, mess_id)
Пример #2
0
async def yt_download(event: events.newmessage.NewMessage.Event, yt: YouTube) -> None:
    video = io.BytesIO()
    type_ = None
    for stream in yt.streams:
        if stream.audio_codec == 'opus':
            type_ = stream.mime_type.replace('audio/', '')
            break
        else:
            pass
    mess_id = await event.reply(f'__Downloading {yt.title}__')
    yt.streams.get_audio_only(subtype=type_).stream_to_buffer(buffer=video)
    file = io.BytesIO(video.getvalue())
    file.name = f'{yt.title}.{type_}'
    process = (
        ffmpeg
            .input('pipe:')
            .output('pipe:', format='opus')
            .run_async(pipe_stdin=True, pipe_stdout=True, pipe_stderr=True)
    )
    out, err = process.communicate(input=file.read())
    out_file = io.BytesIO(out)
    mutagen_file = oggopus.OggOpus(fileobj=out_file)
    mutagen_file['artist'] = yt.author
    mutagen_file['title'] = f'!{yt.title}'
    mutagen_file.save(out_file)
    out_file = io.BytesIO(out_file.getvalue())
    out_file.name = f'{yt.title}.opus'
    await client.edit_message(mess_id, f'__Uploading {yt.title}__')
    await event.reply(file=out_file)
    await client.delete_messages(event.sender_id, mess_id)
Пример #3
0
def change_opus_file(file_path):
    music_file = mutagen.OggOpus(file_path)

    upper_keys(music_file)
    music_file["COMMENT"] = create_comment(music_file)

    if "description" in music_file.keys():
        #Compare this against what is returned
        #TODO Make this mutable
        find_terms = {
            "Title": ["Title Translation", "Title"],
            "Album": ["Album"],
            "Artist": ["Artist", "Circle"],
            "Date": ["Date"],
            "Origin": ["Original", "Origin", "Source"]
        }
        print(parse_description(music_file["description"][0], find_terms))

    music_file.save()
Пример #4
0
def set_metadata_tags(args, audio_file, idx, track, ripper):
    # log completed file
    print(Fore.GREEN + Style.BRIGHT + os.path.basename(audio_file) +
          Style.NORMAL + "\t[ " + format_size(os.stat(audio_file)[ST_SIZE]) +
          " ]" + Fore.RESET)

    if args.output_type == "wav" or args.output_type == "pcm":
        print(Fore.YELLOW + "Skipping metadata tagging for " +
              args.output_type + " encoding...")
        return

    # ensure everything is loaded still
    if not track.is_loaded:
        track.load()
    if not track.album.is_loaded:
        track.album.load()
    album_browser = track.album.browse()
    album_browser.load()

    # calculate num of tracks on disc and num of dics
    num_discs = 0
    num_tracks = 0
    for track_browse in album_browser.tracks:
        if (track_browse.disc == track.disc and
                track_browse.index > track.index):
            num_tracks = track_browse.index
        if track_browse.disc > num_discs:
            num_discs = track_browse.disc

    # try to get genres from Spotify's Web API
    genres = None
    if args.genres is not None:
        genres = ripper.web.get_genres(args.genres[0], track)

    # use mutagen to update id3v2 tags and vorbis comments
    try:
        audio = None
        on_error = 'replace' if args.ascii_path_only else 'ignore'
        album = to_ascii(track.album.name, on_error)
        artist = to_ascii(track.artists[0].name, on_error)
        title = to_ascii(track.name, on_error)

        # the comment tag can be formatted
        if args.comment is not None:
            comment = \
                format_track_string(ripper, args.comment[0], idx, track)
            comment_ascii = to_ascii(comment, on_error)

        if args.grouping is not None:
            grouping = \
                format_track_string(ripper, args.grouping[0], idx, track)
            grouping_ascii = to_ascii(grouping, on_error)

        if genres is not None and genres:
            genres_ascii = [to_ascii(genre) for genre in genres]

        # cover art image
        def get_cover_image(image_link):
            image_link = 'http://i.scdn.co%s' % (
                image_link[len('spotify'):].replace(':', '/'))
            cover_file = urllib.request.urlretrieve(image_link)[0]

            with open(cover_file, "rb") as f:
                if f.mode == "rb":
                    return f.read()
                else:
                    return None

        image_link = str(track.album.cover(0).link)
        image = get_cover_image(image_link)
        
        def tag_to_ascii(_str, _str_ascii):
            return _str if args.ascii_path_only else _str_ascii

        def idx_of_total_str(_idx, _total):
            if _total > 0:
                return "%d/%d" % (_idx, _total)
            else:
                return "%d" % (_idx)

        def save_cover_image(embed_image_func):
            if image is not None:
                def write_image(file_name):
                    cover_path = os.path.dirname(audio_file)
                    cover_file = os.path.join(cover_path, file_name)
                    if not path_exists(cover_file):
                        with open(cover_file, "wb") as f:
                            f.write(image)

                if args.cover_file is not None:
                    write_image(args.cover_file[0])
                elif args.cover_file_and_embed is not None:
                    write_image(args.cover_file_and_embed[0])
                    embed_image_func()
                else:
                    embed_image_func()

        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
                    )
                )

            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(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()

        # aac is not well supported
        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
                    )
                )

            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(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

        def set_vorbis_comments(audio):
            # add Vorbis comment block if it doesn't exist
            if audio.tags is None:
                audio.add_tags()

            def embed_image():
                pic = flac.Picture()
                pic.type = 3
                pic.mime = "image/jpeg"
                pic.desc = "Front Cover"
                pic.data = image
                if args.output_type == "flac":
                    audio.add_picture(pic)
                else:
                    data = base64.b64encode(pic.write())
                    audio["METADATA_BLOCK_PICTURE"] = [data.decode("ascii")]

            save_cover_image(embed_image)

            if album is not None:
                audio.tags["ALBUM"] = tag_to_ascii(track.album.name, album)
            audio.tags["TITLE"] = tag_to_ascii(track.name, title)
            audio.tags["ARTIST"] = tag_to_ascii(track.artists[0].name, artist)
            audio.tags["DATE"] = str(track.album.year)
            audio.tags["YEAR"] = str(track.album.year)
            audio.tags["DISCNUMBER"] = str(track.disc)
            audio.tags["DISCTOTAL"] = str(num_discs)
            audio.tags["TRACKNUMBER"] = str(track.index)
            audio.tags["TRACKTOTAL"] = str(num_tracks)
            if args.comment is not None:
                audio.tags["COMMENT"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags["GROUPING"] = \
                    tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags["GENRE"] = ", ".join(_genres)

            audio.save()

        # only called by Python 3
        def set_mp4_tags(audio):
            # add MP4 tags if it doesn't exist
            if audio.tags is None:
                audio.add_tags()

            def embed_image():
                audio.tags["covr"] = mp4.MP4Cover(image)

            save_cover_image(embed_image)

            if album is not None:
                audio.tags["\xa9alb"] = tag_to_ascii(track.album.name, album)
            audio["\xa9nam"] = tag_to_ascii(track.name, title)
            audio.tags["\xa9ART"] = tag_to_ascii(track.artists[0].name, artist)
            audio.tags["\xa9day"] = str(track.album.year)
            audio.tags["disk"] = [(track.disc, num_discs)]
            audio.tags["trkn"] = [(track.index, num_tracks)]
            if args.comment is not None:
                audio.tags["\xa9cmt"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags["\xa9grp"] = tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags["\xa9gen"] = ", ".join(_genres)

            audio.save()

        def set_m4a_tags(audio):
            # add M4A tags if it doesn't exist
            audio.add_tags()

            def embed_image():
                audio.tags[str("covr")] = m4a.M4ACover(image)

            save_cover_image(embed_image)

            if album is not None:
                audio.tags[b"\xa9alb"] = tag_to_ascii(track.album.name, album)
            audio[b"\xa9nam"] = tag_to_ascii(track.name, title)
            audio.tags[b"\xa9ART"] = tag_to_ascii(
                track.artists[0].name, artist)
            audio.tags[b"\xa9day"] = str(track.album.year)
            audio.tags[str("disk")] = (track.disc, num_discs)
            audio.tags[str("trkn")] = (track.index, num_tracks)
            if args.comment is not None:
                audio.tags[b"\xa9cmt"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags[b"\xa9grp"] = tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags[b"\xa9gen"] = ", ".join(_genres)

            audio.save()

        if args.output_type == "flac":
            audio = flac.FLAC(audio_file)
            set_vorbis_comments(audio)
        elif args.output_type == "ogg":
            audio = oggvorbis.OggVorbis(audio_file)
            set_vorbis_comments(audio)
        elif args.output_type == "opus":
            audio = oggopus.OggOpus(audio_file)
            set_vorbis_comments(audio)
        elif args.output_type == "aac":
            audio = aac.AAC(audio_file)
            set_id3_tags_raw(audio, audio_file)
        elif args.output_type == "m4a":
            if sys.version_info >= (3, 0):
                from mutagen import mp4

                audio = mp4.MP4(audio_file)
                set_mp4_tags(audio)
            else:
                from mutagen import m4a, mp4

                audio = m4a.M4A(audio_file)
                set_m4a_tags(audio)
                audio = mp4.MP4(audio_file)
        elif args.output_type == "alac.m4a":
            if sys.version_info >= (3, 0):
                from mutagen import mp4

                audio = mp4.MP4(audio_file)
                set_mp4_tags(audio)
            else:
                from mutagen import m4a, mp4

                audio = m4a.M4A(audio_file)
                set_m4a_tags(audio)
                audio = mp4.MP4(audio_file)
        elif args.output_type == "mp3":
            audio = mp3.MP3(audio_file, ID3=id3.ID3)
            set_id3_tags(audio)

        def bit_rate_str(bit_rate):
            brs = "%d kb/s" % bit_rate
            if not args.cbr:
                brs = "~" + brs
            return brs

        def mode_str(mode):
            modes = ["Stereo", "Joint Stereo", "Dual Channel", "Mono"]
            if mode < len(modes):
                return modes[mode]
            else:
                return ""

        def channel_str(num):
            channels = ["", "Mono", "Stereo"]
            if num < len(channels):
                return channels[num]
            else:
                return ""

        # log id3 tags
        print("-" * 79)
        print(Fore.YELLOW + "Setting artist: " + artist + Fore.RESET)
        if album is not None:
            print(Fore.YELLOW + "Setting album: " + album + Fore.RESET)
        print(Fore.YELLOW + "Setting title: " + title + Fore.RESET)
        print(Fore.YELLOW + "Setting track info: (" +
              str(track.index) + ", " + str(num_tracks) + ")" + Fore.RESET)
        print(Fore.YELLOW + "Setting disc info: (" + str(track.disc) +
              ", " + str(num_discs) + ")" + Fore.RESET)
        print(Fore.YELLOW + "Setting release year: " +
              str(track.album.year) + Fore.RESET)
        if genres is not None and genres:
            print(Fore.YELLOW + "Setting genres: " +
                  " / ".join(genres_ascii) + Fore.RESET)
        if image is not None:
            print(Fore.YELLOW + "Adding cover image" + Fore.RESET)
        if args.comment is not None:
            print(Fore.YELLOW + "Adding comment: " + comment_ascii +
                  Fore.RESET)
        if args.grouping is not None:
            print(Fore.YELLOW + "Adding grouping: " + grouping_ascii +
                  Fore.RESET)
        if args.output_type == "flac":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tFree Lossless Audio Codec" +
                  "\t[ " + bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) +
                  " Hz - " + channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            print(Fore.YELLOW + "Writing Vorbis comments - " +
                  audio.tags.vendor + Fore.RESET)
            print("-" * 79)
        if args.output_type == "alac.m4a":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tApple Lossless" +
                  "\t[ " + bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) +
                  " Hz - " + channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            print(Fore.YELLOW + "Writing Apple iTunes metadata - " +
                  Fore.RESET)
            print("-" * 79)
        elif args.output_type == "ogg":
            print("Time: " + format_time(audio.info.length) +
                  "\tOgg Vorbis Codec" +
                  "\t[ " + bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) +
                  " Hz - " + channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            print(Fore.YELLOW + "Writing Vorbis comments - " +
                  audio.tags.vendor + Fore.RESET)
            print("-" * 79)
        elif args.output_type == "opus":
            print("Time: " + format_time(audio.info.length) + "\tOpus Codec" +
                  "\t[ " + channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            print(Fore.YELLOW + "Writing Vorbis comments - " +
                  audio.tags.vendor + Fore.RESET)
            print("-" * 79)
        elif args.output_type == "mp3":
            print("Time: " + format_time(audio.info.length) + "\tMPEG" +
                  str(audio.info.version) +
                  ", Layer " + ("I" * audio.info.layer) + "\t[ " +
                  bit_rate_str(audio.info.bitrate / 1000) +
                  " @ " + str(audio.info.sample_rate) + " Hz - " +
                  mode_str(audio.info.mode) + " ]")
            print("-" * 79)
            id3_version = "v%d.%d" % (
                audio.tags.version[0], audio.tags.version[1])
            print("ID3 " + id3_version + ": " +
                  str(len(audio.tags.values())) + " frames")
            print(
                Fore.YELLOW + "Writing ID3 version " +
                id3_version + Fore.RESET)
            print("-" * 79)
        elif args.output_type == "aac":
            print("Time: " + format_time(audio.info.length) +
                  "\tAdvanced Audio Coding" +
                  "\t[ " + bit_rate_str(audio.info.bitrate / 1000) +
                  " @ " + str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            id3_version = "v%d.%d" % (
                audio.tags.version[0], audio.tags.version[1])
            print("ID3 " + id3_version + ": " +
                  str(len(audio.tags.values())) + " frames")
            print(
                Fore.YELLOW + "Writing ID3 version " +
                id3_version + Fore.RESET)
            print("-" * 79)
        elif args.output_type == "m4a":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tMPEG-4 Part 14 Audio" +
                  "\t[ " + bit_rate_str(bit_rate / 1000) +
                  " @ " + str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print("-" * 79)
            print(Fore.YELLOW + "Writing Apple iTunes metadata - " +
                  str(audio.info.codec) + Fore.RESET)
            print("-" * 79)

    except id3.error:
        print(Fore.YELLOW + "Warning: exception while saving id3 tag: " +
              str(id3.error) + Fore.RESET)
Пример #5
0
def set_metadata_tags(args, audio_file, idx, track, ripper):
    if args.output_type == "wav" or args.output_type == "pcm":
        print(Fore.YELLOW + "Skipping metadata tagging for " +
              args.output_type + " encoding..." + Fore.RESET)
        return

    # ensure everything is loaded still
    if not track.is_loaded:
        track.load(args.timeout)
    if not track.album.is_loaded:
        track.album.load(args.timeout)
    album_browser = track.album.browse()
    album_browser.load(args.timeout)

    # calculate num of tracks on disc and num of dics
    num_discs = 0
    num_tracks = 0
    for track_browse in album_browser.tracks:
        if (track_browse.disc == track.disc
                and track_browse.index > track.index):
            num_tracks = track_browse.index
        if track_browse.disc > num_discs:
            num_discs = track_browse.disc

    # try to get genres from Spotify's Web API
    genres = None
    if args.genres is not None:
        genres = ripper.web.get_genres(args.genres, track)

    # use mutagen to update id3v2 tags and vorbis comments
    try:
        audio = None
        on_error = 'replace' if args.ascii_path_only else 'ignore'
        album = to_ascii(track.album.name, on_error)
        artists = ", ".join([artist.name for artist in track.artists]) \
            if args.all_artists else track.artists[0].name
        artists_ascii = to_ascii(artists, on_error)
        album_artist = to_ascii(track.album.artist.name, on_error)
        title = to_ascii(track.name, on_error)

        # the comment tag can be formatted
        if args.comment is not None:
            comment = \
                format_track_string(ripper, args.comment, idx, track)
            comment_ascii = to_ascii(comment, on_error)

        if args.grouping is not None:
            grouping = \
                format_track_string(ripper, args.grouping, idx, track)
            grouping_ascii = to_ascii(grouping, on_error)

        if genres is not None and genres:
            genres_ascii = [to_ascii(genre) for genre in genres]

        # cover art image
        image = None
        if args.large_cover_art:
            image = ripper.web.get_large_coverart(track.link.uri)

        # if we fail, use regular cover size
        if image is None:
            image = track.album.cover()
            if image is not None:
                image.load(args.timeout)
                image = image.data

        def tag_to_ascii(_str, _str_ascii):
            return _str if args.ascii_path_only else _str_ascii

        def idx_of_total_str(_idx, _total):
            if _total > 0:
                return "%d/%d" % (_idx, _total)
            else:
                return "%d" % (_idx)

        def save_cover_image(embed_image_func):
            if image is not None:

                def write_image(file_name):
                    cover_path = os.path.dirname(audio_file)
                    cover_file = os.path.join(cover_path, file_name)
                    if not path_exists(cover_file):
                        with open(enc_str(cover_file), "wb") as f:
                            f.write(image)

                if args.cover_file is not None:
                    write_image(args.cover_file)
                elif args.cover_file_and_embed is not None:
                    write_image(args.cover_file_and_embed)
                    embed_image_func(image)
                else:
                    embed_image_func(image)

        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()

        # aac is not well supported
        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

        def set_vorbis_comments(audio):
            # add Vorbis comment block if it doesn't exist
            if audio.tags is None:
                audio.add_tags()

            def embed_image(data):
                pic = flac.Picture()
                pic.type = 3
                pic.mime = "image/jpeg"
                pic.desc = "Front Cover"
                pic.data = data
                if args.output_type == "flac":
                    audio.add_picture(pic)
                else:
                    data = base64.b64encode(pic.write())
                    audio["METADATA_BLOCK_PICTURE"] = [data.decode("ascii")]

            save_cover_image(embed_image)

            if album is not None:
                audio.tags["ALBUM"] = tag_to_ascii(track.album.name, album)
            audio.tags["TITLE"] = tag_to_ascii(track.name, title)
            audio.tags["ARTIST"] = tag_to_ascii(artists, artists_ascii)
            if album_artist is not None:
                audio.tags["ALBUMARTIST"] = \
                    tag_to_ascii(track.album.artist.name, album_artist)
            audio.tags["DATE"] = str(track.album.year)
            audio.tags["YEAR"] = str(track.album.year)
            audio.tags["DISCNUMBER"] = str(track.disc)
            audio.tags["DISCTOTAL"] = str(num_discs)
            audio.tags["TRACKNUMBER"] = str(track.index)
            audio.tags["TRACKTOTAL"] = str(num_tracks)
            if args.comment is not None:
                audio.tags["COMMENT"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags["GROUPING"] = \
                    tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags["GENRE"] = ", ".join(_genres)

            audio.save()

        # only called by Python 3
        def set_mp4_tags(audio):
            # add MP4 tags if it doesn't exist
            if audio.tags is None:
                audio.add_tags()

            def embed_image(data):
                audio.tags["covr"] = mp4.MP4Cover(data)

            save_cover_image(embed_image)

            if album is not None:
                audio.tags["\xa9alb"] = tag_to_ascii(track.album.name, album)
            audio["\xa9nam"] = tag_to_ascii(track.name, title)
            audio.tags["\xa9ART"] = tag_to_ascii(artists, artists_ascii)
            if album_artist is not None:
                audio.tags["aART"] = \
                    tag_to_ascii(track.album.artist.name, album_artist)
            audio.tags["\xa9day"] = str(track.album.year)
            audio.tags["disk"] = [(track.disc, num_discs)]
            audio.tags["trkn"] = [(track.index, num_tracks)]
            if args.comment is not None:
                audio.tags["\xa9cmt"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags["\xa9grp"] = tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags["\xa9gen"] = ", ".join(_genres)

            audio.save()

        def set_m4a_tags(audio):
            # add M4A tags if it doesn't exist
            audio.add_tags()

            def embed_image(data):
                audio.tags[str("covr")] = m4a.M4ACover(data)

            save_cover_image(embed_image)

            if album is not None:
                audio.tags[b"\xa9alb"] = tag_to_ascii(track.album.name, album)
            audio[b"\xa9nam"] = tag_to_ascii(track.name, title)
            audio.tags[b"\xa9ART"] = tag_to_ascii(artists, artists_ascii)
            if album_artist is not None:
                audio.tags[str("aART")] = tag_to_ascii(track.album.artist.name,
                                                       album_artist)
            audio.tags[b"\xa9day"] = str(track.album.year)
            audio.tags[str("disk")] = (track.disc, num_discs)
            audio.tags[str("trkn")] = (track.index, num_tracks)
            if args.comment is not None:
                audio.tags[b"\xa9cmt"] = tag_to_ascii(comment, comment_ascii)
            if args.grouping is not None:
                audio.tags[b"\xa9grp"] = tag_to_ascii(grouping, grouping_ascii)

            if genres is not None and genres:
                _genres = genres if args.ascii_path_only else genres_ascii
                audio.tags[b"\xa9gen"] = ", ".join(_genres)

            audio.save()

        if args.output_type == "flac":
            audio = flac.FLAC(audio_file)
            set_vorbis_comments(audio)
        if args.output_type == "aiff":
            audio = aiff.AIFF(audio_file)
            set_id3_tags(audio)
        elif args.output_type == "ogg":
            audio = oggvorbis.OggVorbis(audio_file)
            set_vorbis_comments(audio)
        elif args.output_type == "opus":
            audio = oggopus.OggOpus(audio_file)
            set_vorbis_comments(audio)
        elif args.output_type == "aac":
            audio = aac.AAC(audio_file)
            set_id3_tags_raw(audio, audio_file)
        elif args.output_type == "m4a":
            audio = mp4.MP4(audio_file)
            set_mp4_tags(audio)
        elif args.output_type == "alac.m4a":
            audio = mp4.MP4(audio_file)
            set_mp4_tags(audio)
        elif args.output_type == "mp3":
            audio = mp3.MP3(audio_file, ID3=id3.ID3)
            set_id3_tags(audio)

        def bit_rate_str(bit_rate):
            brs = "%d kb/s" % bit_rate
            if not args.cbr:
                brs = "~" + brs
            return brs

        def mode_str(mode):
            modes = ["Stereo", "Joint Stereo", "Dual Channel", "Mono"]
            if mode < len(modes):
                return modes[mode]
            else:
                return ""

        def channel_str(num):
            channels = ["", "Mono", "Stereo"]
            if num < len(channels):
                return channels[num]
            else:
                return ""

        # log id3 tags
        print(Fore.YELLOW + "  Artist:\t" + Fore.RESET + artists_ascii)
        if album is not None:
            print(Fore.YELLOW + "  Album:\t" + Fore.RESET + album)
        if album_artist is not None:
            print(Fore.YELLOW + "  Album artist:\t" + Fore.RESET +
                  album_artist)
        print(Fore.YELLOW + "  Title:\t" + Fore.RESET + title)
        print(Fore.YELLOW + "  Track number:\t" + Fore.RESET +
              str(track.index) + "/" + str(num_tracks))
        print(Fore.YELLOW + "  Disc number:\t" + Fore.RESET + str(track.disc) +
              "/" + str(num_discs))
        print(Fore.YELLOW + "  Year:\t\t" + Fore.RESET + str(track.album.year))
        if genres is not None and genres:
            print(Fore.YELLOW + "  Genres:\t" + Fore.RESET +
                  " / ".join(genres_ascii))
        if image is not None:
            print(Fore.YELLOW + "  Cover image:\t" + Fore.RESET + "Yes")
        if args.comment is not None:
            print(Fore.YELLOW + "  Comment:\t" + Fore.RESET + comment_ascii)
        if args.grouping is not None:
            print(Fore.YELLOW + "  Grouping:\t" + Fore.RESET + grouping_ascii)
        print(Fore.YELLOW + "  Time:\t\t" + Fore.RESET +
              format_time(audio.info.length))
        print(Fore.YELLOW + "  Size:\t\t" + Fore.RESET +
              format_size(os.stat(enc_str(audio_file))[ST_SIZE]))

        if args.output_type == "flac":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET +
                  "Free Lossless Audio Codec")
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            print(Fore.YELLOW + "  Comment:\t" + Fore.RESET +
                  audio.tags.vendor)

        if args.output_type == "aiff":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET +
                  "Audio Interchange File Format")
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print(Fore.YELLOW + "  ID3:\t\t" + Fore.RESET + id3_version +
                  " - " + str(len(audio.tags.values())) + " frames")

        elif args.output_type == "alac.m4a":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET + "Apple Lossless")
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            print(Fore.YELLOW + "  iTunes:\t" + Fore.RESET +
                  str(audio.info.codec))

        elif args.output_type == "ogg":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET +
                  "Ogg Vorbis Codec")
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            print(Fore.YELLOW + "  Comment:\t" + Fore.RESET +
                  audio.tags.vendor)

        elif args.output_type == "opus":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET + "Opus Codec")
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  channel_str(audio.info.channels))
            print(Fore.YELLOW + "  Comment:\t" + Fore.RESET +
                  audio.tags.vendor)

        elif args.output_type == "mp3":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET + "MPEG" +
                  str(audio.info.version) + ", Layer " +
                  ("I" * audio.info.layer))
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  mode_str(audio.info.mode))
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print(Fore.YELLOW + "  ID3:\t\t" + Fore.RESET + id3_version +
                  " - " + str(len(audio.tags.values())) + " frames")

        elif args.output_type == "aac":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET +
                  "Advanced Audio Coding")
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print(Fore.YELLOW + "  ID3:\t\t" + Fore.RESET + id3_version +
                  " - " + str(len(audio.tags.values())) + " frames")

        elif args.output_type == "m4a":
            print(Fore.YELLOW + "  Format:\t" + Fore.RESET +
                  "MPEG-4 Part 14 Audio")
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print(Fore.YELLOW + "  Quality:\t" + Fore.RESET +
                  bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels))
            print(Fore.YELLOW + "  iTunes:\t" + Fore.RESET +
                  str(audio.info.codec))

    except id3.error:
        print(Fore.YELLOW + "Warning: exception while saving id3 tag: " +
              str(id3.error) + Fore.RESET)
Пример #6
0
def set_metadata_tags(args, audio_file, idx, track, ripper):
    # log completed file
    print(Fore.GREEN + Style.BRIGHT + os.path.basename(audio_file) +
          Style.NORMAL + "\t[ " +
          format_size(os.stat(enc_str(audio_file))[ST_SIZE]) + " ]" +
          Fore.RESET)

    if args.output_type == "wav" or args.output_type == "pcm":
        print_yellow("Skipping metadata tagging for " + args.output_type +
                     " encoding...")
        return

    # ensure everything is loaded still
    if not track.is_loaded:
        track.load(args.timeout)
    if not track.album.is_loaded:
        track.album.load(args.timeout)

    # use mutagen to update audio file tags
    try:
        audio = None
        tags = None

        if args.output_type == "flac":
            audio = flac.FLAC(audio_file)
            tags = VorbisTags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        elif args.output_type == "aiff":
            audio = aiff.AIFF(audio_file)
            tags = Id3Tags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        elif args.output_type == "ogg":
            audio = oggvorbis.OggVorbis(audio_file)
            tags = VorbisTags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        elif args.output_type == "opus":
            audio = oggopus.OggOpus(audio_file)
            tags = VorbisTags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        elif args.output_type == "aac":
            audio = aac.AAC(audio_file)
            tags = RawId3Tags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        elif args.output_type == "m4a" or args.output_type == "alac.m4a":
            if sys.version_info >= (3, 0):
                audio = mp4.MP4(audio_file)
                tags = MP4Tags(args, audio_file, idx, track, ripper)
                tags.set_tags(audio)
            else:
                audio = m4a.M4A(audio_file)
                tags = M4ATags(args, audio_file, idx, track, ripper)
                tags.set_tags(audio)
                audio = mp4.MP4(audio_file)

        elif args.output_type == "mp3":
            audio = mp3.MP3(audio_file, ID3=id3.ID3)
            tags = Id3Tags(args, audio_file, idx, track, ripper)
            tags.set_tags(audio)

        # utility functions
        def bit_rate_str(bit_rate):
            brs = "%d kb/s" % bit_rate
            if not args.cbr:
                brs = "~" + brs
            return brs

        def mode_str(mode):
            modes = ["Stereo", "Joint Stereo", "Dual Channel", "Mono"]
            return modes[mode] if mode < len(modes) else ""

        def channel_str(num):
            channels = ["", "Mono", "Stereo"]
            return channels[num] if num < len(channels) else ""

        def print_line():
            print("-" * 79)

        # log tags
        print_line()
        print_yellow("Setting artist: " + tags.artists())

        if tags.album() is not None:
            print_yellow("Setting album: " + tags.album())

        if tags.album_artist() is not None:
            print_yellow("Setting album artist: " + tags.album_artist())

        print_yellow("Setting title: " + tags.title())
        print_yellow("Setting track info: (" + tags.track_idx() + ", " +
                     tags.num_tracks() + ")")
        print_yellow("Setting disc info: (" + tags.disc_idx() + ", " +
                     tags.num_discs() + ")")
        print_yellow("Setting release year: " + tags.year())

        if tags.genres() is not None:
            print_yellow("Setting genres: " + " / ".join(tags.genres()))

        if tags.image is not None:
            print_yellow("Adding cover image")

        if tags.comment() is not None:
            print_yellow("Adding comment: " + tags.comment())

        if tags.grouping() is not None:
            print_yellow("Adding grouping: " + tags.grouping())

        # log bitrate info
        if args.output_type == "flac":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tFree Lossless Audio Codec" + "\t[ " +
                  bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            print_yellow("Writing Vorbis comments - " + audio.tags.vendor)
            print_line()

        elif args.output_type == "aiff":
            print("Time: " + format_time(audio.info.length) +
                  "\tAudio Interchange File Format" + "\t[ " +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print("ID3 " + id3_version + ": " + str(len(audio.tags.values())) +
                  " frames")
            print(Fore.YELLOW + "Writing ID3 version " + id3_version)
            print_line()

        elif args.output_type == "alac.m4a":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tApple Lossless" + "\t[ " + bit_rate_str(bit_rate / 1000) +
                  " @ " + str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            print_yellow("Writing Apple iTunes metadata")
            print_line()

        elif args.output_type == "ogg":
            print("Time: " + format_time(audio.info.length) +
                  "\tOgg Vorbis Codec" + "\t[ " +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            print_yellow("Writing Vorbis comments - " + audio.tags.vendor)
            print_line()

        elif args.output_type == "opus":
            print("Time: " + format_time(audio.info.length) + "\tOpus Codec" +
                  "\t[ " + channel_str(audio.info.channels) + " ]")
            print_line()
            print_yellow("Writing Vorbis comments - " + audio.tags.vendor)
            print_line()

        elif args.output_type == "mp3":
            print("Time: " + format_time(audio.info.length) + "\tMPEG" +
                  str(audio.info.version) + ", Layer " +
                  ("I" * audio.info.layer) + "\t[ " +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  mode_str(audio.info.mode) + " ]")
            print_line()
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print("ID3 " + id3_version + ": " + str(len(audio.tags.values())) +
                  " frames")
            print_yellow("Writing ID3 version " + id3_version)
            print_line()

        elif args.output_type == "aac":
            print("Time: " + format_time(audio.info.length) +
                  "\tAdvanced Audio Coding" + "\t[ " +
                  bit_rate_str(audio.info.bitrate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            id3_version = "v%d.%d" % (audio.tags.version[0],
                                      audio.tags.version[1])
            print("ID3 " + id3_version + ": " + str(len(audio.tags.values())) +
                  " frames")
            print("Writing ID3 version " + id3_version)
            print_line()

        elif args.output_type == "m4a":
            bit_rate = ((audio.info.bits_per_sample * audio.info.sample_rate) *
                        audio.info.channels)
            print("Time: " + format_time(audio.info.length) +
                  "\tMPEG-4 Part 14 Audio" + "\t[ " +
                  bit_rate_str(bit_rate / 1000) + " @ " +
                  str(audio.info.sample_rate) + " Hz - " +
                  channel_str(audio.info.channels) + " ]")
            print_line()
            print_yellow("Writing Apple iTunes metadata - " +
                         str(audio.info.codec))
            print_line()

    except id3.error:
        print_yellow("Warning: exception while saving id3 tag: " +
                     str(id3.error))