Skip to content

Instantly share code, notes, and snippets.

@micycle1
Created July 5, 2024 16:57
Show Gist options
  • Save micycle1/10267acd358c745879963767101a5833 to your computer and use it in GitHub Desktop.
Save micycle1/10267acd358c745879963767101a5833 to your computer and use it in GitHub Desktop.
Groups flac or mp3 files into album folders, saving with appropriate filenames. Preserves singles.
# Ensure ffprobe is available in the system's PATH or specify its full path
$ffprobePath = "ffprobe"
$files = Get-ChildItem -Path "." -File | Where-Object { $_.Extension -eq ".mp3" -or $_.Extension -eq ".flac" }
Write-Host "Found $($files.Count) files to process."
# Store album information
$albums = @{}
foreach ($file in $files) {
# Use ffprobe to get file metadata
# Use the new ffprobe command
$output = & $ffprobePath -v error -select_streams a:0 -show_entries "stream=codec_name,bit_rate,channels,sample_rate : format=duration : format_tags : stream_tags" -of default=noprint_wrappers=1 "$file" 2>&1
# Split the output into lines
$metadataLines = $output -split "`n"
#Write-Host $metadataLines
# Initialize variables to hold metadata
$albumName = $null
$albumArtist = $null
$artist = $null
$trackNumber = $null
$title = 0
# Iterate over each line and extract the metadata based on the TAG: prefix
foreach ($line in $metadataLines) {
if ($line -match "^TAG:TITLE=(.+)") {
$title = $matches[1]
} elseif ($line -match "^TAG:ALBUM_ARTIST=(.+)") {
$albumArtist = $matches[1]
} elseif ($line -match "^TAG:ARTIST=(.+)") {
$artist = $matches[1]
} elseif ($line -match "^TAG:ALBUM=(.+)") {
$albumName = $matches[1]
} elseif ($line -match "^TAG:track=(.+)") {
$trackNumber = $matches[1]
}
}
# Handle missing album artist
if (-not $albumArtist) {
# $albumArtist = "Unknown Artist"
}
# Create album identifier
$albumID = "$albumArtist - $albumName"
if (-not $albumArtist -or $albumArtist -eq "") {
$albumID = $albumName
}
# Add track to album
if (-not $albums.ContainsKey($albumID)) {
$albums[$albumID] = @()
}
$albums[$albumID] += @{"file"=$file.FullName; "trackNumber"=$trackNumber; "title"=$title; "artist"=$artist}
}
# Write $albums object to console for debugging
Write-Host ""
Write-Host "================================================="
Write-Host ""
Write-Host "Albums:"
foreach ($album in $albums.GetEnumerator()) {
# Check if the album has more than one track
if ($album.Value.Count -gt 1) {
Write-Host " Album: $($album.Key)"
foreach ($track in $album.Value) {
$trackDetails = "$($track.trackNumber) $($track.title)"
Write-Host " $trackDetails"
}
}
}
Write-Host ""
Write-Host "================================================="
Write-Host ""
Write-Host "Organizing files into albums..."
# Process albums
foreach ($album in $albums.GetEnumerator()) {
# Process differently based on track count
if ($album.Value.Count -eq 1) {
# Handle single track album
$track = $album.Value[0]
$artistWithReplacements = $track.artist -replace "[\\\/:\*\?""<>\|]", "_"
$titleWithReplacements = $track.title -replace "[\\\/:\*\?""<>\|]", "_"
$fileExtension = [System.IO.Path]::GetExtension($track.file)
$newFileName = "$artistWithReplacements - $titleWithReplacements$fileExtension"
$newFilePath = Join-Path -Path "." -ChildPath $newFileName
Move-Item -Path $track.file -Destination $newFilePath
$relativeFileName = Split-Path $track.file -Leaf
Write-Host "Moved `"$relativeFileName`" to `"$newFilePath`""
}
elseif ($album.Value.Count -gt 1) {
$albumPath = Join-Path -Path "." -ChildPath ($album.Key -replace "[\\\/:\*\?""<>\|]", "_") # Replace invalid characters
Write-Host "Processing album: $($album.Key)"
# Create album directory if it doesn't exist
if (-not (Test-Path $albumPath)) {
New-Item -ItemType Directory -Path $albumPath | Out-Null
Write-Host "Created directory: $albumPath"
}
# Move and rename files for multiple tracks
foreach ($track in $album.Value) {
$titleWithReplacements = $track.title -replace "[\\\/:\*\?""<>\|]", "_"
$fileExtension = [System.IO.Path]::GetExtension($track.file)
$newFileName = "{0} - {1}{2}" -f $track.trackNumber, $titleWithReplacements, $fileExtension
$newFilePath = Join-Path -Path $albumPath -ChildPath $newFileName
Move-Item -Path $track.file -Destination $newFilePath
$relativeFileName = Split-Path $track.file -Leaf
Write-Host "Moved `"$relativeFileName`" to `"$newFilePath`""
}
}
}
Write-Host "Operation completed. Press any key to exit."
$null = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment