So I finally took the time to try and do something about this.
Thanks to YourMum's suggestion (I just love writing this), I went ahead and made use of the log file that Firefly can generate. You should configure the debug level so that the log file contains the filename of the songs it streams to the Roku. I'm using Debug Level 5.
I wrote a javascript (I'm on a WinXP machine) that reads the log file, and tries to determine which song was played based on song title, track number, and filename. When there is a match I update the playcounter and the playeddate accordingly.
I am going to run this script on a regular basis so that my XP iTunes installation is aware of what was played on the Roku in the living room, probably using the Task Scheduler.
I am by no means a great coder so I'm sure the script below is not perfect. I was lazy and hardcoded a few things. However it is moderately commented. Oh and performance (meaning speed) is terrible but function matters most for me.
Usual caveats - I tested this for a few days at home but make no claims and will not be held responsible if your computer catches fire or a plane engine crashes on your roof
/*
File: UpdateTrackLog.js
Take mtdaapd.log and update the PlayCount/LastPlayTime accordingly
Version: 1.0
*/
var ITTrackKindFile = 1;
var iTunesApp = WScript.CreateObject("iTunes.Application");
var mainLibrary = iTunesApp.LibraryPlaylist;
var tracks = mainLibrary.Tracks;
var i;
var numScanned = 0;
var numUpdated = 0;
var numLogLine = 0;
var verbose = true;
objFSO = WScript.CreateObject("Scripting.FileSystemObject");
// Open the log file
objTextFile = objFSO.OpenTextFile("Z:\\mt-daapd.log", 1);
objLogFile = objFSO.CreateTextFile("D:\\My Documents\\My Music\\iTunes\\messages.log", true);
while (objTextFile.AtEndOfStream == 0)
{
// read line
strLine = objTextFile.Readline();
numLogLine++;
// split timestamp and msg
strSplitLog = strLine.split("): ");
strTimeStamp = strSplitLog[0];
strMessage = strSplitLog[1];
if ((strTimeStamp == null) || (strMessage == null))
{
if (verbose)
objLogFile.WriteLine ("LOG: Cannot split timestamp/message on line " + numLogLine);
}
else
{
strDate = strTimeStamp.substr(0, 10);
strTime = strTimeStamp.substr(11, 8);
// does the Message contain "Session 0: Streaming file " ???
re = /Session 0: Streaming file '/
numMatches = 0;
if (strMessage.search(re) == 0)
{
// OK this line matches our pattern now let's get the file name between quotes
if (verbose)
objLogFile.WriteLine ("LOG: Found song on line " + numLogLine + " : \"" + strMessage + "\"");
numScanned++;
strSongFileName = strMessage.substring(27, strMessage.indexOf(".mp3'") );
strSplitFileName = strSongFileName.split(" - ");
strSongNumber = strSplitFileName[0];
strSongTitle = strSplitFileName[1];
if (verbose)
objLogFile.WriteLine ("LOG: song is \"" + strSongTitle + "\" and track number is " + strSongNumber);
// now search the song in iTunes with IITPlaylist::Search
// hardcoded 5 is for search in title
if (strSongTitle == null)
{
objLogFile.WriteLine ("LOG: cannot determine title and/or track number - exiting");
splayList = null;
}
else
splayList = mainLibrary.search(strSongTitle, 5);
if (splayList == null)
{
numHits = 0;
if (verbose)
objLogFile.WriteLine ("ITUNES: \"" + strSongTitle + "\" " + "not found");
}
else
{
numHits = splayList.Count;
if (verbose)
objLogFile.WriteLine ("ITUNES: \"" + strSongTitle + "\" found " + numHits + " time(s)");
}
for (i = 1; i <= numHits; i++)
{
if (verbose)
objLogFile.WriteLine ("ITUNES: Hit #" + i + " points to " + splayList.Item(i).Location);
if (splayList.Item(i).TrackNumber == strSongNumber)
{
if (verbose)
objLogFile.WriteLine ("ITUNES: Hit #" + i + " also matches track number");
// okay so the search above is not an exact match. Ie for a song titled "wrong", the search
// will return all songs that contain "wrong" in the title
// so I need to search on filename. Easy for the LOG, but for the iTunes file I will
// need to clean up the location... (ie remove path)
strTemp = splayList.Item(i).Location.split("\\");
strFileName = strTemp[strTemp.length-1];
// now compare strFileName with strSongFileName.mp3
if (strFileName == (strSongFileName + ".mp3"))
{
if (verbose)
objLogFile.WriteLine("ITUNES: file name match for \"" + strSongFileName + ".mp3\"");
numMatches++;
}
if (numMatches == 1)
{
if (verbose)
objLogFile.WriteLine ("ITUNES: Playcount was " + splayList.Item(i).PlayedCount + ", PlayedDate was " + splayList.Item(i).PlayedDate);
dBefore = splayList.Item(i).PlayedDate;
logYear = strDate.substring(0,4);
logMonth = strDate.substring(5,7);
logDay = strDate.substring(8,10);
logHour = strTime.substring(0,2);
logMinutes = strTime.substring(3,5);
logSeconds = strTime.substring(6,8);
dAfter = new Date();
dAfter = logDay + "/" + logMonth + "/" + logYear + " " + logHour + ":" + logMinutes + ":" + logSeconds;
//if (verbose)
// objLogFile.WriteLine ("DLOG: " + dAfter);
splayList.Item(i).PlayedDate = dAfter;
splayList.Item(i).PlayedCount++;
numUpdated++;
if (verbose)
objLogFile.WriteLine ("ITUNES: Playcount is now " + splayList.Item(i).PlayedCount + ", PlayedDate is now " + splayList.Item(i).PlayedDate);
}
else
{
if (numMatches == 0) {}
else
{
if (verbose)
objLogFile.WriteLine("More than one match for " + strSongFileName + " - doing nothing");
i = numHits + 1;
}
}
}
}
}
}
} //while (objTextFile.AtEndOfStream == 0)
// we're done, print some numbers
objLogFile.WriteLine ("DONE: Scanned " + numScanned + " songs, updated " + numUpdated);
WScript.Echo ("DONE: Scanned " + numScanned + " songs, updated " + numUpdated);
objTextFile.Close();
objLogFile.Close();
if (verbose)
WScript.Echo ("Log file is D:\\My Documents\\My Music\\iTunes\\messages.log");
WScript.Echo ("You should probably delete Z:\\mt-daapd.log now");
// ENDFILE