隨着數字音樂收藏的增長,本地音樂庫往往變得雜亂無章——歌曲散落在不同文件夾,命名不規範,元數據缺失。其實,大多數音頻文件(如 MP3、FLAC)都嵌入了 ID3 標籤(或其他格式的元數據),包含藝術家、專輯、年份等信息。藉助 Python,我們可以自動讀取這些信息,並將音樂文件按 藝術家/專輯/歌曲.mp3 的結構重新組織,打造一個整潔有序的個人音樂庫。

1. 準備工作:安裝依賴庫

我們將使用 mutagen 庫解析音頻元數據,它支持 MP3、FLAC、M4A、OGG 等主流格式:

pip install mutagen

💡 mutagen 是純 Python 實現,無需系統依賴,跨平台兼容性好。

2. 讀取音頻文件的元數據

以下函數可安全提取藝術家和專輯信息,並處理缺失或編碼問題:

from mutagen import File
import os

def get_audio_metadata(filepath):
    """提取音頻文件的藝術家和專輯信息"""
    try:
        audio = File(filepath)
        if audio is None:
            return None, None
        
        # 嘗試常見標籤字段
        artist = None
        album = None
        
        if hasattr(audio, 'tags') and audio.tags:
            tags = audio.tags
            # MP3 常用 TPE1(藝術家)、TALB(專輯)
            artist = str(tags.get('TPE1', ['Unknown Artist'])[0])
            album = str(tags.get('TALB', ['Unknown Album'])[0])
            
            # FLAC/M4A 等格式使用通用鍵
            if not artist or artist == 'Unknown Artist':
                artist = str(tags.get('artist', ['Unknown Artist'])[0])
            if not album or album == 'Unknown Album':
                album = str(tags.get('album', ['Unknown Album'])[0])
        
        # 清理非法文件名字符
        def sanitize(s):
            return "".join(c for c in s if c not in r'<>:"/\|?*').strip()
        
        return sanitize(artist), sanitize(album)
    
    except Exception as e:
        print(f"⚠️  無法讀取 {filepath}: {e}")
        return "Unknown Artist", "Unknown Album"

3. 構建目標路徑並移動文件

根據元數據生成目標路徑,並安全移動文件(避免覆蓋):

import shutil
from pathlib import Path

def organize_music_file(src_path, dest_root="Music_Library"):
    artist, album = get_audio_metadata(src_path)
    if artist is None:
        return
    
    # 構建目標目錄:Music_Library/Artist/Album/
    dest_dir = Path(dest_root) / artist / album
    dest_dir.mkdir(parents=True, exist_ok=True)
    
    # 目標文件路徑
    dest_file = dest_dir / os.path.basename(src_path)
    
    # 避免重名:添加序號
    counter = 1
    stem = dest_file.stem
    suffix = dest_file.suffix
    while dest_file.exists():
        dest_file = dest_dir / f"{stem}_{counter}{suffix}"
        counter += 1
    
    # 移動文件
    shutil.move(str(src_path), str(dest_file))
    print(f"✅ {os.path.basename(src_path)} → {artist}/{album}/")

4. 批量處理整個音樂目錄

遞歸遍歷源文件夾,處理所有支持的音頻文件:

def batch_organize_music(source_folder, dest_root="Music_Library"):
    supported_ext = {'.mp3', '.flac', '.m4a', '.ogg', '.wav'}
    
    for root, _, files in os.walk(source_folder):
        for file in files:
            if Path(file).suffix.lower() in supported_ext:
                src_path = os.path.join(root, file)
                try:
                    organize_music_file(src_path, dest_root)
                except Exception as e:
                    print(f"❌ 處理失敗 {src_path}: {e}")

# 使用示例
if __name__ == "__main__":
    batch_organize_music("Downloads/Music/")  # 源文件夾
    # 整理後結果存放在 Music_Library/周杰倫/范特西/...

5. 注意事項與優化建議

⚠️ 安全第一:先複製再刪除

為防止意外丟失,可先用 shutil.copy2() 複製文件,確認無誤後再清理原目錄。

🎵 處理“Various Artists”合輯

部分合輯的藝術家為 "Various Artists",可單獨歸類到 Compilations/專輯名/ 目錄:

if artist.lower() in ("various artists", "various"):
    dest_dir = Path(dest_root) / "Compilations" / album

🔤 統一大小寫與別名

可建立映射表統一藝術家名稱(如 "Jay Chou" → "周杰倫"),避免重複文件夾。

📊 生成整理報告

記錄成功/失敗數量,便於後續檢查:

stats = {"success": 0, "failed": 0}
# 在 organize_music_file 中更新 stats
print(f"整理完成:{stats['success']} 成功,{stats['failed']} 失敗")

🧹 清理空文件夾

整理後,可用腳本刪除源目錄中留下的空文件夾。

6. 擴展方向

  • 封面圖提取:從音頻文件中提取專輯封面並保存為 cover.jpg
  • 重命名歌曲:按 01 - 歌名.mp3 格式重命名,保留音軌序號;
  • GUI 界面:用 tkinter 製作圖形化工具,方便非技術用户使用;
  • 雲同步:整理後自動上傳至 NAS 或網盤。

通過不到 60 行核心代碼,我們就實現了一個智能音樂整理器。它不僅能解放雙手,還能讓本地音樂庫變得專業而有序。Python 強大的生態(如 mutagen)使得操作多媒體元數據變得異常簡單。現在,運行這個腳本,讓你的音樂收藏告別混亂,享受井井有條的聽覺體驗吧!