Extended iTunes Track class for PHP

  • September 26, 2010
  • James Skemp
  • article

In a previous article, I had outlined classes in C# and PHP to handle iTunes Playlists to Xml outputs.

Having let it sit on the back burner for long enough, I finally went back to the PHP class and finalized the constructor. I also added two functions for sorting.

Below I have the current code for the class (a current version of the Track class for PHP will always be available elsewhere) and then an example implementation.

Track class for PHP, version 1.0

<?php
/**
 * Music track object.
 *
 * @author James Skemp - http://jamesrskemp.com
 * @license http://creativecommons.org/licenses/by/3.0/us/
 * @version 1.0
 */
class Track {
    /**
     * How long the track is.
     * @var string
     */
    var $Time;
    /**
     * Name or title of the track.
     * @var string
     */
    var $Name;
    /**
     * Name of the artist.
     * @var string
     */
    var $Artist;
    /**
     * Rating assigned to the track by the playlist's owner.
     * @var int
     */
    var $Rating;
    /**
     * Number of times the track has been played.
     * @var int
     */
    var $PlayCount;
    /**
     * Date and time the track was last played (and finished).
     */
    var $LastPlayed;
    /**
     * Name of the album the track is from.
     * @var string
     */
    var $Album;
    /**
     * True if the album the track is on is a compilation, false otherwise.
     * @var bool
     */
    var $Compilation;
    /**
     * Order this track is on the album.
     * @var int
     */
    var $TrackNumber;
    /**
     * Total number of tracks on the album.
     * @var int
     */
    var $TrackCount;
    /**
     * The album disc the track is on.
     * @var int
     */
    var $DiscNumber;
    /**
     * Total number of discs in the album.
     * @var int
     */
    var $DiscCount;
    /**
     * Year the track/album was released/published.
     * @var int
     */
    var $Year;
    /**
     * Genre of music the track falls into.
     * @var string
     */
    var $Genre;
    /**
     * Date and time the track was added.
     */
    var $DateAdded;

    public function  __get($name) {
        return $this->$name;
    }

    public function  __set($name, $value) {
        $this->$name = $value;
    }

    /**
     * Constructs a Track object from an iTunes Playlists to Xml XML output file.
     *
     * @param object $xml
     */
    function __construct($xml) {
        $this->Name = (string)$xml->name;
        $this->Album = (string)$xml->album;
        $this->Artist = (string)$xml->artist;
        $this->Time = (string)$xml['time'];
        $this->Rating = (int)$xml->rating;
        $this->PlayCount = (int)$xml->playCount;
        $this->LastPlayed = (string)$xml->lastPlayed;
        $this->Compilation = (bool)$xml->compilation;
        $this->TrackNumber = (int)$xml->trackNumber;
        $this->TrackCount = (int)$xml->trackCount;
        $this->DiscNumber = (int)$xml->discNumber;
        $this->DiscCount = (int)$xml->discCount;
        $this->Year = (int)$xml->year;
        $this->Genre = (string)$xml->genre;
        $this->DateAdded = (string)$xml->dateAdded;
    }

    /**
     * Function for sorting Track objects by PlayCount, ascending. Uses LastPlayed for ties.
     *
     * @access public
     * @param Track $x First object to compare.
     * @param Track $y Second object to compare.
     * @return integer Standard sorting returns.
     */
    public function SortPlayCountAsc($x, $y) {
        if ($x->PlayCount == $y->PlayCount) {
            if ($x->LastPlayed == $y->LastPlayed) {
                return 0;
            } else if ($x->LastPlayed < $y->LastPlayed) {
                return -1;
            } else {
                return 1;
            }
        } else if ($x->PlayCount < $y->PlayCount) {
            return -1;
        } else {
            return 1;
        }
    }

    /**
     * Function for sorting Track objects by PlayCount, descending. Uses LastPlayed for ties.
     *
     * @access public
     * @param Track $x First object to compare.
     * @param Track $y Second object to compare.
     * @return integer Standard sorting returns.
     */
    public function SortPlayCountDesc($x, $y) {
        if ($x->PlayCount == $y->PlayCount) {
            if ($x->LastPlayed == $y->LastPlayed) {
                return 0;
            } else if ($x->LastPlayed > $y->LastPlayed) {
                return -1;
            } else {
                return 1;
            }
        } else if ($x->PlayCount < $y->PlayCount) {
            return 1;
        } else {
            return -1;
        }
    }
}
?>

Usage example

Update XML file location as necessary. Note also I'm using the Windows Cache Extension for PHP. Modify the initial if statement accordingly if running in an environment that does not have this enabled.

<?php include_once 'Track.php'; ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Track class example</title>
        <style type="text/css">
            .error {
                color:red;
            }
        </style>
    </head>
    <body>
        <?php
            $tracks = array();

            // Determine if we've already grabbed this for the user and either pull or populate their cache.
            if (!wincache_ucache_exists('tracksData')) {
                $xml = @simplexml_load_file('playlistXml-2010-09-25T15-26-50.xml');

                if (!$xml) {
                    echo '<p class="error">Could not load XML data.</p>';
                } else {
                    echo "Start creating array of tracks.<br />";

                    foreach($xml->track as $trackXml) {
                        $tracks[] = new Track($trackXml);
                    }
                    unset($trackXml);

                    echo "Finished creating array of tracks.<br />";

                    wincache_ucache_set('tracksData', $tracks);
                }
                unset($xml);
            } else {
                $tracks = wincache_ucache_get('tracksData');
            }

            echo "Count = ".count($tracks)."<br />";

            usort($tracks, array('Track', 'SortPlayCountDesc'));

            echo "<pre>";
            //var_dump($tracks[2]);
            echo "</pre>";

            echo "<pre>";
            for ($i = 0; $i < 10; $i++) {
                var_dump($tracks[$i]);
            }
            unset($i);

            unset($tracks);
        ?>
    </body>
</html>

Memory usage seems a bit high at the end of this script, but ... at this point I'm not sure what the fix is.

The fact that PHP doesn't have an easy way to store data in an application cache (in memory) is rather disappointing, so other than fixing minor bugs, I don't expect I'll expand too much on this implementation.