嗯,我还是喜欢下载mp3
老朋友应该知道,很久很久以前,由于喜欢下载mp3,我写过一个下载器,叫 gmbox,当时还是从Google music下载的,用户还不少。
后面 Google music 都退出中国了,gmbox肯定也不能用了。再后来各种在线的流媒体也非常丰富了,加上播客等其他内容也都兴起了,我自己也都不怎么听离线的mp3了。
这次又想下载mp3,是因为坐飞机。由于近期坐飞机会比较频繁,算了下,2个月得坐14趟飞机,累积飞行80+个小时。同时,希望在坐飞机的时候可以看看电纸书,那播客就会过度消耗我的注意力了,还是听听老歌比较合适。于是,就有了这个标题。
研究了下,国内的网易、酷狗等,应该也是可以下载的,但看起来API比较复杂。于是我把目光又投向了 YouTube music,对,我还是喜欢逮着Google家薅,哈哈!
之前在YouTube music就发现了一些不错的歌单,特别适合我这种要求不高的无脑批量下载。于是请出 yt-dlp,让GPT写了一行shell,原码率下载mp3,如果有视频则忽略视频只保留音频,就像这样就比较完美的解决我的问题了:
|
1 2 3 4 5 6 7 |
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=PLdE3Y3U0HligtAoAay48Kwl7RE_PD1RfG' |
一个命令下去,就能下载800+首热歌,效果不错。
导入macOS的music library,再倒入iPhone都很顺利,但听歌的时候我又发现问题了,这批歌曲质量其实非常高,连专辑封面都是自带的。但就是没有歌词。
虽然其实我的场景并不是很需要歌词,但好奇心上来以后,就又研究了下ID3信息。
其实,mp3文件里,基本上都是带了“不带时间轴”的歌词的,但都在 user_text_frames 字段的 description 里,而 Music.app 只认 USLT 这个 frame,好嘛,那咱就再顺便写个代码再处理一下这些mp3文件咯。
如下:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
import sys import eyed3 from eyed3.id3.frames import LyricsFrame, LYRICS_FID def process_file(file_path): """处理单个 MP3 文件,将 description 字段的内容复制到 USLT 帧""" import os # 获取文件名(不含路径) file_name = os.path.basename(file_path) try: 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 # 查找 description 字段 lyrics_text = None for frame in tag.user_text_frames: if frame.description == "description": # frame.text 可能是一个字符串或列表 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 # 直接创建并设置 USLT 帧(苹果系播放器只认 USLT) # 对于 macOS/iOS Music app,使用空的 description 和 'chi' 语言代码(中文) try: # 删除所有现有的 USLT 帧 if tag.frame_set: frames_to_remove = [] for frame_id in list(tag.frame_set.keys()): if isinstance(frame_id, bytes) and frame_id == LYRICS_FID: frames_to_remove.append(frame_id) for frame_id in frames_to_remove: del tag.frame_set[frame_id] # 创建新的 USLT 帧,使用构造函数参数 uslt_frame = LyricsFrame(text=lyrics_text, description="", lang=b"chi") # 直接赋值给 frame_set(frame_set.__setitem__ 会处理成列表) tag.frame_set[LYRICS_FID] = uslt_frame # 保存更改,使用 ID3 v2.3 版本以确保兼容性 tag.save(version=eyed3.id3.ID3_V2_3) print(f"{file_name}: ✅ 成功写入 USLT 帧 ({len(lyrics_text)} 字符)") return True except Exception as e: print(f"{file_name}: ❌ 设置 USLT 帧失败 - {str(e)}") return False except Exception as e: print(f"{file_name}: ❌ 处理失败 - {str(e)}") return False # 主程序:遍历所有输入的文件 if len(sys.argv) < 2: print("用法: python deal.py <文件1> [文件2] [文件3] ...") sys.exit(1) files = sys.argv[1:] success_count = 0 fail_count = 0 for file_path in files: if process_file(file_path): success_count += 1 else: fail_count += 1 print() print(f"处理完成: 成功 {success_count} 个,失败 {fail_count} 个") |
这个代码跑得很快,800+个mp3,1分钟就搞定了~
重新导入一次,果然有歌词了,赞!

所以,大家有推荐的歌单吗?可以留言~
发表回复