time(); $headers = array('Content-type: text/html; charset=UTF-8'); $status = '200 OK'; function sendHead() { global $headers, $status; header('HTTP/1.1 '.$status); foreach ($headers as $header) { header($header); } } if ($cacheValid) { $etag = md5($cacheStat['dev'].':'.$cacheStat['ino'] .':'.$cacheStat['size'].':'.$cacheStat['mtime']); $headers[] = 'Last-modified: '.gmdate('r', $cacheStat['mtime']); $headers[] = 'Etag: "'.$etag.'"'; if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { if ($etag === trim($_SERVER['HTTP_IF_NONE_MATCH'],'"')) { $headers[] = 'Content-length: 0'; $status = '304 Not Modified'; sendHead(); exit(0); } } $headers[] = 'Content-length: '.$cacheStat['size']; sendHead(); readfile($cachePath); exit(0); } $headers[] = 'Cache-control: must-revalidate'; $albums = array(); $vaAlbums = array(); $fetchPageLimit = 5; $totalResults = $startIndex = $itemsPerPage = 0; function loadCountryCodesMap($path) { $map = array(); $buf = file_get_contents($path); $buf = explode("\n", $buf); foreach ($buf as $line) { $line = explode("\t", $line); if (count($line) > 1 && strlen($line[0]) === 2) { $map[$line[0]] = $line[1]; } } return $map; } $allCountries = loadCountryCodesMap($baseDir.'/ISO-3166-1-alpha-2-country-codes.tsv'); $spotifyCountries = loadCountryCodesMap($baseDir.'/ISO-3166-1-alpha-2-country-codes-spotify.tsv'); $spotifyCountriesList = array_keys($spotifyCountries); function countryCodeToName($xx) { global $allCountries; return isset($allCountries[$xx]) ? $allCountries[$xx] : $xx; } function spotifyCountriesFilter($v) { global $spotifyCountries; return isset($spotifyCountries[$v]); } function xe($s) { static $u = array('&','"','<','>'); static $e = array('&','"','<','>'); return str_replace($u, $e, $s); } function firstChild($node, $nodeName) { $nl = $node->childNodes; for ($i=0;$ilength,4);$i++) { $n = $nl->item($i); if ($n->nodeType === XML_ELEMENT_NODE && $n->nodeName === $nodeName) { return $n; } } } function parseArtist($n) { return (object)array( 'uri' => $n->getAttribute('href'), 'name' => firstChild($n, 'name')->nodeValue, ); } function parseId($n) { return (object)array( 'type' => $n->getAttribute('type'), 'id' => $n->nodeValue, 'href' => $n->hasAttribute('href') ? $n->getAttribute('href') : null, ); } function parseAvailability($n) { global $spotifyCountriesList; $terrs = array(); $unrestricted = false; $nl = $n->childNodes; for ($i=0;$i<$nl->length;$i++) { $n2 = $nl->item($i); if ($n2->nodeName === 'territories') { if ($n2->nodeValue === 'worldwide') $unrestricted = true; else $terrs = explode(' ', $n2->nodeValue); break; } } $terrs = array_filter($terrs, 'spotifyCountriesFilter'); if (!$unrestricted) $unrestricted = count($terrs) === count($spotifyCountriesList); return (object)array( 'unrestricted' => $unrestricted, 'territories' => $unrestricted ? array() : $terrs, ); } function parseAlbum($n) { $artists = array(); $ids = array(); $album = array( 'uri' => $n->getAttribute('href'), 'name' => null, 'artists' => array(), 'ids' => array(), 'popularity' => 0.0, 'isVariousArtists' => false, 'availability' => (object)array( 'unrestricted' => false, 'territories' => array()), ); $nl = $n->childNodes; for ($i=0;$i<$nl->length;$i++) { $n2 = $nl->item($i); if ($n2->nodeType === XML_ELEMENT_NODE) { switch ($n2->nodeName) { case 'name': $album['name'] = $n2->nodeValue; break; case 'artist': $artist = parseArtist($n2); $artists[] = $artist; if ($album['isVariousArtists'] === false) $album['isVariousArtists'] = ($artist->name === 'Various Artists' ? true : false); break; case 'id': $ids[] = parseId($n2); break; case 'popularity': $album['popularity'] = floatval($n2->nodeValue); break; case 'availability': $album['availability'] = parseAvailability($n2); break; } } } $album['artists'] = $artists; $album['ids'] = $ids; return (object)$album; } $totalPages = 1; for ($pageNo = 1; $pageNo <= $totalPages; $pageNo++) { $startIndex = $itemsPerPage = 0; # reset $dom = new DOMDocument(); $xml->preserveWhiteSpace = false; if ($isDevel) $dom->load(sprintf('page%d.xml', $pageNo)); else $dom->load('http://ws.spotify.com/search/1/album?q=tag:new&page='.$pageNo); $doc = $dom->documentElement; $nl = $doc->childNodes; for ($i=0;$i<$nl->length;$i++) { $n = $nl->item($i); if ($n->nodeType === XML_ELEMENT_NODE) { switch ($n->nodeName) { case 'opensearch:totalResults': $totalResults = max(intval($n->nodeValue), $totalResults); if ($itemsPerPage !== 0) $totalPages = ceil($totalResults/$itemsPerPage); break; case 'opensearch:startIndex': $startIndex = intval($n->nodeValue); break; case 'opensearch:itemsPerPage': $itemsPerPage = intval($n->nodeValue); if ($totalResults !== 0) $totalPages = ceil($totalResults/$itemsPerPage); break; case 'album': $album = parseAlbum($n); if ($album->availability->unrestricted || count($album->availability->territories)) { # separate VA so we can put the at bottom later if ($album->isVariousArtists) $vaAlbums[] = $album; else $albums[] = $album; } break; } } } if ($isDevel) break; } # mux vaAlbums foreach ($vaAlbums as $album) $albums[] = $album; ob_start(); ?> New releases on Spotify

New releases on Spotify

Showing the latest albums released during the last 7 days, sorted on artist popularity. Updated UTC.

    $album): ?>
  1. name)?> by artists as $artist) { $buf[] = 'uri ? ' href="'.xe($artist->uri).'"':'').'>' .xe($artist->name).''; } echo implode(', ',$buf); ?>

    availability->unrestricted): ?> Available to all Spotify users. Only available in availability->territories))) ?>