From 47e270161b93d77df5936bd87da0d41f38929c8c Mon Sep 17 00:00:00 2001
From: Joseph
Date: Thu, 5 Aug 2021 13:25:22 +0100
Subject: [PATCH 1/6] [SoundcloudBridge] Add support for albums, reposts &
likes
---
bridges/SoundcloudBridge.php | 95 ++++++++++++++++++++++++------------
1 file changed, 63 insertions(+), 32 deletions(-)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index fe1e9414c37..835119e1edc 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -1,28 +1,35 @@
array(
'name' => 'username',
'required' => true
),
't' => array(
- 'name' => 'type',
+ 'name' => 'Content',
'type' => 'list',
'defaultValue' => 'tracks',
'values' => array(
+ 'All' => 'all',
'Tracks' => 'tracks',
- 'Playlists' => 'playlists'
+ 'Albums' => 'albums',
+ 'Playlists' => 'playlists',
+ 'Reposts' => 'reposts',
+ 'Likes' => 'likes'
)
)
));
+ private $apiUrl = 'https://api-v2.soundcloud.com/';
+ private $playerUrl = 'https://w.soundcloud.com/player/?url=http';
+ private $widgetUrl = 'https://widget.sndcdn.com/';
+
private $feedTitle = null;
private $feedIcon = null;
private $clientIDCache = null;
@@ -30,35 +37,31 @@ class SoundCloudBridge extends BridgeAbstract {
private $clientIdRegex = '/client_id.*?"(.+?)"/';
private $widgetRegex = '/widget-.+?\.js/';
- public function collectData(){
- $res = $this->apiGet('resolve', array(
- 'url' => 'https://soundcloud.com/' . $this->getInput('u')
- )) or returnServerError('No results for this query');
+ public function collectData() {
+ $res = $this->getUser($this->getInput('u'))
+ or returnServerError('No results for this query');
$this->feedTitle = $res->username;
$this->feedIcon = $res->avatar_url;
- $tracks = $this->apiGet(
- 'users/' . urlencode($res->id) . '/' . $this->getInput('t'),
- array('limit' => 31)
- ) or returnServerError('No results for this user/playlist');
+ $tracks = $this->getUserItems($res->id, $this->getInput('t'))
+ or returnServerError('No results for ' . $this->getInput('t'));
+
+ $hasTrackObject = array('all', 'reposts', 'likes');
foreach ($tracks->collection as $index => $track) {
+ if (in_array($this->getInput('t'), $hasTrackObject) === true) {
+ $track = $track->track;
+ }
+
$item = array();
$item['author'] = $track->user->username;
$item['title'] = $track->user->username . ' - ' . $track->title;
$item['timestamp'] = strtotime($track->created_at);
$item['content'] = nl2br($track->description);
$item['enclosures'][] = $track->artwork_url;
-
- $item['id'] = self::URI
- . urlencode($this->getInput('u'))
- . '/'
- . urlencode($track->permalink);
- $item['uri'] = self::URI
- . urlencode($this->getInput('u'))
- . '/'
- . urlencode($track->permalink);
+ $item['id'] = $track->permalink_url;
+ $item['uri'] = $track->permalink_url;
$this->items[] = $item;
if (count($this->items) >= 10) {
@@ -75,13 +78,17 @@ public function getIcon(){
return parent::getIcon();
}
- public function getURI(){
- return 'https://soundcloud.com/' . $this->getInput('u');
+ public function getURI() {
+ if ($this->getInput('u')) {
+ return self::URI . $this->getInput('u') . '/' . $this->getInput('t');
+ }
+
+ return parent::getURI();
}
- public function getName(){
+ public function getName() {
if($this->feedTitle) {
- return $this->feedTitle . ' - ' . self::NAME;
+ return $this->feedTitle . ' - ' . ucfirst($this->getInput('t')) . ' - ' . self::NAME;
}
return parent::getName();
@@ -114,7 +121,7 @@ private function refreshClientID(){
$this->initClientIDCache();
// Without url=http, this returns a 404
- $playerHTML = getContents('https://w.soundcloud.com/player/?url=http')
+ $playerHTML = getContents($this->playerUrl)
or returnServerError('Unable to get player page.');
// Extract widget JS filenames from player page
@@ -125,7 +132,7 @@ private function refreshClientID(){
// Loop widget js files and extract client ID
foreach ($matches[0] as $widgetFile) {
- $widgetURL = 'https://widget.sndcdn.com/' . $widgetFile;
+ $widgetURL = $this->widgetUrl . $widgetFile;
$widgetJS = getContents($widgetURL)
or returnServerError('Unable to get widget JS page.');
@@ -143,22 +150,46 @@ private function refreshClientID(){
}
}
- private function buildAPIURL($endpoint, $parameters){
- return 'https://api-v2.soundcloud.com/'
+ private function buildApiUrl($endpoint, $parameters) {
+ return $this->apiUrl
. $endpoint
. '?'
. http_build_query($parameters);
}
- private function apiGet($endpoint, $parameters = array()) {
+ private function getUser($username) {
+ $parameters = array('url' => self::URI . $username);
+
+ return $this->getApi('resolve', $parameters);
+ }
+
+ private function getUserItems($userId, $type) {
+ $parameters = array('limit' => 10);
+ $endpoint = 'users/' . $userId . '/' . $type;
+
+ if ($type === 'all') {
+ $endpoint = 'stream/users/' . $userId;
+ }
+
+ if ($type === 'reposts') {
+ $endpoint = 'stream/users/' . $userId . '/' . $type;
+ }
+
+ return $this->getApi($endpoint, $parameters);
+ }
+
+ private function getApi($endpoint, $parameters) {
$parameters['client_id'] = $this->getClientID();
+ $url = $this->buildApiUrl($endpoint, $parameters);
try {
- return json_decode(getContents($this->buildAPIURL($endpoint, $parameters)));
+ return json_decode(getContents($url));
} catch (Exception $e) {
// Retry once with refreshed client ID
$parameters['client_id'] = $this->refreshClientID();
- return json_decode(getContents($this->buildAPIURL($endpoint, $parameters)));
+ $url = $this->buildApiUrl($endpoint, $parameters);
+
+ return json_decode(getContents($url));
}
}
}
From b204e80f476e90d7dd85524a2bc1b4dea8e0ae78 Mon Sep 17 00:00:00 2001
From: Joseph
Date: Thu, 5 Aug 2021 16:07:57 +0100
Subject: [PATCH 2/6] [SoundcloudBridge] Move comment
---
bridges/SoundcloudBridge.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index 835119e1edc..6a3d2875711 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -16,7 +16,7 @@ class SoundCloudBridge extends BridgeAbstract {
'type' => 'list',
'defaultValue' => 'tracks',
'values' => array(
- 'All' => 'all',
+ 'All (except likes)' => 'all',
'Tracks' => 'tracks',
'Albums' => 'albums',
'Playlists' => 'playlists',
@@ -27,6 +27,7 @@ class SoundCloudBridge extends BridgeAbstract {
));
private $apiUrl = 'https://api-v2.soundcloud.com/';
+ // Without url=http, player URL returns a 404
private $playerUrl = 'https://w.soundcloud.com/player/?url=http';
private $widgetUrl = 'https://widget.sndcdn.com/';
@@ -120,7 +121,6 @@ private function getClientID(){
private function refreshClientID(){
$this->initClientIDCache();
- // Without url=http, this returns a 404
$playerHTML = getContents($this->playerUrl)
or returnServerError('Unable to get player page.');
From a39c2d0bed2701aed65c5b99774ab70d886ca6c2 Mon Sep 17 00:00:00 2001
From: Joseph
Date: Sat, 18 Sep 2021 22:54:18 +0100
Subject: [PATCH 3/6] [SoundcloudBridge] Use correct endpoint for playlists
---
bridges/SoundcloudBridge.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index 6a3d2875711..443f72769f5 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -167,6 +167,10 @@ private function getUserItems($userId, $type) {
$parameters = array('limit' => 10);
$endpoint = 'users/' . $userId . '/' . $type;
+ if ($type === 'playlists') {
+ $endpoint = 'users/' . $userId . '/playlists_without_albums';
+ }
+
if ($type === 'all') {
$endpoint = 'stream/users/' . $userId;
}
From 55fdc1f657cc98b06e8e3db868b5877c7b15dc1e Mon Sep 17 00:00:00 2001
From: Joseph
Date: Sat, 18 Sep 2021 22:55:32 +0100
Subject: [PATCH 4/6] [SoundcloudBridge] Add method getTrackList()
---
bridges/SoundcloudBridge.php | 60 ++++++++++++++++++++++++++++++------
1 file changed, 50 insertions(+), 10 deletions(-)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index 443f72769f5..c51f5fce481 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -45,24 +45,39 @@ public function collectData() {
$this->feedTitle = $res->username;
$this->feedIcon = $res->avatar_url;
- $tracks = $this->getUserItems($res->id, $this->getInput('t'))
+ $apiItems = $this->getUserItems($res->id, $this->getInput('t'))
or returnServerError('No results for ' . $this->getInput('t'));
$hasTrackObject = array('all', 'reposts', 'likes');
- foreach ($tracks->collection as $index => $track) {
+ foreach ($apiItems->collection as $index => $apiItem) {
if (in_array($this->getInput('t'), $hasTrackObject) === true) {
- $track = $track->track;
+ $apiItem = $apiItem->track;
}
$item = array();
- $item['author'] = $track->user->username;
- $item['title'] = $track->user->username . ' - ' . $track->title;
- $item['timestamp'] = strtotime($track->created_at);
- $item['content'] = nl2br($track->description);
- $item['enclosures'][] = $track->artwork_url;
- $item['id'] = $track->permalink_url;
- $item['uri'] = $track->permalink_url;
+ $item['author'] = $apiItem->user->username;
+ $item['title'] = $apiItem->user->username . ' - ' . $apiItem->title;
+ $item['timestamp'] = strtotime($apiItem->created_at);
+
+ $description = nl2br($apiItem->description);
+
+ $item['content'] = <<{$description}
+ HTML;
+
+ if (isset($apiItem->tracks) && $apiItem->track_count > 0) {
+ $list = $this->getTrackList($apiItem->tracks);
+
+ $item['content'] .= <<Tracks ({$apiItem->track_count})
+ {$list}
+ HTML;
+ }
+
+ $item['enclosures'][] = $apiItem->artwork_url;
+ $item['id'] = $apiItem->permalink_url;
+ $item['uri'] = $apiItem->permalink_url;
$this->items[] = $item;
if (count($this->items) >= 10) {
@@ -196,4 +211,29 @@ private function getApi($endpoint, $parameters) {
return json_decode(getContents($url));
}
}
+
+ private function getTrackList($tracks) {
+ $trackids = '';
+
+ foreach ($tracks as $track) {
+ $trackids .= $track->id . ',';
+ }
+
+ $apiItems = $this->getApi(
+ 'tracks', array('ids' => $trackids)
+ );
+
+ $list = '';
+ foreach($apiItems as $track) {
+ $list .= <<{$track->user->username} — {$track->title}
+ HTML;
+ }
+
+ $html = <<{$list}
+ HTML;
+
+ return $html;
+ }
}
From 8df2a53a51ee0007734fd9e287ba36c2a30814e1 Mon Sep 17 00:00:00 2001
From: Joseph
Date: Sat, 18 Sep 2021 23:26:13 +0100
Subject: [PATCH 5/6] [SoundcloudBridge] Fix Lint
---
bridges/SoundcloudBridge.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index c51f5fce481..d2375a05707 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -72,7 +72,7 @@ public function collectData() {
$item['content'] .= <<Tracks ({$apiItem->track_count})
{$list}
- HTML;
+HTML;
}
$item['enclosures'][] = $apiItem->artwork_url;
@@ -232,7 +232,7 @@ private function getTrackList($tracks) {
$html = <<{$list}
- HTML;
+HTML;
return $html;
}
From 49eca729a5f8dfd43643771f7357cf71f48d21c0 Mon Sep 17 00:00:00 2001
From: Joseph
Date: Sat, 18 Sep 2021 23:31:40 +0100
Subject: [PATCH 6/6] [SoundcloudBridge] Fix Lint (again)
---
bridges/SoundcloudBridge.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/bridges/SoundcloudBridge.php b/bridges/SoundcloudBridge.php
index d2375a05707..86d069a0714 100644
--- a/bridges/SoundcloudBridge.php
+++ b/bridges/SoundcloudBridge.php
@@ -64,7 +64,7 @@ public function collectData() {
$item['content'] = <<{$description}
- HTML;
+HTML;
if (isset($apiItem->tracks) && $apiItem->track_count > 0) {
$list = $this->getTrackList($apiItem->tracks);
@@ -227,7 +227,7 @@ private function getTrackList($tracks) {
foreach($apiItems as $track) {
$list .= <<{$track->user->username} — {$track->title}
- HTML;
+HTML;
}
$html = <<