diff --git a/bridges/SpotifyBridge.php b/bridges/SpotifyBridge.php
new file mode 100644
index 00000000..298fd3d8
--- /dev/null
+++ b/bridges/SpotifyBridge.php
@@ -0,0 +1,238 @@
+ array(
+ 'name' => 'Client ID',
+ 'type' => 'text',
+ 'required' => true
+ ),
+ 'clientsecret' => array(
+ 'name' => 'Client secret',
+ 'type' => 'text',
+ 'required' => true
+ ),
+ 'spotifyuri' => array(
+ 'name' => 'Spotify URIs',
+ 'type' => 'text',
+ 'required' => true,
+ 'exampleValue' => 'spotify:artist:4lianjyuR1tqf6oUX8kjrZ [,spotify:artist:3JsMj0DEzyWc0VDlHuy9Bx]',
+ ),
+ 'albumtype' => array(
+ 'name' => 'Album type',
+ 'type' => 'text',
+ 'required' => false,
+ 'exampleValue' => 'album,single,appears_on,compilation',
+ 'defaultValue' => 'album,single'
+ ),
+ 'country' => array(
+ 'name' => 'Country',
+ 'type' => 'text',
+ 'required' => false,
+ 'exampleValue' => 'US',
+ 'defaultValue' => 'US'
+ )
+ ));
+
+ const TOKENURI = 'https://accounts.spotify.com/api/token';
+ const APIURI = 'https://api.spotify.com/v1/';
+
+ private $uri = '';
+ private $name = '';
+ private $token = '';
+ private $artists = array();
+ private $albums = array();
+
+ public function getURI() {
+ if(empty($this->uri))
+ $this->getArtist();
+
+ return $this->uri;
+ }
+
+ public function getName() {
+ if(empty($this->name))
+ $this->getArtist();
+
+ return $this->name;
+ }
+
+ public function getIcon() {
+ return 'https://www.scdn.co/i/_global/favicon.png';
+ }
+
+ private function getId($artist) {
+ return explode(':', $artist)[2];
+ }
+
+ private function getDate($album_date) {
+ if(strlen($album_date) == 4)
+ $album_date .= '-01-01';
+ elseif(strlen($album_date) == 7)
+ $album_date .= '-01';
+
+ return DateTime::createFromFormat('Y-m-d', $album_date)->getTimestamp();
+ }
+
+ private function getAlbumType() {
+ return $this->getInput('albumtype');
+ }
+
+ private function getCountry() {
+ return $this->getInput('country');
+ }
+
+ private function getToken() {
+ $cacheFac = new CacheFactory();
+ $cacheFac->setWorkingDir(PATH_LIB_CACHES);
+ $cache = $cacheFac->create(Configuration::getConfig('cache', 'type'));
+ $cache->setScope(get_called_class());
+ $cache->setKey(array('token'));
+
+ if($cache->getTime()) {
+ $time = (new DateTime)->getTimestamp() - $cache->getTime();
+ Debug::log('Token time: ' . $time);
+ }
+
+ if($cache->getTime() == false || $time >= 3600) {
+ Debug::log('Fetching token from Spotify');
+ $this->fetchToken();
+ $cache->saveData($this->token);
+ } else {
+ Debug::log('Loading token from cache');
+ $this->token = $cache->loadData();
+ }
+
+ Debug::log('Token: ' . $this->token);
+ }
+
+ private function getArtist() {
+ if(!is_null($this->getInput('spotifyuri')) && strpos($this->getInput('spotifyuri'), ',') === false) {
+ $artist = $this->fetchContent(self::APIURI . 'artists/'
+ . $this->getId($this->artists[0]));
+ $this->uri = $artist['external_urls']['spotify'];
+ $this->name = $artist['name'] . ' - Spotify';
+ } else {
+ $this->uri = parent::getURI();
+ $this->name = parent::getName();
+ }
+ }
+
+ private function getAllArtists() {
+ Debug::log('Parsing all artists');
+ $this->artists = explode(',', $this->getInput('spotifyuri'));
+ }
+
+ private function getAllAlbums() {
+ $this->albums = array();
+
+ $this->getAllArtists();
+
+ Debug::log('Fetching all albums');
+ foreach($this->artists as $artist) {
+ $fetch = true;
+ $offset = 0;
+
+ while($fetch) {
+ $partial_albums = $this->fetchContent(self::APIURI . 'artists/'
+ . $this->getId($artist)
+ . '/albums?limit=50&include_groups='
+ . $this->getAlbumType()
+ . '&country='
+ . $this->getCountry()
+ . '&offset='
+ . $offset);
+
+ if(!empty($partial_albums['items']))
+ $this->albums = array_merge($this->albums,
+ $partial_albums['items']);
+ else
+ $fetch = false;
+
+ $offset += 50;
+ }
+ }
+ }
+
+ private function fetchToken() {
+ $curl = curl_init();
+
+ curl_setopt($curl, CURLOPT_URL, self::TOKENURI);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_POST, 1);
+ curl_setopt($curl, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Basic '
+ . base64_encode($this->getInput('clientid')
+ . ':'
+ . $this->getInput('clientsecret'))));
+
+ $json = curl_exec($curl);
+ $json = json_decode($json)->access_token;
+ curl_close($curl);
+
+ $this->token = $json;
+ }
+
+ private function fetchContent($url) {
+ $this->getToken();
+ $curl = curl_init();
+
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Bearer '
+ . $this->token));
+
+ Debug::log('Fetching content from ' . $url);
+ $json = curl_exec($curl);
+ $json = json_decode($json, true);
+ curl_close($curl);
+
+ return $json;
+ }
+
+ private function sortAlbums() {
+ Debug::log('Sorting albums');
+ usort($this->albums, function($album1, $album2) {
+ if($this->getDate($album1['release_date']) < $this->getDate($album2['release_date']))
+ return 1;
+ else
+ return -1;
+ });
+ }
+
+ public function collectData() {
+ $offset = 0;
+
+ $this->getAllAlbums();
+ $this->sortAlbums();
+
+ Debug::log('Building RSS feed');
+ foreach($this->albums as $album) {
+ $item = array();
+ $item['title'] = $album['name'];
+ $item['uri'] = $album['external_urls']['spotify'];
+
+ $item['timestamp'] = $this->getDate($album['release_date']);
+ $item['author'] = $album['artists'][0]['name'];
+ $item['categories'] = array($album['album_type']);
+
+ $item['content'] = '';
+
+ if($album['total_tracks'] > 1)
+ $item['content'] .= '
Total tracks: ' + . $album['total_tracks'] + . '
'; + + $this->items[] = $item; + + if(count($this->items) >= 10) + break; + } + } +}