Apple Event: May 7th at 7 am PT

FixLinks - an AppleScript to repair broken links in Music

Last modified: Oct 22, 2022 11:25 AM
27 20444 Last modified Oct 22, 2022 11:25 AM

This script is potentially a work in progress and is posted here so that I can edit it if needs be. It was written in response to this thread: Can I change the location of a song in Catalina? - Apple Community. While it works in the scenarios that I have tested with tracks organized following standard iTunes/Music conventions it may be possible to adapt it where a user has imposed their own file and folder naming rules.


The entire script below should be copied into a new document in Script Editor and saved as FixLinks. To use select some tracks in Music that show with exclamation marks indicating broken links, then run the script. You will be prompted for the media folder that holds these tracks. This should be where the artist folders are located. The script will process each track in the selection, ignoring any that are not broken, and attempting to fix any that are. In its current form it will show the path of each attempt where its guess is wrong so that the information may be used to refine the script. The script should be able to fix broken links where the files are stored at:


<Target Folder>/<[Album]Artist>/<Album>/[[D-]## ]<Name>[ 1].<Ext>


The first subfolder will be the Compilations folder if the track is marked as a compilation, otherwise Album Artist, or Artist if Album Artist is blank, or Unknown Artist if Artist is blank too. The second subfolder is the Album title, or Unknown Album if blank. A leading disc number is used if disc number or disc count are greater than 1. If the file isn't found at the initially predicted path a second search will be made that includes a trailing " 1" in the filename, and if that fails some more variations are explored.


tt2



Copy the text between the two horizontal lines:


_________________________________________________________________________________________



-- FixLinks - V1.08 - © Steve MacGuire - 2022-10-22

-- An AppleScript to repair broken track links in Music or iTunes

-- Downloaded from https://discussions.apple.com/docs/DOC-250002671



set mediaPath to "" -- preset media folder here with form /<path>/ here to avoid opening prompt

set showMissing to true -- set to false to suppress any reporting of missing tracks

set maxLen to 0 -- use to truncate predicted paths to a max. length, e.g. 40 to match iTunes for Windows


-- tell application "iTunes" -- Mojave or earlier

tell application "Music" -- Catalina or later

if selection is {} then

display dialog "Please select some tracks with broken links before calling this script" with title "FixLinks"

else

set mySelection to selection

set m to 0

set p to 0

set u to 0

set s to 0

repeat with aTrack in mySelection

set p to p + 1

set aPath to ""

try

set aPath to location of aTrack as text

end try

-- display dialog aPath & return & mediaPath -- enable for debugging

if aPath is "missing value" then -- only work with missing tracks

if mediaPath is "" then set mediaPath to my getMediaPath()

-- evaluate artist folder

set theArtist to album artist of aTrack

if theArtist = "" then set theArtist to artist of aTrack

if theArtist = "" then set theArtist to "Unknown Artist"

if compilation of aTrack = true then set theArtist to "Compilations"

set theArtist to my safePath(theArtist)

-- evaluate album folder

set theAlbum to album of aTrack

if theAlbum = "" then set theAlbum to "Unknown Album"

set theAlbum to my safePath(theAlbum)

-- evaluate file name

set theFile to ""

if track number of aTrack > 0 then

set theFile to theFile & track number of aTrack & " "

if track number of aTrack < 10 then set theFile to "0" & theFile

-- add leading disc number if implied

if disc number of aTrack > 1 or disc count of aTrack > 1 then set theFile to (disc number of aTrack as text) & "-" & theFile

-- or always add leading disc number

-- if disc number of aTrack > 0 then set theFile to (disc number of aTrack as text) & "-" & theFile

end if

set theFile to theFile & name of aTrack

set theFile to my safeFile(theFile, true)

-- calculate file extension

set k to kind of aTrack

if k = "AAC audio file" then

set ext to ".m4a"

else if k = "AIFF audio file" then

set ext to ".aif"

else if k = "Apple Lossless audio file" then

set ext to ".m4a"

else if k = "Apple Music AAC audio file" then

set ext to ".m4p"

else if k = "iTunes LP" then

set ext to ".itlp"

else if k = "Matched AAC audio file" then

set ext to ".m4a"

else if k = "MPEG audio file" then

set ext to ".mp3"

else if k = "MPEG-4 video file" then

set ext to ".mp4"

else if k = "PDF document" then

set ext to ".pdf"

else if k = "Purchased AAC audio file" then

set ext to ".m4a"

else if k = "Purchased MPEG-4 video file" then

set ext to ".mp4" -- might also be ".m4v", alternatives will be checked later  

else if k = "WAV audio file" then

set ext to ".wav"

else

display dialog "Edit script to provide extension for tracks of kind " & k with title "FixLinks"

set ext to ""

end if

-- extend this pattern as required

set newPath to theArtist & "/" & theAlbum & "/" & theFile -- Normal <Artist>/<Album>/[D-]## <Name>.<Ext> layout

-- set newPath to theArtist & "/" & theFile -- Option for no album folders within artist folders

set testPath to mediaPath & newPath & ext

if not my fileExists(testPath) then set testPath to mediaPath & newPath & " 1" & ext

if not my fileExists(testPath) then set testPath to mediaPath & newPath & " 2" & ext

if not my fileExists(testPath) then set testPath to mediaPath & "Music/" & newPath & ext

if not my fileExists(testPath) then set testPath to mediaPath & "Music/" & newPath & " 1" & ext

if not my fileExists(testPath) then set testPath to mediaPath & "Music/" & newPath & " 2" & ext

if ext = ".mp4" then

if not my fileExists(testPath) then set testPath to mediaPath & newPath & ".m4v"

if not my fileExists(testPath) then set testPath to mediaPath & newPath & " 1.m4v"

if not my fileExists(testPath) then set testPath to mediaPath & "Music/" & newPath & ".m4v"

if not my fileExists(testPath) then set testPath to mediaPath & "Music/" & newPath & " 1.m4v"

end if

-- pattern above could be extended for other variations, e.g. trailing 2

-- display dialog mediaPath & return & testPath -- enable for debugging

if my fileExists(testPath) then

-- display dialog "Connecting broken track to:" & return & testPath & with title "FixLinks" -- enable for debugging

try -- Workaround for Big Sur -- error "Music got an error: Parameter error." number -50 

set location of aTrack to testPath

end try

-- note this script needs tweaking to correctly repair broken iTunes LP entries

set u to u + 1

else

set m to m + 1

if showMissing then

set msg to "File not found at:" & return & return & mediaPath & newPath & ext

set msg to msg & return & return & "Continue reporting?"

set answer to the button returned of (display dialog msg buttons {"Yes", "No", "Cancel"} with title "FixLinks")

if answer = "No" then set showMissing to false

end if

end if

else

-- display dialog location of aTrack as string with title "FixLinks" -- enable for debugging

set s to s + 1

end if

end repeat

-- report on script activity

set msg to (p as string) & " item"

set msg to msg & my plural(p, "s were", " was")

set msg to msg & " processed,"

set msg to msg & return & (u as string) & " item"

set msg to msg & my plural(u, "s were", " was")

set msg to msg & " updated"

if m > 0 then

set msg to msg & "," & return & (m as string) & " item"

set msg to msg & my plural(m, "s were", " was")

set msg to msg & " not located"

end if

if s > 0 then

set msg to msg & "," & return & (s as string) & " item"

set msg to msg & my plural(s, "s", "")

set msg to msg & " needed no action"

end if

set msg to msg & "."

display dialog msg with title "FixLinks" giving up after 300

end if

end tell



-- check that a file exists at a given path

on fileExists(theFile) -- (String) as Boolean

tell application "System Events"

if exists file (my replace(theFile, "/", ":")) then

-- display dialog theFile & " exists!"

return true

else

-- display dialog theFile & " does not exist!"

return false

end if

end tell

end fileExists



-- prompt for media folder location

on getMediaPath()

set aPath to choose folder with prompt "Select the media folder you wish to find missing tracks in" default location path to music folder

set aPath to POSIX path of aPath

return aPath

end getMediaPath



-- return plural or singular form dependent on V

on plural(V, p, s)

if V = 1 then

return s

else

return p

end if

end plural



-- find : Text to be found

-- replace : Text to replace with

-- someText : Text to be searched

on replace(someText, find, replace)

set prevTIDs to text item delimiters of AppleScript

set text item delimiters of AppleScript to find

set someText to text items of someText

set text item delimiters of AppleScript to replace

set someText to "" & someText

set text item delimiters of AppleScript to prevTIDs

return someText

end replace



-- Replace characters that are invalid in file paths and trim any spaces

on safeFile(someText, isFile)

-- optionally truncate filename when something other than iTunes/Music has organized files

set theLen to my maxLen

if theLen > 9 then -- catch errors with really small setting

if isFile then set theLen to theLen - 4

if length of someText > theLen then

set someText to text 1 thru theLen of someText

end if

end if

-- trim spaces and replace characters

set someText to trim(someText)

set someText to my replace(someText, "/", "_")

set someText to my replace(someText, "?", "_")

set someText to my replace(someText, "<", "_")

set someText to my replace(someText, ">", "_")

set someText to my replace(someText, "\\", "_")

set someText to my replace(someText, ":", "_")

set someText to my replace(someText, "*", "_")

set someText to my replace(someText, "|", "_")

set someText to my replace(someText, "\"", "_")

end safeFile



-- Additional replacements for folders only

on safePath(someText)

if someText begins with " " then set someText to "_" & text 2 thru -1 of someText

if someText begins with "." then set someText to "_" & text 2 thru -1 of someText

if someText ends with "." then set someText to text 1 thru -2 of someText & "_"

-- custom option for me that needs commenting out

-- if someText begins with "The " then set someText to text 5 thru -1 of someText & ", The"

set someText to safeFile(someText, false)

return someText

end safePath



-- strip leading and trailing spaces

on trim(someText)

repeat until someText does not start with " "

set someText to text 2 thru -1 of someText

end repeat

repeat until someText does not end with " "

set someText to text 1 thru -2 of someText

end repeat

return someText

end trim


_________________________________________________________________________________________



Paste into a new empty document window in the Script Editor app and save as FixLinks. Alternatively download using this link - FixLinks.zip - and extract the file. Save to ~/Library/Music/Scripts if you want to be able to call it from the Music menu bar.




Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.