本文目录导读:

我来教你用脚本整理音乐库,这里提供一个Python脚本方案,能自动处理常见问题:
基础整理脚本
#!/usr/bin/env python3
import os
import re
import shutil
import json
from pathlib import Path
import mutagen
from mutagen.easyid3 import EasyID3
from mutagen.mp3 import MP3
from mutagen.flac import FLAC
class MusicOrganizer:
def __init__(self, music_dir):
self.music_dir = Path(music_dir)
self.organized_dir = self.music_dir / "已整理"
def get_audio_metadata(self, file_path):
"""读取音频文件元数据"""
try:
ext = file_path.suffix.lower()
if ext == '.mp3':
audio = EasyID3(file_path)
return {
'artist': audio.get('artist', [''])[0],
'album': audio.get('album', [''])[0],
'title': audio.get('title', [''])[0],
'tracknumber': audio.get('tracknumber', [''])[0]
}
elif ext == '.flac':
audio = FLAC(file_path)
return {
'artist': audio.get('artist', [''])[0],
'album': audio.get('album', [''])[0],
'title': audio.get('title', [''])[0],
'tracknumber': audio.get('tracknumber', [''])[0]
}
except Exception as e:
print(f"读取 {file_path} 元数据失败: {e}")
return None
def sanitize_filename(self, name):
"""清理文件名中的非法字符"""
# 替换不合法字符
illegal_chars = r'[<>:"/\\|?*]'
return re.sub(illegal_chars, '_', name).strip()
def organize_by_artist_album(self):
"""按 艺术家/专辑 结构整理"""
if not self.music_dir.exists():
print("音乐目录不存在!")
return
# 创建整理目录
self.organized_dir.mkdir(exist_ok=True)
# 遍历所有音频文件
audio_exts = {'.mp3', '.flac', '.wav', '.m4a', '.ogg'}
moved_files = 0
for file_path in self.music_dir.rglob('*'):
if file_path.suffix.lower() not in audio_exts:
continue
metadata = self.get_audio_metadata(file_path)
# 如果没有元数据,使用文件名推测
if metadata is None or not metadata['artist']:
artist = '未知艺术家'
album = '未知专辑'
else:
artist = self.sanitize_filename(metadata['artist'])
album = self.sanitize_filename(metadata['album'] or '未知专辑')
# 构建目标路径
target_dir = self.organized_dir / artist / album
target_dir.mkdir(parents=True, exist_ok=True)
# 重命名文件(添加序号)
filename = file_path.name
if metadata and metadata['tracknumber']:
try:
track_num = int(re.search(r'\d+', metadata['tracknumber']).group())
filename = f"{track_num:02d} - {self.sanitize_filename(metadata['title'] or file_path.stem)}{file_path.suffix}"
except:
pass
# 处理重名
target_file = target_dir / filename
if target_file.exists():
base = target_file.stem
target_file = target_dir / f"{base}_1{target_file.suffix}"
# 移动文件
try:
shutil.move(str(file_path), str(target_file))
moved_files += 1
print(f"✓ {file_path.name} → {artist}/{album}/{filename}")
except Exception as e:
print(f"✗ 移动 {file_path} 失败: {e}")
print(f"\n完成!共整理 {moved_files} 个文件")
def fix_missing_tags(self):
"""智能修复文件名中的元数据"""
# 从文件名提取信息: 艺术家 - 专辑 - 曲目号 歌曲名.mp3
pattern = r'(.+?)\s*-\s*(.+?)\s*-\s*(\d+)\s*(.+)'
for file_path in self.music_dir.rglob('*.mp3'):
match = re.match(pattern, file_path.stem)
if match and not self.get_audio_metadata(file_path):
artist, album, track, title = match.groups()
try:
audio = EasyID3(file_path)
audio['artist'] = artist.strip()
audio['album'] = album.strip()
audio['title'] = title.strip()
audio['tracknumber'] = track.strip()
audio.save()
print(f"修复标签: {file_path.name}")
except Exception as e:
print(f"修复失败 {file_path.name}: {e}")
def generate_playlist(self):
"""生成通过播放列表"""
# 按流派分类
genres = {}
for file_path in self.organized_dir.rglob('*.mp3'):
try:
audio = EasyID3(file_path)
genre = audio.get('genre', ['未知'])[0]
if genre not in genres:
genres[genre] = []
genres[genre].append(str(file_path))
except:
pass
# 生成M3U播放列表
playlist_dir = self.music_dir / '播放列表'
playlist_dir.mkdir(exist_ok=True)
for genre, files in genres.items():
playlist_file = playlist_dir / f"{genre}.m3u"
with open(playlist_file, 'w', encoding='utf-8') as f:
f.write("#EXTM3U\n")
for file_path in files:
f.write(f"#EXTINF:{Path(file_path).stat().st_size // 1000},{Path(file_path).stem}\n")
f.write(f"{file_path}\n")
print(f"生成播放列表: {genre}.m3u ({len(files)}首)")
# 使用示例
if __name__ == "__main__":
# 使用方法:
# python music_organizer.py /path/to/music
import sys
if len(sys.argv) < 2:
print("用法: python music_organizer.py <音乐文件夹路径>")
sys.exit(1)
organizer = MusicOrganizer(sys.argv[1])
print("选择操作方式:")
print("1. 按艺术家/专辑整理")
print("2. 修复缺失的标签")
print("3. 生成播放列表")
print("4. 全部执行")
choice = input("输入选择 (1-4): ")
if choice in ['1', '4']:
organizer.organize_by_artist_album()
if choice in ['2', '4']:
organizer.fix_missing_tags()
if choice in ['3', '4']:
organizer.generate_playlist()
高级功能版本
如果你想处理更复杂的情况,这里有个增强版:
# 增强功能
def advanced_functions(self):
"""高级整理功能"""
# 1. 去重功能
def find_duplicates(self):
"""根据文件大小和MD5查找重复音乐"""
import hashlib
seen_files = {}
duplicates = []
for file_path in self.music_dir.rglob('*'):
if file_path.suffix.lower() not in ['.mp3', '.flac', '.wav']:
continue
# 计算文件哈希
file_hash = hashlib.md5(file_path.read_bytes()).hexdigest()
if file_hash in seen_files:
duplicates.append((seen_files[file_hash], file_path))
else:
seen_files[file_hash] = file_path
return duplicates
# 2. 批量重命名
def batch_rename(self):
"""批量重命名文件,统一格式"""
for file_path in self.music_dir.rglob('*'):
if file_path.suffix.lower() not in ['.mp3', '.flac']:
continue
# 智能识别格式并规范化
# 01-song.mp3 → 01_song.mp3
# artist-album-track.mp3 → 艺术家-专辑-01 歌曲名.mp3
pass # 实现你的重命名逻辑
# 3. 封面管理
def manage_covers(self):
"""下载和嵌入封面"""
import requests
cover_dir = self.music_dir / 'covers'
cover_dir.mkdir(exist_ok=True)
# 对没有封面的专辑下载封面
# 可以使用 iTunes API 或 Last.fm API
pass
# 4. 格式转换
def convert_formats(self):
"""批量格式转换(如flac转mp3)"""
import subprocess
for flac_file in self.music_dir.rglob('*.flac'):
mp3_file = flac_file.with_suffix('.mp3')
# 使用 ffmpeg 转换
subprocess.run([
'ffmpeg', '-i', str(flac_file),
'-codec:a', 'libmp3lame',
'-qscale:a', '2',
str(mp3_file)
])
使用方法
-
安装依赖:
pip install mutagen
-
基础使用:
python music_organizer.py ~/Music
-
高级使用(可添加到crontab定期执行):
# 每周日晚上整理 0 20 * * 0 python /path/to/music_organizer.py ~/Music
注意事项
- 备份原始文件:整理前务必备份,脚本会移动文件
- 测试运行:先在小目录测试,确认无误后再处理完整音乐库
- 保留原文件:修改脚本中的
shutil.move为shutil.copy即可保留原文件 - 处理特殊情况:歌手"Various Artists"、日本艺名、多艺术家合作等特殊场景需要额外处理
这个脚本基本能满足大部分整理需求,如果需要修改特定行为,告诉我你的具体需求,我可以提供定制版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播