Skip to content

Instantly share code, notes, and snippets.

@jahir07
Forked from sanderdewijs/IceCastPlaylist.php
Created October 29, 2022 11:00
Show Gist options
  • Save jahir07/27d0ab5891131a3ff7b9221fd5265109 to your computer and use it in GitHub Desktop.
Save jahir07/27d0ab5891131a3ff7b9221fd5265109 to your computer and use it in GitHub Desktop.
This is an idea to create a playlist from an Icecast server storing the songdata and cover image into a database.
<?php
/**
* Class IceCastPlaylist
* See https://stackoverflow.com/questions/60502076/how-to-get-icecast-server-songs-history/60798774#60798774 for context
*
* This class can be used as follows:
* global $wpdb
* $playlistClass = new IceCastPlaylist($wpdb);
* $playlistClass->fetchSongInfo();
* $playlist = $songInfoClass->getPlaylist();
* header('Content-Type: application/json;charset=utf-8');
* echo $playlist;
* die();
*/
class IceCastPlaylist {
/**
* @var wpdb
*/
protected $db;
/**
* @var string
*/
protected $table = '[replace with playlist table]';
/**
* Replace this with your server URL
* @var string
*/
protected $songDataUrl = 'https://serveraddress:portnumber/stream.xspf';
/**
* @var string
*/
protected $albumCoverUrl = 'https://itunes.apple.com/search?entity=musicTrack&term=';
/**
* Replace this with your storage path
* @var string
*/
protected $albumCoverPath = '[absolute_path_to_cover_images_folder e.g /media/covers/]';
/**
* Replace with your site URL
* Most of the time you will want to set the URL to the site dynamically,
* so we do this in the constructor
*/
protected $siteUrl = '';
/**
* Replace this with the desired length of your playlist
* @var int
*/
protected $playlistLength = 20;
/**
* IceCastPlaylist constructor.
* In this case, I used WordPress wpdb, but it can be replaced with another DB instance
* When using something else than wpdb, the query functions will need to be adjusted
*
* @param $db
*/
public function __construct(wpdb $db) {
$this->db = $db;
// If you need to set the site URL via a function, you can set it here in the constructor
$this->siteUrl = get_site_url() . '/wp-content/media/covers/';
}
public function getPlaylist() {
$result = $this->db->get_results("SELECT * FROM {$this->table} as songs ORDER BY `songs`.`id` DESC LIMIT {$this->playlistLength}");
return json_encode($result);
}
/**
* [
* 'playedat' => 'H:i',
* 'title' => 'title',
* 'artist' => 'bla',
* 'coverImage' => 'linkToCoverArt',
* 'created_at' => 'Y-m-d',
* ]
* @param array $entry
*/
public function storeEntry(array $entry) {
$this->db->insert($this->table, $entry);
}
/**
* @return mixed
* @throws Exception
*/
public function fetchSongInfo() {
$rawData = file_get_contents($this->songDataUrl);
$now = new DateTime('now');
if(!$rawData) {
throw new Exception('Error retrieving song data');
}
$xml = new SimpleXMLElement($rawData);
$titleArtist = preg_split("/\s-\s/", (string) $xml->trackList->track->title);
if($this->isNewSong($titleArtist[1])) {
$stream['playedAt'] = $now->format('H:i');
$stream['title'] = $titleArtist[1];
$stream['artist'] = $titleArtist[0];
$stream['coverImage'] = $this->getCoverArt($xml->trackList->track->title);
$stream['created_at'] = $now->format('Y-m-d H:i:s');
$this->storeEntry($stream);
}
}
/**
* Use in your daily cleanup cron
*/
public function dailyCleanup() {
$this->db->query("TRUNCATE TABLE {$this->table}");
}
/**
* @param string $title
*
* @return bool
*/
private function isNewSong(string $title) {
$result = $this->db->get_results("SELECT * FROM {$this->table} as songs ORDER BY `songs`.`id` DESC LIMIT 1");
if(empty($result)) {
return true;
}
return $result[0]->title !== $title;
}
/**
* Take the raw 'songtitle - artist' and try to find cover art
* @param string $title
*
* @return string|null
*/
private function getCoverArt(string $title) {
$itunesData = wp_remote_get($this->albumCoverUrl . urlencode($title), array(
'timeout' => 45,
'redirection' => 5,
'httpversion' => '1.0',
'blocking' => true,
'headers' => array(
'accept-encoding' => 'gzip, deflate, br',
'pragma' => 'no-cache',
'accept-language' => 'en-US,en;q=0.8',
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36',
'accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
),
'cookies' => array(),
));
$songInfo = json_decode(trim(wp_remote_retrieve_body($itunesData)));
$imageHash = '';
if(isset($songInfo->results[0])) {
$coverImage = str_replace('100x100bb.jpg', '', $songInfo->results[0]->artworkUrl100);
$imageHash = md5($title) . '.jpg';
if(!file_exists($this->albumCoverPath . $imageHash) && $coverImage !== '') {
$img = file_get_contents($coverImage . '200x200bb.jpg');
file_put_contents($this->albumCoverPath . $imageHash, $img);
}
}
return (empty($imageHash)) ? null : $this->siteUrl . $imageHash;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment