本文目录导读:

我来介绍几种用脚本批量整理音乐文件的方法,主要使用Python和shell脚本。
Python脚本(最灵活)
基础整理脚本
import os
import shutil
import re
from pathlib import Path
import eyed3 # 需要安装:pip install eyed3
def organize_music(source_dir, dest_dir):
"""
按艺术家/专辑结构整理音乐文件
"""
# 支持的音频格式
audio_extensions = {'.mp3', '.flac', '.wav', '.m4a', '.ogg', '.wma'}
for root, dirs, files in os.walk(source_dir):
for file in files:
file_path = os.path.join(root, file)
ext = os.path.splitext(file)[1].lower()
if ext not in audio_extensions:
continue
try:
# 尝试读取ID3标签
audio_file = eyed3.load(file_path)
if audio_file and audio_file.tag:
artist = audio_file.tag.artist or "Unknown Artist"
album = audio_file.tag.album or "Unknown Album"
else:
artist, album = extract_info_from_filename(file)
except:
artist, album = extract_info_from_filename(file)
# 清理非法字符
artist = clean_filename(artist)
album = clean_filename(album)
# 创建目标目录
dest_path = os.path.join(dest_dir, artist, album)
os.makedirs(dest_path, exist_ok=True)
# 复制文件
shutil.copy2(file_path, os.path.join(dest_path, file))
print(f"已整理: {file} -> {artist}/{album}/")
def extract_info_from_filename(filename):
"""从文件名提取艺术家和专辑信息"""
# 示例格式: "Artist - Album - Song.mp3"
name = os.path.splitext(filename)[0]
parts = name.split(" - ")
if len(parts) >= 3:
return parts[0], parts[1]
else:
return "Unknown Artist", "Unknown Album"
def clean_filename(name):
"""清理文件名中的非法字符"""
# Windows不允许的字符
illegal_chars = r'[<>:"/\\|?*]'
return re.sub(illegal_chars, '_', name)
# 使用示例
if __name__ == "__main__":
source = r"C:\Music\Downloaded"
dest = r"C:\Music\Organized"
organize_music(source, dest)
批量重命名脚本
import os
import re
from pathlib import Path
def rename_music_files(directory, pattern="track_num - title"):
"""
批量重命名音乐文件
支持的模式: track_num, title, artist, album
"""
audio_extensions = {'.mp3', '.flac', '.wav', '.m4a', '.ogg'}
for file in os.listdir(directory):
file_path = os.path.join(directory, file)
if not os.path.isfile(file_path):
continue
ext = os.path.splitext(file)[1].lower()
if ext not in audio_extensions:
continue
# 这里简化处理,实际可以使用eyed3读取元数据
# 假设文件名格式为: "01 - Song Title.mp3"
parts = os.path.splitext(file)[0].split(" - ")
if len(parts) >= 2:
track_num = parts[0].zfill(2) # 补零
title = parts[1]
if pattern == "track_num - title":
new_name = f"{track_num} - {title}{ext}"
elif pattern == "title":
new_name = f"{title}{ext}"
else:
continue
new_path = os.path.join(directory, new_name)
os.rename(file_path, new_path)
print(f"重命名: {file} -> {new_name}")
# 使用示例
rename_music_files("C:/Music/Album", "track_num - title")
Shell脚本(Linux/Mac)
基础整理脚本
#!/bin/bash
# organize_music.sh
# 使用: ./organize_music.sh /source/dir /dest/dir
SOURCE_DIR="${1:-./music}"
DEST_DIR="${2:-./organized}"
# 支持的音频格式
EXTENSIONS="\.(mp3|flac|wav|m4a|ogg|wma)$"
find "$SOURCE_DIR" -type f | grep -iE "$EXTENSIONS" | while read -r file; do
filename=$(basename "$file")
# 使用exiftool获取元数据
if command -v exiftool &> /dev/null; then
artist=$(exiftool -Artist -b "$file" 2>/dev/null)
album=$(exiftool -Album -b "$file" 2>/dev/null)
fi
# 如果获取失败,尝试从文件名提取
if [ -z "$artist" ]; then
# 假设格式: "Artist - Album - Song.mp3"
artist=$(echo "$filename" | cut -d' -' -f1 | xargs)
album=$(echo "$filename" | cut -d' -' -f2 | xargs)
fi
# 清理文件名(替换非法字符)
artist=${artist//[<>:"\/\\|?*]/_}
album=${album//[<>:"\/\\|?*]/_}
# 设置默认值
artist=${artist:-"Unknown Artist"}
album=${album:-"Unknown Album"}
# 创建目标目录
dest_dir="$DEST_DIR/$artist/$album"
mkdir -p "$dest_dir"
# 复制文件
cp -n "$file" "$dest_dir/$filename"
echo "已整理: $filename -> $artist/$album/"
done
echo "整理完成!"
高级Shell脚本(带进度显示)
#!/bin/bash
# advanced_organize.sh
# 功能: 批量整理并备份音乐文件
clean_filename() {
echo "$1" | sed 's/[<>:"\/\\|?*]/_/g'
}
get_file_info() {
local file="$1"
local artist=""
local album=""
local title=""
# 尝试使用ffprobe获取元数据
if command -v ffprobe &> /dev/null; then
artist=$(ffprobe -v error -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
album=$(ffprobe -v error -show_entries format_tags=album -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
title=$(ffprobe -v error -show_entries format_tags=title -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
fi
# 如果获取失败,尝试从文件名提取
if [ -z "$artist" ]; then
local filename=$(basename "$file")
# 格式: "Artist - Title.mp3"
if [[ "$filename" =~ ^(.+)\ -\ (.+)\..+$ ]]; then
artist="${BASH_REMATCH[1]}"
title="${BASH_REMATCH[2]}"
fi
fi
echo "$artist:${album:-'Unknown'}:${title:-$(basename "$file" .*) }"
}
# 主程序
main() {
local source_dir="${1:-./music}"
local dest_dir="${2:-./organized}"
local total_files=0
local processed=0
# 计数总文件数
total_files=$(find "$source_dir" -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.wav" -o -iname "*.m4a" -o -iname "*.ogg" \) | wc -l)
echo "找到 $total_files 个音乐文件,开始整理..."
find "$source_dir" -type f \( -iname "*.mp3" -o -iname "*.flac" -o -iname "*.wav" -o -iname "*.m4a" -o -iname "*.ogg" \) | while read -r file; do
((processed++))
# 显示进度
printf "\r处理进度: %d/%d (%d%%)" $processed $total_files $((processed * 100 / total_files))
# 获取文件信息
IFS=':' read artist album title <<< "$(get_file_info "$file")"
# 清理并创建目录
artist=$(clean_filename "$artist")
album=$(clean_filename "$album")
dest_path="$dest_dir/$artist/$album"
mkdir -p "$dest_path"
# 复制文件(带校验)
cp -np "$file" "$dest_path/$title.${file##*.}" 2>/dev/null || {
echo -e "\n警告: 复制文件失败: $file"
}
done
echo -e "\n整理完成!"
}
# 运行主程序
main "$@"
PowerShell脚本(Windows)
# organize_music.ps1
# 使用: .\organize_music.ps1 -Source "C:\Music" -Destination "D:\Organized"
param(
[Parameter(Mandatory=$true)]
[string]$Source,
[Parameter(Mandatory=$false)]
[string]$Destination = ".\Organized",
[Parameter(Mandatory=$false)]
[switch]$CopyOnly = $false
)
# 加载Windows Media COM组件(需要管理员权限)
function Get-MusicMetadata {
param([string]$FilePath)
$shell = New-Object -ComObject Shell.Application
$folder = $shell.Namespace([System.IO.Path]::GetDirectoryName($FilePath))
$file = $folder.ParseName([System.IO.Path]::GetFileName($FilePath))
# 元数据列索引:20=艺术家, 14=专辑, 21=标题
$artist = $folder.GetDetailsOf($file, 20)
$album = $folder.GetDetailsOf($file, 14)
$title = $folder.GetDetailsOf($file, 21)
return @{
Artist = if ($artist) { $artist } else { "Unknown Artist" }
Album = if ($album) { $album } else { "Unknown Album" }
Title = if ($title) { $title } else { [System.IO.Path]::GetFileNameWithoutExtension($FilePath) }
}
}
# 清理文件名中的非法字符
function Clean-Name {
param([string]$Name)
$Name -replace '[<>:"/\\|?*]', '_'
}
# 主程序
Write-Host "开始整理音乐文件..." -ForegroundColor Green
$audioExtensions = @('.mp3', '.flac', '.wav', '.m4a', '.ogg', '.wma')
$files = Get-ChildItem -Path $Source -Recurse -File | Where-Object {
$_.Extension -in $audioExtensions
}
$total = $files.Count
$current = 0
foreach ($file in $files) {
$current++
$percent = [math]::Round(($current / $total) * 100, 1)
Write-Progress -Activity "整理音乐文件" -Status "处理: $($file.Name)" -PercentComplete $percent
try {
$metadata = Get-MusicMetadata -FilePath $file.FullName
$artist = Clean-Name -Name $metadata.Artist
$album = Clean-Name -Name $metadata.Album
$destFolder = Join-Path -Path $Destination -ChildPath "$artist\$album"
New-Item -ItemType Directory -Path $destFolder -Force | Out-Null
$destFile = Join-Path -Path $destFolder -ChildPath $file.Name
if ($CopyOnly) {
Copy-Item -Path $file.FullName -Destination $destFile -Force
} else {
Move-Item -Path $file.FullName -Destination $destFile -Force
}
Write-Host "处理完成: $($file.Name) -> $artist\$album" -ForegroundColor Green
}
catch {
Write-Warning "处理失败: $($file.Name) - $_"
}
}
Write-Progress -Activity "整理音乐文件" -Completed
Write-Host "整理完成!共处理 $total 个文件。" -ForegroundColor Green
使用建议
安装必要工具
# Python pip install eyed3 mutagen # Linux/Mac sudo apt install exiftool ffmpeg # Ubuntu/Debian brew install exiftool ffmpeg # Mac
先测试后正式运行
- 先在少量文件上测试
- 备份原始文件
- 使用
--dry-run参数预览操作
常见问题处理
- 乱码问题:使用
chardet库检测编码 - 重复文件:添加 MD5 校验
- 特殊字符:使用正则表达式清理
需要我详细解释某个部分或提供其他特定功能的脚本吗?