diff --git a/bridges/BandcampBridge.php b/bridges/BandcampBridge.php
index 6c75ed5e..fa071465 100644
--- a/bridges/BandcampBridge.php
+++ b/bridges/BandcampBridge.php
@@ -1,73 +1,262 @@
array(
- 'name' => 'tag',
- 'type' => 'text',
- 'required' => true
+ const DESCRIPTION = 'New bandcamp releases by tag, band or album';
+ const PARAMETERS = array(
+ 'By tag' => array(
+ 'tag' => array(
+ 'name' => 'tag',
+ 'type' => 'text',
+ 'required' => true
+ )
+ ),
+ 'By band' => array(
+ 'band' => array(
+ 'name' => 'band',
+ 'type' => 'text',
+ 'title' => 'Band name as seen in the band page URL',
+ 'required' => true
+ ),
+ 'type' => array(
+ 'name' => 'Articles are',
+ 'type' => 'list',
+ 'values' => array(
+ 'Releases' => 'releases',
+ 'Releases, new one when track list changes' => 'changes',
+ 'Individual tracks' => 'tracks'
+ ),
+ 'defaultValue' => 'changes'
+ ),
+ 'limit' => array(
+ 'name' => 'limit',
+ 'type' => 'number',
+ 'title' => 'Number of releases to return',
+ 'defaultValue' => 5
+ )
+ ),
+ 'By album' => array(
+ 'band' => array(
+ 'name' => 'band',
+ 'type' => 'text',
+ 'title' => 'Band name as seen in the album page URL',
+ 'required' => true
+ ),
+ 'album' => array(
+ 'name' => 'album',
+ 'type' => 'text',
+ 'title' => 'Album name as seen in the album page URL',
+ 'required' => true
+ ),
+ 'type' => array(
+ 'name' => 'Articles are',
+ 'type' => 'list',
+ 'values' => array(
+ 'Releases' => 'releases',
+ 'Releases, new one when track list changes' => 'changes',
+ 'Individual tracks' => 'tracks'
+ ),
+ 'defaultValue' => 'tracks'
+ )
)
- ));
+ );
const IMGURI = 'https://f4.bcbits.com/';
const IMGSIZE_300PX = 23;
const IMGSIZE_700PX = 16;
+ private $feedName;
+
public function getIcon() {
return 'https://s4.bcbits.com/img/bc_favicon.ico';
}
public function collectData(){
- $url = self::URI . 'api/hub/1/dig_deeper';
- $data = $this->buildRequestJson();
- $header = array(
- 'Content-Type: application/json',
- 'Content-Length: ' . strlen($data)
- );
- $opts = array(
- CURLOPT_CUSTOMREQUEST => 'POST',
- CURLOPT_POSTFIELDS => $data
- );
- $content = getContents($url, $header, $opts)
- or returnServerError('Could not complete request to: ' . $url);
-
- $json = json_decode($content);
-
- if ($json->ok !== true) {
- returnServerError('Invalid response');
- }
-
- foreach ($json->items as $entry) {
- $url = $entry->tralbum_url;
- $artist = $entry->artist;
- $title = $entry->title;
- // e.g. record label is the releaser, but not the artist
- $releaser = $entry->band_name !== $entry->artist ? $entry->band_name : null;
-
- $full_title = $artist . ' - ' . $title;
- $full_artist = $artist;
- if (isset($releaser)) {
- $full_title .= ' (' . $releaser . ')';
- $full_artist .= ' (' . $releaser . ')';
- }
- $small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX);
- $img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX);
-
- $item = array(
- 'uri' => $url,
- 'author' => $full_artist,
- 'title' => $full_title
+ switch($this->queriedContext) {
+ case 'By tag':
+ $url = self::URI . 'api/hub/1/dig_deeper';
+ $data = $this->buildRequestJson();
+ $header = array(
+ 'Content-Type: application/json',
+ 'Content-Length: ' . strlen($data)
);
- $item['content'] = "
$full_title";
- $item['enclosures'] = array($img);
- $this->items[] = $item;
+ $opts = array(
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_POSTFIELDS => $data
+ );
+ $content = getContents($url, $header, $opts)
+ or returnServerError('Could not complete request to: ' . $url);
+
+ $json = json_decode($content);
+
+ if ($json->ok !== true) {
+ returnServerError('Invalid response');
+ }
+
+ foreach ($json->items as $entry) {
+ $url = $entry->tralbum_url;
+ $artist = $entry->artist;
+ $title = $entry->title;
+ // e.g. record label is the releaser, but not the artist
+ $releaser = $entry->band_name !== $entry->artist ? $entry->band_name : null;
+
+ $full_title = $artist . ' - ' . $title;
+ $full_artist = $artist;
+ if (isset($releaser)) {
+ $full_title .= ' (' . $releaser . ')';
+ $full_artist .= ' (' . $releaser . ')';
+ }
+ $small_img = $this->getImageUrl($entry->art_id, self::IMGSIZE_300PX);
+ $img = $this->getImageUrl($entry->art_id, self::IMGSIZE_700PX);
+
+ $item = array(
+ 'uri' => $url,
+ 'author' => $full_artist,
+ 'title' => $full_title
+ );
+ $item['content'] = "
$full_title";
+ $item['enclosures'] = array($img);
+ $this->items[] = $item;
+ }
+ break;
+ case 'By band':
+ case 'By album':
+ $html = getSimpleHTMLDOMCached($this->getURI(), 86400);
+
+ $titleElement = $html->find('head meta[name=title]', 0)
+ or returnServerError('Unable to find title on: ' . $this->getURI());
+ $this->feedName = $titleElement->content;
+
+ $regex = '/band_id=(\d+)/';
+ if(preg_match($regex, $html, $matches) == false)
+ returnServerError('Unable to find band ID on: ' . $this->getURI());
+ $band_id = $matches[1];
+
+ $tralbums = array();
+ switch($this->queriedContext) {
+ case 'By band':
+ $query_data = array(
+ 'band_id' => $band_id
+ );
+ $band_data = $this->apiGet('mobile/22/band_details', $query_data);
+
+ $num_albums = min(count($band_data->discography), $this->getInput('limit'));
+ for($i = 0; $i < $num_albums; $i++) {
+ $album_basic_data = $band_data->discography[$i];
+
+ // 'a' or 't' for albums and individual tracks respectively
+ $tralbum_type = substr($album_basic_data->item_type, 0, 1);
+
+ $query_data = array(
+ 'band_id' => $band_id,
+ 'tralbum_type' => $tralbum_type,
+ 'tralbum_id' => $album_basic_data->item_id
+ );
+ $tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data);
+ }
+ break;
+ case 'By album':
+ $regex = '/album=(\d+)/';
+ if(preg_match($regex, $html, $matches) == false)
+ returnServerError('Unable to find album ID on: ' . $this->getURI());
+ $album_id = $matches[1];
+
+ $query_data = array(
+ 'band_id' => $band_id,
+ 'tralbum_type' => 'a',
+ 'tralbum_id' => $album_id
+ );
+ $tralbums[] = $this->apiGet('mobile/22/tralbum_details', $query_data);
+
+ break;
+ }
+
+ foreach ($tralbums as $tralbum_data) {
+ if ($tralbum_data->type === 'a' && $this->getInput('type') === 'tracks') {
+ foreach ($tralbum_data->tracks as $track) {
+ $query_data = array(
+ 'band_id' => $band_id,
+ 'tralbum_type' => 't',
+ 'tralbum_id' => $track->track_id
+ );
+ $track_data = $this->apiGet('mobile/22/tralbum_details', $query_data);
+
+ $this->items[] = $this->buildTralbumItem($track_data);
+ }
+ } else {
+ $this->items[] = $this->buildTralbumItem($tralbum_data);
+ }
+ }
+ break;
}
}
+ private function buildTralbumItem($tralbum_data){
+ $band_data = $tralbum_data->band;
+
+ // Format title like: ARTIST - ALBUM/TRACK (OPTIONAL RELEASER)
+ // Format artist/author like: ARTIST (OPTIONAL RELEASER)
+ //
+ // If the album/track is released under a label/a band other than the artist
+ // themselves, append that releaser name to the title and artist/author.
+ //
+ // This sadly doesn't always work right for individual tracks as the artist
+ // of the track is always set to the releaser.
+ $artist = $tralbum_data->tralbum_artist;
+ $full_title = $artist . ' - ' . $tralbum_data->title;
+ $full_artist = $artist;
+ if (isset($tralbum_data->label)) {
+ $full_title .= ' (' . $tralbum_data->label . ')';
+ $full_artist .= ' (' . $tralbum_data->label . ')';
+ } elseif ($band_data->name !== $artist) {
+ $full_title .= ' (' . $band_data->name . ')';
+ $full_artist .= ' (' . $band_data->name . ')';
+ }
+
+ $small_img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_300PX);
+ $img = $this->getImageUrl($tralbum_data->art_id, self::IMGSIZE_700PX);
+
+ $item = array(
+ 'uri' => $tralbum_data->bandcamp_url,
+ 'author' => $full_artist,
+ 'title' => $full_title,
+ 'enclosures' => array($img),
+ 'timestamp' => $tralbum_data->release_date
+ );
+
+ $item['categories'] = array();
+ foreach ($tralbum_data->tags as $tag) {
+ $item['categories'][] = $tag->norm_name;
+ }
+
+ // Give articles a unique UID depending on its track list
+ // Releases should then show up as new articles when tracks are added
+ if ($this->getInput('type') === 'changes') {
+ $item['uid'] = "bandcamp/$band_data->band_id/$tralbum_data->id/";
+ foreach ($tralbum_data->tracks as $track) {
+ $item['uid'] .= $track->track_id;
+ }
+ }
+
+ $item['content'] = "
$full_title
";
+ if ($tralbum_data->type === 'a') {
+ $item['content'] .= '
' + . nl2br($tralbum_data->about) + . '
'; + } + + return $item; + } + private function buildRequestJson(){ $requestJson = array( 'tag' => $this->getInput('tag'), @@ -81,11 +270,94 @@ class BandcampBridge extends BridgeAbstract { return self::IMGURI . 'img/a' . $id . '_' . $size . '.jpg'; } + private function apiGet($endpoint, $query_data) { + $url = self::URI . 'api/' . $endpoint . '?' . http_build_query($query_data); + $data = json_decode(getContents($url)) + or returnServerError('API request to "' . $url . '" failed.'); + return $data; + } + + public function getURI(){ + switch($this->queriedContext) { + case 'By tag': + if(!is_null($this->getInput('tag'))) { + return self::URI + . 'tag/' + . urlencode($this->getInput('tag')) + . '?sort_field=date'; + } + break; + case 'By band': + if(!is_null($this->getInput('band'))) { + return 'https://' + . $this->getInput('band') + . '.bandcamp.com/music'; + } + break; + case 'By album': + if(!is_null($this->getInput('band')) && !is_null($this->getInput('album'))) { + return 'https://' + . $this->getInput('band') + . '.bandcamp.com/album/' + . $this->getInput('album'); + } + break; + } + + return parent::getURI(); + } + public function getName(){ - if(!is_null($this->getInput('tag'))) { - return $this->getInput('tag') . ' - Bandcamp Tag'; + switch($this->queriedContext) { + case 'By tag': + if(!is_null($this->getInput('tag'))) { + return $this->getInput('tag') . ' - Bandcamp Tag'; + } + break; + case 'By band': + if(isset($this->feedName)) { + return $this->feedName . ' - Bandcamp Band'; + } elseif(!is_null($this->getInput('band'))) { + return $this->getInput('band') . ' - Bandcamp Band'; + } + break; + case 'By album': + if(isset($this->feedName)) { + return $this->feedName . ' - Bandcamp Album'; + } elseif(!is_null($this->getInput('album'))) { + return $this->getInput('album') . ' - Bandcamp Album'; + } + break; } return parent::getName(); } + + public function detectParameters($url) { + $params = array(); + + // By tag + $regex = '/^(https?:\/\/)?bandcamp\.com\/tag\/([^\/.&?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['tag'] = urldecode($matches[2]); + return $params; + } + + // By band + $regex = '/^(https?:\/\/)?([^\/.&?\n]+?)\.bandcamp\.com/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['band'] = urldecode($matches[2]); + return $params; + } + + // By album + $regex = '/^(https?:\/\/)?([^\/.&?\n]+?)\.bandcamp\.com\/album\/([^\/.&?\n]+)/'; + if(preg_match($regex, $url, $matches) > 0) { + $params['band'] = urldecode($matches[2]); + $params['album'] = urldecode($matches[3]); + return $params; + } + + return null; + } }