Category: Javascript


I happen to have an iPhone and an iPod Touch sync’d to my iTunes back in the US, but now I’m in Iraq and don’t have access to my computer with the iTunes library on it. I do have the music, but I don’t want to sync my iPod to my iTunes because all the play counts and ratings will be gone. I had a little free time last night so I wrote a script to update these attributes for me! It is written in JScript/JavaScript and uses the iTunes COM Interface to communicate with your device and the iTunes Library. It is not optimized very well so it will iterate over the entire iTunes Library for each track it encounters on your device, looking for a matching Artist, Album and Track Name to update. It also maintains a log file that lists every track that was updated including it’s old and new values, as well as any tracks on the iPod/iPhone that it could not find a match for in the iTunes Library. I created this script for my own purposes and decided to share it, so I don’t intend to provide much support for it. The zip file contains two files: UpdatePlayCount.bat and UpdatePlayCount.js. Extract the files somewhere, plug in your iPod/iPhone, then open iTunes and click on your device, then check “Manually manage music and movies” and restart iTunes, then double click on UpdatePlayCount.bat to update your library. You can see that progress is being made in iTunes by clicking on your Library’s Music folder then sorting the music by Play Count or Rating. This list is updated in real time.

Download UpdatePlayCount.zip (2KB)

Source Code (JScript/JavaScript)

/**
 * UpdatePlayCount.js
 *
 * Description
 * ---------------------------------------------------------------------------------------------------------
 * This script will update your iTunes library with the play counts and ratings from any iPod or iPhone.
 * It uses the iTunes COM Interface to communicate with your device.  In order to determine which tracks
 * match, the script will search through the iTunes Library looking for a matching Artist, Album and Title;
 * as a result, this process can take a long time.  Updates all the music and movies in the "Music" and
 * "Movies" playlists on your device.  If you need to update more folders you can modify the code.
 *
 * Usage
 * ---------------------------------------------------------------------------------------------------------
 * Double click on UpdatePlayCount.bat
 *
 *
 * @package UpdatePlayCount
 * @author Steve Kamerman, stevekamerman AT gmail.com
 * @version Alpha 1.0 $Date: 2009/12/22 13:19
 * @license http://www.mozilla.org/MPL/ MPL Vesion 1.1
 * @language Microsoft JScript / JavaScript
 *
 */


var logObject, logFile;
var logfileName = "UpdateItunes.log";
logObject = new ActiveXObject("Scripting.FileSystemObject");
logFile = logObject.CreateTextFile(logfileName, true);

var ITTrackKindFile = 1;
var iTunesApp = WScript.CreateObject("iTunes.Application");
var sources = iTunesApp.Sources;
var i;
var updateTracksCount = 0;
var missingTracksCount = 0;
var ipod;
var itunes;
var playlists;
var itunesPlaylists;
var iTunesXML;
iTunesXML = "";

for(i=1;i<sources.Count;i++){
    if(sources.Item(i).Kind == 2){
        ipod = sources.Item(i);
        playlists = ipod.Playlists;
    }
    if(sources.Item(i).Kind == 1){
        itunes = sources.Item(i);
        itunesPlaylists = itunes.Playlists;
    }
}

if(ipod == undefined){
    WScript.Echo("Error: No iPod or iPhone found.  Please make sure your device is listed in iTunes, then click on it's name and check "Manually manage music and videos".  Restart iTunes and rerun this script.");
    WScript.Quit(0);
}
WScript.Echo("iPod found, press OK to update iTunes with the play counts and ratings from your iPod.");
WScript.Echo("This process can take a long time to complete.  To monitor the progress,\nopen iTunes and click on your iTunes Music folder\nthen sort by play count or rating and watch them change.\nPress OK to continue");
var currentPlaylist;
var currentTracks;
var currentTrack;
for(i=1;i<playlists.Count;i++){
    currentPlaylist = playlists.Item(i);
    if(currentPlaylist.Name != "Music" && currentPlaylist.Name != "Movies")continue;
    currentTracks = currentPlaylist.Tracks;
    for(a=1;a<currentTracks.Count;a++){
        currentTrack = currentTracks.Item(a);
        if(currentTrack.PlayedCount > 0){
            updateITunesEntry(currentPlaylist.Name,currentTrack.Artist,currentTrack.Album,currentTrack.Name,currentTrack.PlayedCount,currentTrack.Rating);
        }
    }
}

WScript.Echo("Finished processing "+(updateTracksCount+missingTracksCount)+" tracks.\nUpdated Tracks: "+updateTracksCount+"\nMissing Tracks: "+missingTracksCount+"\nSee the logfile ("+logfileName+") for more details.");

function updateITunesEntry(playlist, artist, album, song, playCount, rating){
    var itunesPlaylist;
    var itunesTracks;
    var itunesTrack;
    var i;
    var a;
    for(i=1;i<itunesPlaylists.Count;i++){
        itunesPlaylist = itunesPlaylists.Item(i);
        if(itunesPlaylist.Name != playlist)continue;
        itunesTracks = itunesPlaylist.Tracks;
        for(a=1;a<itunesTracks.Count;a++){
            itunesTrack = itunesTracks.Item(a);
            if(itunesTrack.Artist == artist && itunesTrack.Album == album && itunesTrack.Name == song){
                logFile.WriteLine(itunesTrack.Name+": count: "+itunesTrack.PlayedCount+"->"+playCount+", rating: "+itunesTrack.Rating+"->"+rating);
                itunesTrack.PlayedCount = playCount;
                itunesTrack.Rating = rating;
                updateTracksCount++;
                return(1);
            }
        }
    }
    missingTracksCount++;
    logFile.WriteLine("WARNING: Track not found in iTunes Library: "+artist+" - "+song);
}

UPDATE 25Feb2008 – Adobe has published the recommended workaround for this problem.

This is another major release – I rewrote some of the code with some inspiration from Zelph.com’s onDOMload as suggested by Geoff Stearns, Author of SWFObject. I have now optimized the code to the point where all you need to do is include it in the head of your document and as the page loads, each object will be fixed, so by the time the page is done loading, everything is fixed automatically!

———EDIT 19Jan2007———
I found yet another IE bug related to this topic. After a page is cached by IE and reloaded, the SWF is loaded before it’s embedded, so any callback functions the the SWF tries to setup when it loads (like the JS->Flash ExternalInterface code) will fail with an error “objectID” is undefined. Then when you try to use the callback function you get Object doesn’t support this property or method because the functions didn’t get assigned to the Flash object properly.

To fix this error you need to put this line above your SWFObject code (or above your <object> tag):

window["objectid"] = new Object();

Here’s an example document:
http://devel.teratechnologies.net/swfformfix/extinterface-swfformfix2.php

You can download SWFFormFix2 Here:
http://devel.teratechnologies.net/swfformfix/swfformfix2.js

You can see the nicely formatted and highlighted source code here:
http://devel.teratechnologies.net/swfformfix/swfformfix2.js.source

Here’s a great example of bi-directional communication with Flash / Actionscript and Javascript inside an HTML form using SWFObject with my SWFFormFix patch.

http://devel.teratechnologies.net/swfformfix/extinterfaceexample.php

Unlike my previous example pages, this one includes the source code for the Flash movie (the FLA). Let me know if you like it!

I have patched the newest version of SWFObject (1.5) to include FlashFormFix 1.0.0. If you use this version in place of the standard SWFObject it will automatically apply SWFFormFix (bugfix for ExternalInterface() in a Form with IE) when you use it – this means all you have to do is replace your standard swfobject.js with the new swfobject_swfformfix.js and you’re done!

Here’s the optimized version:
http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix.js
(to download it right click and “Save Link As” or something similar)

Here’s the human-readable version in case you want to see what I changed:
http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
(to download it right click and “Save Link As” or something similar)

I just finished SWFFormFix 1.0.0 – a BIG update from the 0.1.0 prerelease! This new version introduces Auto Mode which takes care of everything for you! All you need to do is include the script in you and call SWFFormFixAuto() before the closing tag!

For more specific instructions or to download it go here:

http://devel.teratechnologies.net/swfformfix/swfformfix.js
(to download it right click and “Save Link As” or something similar)

This version also contains an updated version of the previous function “SWFFormFix()” that is more optimized and probably faster than the Auto version.

It seems every time I try something new I need to fix other people’s problems to get it to work, arrrrg! [:(] I decided to try use Flash 8’s ExternalInterface() class to communicate with the Javascript function on my page. I liked the sound of this method because I can pass an array of arguments with it and return a variable back from the Javascript to my Actionscript – all in one command! I whipped something up real quick and bam! it works! Then I moved the SWF into it’s destination: the middle of an HTML form – to my amazement it didn’t work! I was using Internet Explorer 6, so I tried Firefox 2.0 and it worked fine. It also worked fine in Firefox 1.5 (a little less compatible) and even Opera 9.00 Beta! Wow, seriously IE – you got beat by Opera Beta [:P]. It also failed in IE7. To make a long story short, I spent 6+ hours trying to figure out what was wrong – finally I realized the code was fine and it was a IE bug. There’s a bunch of speculation and suggested fixes on the Adobe / Macromedia Flash 8 ExternalInterface() LiveDocs page, but they’re either overly-complicated or they don’t work. So I sat down and figured it out, then I made my own fix, which I consider to be very easy :D.

Here’s the solution: SWFFormFix by me, Steve Kamerman 😀. Here’s the deal, basically, you need to trick Internet Explorer because if you put an object in a form, IE’s implementation of Javascript seems to want to look for “window.yourObject” and not “document.form[x].yourObject”, so my script figures out which form you are in and makes an alias at the wrong location that points to the right location. Don’t believe me? Try it out.

Here are some examples:
A SWF outside of a FORM (using SWFObject to embed)
A SWF inside of a FORM (using SWFObject to embed)
A SWF inside of a FORM (using std Flash EMBED tags)
A SWF inside of a FORM (using SWFObject and SWFFormFix)

As you should see, SWFFormFix fixes the problem and leaves you with zero errors – plus it’s free!

Download SWFFormFix:
http://devel.teratechnologies.net/swfformfix/swfformfix.js

Usage:
1. Include the swfformfix.js script in the head of your document

<html>
<head>
<script type="text/javascript" src="swfformfix.js"></script>
</head>

2. Run the SWFFormFix(yourObject) command on your SWF.

Example with SWFObject (recommended):

<div id="swfdiv_ttpreview" style="width:200px;height:100px;">
This is replaced by the Flash movie.
</div>
<script type="text/javascript">
// <![CDATA[
 var so = new SWFObject("myMovie.swf", "myMovieObjectName",
"200", "100", "6.0.0", "#ffffff");
 so.addParam("quality", "high");
 so.write("swfdiv_ttpreview");
 SWFFormFix("myMovieObjectName");
// ]]>
</script>

Example with std Flash EMBED tags:

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
width="200" height="100" id="myMovieObjectName" align="middle">
<param name="movie" value="myMovie.swf" />
<param name="quality" value="high" />
<embed src="myMovie.swf" quality="high" width="200" height="100"
name="myMovieObjectName" type="application/x-shockwave-flash" />
</object>
<script type="text/javascript">
// <![CDATA[
 SWFFormFix("myMovieObjectName");
// ]]>
</script>

If you are still using the old school EMBED tags, you should really get with the program and start using SWFObject!! SWFObject (by Geoff Stearns) not only cleans up your code, but it removes the annoying gray box around your Flash movies in Internet Explorer 7 (or earlier with updates). I made a nice little script called HTML2SWFObject a couple months back that converts your old EMBED code to SWFObject code – check it out!

Have you ever seen the annoying gray box around Flash content on websites? If you have, you must have done the unthinkable and used Windows Update [:O]. To make a long story short, a company called Eolas Technologies got in a yelling match with Microsoft and the two companies have since tried to make life more difficult for each other. Microsoft decided to require Internet Explorer users to click once on EVERY ActiveX control (actually anything in an EMBED or OBJECT tag) as a safety precaution. You can read more about that battle here: Microsoft tweaks browser to avoid liability | CNET News.com. The solution to this problem is to embed the object in the page dynamically – after the page is loaded. This is exactly what SWFObject by deconcept does – and it does it well! SWFObject is also capable of Flash Player version detection in Javascript and has been used on some big name sites like YouTube.

Everytime I want to use SWFObject I am annoyed that I don’t remember the syntax, so I wrote a nice little script that will convert the <object>…</object> code that you get when you publish in Flash into SWFObject friendly code! The script is located here:

http://devel.teratechnologies.net/swfhelp/

As an example, it will convert this HTML code:

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash
/swflash.cab#version=8,0,0,0" width="100" height="50" id="flashtab"

align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="flashtab.swf" />
<param name="quality" value="high" />
<param name="wmode" value="transparent" />
<param name="bgcolor" value="#ffffff" />
<embed src="flashtab.swf" quality="high" wmode="transparent"
bgcolor="#ffffff" width="100" height="50" name="flashtab"
align="middle" allowscriptaccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>

To this SWFObject code:

<div id="swfdiv_flashtab">  
This text is replaced by the Flash movie.  
</div>  
<script type="text/javascript">  
  var so = new SWFObject("flashtab.swf", "flashtab", "100", "50",
"8.0.0", "#ffffff");  
  so.addParam("allowscriptaccess", "samedomain");  
  so.addParam("quality", "high");  
  so.addParam("wmode", "transparent");  
  so.write("swfdiv_flashtab");  
</script>