From e518936be75a0d9ede72db9fa78301a809e31f63 Mon Sep 17 00:00:00 2001 From: Roliga Date: Sun, 1 Dec 2019 12:42:53 +0100 Subject: [PATCH] [SoundcloudBridge] Automatically acquire client_id (#1375) Also some slight refactoring, as well as adding Roliga as maintainer. --- bridges/SoundcloudBridge.php | 87 +++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php index 8938ff96..9607d33d 100644 --- a/bridges/SoundcloudBridge.php +++ b/bridges/SoundcloudBridge.php @@ -1,7 +1,7 @@ getInput('u')) - . '&client_id=' - . self::CLIENT_ID + $res = $this->apiGet('resolve', array( + 'url' => 'http://www.soundcloud.com/' . $this->getInput('u') )) or returnServerError('No results for this query'); $this->feedIcon = $res->avatar_url; - $tracks = json_decode(getContents( - 'https://api.soundcloud.com/users/' - . urlencode($res->id) - . '/tracks?client_id=' - . self::CLIENT_ID - )) or returnServerError('No results for this user'); + $tracks = $this->apiGet('users/' . urlencode($res->id) . '/tracks') + or returnServerError('No results for this user'); $numTracks = min(count($tracks), 10); for($i = 0; $i < $numTracks; $i++) { @@ -45,7 +36,7 @@ class SoundCloudBridge extends BridgeAbstract { $item['content'] = $tracks[$i]->description; $item['enclosures'] = array($tracks[$i]->uri . '/stream?client_id=' - . self::CLIENT_ID); + . $this->getClientID()); $item['id'] = self::URI . urlencode($this->getInput('u')) @@ -75,4 +66,68 @@ class SoundCloudBridge extends BridgeAbstract { return parent::getName(); } + + private function initClientIDCache(){ + if($this->clientIDCache !== null) + return; + + $cacheFac = new CacheFactory(); + $cacheFac->setWorkingDir(PATH_LIB_CACHES); + $this->clientIDCache = $cacheFac->create(Configuration::getConfig('cache', 'type')); + $this->clientIDCache->setScope(get_called_class()); + $this->clientIDCache->setKey(array('client_id')); + } + + private function getClientID(){ + $this->initClientIDCache(); + + $clientID = $this->clientIDCache->loadData(); + + if($clientID == null) { + return $this->refreshClientID(); + } else { + return $clientID; + } + } + + private function refreshClientID(){ + $this->initClientIDCache(); + + // Without url=http, this returns a 404 + $playerHTML = getContents('https://w.soundcloud.com/player/?url=http') + or returnServerError('Unable to get player page.'); + $regex = '/widget-.+?\.js/'; + if(preg_match($regex, $playerHTML, $matches) == false) + returnServerError('Unable to find widget JS URL.'); + $widgetURL = 'https://widget.sndcdn.com/' . $matches[0]; + + $widgetJS = getContents($widgetURL) + or returnServerError('Unable to get widget JS page.'); + $regex = '/client_id.*?"(.+?)"/'; + if(preg_match($regex, $widgetJS, $matches) == false) + returnServerError('Unable to find client ID.'); + $clientID = $matches[1]; + + $this->clientIDCache->saveData($clientID); + return $clientID; + } + + private function buildAPIURL($endpoint, $parameters){ + return 'https://api.soundcloud.com/' + . $endpoint + . '?' + . http_build_query($parameters); + } + + private function apiGet($endpoint, $parameters = array()){ + $parameters['client_id'] = $this->getClientID(); + + try { + return json_decode(getContents($this->buildAPIURL($endpoint, $parameters))); + } catch (Exception $e) { + // Retry once with refreshed client ID + $parameters['client_id'] = $this->refreshClientID(); + return json_decode(getContents($this->buildAPIURL($endpoint, $parameters))); + } + } }