Cleaning Out the Itunes Library

  • Upload
    tombal

  • View
    212

  • Download
    0

Embed Size (px)

Citation preview

  • 8/3/2019 Cleaning Out the Itunes Library

    1/14

    Cleaning up your iTunes library (on a mac)

    After merging two iTunes libraries I was left with many duplicates whichiTunes asked me to delete one by one. I am always looking for efficient

    ways to solve boring tasks, so I went off to find a way to solve thisautomatically. Having a mac is great, because it has so many useful andeasy tools to handle those kinds of problems. First of all, there isapplescript, which I never touched before, but it really is the easiest wayto deal with applications on a mac. To give you one example of its greatpowers consider the simple command you can enter in any applescripteditor window

    tell application "iTunes" to play

    Click "Run" and it plays! Easy, right?

    Anyway, I wrote a few applescripts to clean up my library. I couldn't findsimilar scripts or at least not of the kind I wanted them to be (also,deleting duplicates is often available only for cash). I also wanted to learnapplescript. So why not write my own scripts?

    I want to share my experiences with other users and I hope they can beuseful for more people out there. I trust on google to spread the word :)

    The scripts are (to some extent) optimized to be fast, using some tricks(or flaws) of applescript. Still, deleting the duplicates takes some time,

    especially for large libraries. This is however because of iTunes. Deletingis not a simple task for iTunes. It has to update quite a few things in thebackground, so dont be alarmed if you have to wait for some time. Forme, with about 13.000 tracks deleting 6.000 duplicates took about onehour.

    All scripts support (at least a simple) logging, i.e. you can check theirprogress by opening a log file, containing stuff like "Handling file xyz,Deleting file uvw". You can use it to check what is happening. You caneasily change it and add more logging messages. You can also turn it off(by writing "false" after the doLogging property). Especially for the script"Clean up your media folder", you might want to try it with a smallerlibrary first, to convince yourself that everything works finely. After all,your music files are valuable and you don't want them to be gone foreveraccidentally! However, my scripts don't really delete files, they just movethem to the trash. So you can always save files, by checking there afterthe whole process.

    Finally, here are some of the scripts:

    Delete duplicates. This little script finds and deletes duplicates in your

    iTunes library (It deletes the library entry, NOT the physical file. Todelete the physical file, look at the "Clean up your music folder"

    http://randystraeume.blogspot.com/2011/03/cleaning-up-your-itunes-library-on-mac.htmlhttp://randystraeume.blogspot.com/2011/03/cleaning-up-your-itunes-library-on-mac.html
  • 8/3/2019 Cleaning Out the Itunes Library

    2/14

    script below. This is to avoid deleting files accidentally which youjust added to your iTunes library, without copying to your musicfolder). Two tracks are considered duplicates if they share the sametrack name, artist and album title. Only if those 3 fields are thesame, all of the tracks except one can be deleted. Additionally the

    play counts and the grouping entries are "merged" together, i.e. thehighest play count among the duplicates is adopted and anygrouping entry. If you have better suggestions on how to mergetracks, I am open to any suggestions.

    Delete dead tracks. This script finds and deletes dead tracks in youriTunes library, i.e. tracks whose path do not point to an existing filein the file system.

    Clean up your music folder. This script finds and deletes files in yourmedia folder which are not represented by entries in your iTuneslibrary. I say "files" because you might have copied other files likepictures there and forgot about them or because maybe some othermusic program added hidden index files. If one of the folders in themedia folder is empty, it is deleted as well.m WARNING: You need toadapt the "libPath" to change the location of the media folder. Bydefault it is set to "yourHomeFolder/Music/iTunes/Music". If youdon't, ALL files in the specified folder will be deleted, because noneof the files are present in YOUR iTunes library. You also might wantto change the valid file endings, i.e. the list of file endings, whichare considered to contain media data. ALL other files will be deletedfor sure!!! Anyway, on a mac nothing is deleted immediately. All"deleted" files will be moved to the trash, so you can still save them

    if they were deleted incorrectly. Whatever you do, you should firstcheck on a small library if the script does what you want. Don'tblame me later, if all your data are gone!

    Any suggestions are welcome. Hope my scripts help you learning applescript or handle your iTunes problem. And here finally the scripts. To runthem, just copy and paste them to a new text edit window, save as"..".scpt. After clicking the apple script editor opens and you can click run.Alternatively you can save the files in the apple script editor asapplication, which then can be run by clicking like a regular app.

    1. Delete duplicates

    (*This little script finds and deletes duplicates in your iTunes library. Twotracks are considered duplicates if they share the same track name, artistand album title. Only if those 3 fields are the same, all of the tracksexcept one can be deleted. Additionally the play counts and the groupingentries are "merged" together.

    You can also use the main handler to delete duplicates in any otherplaylist than the main library.

    You can turn on or off logging of deleted tracks. The logging goes to the

  • 8/3/2019 Cleaning Out the Itunes Library

    3/14

    "logFile.txt" in your home folder.

    Any comments [email protected]*)

    propertydoLogging : falsepropertytextlog : missing value

    onrun {}tellapplication "iTunes" tosetplListtolibrary playlist1main(plList)

    endrun

    on main(plList)-- set up loggersettextlogtomakeFileLog(((path tohome folder) asstring) &

    "logFile.txt")

    ifdoLoggingthentextlog's logImportant("Starting deletingduplicates...")

    findDuplicates(plList)ifdoLoggingthentextlog's logImportant("Finished deleting

    duplicates...")endmain

    on findDuplicates(plList)tellapplication "iTunes"

    -- find all artistssetartistListtoartistofeverytrackofplListwhoseartistis

    notmissing value

    setactArtListto {}repeatwithainartistList

    ifnot (actArtListcontains (aasstring)) thencopy (aasstring) toendofactArtList

    endrepeat

    -- find all albums for a given artistrepeatwithainactArtList

    setalbListto (albumofeverytrackofplListwhoseartistisaandalbumisnotmissing value)

    setactAlbListto {}

    repeatwithalinalbListifnot (actAlbListcontains (alasstring)) then

    copy (alasstring) toendofactAlbList

    endrepeat

  • 8/3/2019 Cleaning Out the Itunes Library

    4/14

    -- find all tracks with artist a and album alrepeatwithalinactAlbList

    settrListto (nameofeverytrackofplListwhoseartistisaandalbumisalandnameisnotmissing value)

    setactTrListto {}

    repeatwithtrintrListifnot (actTrListcontains (trasstring))

    thencopy (trasstring) toendofactTrListendrepeat

    -- handle those tracksrepeatwithtrinactTrList

    settracksWithThisCombto (everytrackofplListwhoseartistisaandalbumisalandnameistr)

    iflengthoftracksWithThisComb > 1 thenmy

    mergeTracks(tracksWithThisComb)

    repeatwithifrom 2 tolengthoftracksWithThisComb

    setttoitemioftracksWithThisComb

    ifdoLoggingthen

    setstrto (tr & " - " & al &" - " & a)

    textlog'slogMessage("Deleting " & str)

    endif

    deletetendrepeat

    endifendrepeat

    endrepeat

    endrepeatendtell

    end findDuplicates

    on mergeTracks(possDupl)tellapplication "iTunes"

    set mainTrack toitem 1 ofpossDuplset playCount toplayed countofmainTrackset grOfTrack togroupingofmainTrack

    setgrto ""set compOfTrack tocompilationofmainTrack

  • 8/3/2019 Cleaning Out the Itunes Library

    5/14

    setcompto ""

    -- collect all information in mainTrackrepeatwithifrom 2 tolengthofpossDupl

    settrtoitemiofpossDupl

    settrPlCounttoplayed countoftriftrPlCount > playCount thenset playCount to

    trPlCount

    if(grOfTrackisequal to "") thensettrGrouptogroupingoftrifnot (trGroupisequal to "") thensetgrto

    trGroupendif

    if(compOfTrackisequal to "") thensettrComptocompilationoftrifnot (trCompisequal to "") thensetcompto

    trCompendif

    endrepeat

    setplayed countofmainTrack to playCountif(grOfTrackisequal to "") thensetgroupingofmainTrack

    togr

    if(compOfTrackisequal to "") thensetcompilationofmainTracktocomp

    endtellend mergeTracks

    on makeFileLog(file_path)scriptFileLog

    propertyclass : "file log"property_linefeed : characterid 10

    -- Writes log messages to a UTF8-encoded text fileon logMessage(the_text)

    setftoopen for accessfile_pathwith writepermission

    trywrite (the_text & my_linefeed) tofstarting ateof

    as class utf8onerror error_message number error_number

    close accessferror error_message number error_number

    endtryclose accessf

  • 8/3/2019 Cleaning Out the Itunes Library

    6/14

    end logMessage

    on logImportant(the_text)logMessage("****** " & the_text & " ******")

    end logImportant

    endscriptend makeFileLog

    2. Remove dead tracks

    (*This script finds and deletes dead tracks in your iTunes library, i.e. trackswhose path does not point to an existing file in the file system.

    You can turn on or off logging of deleted tracks. The logging goes to the"logFile.txt" in your home folder.

    Any comments [email protected]*)

    propertydoLogging : falsepropertytextlog : missing value

    onrun {}main()

    endrun

    onmain()-- set up loggersettextlogtomakeFileLog(((path tohome folder) asstring) &

    "logFile.txt")

    ifdoLoggingthentextlog's logImportant("Starting deleting dead

    tracks...")

    tellapplication "iTunes"setlocationstolocationofeverytrackoflibrary playlist1setallTrackstoeverytrackoflibrary playlist1setallNamestonameofeverytrackoflibrary playlist1

    repeatwithifrom 1 tolengthoflocationssetloctoitemioflocationsif(locisequal tomissing value) then

    setntoitemiofallNamesifdoLoggingthentextlog's logMessage("Deleting

  • 8/3/2019 Cleaning Out the Itunes Library

    7/14

    dead track " & n)deleteitemiofallTracks

    endifendrepeat

    endtell

    ifdoLoggingthentextlog's logImportant("Finished deleting deadtracks...")endmain

    on makeFileLog(file_path)scriptFileLog

    propertyclass : "file log"property_linefeed : characterid 10

    -- Writes log messages to a UTF8-encoded text fileon logMessage(the_text)

    setftoopen for accessfile_pathwith writepermission

    trywrite (the_text & my_linefeed) tofstarting ateof

    as class utf8onerror error_message number error_number

    close accessferror error_message number error_number

    endtry

    close accessfend logMessage

    on logImportant(the_text)logMessage("****** " & the_text & " ******")

    end logImportantendscript

    end makeFileLog

    3. Clean up music folder

    (*This script finds and deletes files in your media folder which are notrepresented by entries in your iTunes library. I say "files" because youmight have copied pictures there and forgot or because maybe someother music program added hidden index files. If one of the folders in themedia folder is empty, it is deleted as well.

    You can adapt the "libPath" to change the location of the media folder. Bydefault it is set to "yourHomeFolder/Music/iTunes/Music". You also might

  • 8/3/2019 Cleaning Out the Itunes Library

    8/14

    want to change the valid file endings, i.e. the list of file endings, which areconsidered to contain media data. ALL other files will be deleted forsure!!!Anyway, on a mac nothing is deleted immediately. All "deleted" files willbe moved to the trash, so you can still save them if they were deleted

    incorrectly.Whatever you do, you should first see on a small library if the script doeswhat you want. Dont blame me later, if all your data are gone!

    You can turn on or off logging. The logging goes to the "logFile.txt" in yourhome folder.

    The associative list code is from the excellent book "Learn apple script" byHanaan Rosenthal.

    Any comments [email protected]*)

    propertydoLogging : falsepropertytextlog : missing valuepropertylibPath : ((path tohome folder) asstring) &"Music:iTunes:Music"propertyvalidFileEndings : {".mp3", ".wav", ".m4p", ".m4a", ".ogg",".avi"}

    onrun {}main()

    endrun

    onmain()-- set up loggersettextlogtomakeFileLog(((path tohome folder) asstring) &

    "logFile.txt")

    try

    cleanupMediaFolder(libPath)onerrorm

    textlog's logError(m)endtry

    endmain

    on cleanupMediaFolder(libPath)ifdoLoggingthentextlog's logMessage("Starting cleaning up media

    folder...")

    tellapplication "iTunes"-- list all files in the library

  • 8/3/2019 Cleaning Out the Itunes Library

    9/14

    settrackPathstolocationofeverytrackinlibrary playlist1

    -- put them in an associative listset lib tomy make_associative_list()repeatwithtrPathintrackPaths

    my addFileToList(trPath, lib)endrepeat

    -- check for every file in the media folder if its path iscontained in the list above

    set allFilesInMediaFolder tomy listFilesRecursively(libPath)

    set AppleScript's text item delimiters to ":"

    ifdoLoggingthentextlog's logMessage("Checking files inmedia folder...")

    repeatwith fPath in allFilesInMediaFolderifdoLoggingthentextlog's logMessage("Handling " &

    fPath)

    -- check if every single path element can be found in libsetpathItemstotext itemsoffPathsetfoundtotrue

    setcurLsttolib

    repeatwithifrom 1 to (lengthofpathItems)set pathItem toitem i ofpathItems

    if(iisequal to (lengthofpathItems)) thenifnot (curLstcontains (pathItem)) then

    setfoundtofalseendif

    elseset lst4pathItem to getItem(pathItem) of

    curLstif(lst4pathItemisequal tomissing value)

    thensetfoundtofalseexitrepeat

    endifset curLst to lst4pathItem

    endifendrepeat

    -- every file which is not contained, can be deletedifnotfoundthen

    ifdoLoggingthentextlog's logMessage("Deleting" & fPath)

  • 8/3/2019 Cleaning Out the Itunes Library

    10/14

    tellapplication "Finder" todeletefilefPathendif

    endrepeat

    ifdoLoggingthentextlog's logMessage("Finished checking

    files in media folder.")

    set AppleScript's text item delimiters to {""}

    -- delete empty foldersmy deleteFoldersRecursively(libPath)

    endtell

    ifdoLoggingthentextlog's logMessage("Finished cleaning upmedia folder...")end cleanupMediaFolder

    on deleteFoldersRecursively(pathToFolder)setfileListto {}tellapplication "System Events"

    -- handle filessetfilesListtopathofeveryfileinfolderpathToFolder

    repeatwithpathOfFinfilesListset foundValidFileEnding tofalserepeatwith fileEnding in validFileEndings

    if(pathOfFends withfileEnding) thenset foundValidFileEnding totrueexitrepeat

    endifendrepeatiffoundValidFileEnding thencopy pathOfF toendof

    fileListendrepeat

    -- handle folderssetfoldersListtopathofeveryfolderinfolderpathToFolder

    repeatwithpathOfFinfoldersListset fileList to fileList & my

    deleteFoldersRecursively(pathOfF)endrepeat

    iffileListisequal to {} thenifdoLoggingthentextlog's logMessage("Deleting folder

    " & pathToFolder)deletefolderpathToFolder

    endifreturnfileList

  • 8/3/2019 Cleaning Out the Itunes Library

    11/14

    endtellend deleteFoldersRecursively

    on listFilesRecursively(pathToFolder)setfileListto {}

    tellapplication "System Events"-- handle filessetfilesListtopathofeveryfileinfolderpathToFolder

    repeatwithpathOfFinfilesListset foundValidFileEnding tofalserepeatwith fileEnding in validFileEndings

    if(pathOfFends withfileEnding) thenset foundValidFileEnding totrueexitrepeat

    endifendrepeatiffoundValidFileEnding thencopy pathOfF toendof

    fileListendrepeat

    -- handle folderssetfoldersListtopathofeveryfolderinfolderpathToFolder

    repeatwithpathOfFinfoldersListset fileList to fileList & my listFilesRecursively(pathOfF)

    endrepeatreturnfileList

    endtellend listFilesRecursively

    on addFileToList(f, lst)setfPathto (fasstring)

    set AppleScript's text item delimiters to ":"set pathItems totext itemsoffPath

    set AppleScript's text item delimiters to {""}

    setcurLsttolstrepeatwithifrom 1 to ((lengthofpathItems) - 1)

    set pathItem toitem i ofpathItemsset lst4pathItem to getItem(pathItem) ofcurLstif(lst4pathItemisequal tomissing value) then

    if(iisequal to ((lengthofpathItems) - 1)) thensetlst4pathItemto {}

    else

    set lst4pathItem to make_associative_list()endif

  • 8/3/2019 Cleaning Out the Itunes Library

    12/14

    curLst's setItem(pathItem, lst4pathItem)endifset curLst to lst4pathItem

    endrepeat

    copy (lastitemofpathItems) toendofcurLstend addFileToList

    on makeFileLog(file_path)scriptFileLog

    propertyclass : "file log"property_linefeed : characterid 10

    -- Writes log messages to a UTF8-encoded text fileon logMessage(the_text)

    setftoopen for accessfile_pathwith writepermission

    trywrite (the_text & my_linefeed) tofstarting ateof

    as class utf8onerror error_message number error_number

    close accessferror error_message number error_number

    endtryclose accessf

    end logMessage

    on logImportant(the_text)logMessage("****** " & the_text & " ******")

    end logImportant

    on logError(the_text)logMessage("ERROR: " & the_text)

    end logErrorendscript

    end makeFileLog

    on make_associative_list()script AssociativeList

    propertyclass : "associative list"propertythe_items : {}propertytheKeys : {}propertytheKeysRef: a referencetotheKeys

    ongetKeys()settheKeysto {}considering diacriticals, hyphens, punctuation and

    white space butignoring caserepeatwithrecord_refinmythe_items

  • 8/3/2019 Cleaning Out the Itunes Library

    13/14

    set keyOfRec tokeyofrecord_refcopykeyOfRectoendoftheKeysRef

    endrepeatendconsideringreturntheKeys

    end getKeys

    on find_record_for_key(the_key)(* This is a private handler. Users should not use it

    directly. *)considering diacriticals, hyphens, punctuation and

    white space butignoring caserepeatwithrecord_refinmythe_items

    ifkeyofrecord_ref= the_keythenreturnrecord_ref

    endrepeatendconsideringreturnmissing value

    end find_record_for_key

    on setItem(the_key, the_value)set record_refto find_record_for_key(the_key)ifrecord_ref= missing valuethen

    setendofmy the_items to {key:the_key,value:the_value}

    else

    set the_value ofrecord_refto the_valueendifreturn

    end setItem

    on getItem(the_key)set record_refto find_record_for_key(the_key)ifrecord_ref= missing valuethen

    --error "The key wasn't found." number -1728 fromthe_key

    returnmissing value

    endifreturn value ofrecord_ref

    end getItem

    on count_items()returncountmythe_items

    end count_items

    on delete_item(the_key)set record_refto find_record_for_key(the_key)

    ifrecord_refismissing valuethenerror "The key wasn't found." number -1728 from

  • 8/3/2019 Cleaning Out the Itunes Library

    14/14

    the_keyendifsetcontentsofrecord_reftomissing valuesetmythe_itemstoeveryrecordofmythe_itemsreturn

    end delete_itemendscript

    end make_associative_list