如何在 YouTube Music 下载歌曲

youtube-music-1681710563

今天学到用 yt-dlp 下载 YouTube Music 歌曲的方法。该方法来自文章「嗯,我还是喜欢下载mp3」

原文章写得比较简略,针对有一定计算机基础人士。我在 Google Gemini 帮助下,终于搞懂完整过程,怕自己忘记,现记录如下:

首先,安装 yt-dlp。

brew install yt-dlp

接着,需要安装依赖 FFmpeg(第一次因为没有安装这个依赖,导致转换mp3错误)。

brew install ffmpeg

最后,在终端执行如下指令:

yt-dlp -x --audio-format mp3 \
  --audio-quality 0 \
  --embed-metadata --embed-thumbnail \
  --postprocessor-args "ExtractAudio:-q:a 0 -id3v2_version 3" \
  --postprocessor-args "FFmpegMetadata:-metadata comment=YouTubeID=%(id)s" \
  -o "%(artist,uploader)s-%(track,title)s.%(ext)s" \
  'https://music.youtube.com/playlist?list=PLJQHrLUqwS07gskhUSN5akj_2fbs3oIvz'

实现原码率下载 mp3,如果有视频则忽略视频只保留音频,并将视频的元数据(如标题、艺术家、发布者等)作为 ID3 标签嵌入到最终的 MP3 文件中,完美。

上面命令第7行 “https://music.youtube.com/playlist?list=PLJQHrLUqwS07gskhUSN5akj_2fbs3oIvz' Music " YouTube Music 播放列表地址,可以替换成自己的播放列表地址,下载相应歌曲。

以上是使用 Mac OS 执行成功,其他如Linux、Windows 等系统方法类似,仅供参考。


原作者还给出如何给已下载歌曲配上歌词的方法:原理是在 mp3 文件里,基本上已包含“不带时间轴”的歌词,但存在 user_text_frames 字段的 description 里,而 Music.app 只认 USLT 这个 frame,于是利用 Python 语言一段代码实现歌词匹配。代码如下:

import sys
import os
import eyed3
from eyed3.id3.frames import LyricsFrame, LYRICS_FID

def process_file(file_path):
    """处理单个 MP3 文件,将 description 字段的内容复制到 USLT 帧"""
    file_name = os.path.basename(file_path)
    
    try:
        # 1. 加载音频文件
        audio = eyed3.load(file_path)
        if audio is None:
            print(f"{file_name}: ❌ 无法加载文件")
            return False
        
        tag = audio.tag
        if tag is None:
            print(f"{file_name}: ⚠️  没有 ID3 标签,跳过")
            return False
        
        # 2. 查找 description 字段中的歌词内容
        lyrics_text = None
        for frame in tag.user_text_frames:
            if frame.description == "description":
                if isinstance(frame.text, list):
                    lyrics_text = "\n".join(frame.text)
                else:
                    lyrics_text = str(frame.text)
                break
        
        if not lyrics_text:
            print(f"{file_name}: ⚠️  未找到名为 'description' 的文本字段")
            return False
        
        # 3. 写入 USLT 帧(苹果音乐/Music App 识别的歌词格式)
        # 先清除已有的 USLT 帧以防冲突
        if tag.frame_set:
            frames_to_remove = [fid for fid in tag.frame_set.keys() if fid == LYRICS_FID]
            for fid in frames_to_remove:
                del tag.frame_set[fid]
        
        # 创建新歌词帧:lang='chi' 代表中文,description为空是兼容性最好的做法
        uslt_frame = LyricsFrame(text=lyrics_text, description="", lang=b"chi")
        tag.frame_set[LYRICS_FID] = uslt_frame
        
        # 保存为 ID3 v2.3 版本,这是兼容性最好的版本
        tag.save(version=eyed3.id3.ID3_V2_3)
        print(f"{file_name}: ✅ 成功写入歌词 ({len(lyrics_text)} 字符)")
        return True

    except Exception as e:
        print(f"{file_name}: ❌ 发生错误 - {str(e)}")
        return False

# 主程序入口
if __name__ == "__main__":
    # 获取命令行参数(排除脚本名本身)
    input_files = sys.argv[1:]
    
    if not input_files:
        print("用法: python3 edit-ly.py <mp3文件路径或通配符>")
        print("示例: python3 edit-ly.py ~/Downloads/*.mp3")
        sys.exit(1)

    print(f"开始处理 {len(input_files)} 个文件...")
    print("-" * 30)

    success = 0
    fail = 0

    for path in input_files:
        if process_file(path):
            success += 1
        else:
            fail += 1

    print("-" * 30)
    print(f"处理完成!成功: {success}, 失败: {fail}")

将上面代码拷贝存为文件 edit-ly.py, 在终端输入以下命令行,实现歌词转换。

python3 edit-ly.py ~/Downloads/liubin-song/*.mp3