2010-10-30 22 views
6

¿Cómo puedo mover una canción que está en una lista de reproducción a una posición diferente dentro de la lista con un comando de AppleScript?Cómo cambiar el orden de una canción dentro de una lista de reproducción de iTunes mediante AppleScript

Ya tengo la canción y la lista de reproducción, y la una ya está en la otra; Solo necesito cambiar la posición.

Mi objetivo es ordenar las pistas que el usuario ha seleccionado; idealmente, me gustaría mover la pista de primer orden a la posición de la primera pista en la selección, y ordenar todas las otras pistas inmediatamente y secuencialmente después de la primera por orden.

Respuesta

8

El comando move parece ser bastante defectuoso. En mis experimentos, parece que no importa en qué ubicación lo des a mover una pista, la mueve al final de la lista de reproducción. Sin embargo, esto debería ser manejable, aunque un poco ineficiente. La sintaxis de este aspecto:

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

Hay varias otras construcciones que se supone que será capaz de utilizar en lugar de "final de", incluyendo cosas como 'principio de lista de reproducción 'foo'', 'después de la pista 5 de la lista de reproducción "foo" ', y' antes de la pista 5 de la lista de reproducción 'foo' ', pero ninguno de ellos parece funcionar como se esperaba. Pero, si básicamente clasificas tus pistas en una lista ordenada de la manera que deseas, deberías poder iterar la lista, decirle a iTunes que mueva cada pista en sucesión hasta el final de la lista de reproducción, y terminarías con la ordenado después de que todo está hecho.

+0

Intenté: 'establecer sel_playlist para ver la ventana del navegador 1'; 'establecer sel_tracks para la selección'; 'mueve sel_tracks al final de sel_playlist' (así como también una repetición' repeat with t in sel_tracks') y obtiene "Error de permiso de archivo" (-54). No sé si esto funcionaría mejor en una lista de reproducción tonta, pero no es ahí donde necesito ordenar las pistas. –

+0

Seguimiento: Acabo de probarlo en una lista de reproducción tonta y la versión 'repeat with' (mover una pista a la vez) funciona muy bien. No resuelve mi caso de lista de reproducción inteligente, pero haré otra pregunta para eso. Esta será probablemente la respuesta aceptada en este caso. Gracias. –

+0

@Brian Webster ¿Hay alguna manera de hacer esto con js applescript? – Dylanthepiguy

0

No puede hacer eso directamente porque el Diccionario muestra que la propiedad index de una pista en una lista de reproducción es solo de get, no get/set.

La única forma que veo a este respecto sería crear una nueva lista de reproducción, mover las pistas en la nueva en el orden en que desea que estén, y luego desechar la anterior.

+0

La propiedad 'index' no se puede asignar, pero hay un verbo' move'. Sin embargo, no he descubierto el uso correcto de este para reorganizar los elementos (si es que hay uno). –

1

Debido a su comentario a la publicación de Philip Regan, miré el comando de movimiento en iTunes y dice que es para mover listas de reproducción, por lo que no lo ayudará. Sin embargo, puede hacer esto, que básicamente recreará el orden de la lista de reproducción como desee en la lista de reproducción actual.

Supongo que la selección es secuencial. Si no es así, este código tendrá que ajustarse, pero puede usar estas ideas para lograrlo.

NOTA: tiene que poner un código para hacer su clasificación de la selección porque realmente no puedo decir cómo desea ordenar la selección de su descripción. Coloca ese código en el área que he marcado "HAZ TU CLASIFICACIÓN AQUÍ". El resto del código debería funcionar como está.

Espero que esto ayude ... buena suerte.

-- 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 
+0

Buen pensamiento. Ni siquiera había considerado este enfoque porque la lista de reproducción en la que estoy buscando ordenar pistas es una lista de reproducción inteligente. Me disculpo por no mencionar esto en la pregunta. Si nada de lo que puedo usar en una lista de reproducción inteligente aparece durante el período de recompensa, haré una pregunta por separado para listas de reproducción inteligentes, ya que esta es una buena respuesta. –

+0

OK, una lista de reproducción inteligente ... No estoy seguro de que sea posible entonces. Si pienso en algo, te lo haré saber. – regulus6633

+0

Gracias dj bazzie wazzie por las mejoras sugeridas al código. Sugirió usar una verificación de "lista de reproducción especial" en lugar de nombres de listas de reproducción difíciles de codificar. Con sus sugerencias, el código debería funcionar en idiomas no ingleses. – regulus6633

1

Aquí hay una solución, pero es indirecta, porque importa un archivo XML.

La secuencia de comandos crea un archivo XML, como exportar una lista de reproducción de iTunes. Cuando el script ha terminado de crear el archivo XML, lo importa en iTunes, iTunes crea otra Smart Playlist con el mismo nombre, el script cambia a la nueva lista de reproducción y elimina el original. Funciona también en la selección no contigua.

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 

Esta ejecución de secuencias de comandos en (Mac OS X 10.4 ... 10.7), (iTunes 7.5 ... 10.6.3).

La secuencia de comandos no funciona en las versiones anteriores, no sé acerca de las versiones más recientes.


sé:

Mountain Lion utilizar FreeBSD's grep en lugar de GNU's grep, grep de FreeBSD es extremadamente lento en Mountain Lion (30 a 100 veces más lento de acuerdo a lo que he leído), por lo que este script también lo hará Sé lento.

Tunes 11 rompe el comando AppleScript a song repeat una lista de reproducción. El valor de song repeat todavía se puede leer con get, simplemente no se puede establecer, por lo que se comenta la línea en el script.

1

Aquí hay un script que usa el GUI Scripting.

Pero este tipo de secuencia de comandos se rompe fácilmente en función de la versión de iTunes o la versión del sistema operativo . El usuario debe ajustar delay (según la velocidad de la máquina). El usuario también debe cambiar el título localizado en el script.

Este script funciona en iTunes 10.6.3 y Mac OS X 10.5.8, no sé si funciona en otras versiones.

Debe habilitar el Accessibility Frameworks haciendo clic en la casilla de verificación etiquetada "Habilitar el acceso para los dispositivos de asistencia" en el panel de Preferencias del sistema de acceso universal.

-- 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 

Debe desmarcar "vivo actualizar" en la lista de reproducción inteligente, de lo contrario el script no funcionará porque el elemento de menú "Cut " está desactivada. Puede volver a verificarlo después de que haya terminado.

Cuestiones relacionadas