代码之家  ›  专栏  ›  技术社区  ›  Peter Hosey

如何通过AppleScript更改iTunes播放列表中歌曲的顺序

  •  6
  • Peter Hosey  · 技术社区  · 14 年前

    如何使用applescript命令将播放列表中的歌曲移动到列表中的其他位置?

    我已经有了歌曲和播放列表,其中一个已经在另一个;我只需要改变位置。

    我的目标是对用户选择的曲目进行排序;理想情况下,我希望将第一个按顺序的曲目移动到选择曲目中第一个曲目的位置,并在第一个按顺序的曲目之后立即按顺序排列所有其他选定的曲目。

    5 回复  |  直到 12 年前
        1
  •  8
  •   Brian Webster    12 年前

    move

    tell application "iTunes"
    move first track of playlist "foo" to end of playlist "foo"
    end tell
    

        2
  •  1
  •   jackjr300    12 年前

    set b to false
    tell application "iTunes"
        set selTracks to selection
        if (count selTracks) < 2 then return my displayAlert("Select 2 or more tracks")
        set selPlaylist to container of item 1 of selTracks
        try
            tell selPlaylist to set b to special kind is none and smart is true
        end try
        if not b then return my displayAlert("Not a smart playlist")
        set {oldFindexing, fixed indexing} to {fixed indexing, false}
        set firstIndex to index of item 1 of selTracks
        set fixed indexing to oldFindexing
    
        --**** do something with these selections  **********
        set sortedTracks to reverse of selTracks -- ***** This example reverses the order. ********
    end tell
    my moveSelectedTracks(sortedTracks, selPlaylist, firstIndex)
    
    on moveSelectedTracks(selT, selP, n)
        script o
            property tDataIDs : {}
            property sTracks : selT
            property tArgs2 : {}
        end script
        set L to {}
        set tc to count o's sTracks
        tell application "iTunes"
            set o's tDataIDs to database ID of tracks of selP -- get id of the tracks in the playlist
            set theID to persistent ID of selP
            repeat with i from 1 to tc -- get id of the each sorted track
                set item i of o's sTracks to "<key>" & (get database ID of (item i of o's sTracks)) & "<"
            end repeat
        end tell
    
        set tc to count o's tDataIDs
    
        --- make arguments
        repeat with i from 1 to tc
            if i = n then set o's tArgs2 to o's tArgs2 & o's sTracks
            set t to "<key>" & item i of o's tDataIDs & "<"
            if t is not in o's sTracks then set end of o's tArgs2 to t
        end repeat
    
        set {oTID, text item delimiters} to {text item delimiters, linefeed}
        set o's tArgs2 to o's tArgs2 as text --convert a list to text (one argument per line)
        set text item delimiters to oTID
    
        set xmlLib to my get_iTunes_Library_xml() -- get path of "iTunes Library.xml"
        set tFile to (path to temporary items as string) & "__xzaTemp_Playlist321__"
        set tempF to quoted form of POSIX path of tFile
    
        try --- write arguments to a temporary file
            set openfile to open for access file (tFile & ".txt") with write permission
            set eof of openfile to 0
            write (o's tArgs2) to openfile starting at eof
            close access openfile
        on error err
            try
                close access file tFile
            end try
            return my displayAlert("Error when writing to a temporary file.\\n" & err)
        end try
    
        -- ** create the XML file, grep write the beginning of the xml File
        do shell script "/usr/bin/grep -m1 -B40 '   <dict>' " & xmlLib & " > " & (tempF & ".xml")
    
        (* append to the xmlFile:
        grep read each argument and search track info in "iTunes Library.xml", perl clean up the output 
        grep search the info of the smart playlist and write it
        sed change all arguments to array of dicts (this will be the order of each track in the playlist)  
        echo write the end of the xml File.
        *)
        do shell script "(tmp=" & tempF & ".txt; /usr/bin/grep -A62 -F -f \"$tmp\" " & xmlLib & " |/usr/bin/perl -pe 'undef $/; s|</dict> ((?:(?!</dict>).)*)\\n--|</dict>|sgx; s:</dict>(?!.*</dict>).*|</dict>\\s*</dict>\\s*<key>Playlists</key>.*:</dict>:sx;'; echo '</dict>\\n<key>Playlists</key><array>' ; /usr/bin/grep -m1 -A42 -B3 '>Playlist Persistent ID</key><string>" & theID & "<' " & xmlLib & " | /usr/bin/grep -m1 -B40 '<array>'; /usr/bin/sed 's:$:/integer></dict>:; s:^<key>:<dict><key>Track ID</key><integer>:' \"$tmp\" ; echo '</array></dict></array></dict></plist>') >> " & (tempF & ".xml")
    
        set tFolder to ""
        set b to false
        tell application "iTunes"
            set {tName, songRepeat} to {name, song repeat} of selP
            add ((tFile & ".xml") as alias) -- import the XML file as Smart Playlist
            try
                set tFolder to parent of selP -- if the smart playlist is in a folder playlist
            end try
            set selP2 to last user playlist whose name is tName and its smart is true -- get the new smart playlist
    
            if (persistent ID of selP2) is not theID then -- else no importation 
                if tFolder is not "" then move selP2 to tFolder -- move to the folder playlist
                reveal (track n of selP2) -- select the same row in the imported playlist
                try
                    tell current track to set {dataID, b} to {database ID, its container = selP}
                end try
                if b then -- the current track is in the smart playlist
                    set {tState, tPos} to {player state, player position}
                    play (first track of selP2 whose database ID = dataID) -- play the same track
                    set player position to (tPos + 0.4) --  same position
                    if tState = paused then
                        pause
                    else if tState is stopped then
                        stop
                    end if
                    set song repeat of selP2 to songRepeat -- this line doesn't work on iTunes 11
                end if
                delete selP -- delete the smart playlist (the original)
            end if
        end tell
        do shell script "/bin/rm -f " & tempF & "{.txt,.xml} > /dev/null 2>&1 &" -- delete the temp files
    end moveSelectedTracks
    
    on get_iTunes_Library_xml()
        do shell script "/usr/bin/defaults read com.apple.iApps iTunesRecentDatabases |/usr/bin/sed -En 's:^ *\"(.*)\"$:\\1:p' |/usr/bin/perl -MURI -e 'print URI->new(<>)->file;'"
        return quoted form of the result
    end get_iTunes_Library_xml
    
    on displayAlert(t)
        activate
        display alert t
    end displayAlert
    

    Mac OS X 10.4 ... 10.7 iTunes 7.5 ... 10.6.3


    FreeBSD's grep GNU's grep

    song repeat

        3
  •  1
  •   jackjr300    12 年前

    GUI Scripting

    delay

    iTunes 10.6.3 Mac OS X 10.5.8

    Accessibility Frameworks

    -- this script work on smart and user playlist
    property selPlaylist : missing value
    set b to false
    tell application "iTunes"
        set oldV to (get version) as string < "11"
        activate
        set selTracks to selection
        if (count selTracks) < 2 then return my displayAlert("Select 2 or more tracks")
        set selPlaylist to container of item 1 of selTracks
        try
            if oldV and class of front window is not in {browser window, playlist window} then --- no  playlist window on iTunes 11
                return my displayAlert("The front window is not a browser or a playlist window")
            else if class of front window is not browser window then
                return my displayAlert("The front window is not a browser window")
            end if
            tell selPlaylist
                set b to special kind is none
                set tShuffle to shuffle
                set isSmart to smart
            end tell
        end try
        if not b then return my displayAlert("This script will not work on special playlist")
        if tShuffle then return my displayAlert("This script will not work when shuffle is ON")
    
        set {sortOK, gridView, liveUpd} to my checkSortCol()
        if gridView then return my displayAlert("This script will not work on Grid View")
        if not sortOK then return my displayAlert("This script will not work when the sort column is not the 'status' column")
        if isSmart and liveUpd then return my displayAlert("You must uncheck the \"Live updating\" case, (Edit your Smart playlist)")
    
        --**** do something with these selections  **********
        set sortedTracks to reverse of selTracks -- ***** This example reverses the order. ********
    
        set dataID to database ID of item 1 of sortedTracks
        my moveSelectedTracks(item 1 of selTracks, sortedTracks, (count sortedTracks))
        reveal (track 1 of selPlaylist whose database ID is dataID)
    end tell
    
    on moveSelectedTracks(firstTrack, sortedT, n)
        tell application "System Events"
            tell process "iTunes"
                repeat with i from 1 to n
                    my selectRow(item i of sortedT)
                    keystroke "c" using command down --  copy track
                    my selectRow(firstTrack)
                    keystroke "v" using command down -- paste track
                    delay 0.1
                    tell front window to if subrole is "AXDialog" then click last button -- close dialog
                end repeat
                my selectRow(firstTrack)
                repeat with i from 1 to n
                    keystroke "x" using command down -- cut track
                    delay 0.1
                    tell front window to if subrole is "AXDialog" then click last button -- close dialog
                    delay 0.1
                end repeat
            end tell
        end tell
    end moveSelectedTracks
    
    on selectRow(i)
        tell application "iTunes" to reveal i
    end selectRow
    
    on checkSortCol() -- ****** "status" is the localized title, you need to change it according to your system language ******
        tell application "System Events"
            tell process "iTunes"
                if (exists radio group 2 of window 1) then return {true, true, true} -- grid view without outline
                set s to value of attribute "AXSortDirection" of (button "status" of group 1 of outline 1 of (last scroll area of window 1 whose group 1 of outline 1 is not missing value))
    
                set x to value of attribute "AXMenuItemMarkChar" of menu item 3 of menu of menu bar item 5 of menu bar 1 -- menu "as Grid"          
                set y to not (enabled of menu item 4 of menu of menu bar item 4 of menu bar 1) -- menu "Cut"
            end tell
        end tell
        return {s is not "AXUnknownSortDirection", x is not {"�"}, y}
    end checkSortCol
    
    on displayAlert(t)
        activate
        display alert t
    end displayAlert
    

        4
  •  1
  •   regulus6633    12 年前

    -- this is only tested on music tracks, not apps or books etc.
    -- do not use this code on your main music library
    
    -- this will sort the selected tracks
    -- insert sorting code here: DO YOUR SORTING HERE
    -- now the sorting code just reverses the order of the selection
    
    -- it works by getting references of the songs in your playlist from the main library, sorting that,
    -- then deleting the tracks from the current playlist and recreating the playlist from the references
    
    tell application "iTunes"
        -- get the selection
        set selectedTracks to the selection
        set selectionCount to count of selectedTracks
        if selectionCount is 0 then
            error "Error: Nothing is selected!"
        else if selectionCount is 1 then
            error "Error: There is nothing to sort because only 1 item is selected!"
        end if
    
        -- store the player state
        try
            set currentPlaylist to current playlist
        on error
            play
            pause
            set currentPlaylist to current playlist
        end try
        try
            set currentTrack to current track
            set currentTrackID to persistent ID of currentTrack
            set currentTime to player position
            set currentState to player state
        on error
            set currentState to false
        end try
    
        -- are we in the right type of playlist?
        if (special kind of currentPlaylist is not none) or (smart of currentPlaylist) then
            error ("Error: we cannot use this code on playlist " & name of currentPlaylist & "!")
        end if
    
        -- is the selection in the current playlist?
        set firstSelectedTrack to item 1 of selectedTracks
        set firstSelectedTrackID to persistent ID of firstSelectedTrack
        try
            first track of currentPlaylist whose persistent ID is firstSelectedTrackID
        on error
            error "Error: the selected tracks are not in the current playlist, so this code won't work!"
        end try
    
        -- are we dealing with music tracks?
        if class of firstSelectedTrack is not file track then error "Error: this code is only tested on music file tracks!"
    
        (****** DO YOUR SORTING HERE *********)
        -- sort your selected tracks in a list however you need
        -- in this case I'm just reversing the order for simplicity
        set sortedSelection to reverse of selectedTracks
        (*************************************)
    
        -- figure out the index of the first selected track out of the entire playlist
        set playlistTracks to tracks of currentPlaylist
        repeat with i from 1 to count of playlistTracks
            if (item i of playlistTracks) is firstSelectedTrack then exit repeat
        end repeat
    
        -- now we make one big list of the sorted playlist
        set tracksBeforeSelection to {}
        set tracksAfterSelection to {}
        try
            set tracksBeforeSelection to items 1 thru (i - 1) of playlistTracks
        end try
        try
            set tracksAfterSelection to items (i + selectionCount) thru end of playlistTracks
        end try
        set finalTrackList to tracksBeforeSelection & sortedSelection & tracksAfterSelection
    
        -- now we get references to all these tracks from the main library so we can delete the playlist and reorganize it
        set finalTrackListRefs to {}
        repeat with aTrack in finalTrackList
            set trackID to persistent ID of aTrack
            set refTrack to (first track of library playlist 1 whose persistent ID is trackID)
            set end of finalTrackListRefs to refTrack
        end repeat
    
        -- remove all the tracks from the playlist
        delete tracks of currentPlaylist
    
        -- put the playlist back in the new order
        repeat with aTrack in finalTrackListRefs
            duplicate aTrack to currentPlaylist
        end repeat
    
        -- restore the player state
        if currentState is playing then
            play (first track of currentPlaylist whose persistent ID is currentTrackID)
            set player position to currentTime
        end if
    end tell
    
        5
  •  0
  •   Philip Regan    14 年前

    index