怎样用脚本批量整理音乐文件?

wen 实用脚本 2

本文目录导读:

怎样用脚本批量整理音乐文件?

  1. 方法一:Python脚本(最灵活)
  2. 方法二:Shell脚本(Linux/Mac)
  3. 方法三:PowerShell脚本(Windows)
  4. 使用建议

我来介绍几种用脚本批量整理音乐文件的方法,主要使用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 校验
  • 特殊字符:使用正则表达式清理

需要我详细解释某个部分或提供其他特定功能的脚本吗?

抱歉,评论功能暂时关闭!