utility to sync an itunes playlist to a directory (like a mounted sd card/phone)

switch to appscript gem, add fix for newer itunes from my eyetunes project

+344 -9
+331
appscript_itunes_fix.rb
··· 1 + # via http://www.apeth.com/rbappscript/04appobject.html#staticterminology 2 + 3 + module ITunesFix 4 + Version = 1.1 5 + Path = "/" 6 + 7 + Classes = [ 8 + ["EQ_preset", "cEQP"], 9 + ["EQ_window", "cEQW"], 10 + ["URL_track", "cURT"], 11 + ["application", "capp"], 12 + ["artwork", "cArt"], 13 + ["audio_CD_playlist", "cCDP"], 14 + ["audio_CD_track", "cCDT"], 15 + ["browser_window", "cBrW"], 16 + ["device_playlist", "cDvP"], 17 + ["device_track", "cDvT"], 18 + ["encoder", "cEnc"], 19 + ["file_track", "cFlT"], 20 + ["folder_playlist", "cFoP"], 21 + ["item", "cobj"], 22 + ["library_playlist", "cLiP"], 23 + ["playlist", "cPly"], 24 + ["playlist_window", "cPlW"], 25 + ["print_settings", "pset"], 26 + ["radio_tuner_playlist", "cRTP"], 27 + ["shared_track", "cShT"], 28 + ["source", "cSrc"], 29 + ["track", "cTrk"], 30 + ["user_playlist", "cUsP"], 31 + ["visual", "cVis"], 32 + ["window", "cwin"], 33 + ] 34 + 35 + Enumerators = [ 36 + ["Books", "kSpA"], 37 + ["Genius", "kSpG"], 38 + ["Library", "kSpL"], 39 + ["MP3_CD", "kMCD"], 40 + ["Movies", "kSpI"], 41 + ["Music", "kSpZ"], 42 + ["Party_Shuffle", "kSpS"], 43 + ["Podcasts", "kSpP"], 44 + ["Purchased_Music", "kSpM"], 45 + ["TV_Shows", "kSpT"], 46 + ["TV_show", "kVdT"], 47 + ["album_listing", "kAlb"], 48 + ["albums", "kSrL"], 49 + ["all", "kAll"], 50 + ["artists", "kSrR"], 51 + ["audio_CD", "kACD"], 52 + ["cd_insert", "kCDi"], 53 + ["composers", "kSrC"], 54 + ["computed", "kRtC"], 55 + ["detailed", "lwdt"], 56 + ["device", "kDev"], 57 + ["displayed", "kSrV"], 58 + ["fast_forwarding", "kPSF"], 59 + ["folder", "kSpF"], 60 + ["iPod", "kPod"], 61 + ["iTunes_U", "kSpU"], 62 + ["large", "kVSL"], 63 + ["library", "kLib"], 64 + ["medium", "kVSM"], 65 + ["movie", "kVdM"], 66 + ["music_video", "kVdV"], 67 + ["none", "kNon"], 68 + ["off", "kRpO"], 69 + ["one", "kRp1"], 70 + ["paused", "kPSp"], 71 + ["playing", "kPSP"], 72 + ["radio_tuner", "kTun"], 73 + ["rewinding", "kPSR"], 74 + ["shared_library", "kShd"], 75 + ["small", "kVSS"], 76 + ["songs", "kSrS"], 77 + ["standard", "lwst"], 78 + ["stopped", "kPSS"], 79 + ["track_listing", "kTrk"], 80 + ["unknown", "kUnk"], 81 + ["user", "kRtU"], 82 + ] 83 + 84 + Properties = [ 85 + ["EQ", "pEQp"], 86 + ["EQ_enabled", "pEQ "], 87 + ["address", "pURL"], 88 + ["album", "pAlb"], 89 + ["album_artist", "pAlA"], 90 + ["album_rating", "pAlR"], 91 + ["album_rating_kind", "pARk"], 92 + ["artist", "pArt"], 93 + ["band_1", "pEQ1"], 94 + ["band_10", "pEQ0"], 95 + ["band_2", "pEQ2"], 96 + ["band_3", "pEQ3"], 97 + ["band_4", "pEQ4"], 98 + ["band_5", "pEQ5"], 99 + ["band_6", "pEQ6"], 100 + ["band_7", "pEQ7"], 101 + ["band_8", "pEQ8"], 102 + ["band_9", "pEQ9"], 103 + ["bit_rate", "pBRt"], 104 + ["bookmark", "pBkt"], 105 + ["bookmarkable", "pBkm"], 106 + ["bounds", "pbnd"], 107 + ["bpm", "pBPM"], 108 + ["capacity", "capa"], 109 + ["category", "pCat"], 110 + ["closeable", "hclb"], 111 + ["collapseable", "pWSh"], 112 + ["collapsed", "wshd"], 113 + ["collating", "lwcl"], 114 + ["comment", "pCmt"], 115 + ["compilation", "pAnt"], 116 + ["composer", "pCmp"], 117 + ["container", "ctnr"], 118 + ["copies", "lwcp"], 119 + ["current_EQ_preset", "pEQP"], 120 + ["current_encoder", "pEnc"], 121 + ["current_playlist", "pPla"], 122 + ["current_stream_URL", "pStU"], 123 + ["current_stream_title", "pStT"], 124 + ["current_track", "pTrk"], 125 + ["current_visual", "pVis"], 126 + ["data", "pPCT"], 127 + ["database_ID", "pDID"], 128 + ["date_added", "pAdd"], 129 + ["description", "pDes"], 130 + ["disc_count", "pDsC"], 131 + ["disc_number", "pDsN"], 132 + ["downloaded", "pDlA"], 133 + ["duration", "pDur"], 134 + ["enabled", "enbl"], 135 + ["ending_page", "lwlp"], 136 + ["episode_ID", "pEpD"], 137 + ["episode_number", "pEpN"], 138 + ["error_handling", "lweh"], 139 + ["fax_number", "faxn"], 140 + ["finish", "pStp"], 141 + ["fixed_indexing", "pFix"], 142 + ["format", "pFmt"], 143 + ["free_space", "frsp"], 144 + ["frontmost", "pisf"], 145 + ["full_screen", "pFSc"], 146 + ["gapless", "pGpl"], 147 + ["genre", "pGen"], 148 + ["grouping", "pGrp"], 149 + ["id_", "ID "], 150 + ["index", "pidx"], 151 + ["kind", "pKnd"], 152 + ["location", "pLoc"], 153 + ["long_description", "pLds"], 154 + ["lyrics", "pLyr"], 155 + ["minimized", "pMin"], 156 + ["modifiable", "pMod"], 157 + ["modification_date", "asmo"], 158 + ["mute", "pMut"], 159 + ["name", "pnam"], 160 + ["pages_across", "lwla"], 161 + ["pages_down", "lwld"], 162 + ["parent", "pPlP"], 163 + ["persistent_ID", "pPIS"], 164 + ["played_count", "pPlC"], 165 + ["played_date", "pPlD"], 166 + ["player_position", "pPos"], 167 + ["player_state", "pPlS"], 168 + ["podcast", "pTPc"], 169 + ["position", "ppos"], 170 + ["preamp", "pEQA"], 171 + ["printer_features", "lwpf"], 172 + ["rating", "pRte"], 173 + ["rating_kind", "pRtk"], 174 + ["raw_data", "pRaw"], 175 + ["release_date", "pRlD"], 176 + ["requested_print_time", "lwqt"], 177 + ["resizable", "prsz"], 178 + ["sample_rate", "pSRt"], 179 + ["season_number", "pSeN"], 180 + ["selection", "sele"], 181 + ["shared", "pShr"], 182 + ["show", "pShw"], 183 + ["shufflable", "pSfa"], 184 + ["shuffle", "pShf"], 185 + ["size", "pSiz"], 186 + ["skipped_count", "pSkC"], 187 + ["skipped_date", "pSkD"], 188 + ["smart", "pSmt"], 189 + ["song_repeat", "pRpt"], 190 + ["sort_album", "pSAl"], 191 + ["sort_album_artist", "pSAA"], 192 + ["sort_artist", "pSAr"], 193 + ["sort_composer", "pSCm"], 194 + ["sort_name", "pSNm"], 195 + ["sort_show", "pSSN"], 196 + ["sound_volume", "pVol"], 197 + ["special_kind", "pSpK"], 198 + ["start", "pStr"], 199 + ["starting_page", "lwfp"], 200 + ["target_printer", "trpr"], 201 + ["time", "pTim"], 202 + ["track_count", "pTrC"], 203 + ["track_number", "pTrN"], 204 + ["unplayed", "pUnp"], 205 + ["update_tracks", "pUTC"], 206 + ["version", "vers"], 207 + ["video_kind", "pVdK"], 208 + ["view", "pPly"], 209 + ["visible", "pvis"], 210 + ["visual_size", "pVSz"], 211 + ["visuals_enabled", "pVsE"], 212 + ["volume_adjustment", "pAdj"], 213 + ["year", "pYr "], 214 + ["zoomable", "iszm"], 215 + ["zoomed", "pzum"], 216 + ] 217 + 218 + Elements = [ 219 + ["EQ_presets", "cEQP"], 220 + ["EQ_windows", "cEQW"], 221 + ["URL_tracks", "cURT"], 222 + ["application", "capp"], 223 + ["artworks", "cArt"], 224 + ["audio_CD_playlists", "cCDP"], 225 + ["audio_CD_tracks", "cCDT"], 226 + ["browser_windows", "cBrW"], 227 + ["device_playlists", "cDvP"], 228 + ["device_tracks", "cDvT"], 229 + ["encoders", "cEnc"], 230 + ["file_tracks", "cFlT"], 231 + ["folder_playlists", "cFoP"], 232 + ["items", "cobj"], 233 + ["library_playlists", "cLiP"], 234 + ["playlist_windows", "cPlW"], 235 + ["playlists", "cPly"], 236 + ["print_settings", "pset"], 237 + ["radio_tuner_playlists", "cRTP"], 238 + ["shared_tracks", "cShT"], 239 + ["sources", "cSrc"], 240 + ["tracks", "cTrk"], 241 + ["user_playlists", "cUsP"], 242 + ["visuals", "cVis"], 243 + ["windows", "cwin"], 244 + ] 245 + 246 + Commands = [ 247 + ["add", "hookAdd ", [ 248 + ["to", "insh"], 249 + ]], 250 + ["back_track", "hookBack", [ 251 + ]], 252 + ["close", "coreclos", [ 253 + ]], 254 + ["convert", "hookConv", [ 255 + ]], 256 + ["count", "corecnte", [ 257 + ["each", "kocl"], 258 + ]], 259 + ["delete", "coredelo", [ 260 + ]], 261 + ["download", "hookDwnl", [ 262 + ]], 263 + ["duplicate", "coreclon", [ 264 + ["to", "insh"], 265 + ]], 266 + ["eject", "hookEjct", [ 267 + ]], 268 + ["exists", "coredoex", [ 269 + ]], 270 + ["fast_forward", "hookFast", [ 271 + ]], 272 + ["make", "corecrel", [ 273 + ["new", "kocl"], 274 + ["at", "insh"], 275 + ["with_properties", "prdt"], 276 + ]], 277 + ["move", "coremove", [ 278 + ["to", "insh"], 279 + ]], 280 + ["next_track", "hookNext", [ 281 + ]], 282 + ["open", "aevtodoc", [ 283 + ]], 284 + ["open_location", "GURLGURL", [ 285 + ]], 286 + ["pause", "hookPaus", [ 287 + ]], 288 + ["play", "hookPlay", [ 289 + ["once", "POne"], 290 + ]], 291 + ["playpause", "hookPlPs", [ 292 + ]], 293 + ["previous_track", "hookPrev", [ 294 + ]], 295 + ["print", "aevtpdoc", [ 296 + ["print_dialog", "pdlg"], 297 + ["with_properties", "prdt"], 298 + ["kind", "pKnd"], 299 + ["theme", "pThm"], 300 + ]], 301 + ["quit", "aevtquit", [ 302 + ]], 303 + ["refresh", "hookRfrs", [ 304 + ]], 305 + ["resume", "hookResu", [ 306 + ]], 307 + ["reveal", "hookRevl", [ 308 + ]], 309 + ["rewind", "hookRwnd", [ 310 + ]], 311 + ["run", "aevtoapp", [ 312 + ]], 313 + ["search", "hookSrch", [ 314 + ["for", "pTrm"], 315 + ["only", "pAre"], 316 + ]], 317 + ["set", "coresetd", [ 318 + ["to", "data"], 319 + ]], 320 + ["stop", "hookStop", [ 321 + ]], 322 + ["subscribe", "hookpSub", [ 323 + ]], 324 + ["update", "hookUpdt", [ 325 + ]], 326 + ["updateAllPodcasts", "hookUpdp", [ 327 + ]], 328 + ["updatePodcast", "hookUpd1", [ 329 + ]], 330 + ] 331 + end
+13 -9
itunes-rsync.rb
··· 2 2 # $Id: itunes-rsync.rb,v 1.5 2009/01/27 09:11:14 jcs Exp $ 3 3 # 4 4 # rsync the files of an itunes playlist with another directory, most likely a 5 - # usb music device. requires the rubyosa gem ("sudo gem install rubyosa") 5 + # usb music device. 6 + # 7 + # creates symlinks in a scratch directory pointing to the real destination 8 + # directory, then uses rsync to actually copy them out to the destination. 9 + # 10 + # requires the appscript gem 6 11 # 7 - # Copyright (c) 2009 joshua stein <jcs@jcs.org> 12 + # Copyright (c) 2009, 2012 joshua stein <jcs@jcs.org> 8 13 # 9 14 # Redistribution and use in source and binary forms, with or without 10 15 # modification, are permitted provided that the following conditions ··· 31 36 # 32 37 33 38 require "rubygems" 34 - require "rbosa" 39 + require "appscript" 40 + $: << File.dirname(__FILE__) 41 + require "appscript_itunes_fix" 35 42 36 43 if !ARGV[1] 37 44 puts "usage: #{$0} <itunes playlist> <destination directory>" ··· 53 60 54 61 print "querying itunes for playlist \"#{playlist}\"... " 55 62 56 - # disable a stupid xml deprecation warning 57 - $VERBOSE = nil 58 - itunes = OSA.app("iTunes") 63 + itunes = Appscript.app.by_name("iTunes", ITunesFix) 59 64 60 - itpl = itunes.sources.select{|s| s.name == "Library" }.first. 61 - user_playlists.select{|p| p.name.downcase == playlist.downcase }.first 65 + itpl = itunes.playlists[playlist] 62 66 63 67 if !itpl 64 68 puts "could not locate, exiting" 65 69 exit 66 70 end 67 71 68 - tracks = itpl.file_tracks.map{|t| t.location } 72 + tracks = itpl.file_tracks.get.map{|t| t.location.get.path } 69 73 70 74 puts "found #{tracks.length} track#{tracks.length == 1 ? '' : 's'}." 71 75