Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

A script to keep playlists synced with iPhones/iPods iPod
I am always adding to and editing iTunes playlists, particularly the more oft-listened ones like my punk, ambient, and programs & podcasts playlists. Since I listen to a lot of stuff on my iPhone, I naturally want these playlists always available and up-to-date on my device. I can't tell you how many times I plugged in my iPhone to my car stereo and found, to my disappointment, that I forgot to drag-and-drop the most recent version of a playlist to the device.

Why not just set the iPhone to automatically update? Because I want the finite control that manually managing affords me. My experience with auto-updating: unintended results, creates more problems than it solves.

So I created a script that updates a specified list of playlists to all attached iPods/iPhones. It can run on a schedule (with cron), so I never have to worry that my iPhone won't have the most recent versions of my playlists!

Features
  • Adds specified playlists to all iPods attached to your Mac.
  • Will skip the playlist if there's not enough space on an attached device.
  • Retains the order in which the tracks appear on the library playlist.
  • Outputs useful debug info.
You can find the latest version of the script (in case of any changes) in this entry on my site.

Usage

First, the script requires the iPod/iPhone be set to 'Manually manage music and videos.' I named the script updateipod.pl, and placed it in my user's bin directory. It's recommended you specify the playlists that you want to sync in the @playlists array at the top of the script:
my @playlists = (

 "jamz",
 "0pods",
 "punk best",
 "stoner best"
 
 );
After chmoding the script to 755, just invoke it as you would any script: /Users/user/bin/updateipod.pl. Optionally, you can specify the names of the playlists as arguments on the command line, which is useful for one-off updating. Note that if playlists are passed as command-line arguments, they will be processed instead of whatever is specified in the @playlists array at the top of the script.

Make sure to enclose playlist names in quotes if the playlists have spaces or special characters. For example, here's how I'd send three playlists to my connected devices on the command line:
/User/user/bin/updateipod.pl "michael best" 0pods "80's by rory"
I schedule it to run hourly with cron:
0 * * * * /Users/user/bin/updateipod.pl > /dev/null 2>&1
But you can do this if you want more output:
0 * * * * /Users/user/bin/updateipod.pl >> /Users/user/Desktop/ipod_update_log.txt 2>&1
That's it! Here's the script:
#!/usr/bin/perl

# 2009-07-05
# Auto-sync specified playlists to all attached iPods/iPhones
# Specify playlist names in the @playlist array OR enter them
# as arguments (in single quotes) on the command line like this:
#
# $ ./updateipod.pl "michael best" "0pods" "80's by rory"
#
# I run this hourly with the cronjob:
#
# 0 * * * * /Users/user/bin/updateipod.pl > /dev/null 2>&1
# 
# use something like this if you want to see the output for each run:
# 
# 0 * * * * /Users/user/bin/updateipod.pl >> /Users/user/Desktop/ipod_update_log.txt 2>&1
#
# some applescript in this script was borrowed from "Selected Playlists To iPod v2.1" at the very excellent http://www.dougscripts.com/

use strict;
use POSIX qw(strftime);

my @playlists = (

"jamz",
"0pods",
"punk best",
"stoner best"

);

# if there are playlists entered as arguments on the cmd line
# those are gonna trump whatever is specified above
if ($ARGV[0]) {
@playlists = @ARGV;
}

my $time = strftime( "%Y-%m-%d %H:%M:%S",localtime(time));
print "syncing of playlists started at $time\n";

# check if itunes is running, start if not
checkIfRunning();

# get the sources of any attached ipods.  exit if there are none attached.
my ($id_ref,$name_ref) = getiPodSources();
my @ipod_ids = @$id_ref;
my @ipod_names = @$name_ref;
my $devices = @ipod_ids;

# exit if we have no attached ipods
if (!$ipod_ids[0]) {
print "no manually managed iPods detected, exiting...\n";
exit;
}

# make sure the playlists exist in the itunes lib.
my @confirmed_playlists = ();
foreach my $playlist (@playlists) {
my $exists = checkPlaylistExists($playlist);
if($exists) {
 push(@confirmed_playlists,$playlist);
} else {
 print "\"$playlist\" is not a valid playlist in the iTunes library, skipping...\n";
}
}

# make sure we have at least one valid playlist
if (!$confirmed_playlists[0]) {
print "no valid playlists entered, exiting...\n";
exit;
}

# loop thru our ipods first, then within that,
# loop thru our playlists array and sync them to each ipod
for (my $i=0;$i<$devices;$i++) {
foreach my $playlist (@confirmed_playlists) {
 print "telling itunes to sync playlist \"$playlist\" to $ipod_names[$i]\n";
 my $output = syncPlaylist($ipod_ids[$i],$ipod_names[$i],$playlist);
 if ($output ne '1') {
  print "${output}, skipping...\n";
  next;
 }
} # end loop thru playlists
} # end for thru ipods

print "done.\n\n";
exit;

#################################################################################################
###################                      SUBROUTINES                   #####################
#################################################################################################

sub stripNonAlph {
# strips non-alphanumeric characters from strings

my($text) = shift;
$text =~ s/([^0-9a-zA-z ])//g;
return ($text);

} # end sub strip non alph

sub checkIfRunning {
# checks if iTunes is running
# starts it if not

my $start=`/usr/bin/osascript &lt;&lt;END
--start the program if necessary
set isRunning to 0
tell application "System Events"
 set isRunning to ((application processes whose (name is equal to "iTunes")) count)
end tell
if isRunning is 0 then
 tell application "iTunes"
  activate
 end tell
end if
`;

} # end sub check if running

sub getiPodSources {
# gets the system source IDs of any attached ipods
# (assumes there's more than 1 in case there actually are)
# returns in semicolon-delimited list

my $source=`/usr/bin/osascript &lt;&lt;END
tell application "iTunes"
 set validiPods to {}
 set myPods to ""
 set myPodsNames to ""
 set myPodReturn to ""
 set ipodSources to (get every source whose kind is iPod)
 if ipodSources is {} then
  return 0
 end if

 repeat with s in ipodSources
  try -- can't make a playlist on an iPod set to sync automatically, so this will fail.  
   set tp to make new user playlist at s with properties {name:("p)" & my get_temp_name() & "-^")}
   delete tp
   set end of validiPods to s
  end try
 end repeat

 if validiPods is {} then
  return 0
 end if

 repeat with i from 1 to (length of validiPods)
  set myPods to myPods & ";" & id of item i of ipodSources
  set myPodsNames to myPodsNames & ";" & name of item i of ipodSources
 end repeat

 set myPodsReturn to myPods & "|" & myPodsNames
 return myPodsReturn

end tell
to get_temp_name()
 return (get time of (get current date)) as text
end get_temp_name
END`;

chomp($source);
$source =~ /^;(.*?)\|;(.*?)$/;
my ($id,$name) = ($1,$2);
my @ids = split(/;/,$id);
my @names = split(/;/,$name);
return (\@ids,\@names);

} # end sub getiPodSources

sub checkPlaylistExists {
# checks if the itunes playlist exists

my $playlist = shift;
my $exists=`/usr/bin/osascript &lt;&lt;END
tell application "iTunes"
 if (exists playlist "$playlist") then
  return 1
 else
  return 0
 end if
end tell
END`;
$exists = &stripNonAlph($exists);
return ($exists);

} # end check if playlist exist

sub syncPlaylist {
# takes the id of the source (ipod) and the name of the playlist to sync as arguments

my ($ipod_id,$ipod_name,$playlist) = @_;
my $sync = `/usr/bin/osascript &lt;&lt;END

tell application "iTunes"
 set playlistName to "$playlist"
 set main_lib to library playlist 1
 set ipod_src to item 1 of (get every source whose id is $ipod_id)
 set ipod_lib to library playlist 1 of ipod_src
 set playlistSize to 0
 set iPodFreeSpace to free space of ipod_src
 set copySuccess to 0
 set playlistSuccess to 0

 set myPlaylists to (get every user playlist)
 repeat with thisPlaylist in myPlaylists
  if name of thisPlaylist is playlistName then

   --loop thru the playlist to determine if there is enough
   --free space on the ipod for any songs not already on it
   set eop to index of last track of thisPlaylist
   repeat with i from 1 to eop
    --determine if the song is already on ipod lib
    set i_track to track i of thisPlaylist
    if (get class of i_track) is file track then
     tell i_track to set {nom, art, alb, siz, kin, tim, pid} to {get name, get artist, get album, get size, get kind, get time, get persistent ID}
     try
      -- is track already in iPod library?  setting this will fail if not
      set new_i_track to (some track of ipod_lib whose name is nom and artist is art and album is alb and size is siz and kind is kin and time is tim)
     on error -- if not, add size of track to running total of tracks not on ipod
      set playlistSize to playlistSize + siz
     end try
    end if
   end repeat --thru selected playlist

   if free space of ipod_src is greater than playlistSize then
    -- establish iPod playlist
    try
     --does the iPod playlist already exist?  if so we delete it.
     --why?  because if we add additional tracks to the end of it, the track list will no be in the 
     --same order as they are on our iTunes playlist
     set new_ipodplaylist to user playlist playlistName of ipod_src
     delete new_ipodplaylist
     set new_ipodplaylist to (make new user playlist at ipod_src with properties {name:playlistName})
    on error
     -- if not, create the new iPod playlist
     set new_ipodplaylist to (make new user playlist at ipod_src with properties {name:playlistName})
    end try

    --I'm not checking to see if the tracks already exist on the ipod before copying
    --because it *appears* itunes won't duplicate them.  maybe this is a new feature
    try
     duplicate (every track of thisPlaylist) to ipod_lib
     set copySuccess to 1
    on error
     return "error copying tracks to iPod $ipod_name"
     set copySuccess to 0
    end try
    try
     duplicate (every track of thisPlaylist) to new_ipodplaylist
     set playlistSuccess to 1
    on error
     return "error duplicating track listing to playlist $playlist on iPod $ipod_name"
     set playlistSuccess to 0
    end try

    if copySuccess is 1 and playlistSuccess is 1 
     return 1
    end if

   else
    return "not enough free space on iPod $ipod_name to copy all tracks on $playlist"
   end if

  end if --current playlist = selected playlist
 end repeat

end tell
`;
$sync = &stripNonAlph($sync);
return ($sync);

} # end sub syncPlaylist

__END__
[robg adds: I haven't tested this one.]
    •    
  • Currently 1.11 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (9 votes cast)
 
[7,291 views]  

A script to keep playlists synced with iPhones/iPods | 14 comments | Create New Account
Click here to return to the 'A script to keep playlists synced with iPhones/iPods' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
A script to keep playlists synced with iPhones/iPods
Authored by: wsdr on Jul 10, '09 12:33:57PM

Why not just setup a smart playlist that includes the "specified list of playlists" as the criteria, and sync that? This is a serious question. Am I missing something here?

---
--
http://billread.blogspot.com/



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: boxcarl on Jul 10, '09 04:37:09PM

Even easier: Make an iTunes folder called "iPhone"/"iPod" and put the playlists you want synchronized into it.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: midget2000x on Jul 10, '09 09:30:47PM

and sync it how?



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: vincentvw on Jul 11, '09 03:28:42AM

You can set specific playlists to auto-sync with your iPod. It's really not that complicated, except for building the initial smart-list parameters.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: midget2000x on Jul 11, '09 09:50:01AM

I know it's not complicated. The whole idea of this script is to avoid auto-syncing anything, because it causes problems.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: leamanc on Jul 11, '09 12:13:32PM

What you are missing is that he doesn't want to turn on auto-syncing. I have been looking for a script like this because I like having certain playlists sync'ed all the time, but would still like to drag and drop arbitrary files to my iPods and iPhone. Once you turn on auto-syncing, you can only sync playlists or your whole library.

Apple should really offer more flexibility in this regard. You can sync podcasts, photo libraries, address book contacts, etc., without turning on full auto-sync for your iPod/iPhone. Why not offer the ability to sync selected playlists, and still do manual control?

I will be trying out this script, because right now I am in the same boat the author describes in the beginning of the hint--I have to manually update my playlists, and often forget to do so on one device or another.



[ Reply to This | # ]
iTunes supports this already
Authored by: ascarid68 on Jul 10, '09 04:59:38PM

How about using the built in ability to sync only particular playlists to the iPod. Music Tab -> Sync Music -> Selected Playlists. Check the ones you want to keep synced, and it does, every time you sync.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: dethbunny on Jul 10, '09 09:01:09PM

I'll agree with the other commenters - WTH?

Please expand upon the reasons/problems you were having with automatic syncing. That's the way I've handled my iPhone, and my nano before it. It's just too simple, and gets the same behavior that you're trying to get.

For those extra things that don't really fit in a "playlist" so to speak but I still want on my iPhone, there's a special one called "iPhone Singles" that's filled with random stuff.

Anyway, fun way to work around the system, but I just don't see the need for it.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: leamanc on Jul 11, '09 12:16:10PM

Please see my (leamanc) reply to the first comment above for some additional insight into what this script provides vs. turning on syncing of playlists.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: midget2000x on Jul 10, '09 09:28:08PM

The manual syncing is a personal preference. But one BIG problem with automatic syncing is that if you have your music library on an external drive and plug in your ipod and that drive's not attached, it deletes all the music on your ipod.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: GaelicWizard on Jul 12, '09 09:10:43AM

No it doesn't. Please don't make sh*t up. Its bad enough that this hint got run to begin with.

---
Pell



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: midget2000x on Jul 12, '09 10:38:04AM

whiz, you're right, I made it all up. Negative Nancy, always on the job, keeping people honest! Good work, sleuth.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: boxcarl on Jul 13, '09 03:55:43PM

Well, he's right. ITunes doesn't delete songs that can't be found (have a ! by them) from an i-whatever during autosync. To get them deleted, you have to synchronize with an empty library, which is very different from a ! filled library.



[ Reply to This | # ]
A script to keep playlists synced with iPhones/iPods
Authored by: midget2000x on Jul 14, '09 10:17:15AM

Unfortunately, he is. I just hate it when d-bags are right, it makes them into bigger d-bags. The problem wasn't that my drive wasn't attached, it was that I synced it with a computer that didn't have my library on it. Anyway, I do not use autosync for this, and other reasons (see leamanc's post).



[ Reply to This | # ]