Skip to content

Commit 81451dd

Browse files
committed
Added artist links.
Some small visual enhancements.
1 parent be41d50 commit 81451dd

File tree

17 files changed

+219
-62
lines changed

17 files changed

+219
-62
lines changed

about.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function about() {
166166
<ul style="padding-left: 1em;">
167167
<li> added support for HighResAudio (thanks to <a target="_blank" href="https://github.com/marcbth">marcbth</a>)</li>
168168
<li> added badge with audio format info on album cover (thanks to <a target="_blank" href="https://github.com/paradix">paradix</a>)</li>
169-
<li> added support for Tidal oauth2 login</li>
169+
<li> added support for Tidal OAuth2 login</li>
170170
<li> added popularity bar on album cover</li>
171171
<li> added new popularity category (by album year)</li>
172172
<li> compatibillity with PHP8</li>

api/hra_api/hra_api.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,12 @@ function getCategorieContent($categorie, $limit=30, $offset=0) {
263263

264264
function request() {
265265
curl_setopt($this->curl, CURLOPT_POST, 0);
266-
$server_output = curl_exec($this->curl);
266+
for ($i=0; $i<3; $i++) {
267+
$server_output = curl_exec($this->curl);
268+
if (curl_errno($this->curl) == 0 ) {
269+
break;
270+
}
271+
}
267272
$res_json = json_decode($server_output, true);
268273
return $res_json;
269274
}

api/tidal_api/tidal_api.php

+72-32
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ class TidalAPI {
3030
public $fixSSLcertificate = false;
3131
public $deviceCode;
3232
public $apiKey;
33-
//DEL:
34-
public $sessionId;
3533

3634
const AUTH_URL = 'https://auth.tidal.com/v1/oauth2';
3735
const TOKEN_VERIFY_URL = 'https://api.tidal.com/v1/sessions';
3836
const LOGOUT_URL = 'https://api.tidal.com/v1/logout';
39-
const API_URL = "https://api.tidalhifi.com/v1/";
37+
const API_URL = "https://api.tidal.com/v1/";
38+
const API_V2_URL = "https://api.tidal.com/v2/";
4039
const RESOURCES_URL = "https://resources.tidal.com/images/";
4140

4241

4342
public function __construct(){
4443
$this->apiKey = array('clientId' => base64_decode('YVI3Z1VhVEsxaWhwWE9FUA=='), 'clientSecret' => base64_decode('ZVZXQkVrdUwyRkNqeGdqT2tSM3lLMFJZWkViY3JNWFJjMmw4ZlUzWkNkRT0='));
45-
44+
//$this->apiKey = array('clientId' => '', 'clientSecret' => '');
45+
4646
$this->curl = curl_init();
4747
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
4848
//to fix "SSL certificate problem: unable to get local issuer certificate" under Windows uncomment below lines or use function fixSSLcertificate():
@@ -51,7 +51,6 @@ public function __construct(){
5151
}
5252

5353
public function __destruct(){
54-
//$this->logout($this->sessionId);
5554
curl_close($this->curl);
5655
}
5756

@@ -163,63 +162,73 @@ function logout() {
163162

164163
function search($type, $query, $limit = 50) {
165164
$query = urlencode($query);
166-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "search/" . $type . "?sessionId=" . $this->sessionId . "&query=" . $query . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
165+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "search/" . $type . "?query=" . $query . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
167166
return $this->request();
168167
}
169168

170169
function searchAll($query, $limit = 50) {
171170
$query = urlencode($query);
172-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "search?sessionId=" . $this->sessionId . "&query=" . $query . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&types=ARTISTS,ALBUMS,TRACKS,PLAYLISTS");
171+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "search?query=" . $query . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&types=ARTISTS,ALBUMS,TRACKS,PLAYLISTS");
173172
return $this->request();
174173
}
175174

176175
function getTrack($track_id) {
177-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "tracks/" . $track_id . "?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
176+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "tracks/" . $track_id . "?countryCode=" . $this->countryCode);
178177
return $this->request();
179178
}
180179

181180
function getAlbum($album_id) {
182-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "albums/" . $album_id . "?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
181+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "albums/" . $album_id . "?countryCode=" . $this->countryCode);
183182
return $this->request();
184183
}
185184

186185
function getAlbumTracks($album_id) {
187-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "albums/" . $album_id . "/tracks?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
186+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "albums/" . $album_id . "/tracks?countryCode=" . $this->countryCode);
188187
return $this->request();
189188
}
190189

191190
function getAlbumInfo($album_id) {
192-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/album?albumId=" . $album_id . "&deviceType=BROWSER&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
191+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/album?albumId=" . $album_id . "&deviceType=BROWSER&countryCode=" . $this->countryCode);
192+
return $this->request();
193+
}
194+
195+
function getAlbumReview($album_id) {
196+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "albums/" . $album_id . "/review?countryCode=" . $this->countryCode);
193197
return $this->request();
194198
}
195199

196200
function getArtistAll($artist_id) {
197-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/artist?artistId=" . $artist_id . "&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&deviceType=BROWSER");
201+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/artist?artistId=" . $artist_id . "&countryCode=" . $this->countryCode . "&deviceType=BROWSER");
198202
return $this->request();
199203
}
200204

201205
function getArtistAlbums($artist_id, $limit = 50) {
202-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
206+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/albums?countryCode=" . $this->countryCode . "&limit=" . $limit);
203207
return $this->request();
204208
}
205209

206210
function getArtistEPsAndSingles($artist_id, $limit = 50) {
207-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/albums?filter=EPSANDSINGLES&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
211+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/albums?filter=EPSANDSINGLES&countryCode=" . $this->countryCode . "&limit=" . $limit);
208212
return $this->request();
209213
}
210214

211215
function getArtistTopTracks($artist_id, $limit = 10) {
212-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/toptracks?filter=ALL&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
216+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/toptracks?filter=ALL&countryCode=" . $this->countryCode . "&limit=" . $limit);
217+
return $this->request();
218+
}
219+
220+
function getArtistBio($artist_id, $limit = 10) {
221+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/bio?countryCode=" . $this->countryCode . "&limit=" . $limit);
213222
return $this->request();
214223
}
215224

216-
function getArtistBio($artist_id) {
217-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/bio?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
225+
function getArtistLinks($artist_id, $limit = 20) {
226+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "artists/" . $artist_id . "/links?countryCode=" . $this->countryCode . "&limit=" . $limit);
218227
return $this->request();
219228
}
220229

221230
function getRelatedArtists($artist_id) {
222-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/artist?artistId=" . $artist_id . "&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&deviceType=BROWSER");
231+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/artist?artistId=" . $artist_id . "&countryCode=" . $this->countryCode . "&deviceType=BROWSER");
223232
$artistAll = $this->request();
224233
foreach ($artistAll["rows"] as $module){
225234
if ($module["modules"][0]["type"]=='ARTIST_LIST') {
@@ -229,30 +238,30 @@ function getRelatedArtists($artist_id) {
229238
}
230239

231240
function getNewAlbums($limit = 100) {
232-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/show_more_featured_albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&deviceType=BROWSER");
241+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "pages/show_more_featured_albums?countryCode=" . $this->countryCode . "&limit=" . $limit . "&deviceType=BROWSER");
233242
$res = $this->request();
234243
return $res;
235244
$s = array_search("featured-new",array_column($res["rows"][0]["modules"][0]["tabs"],"key"));
236245
return $res["rows"][0]["modules"][0]["tabs"][$s]["pagedList"]["items"];
237246
}
238247

239248
function getFeatured($limit = 100, $offset = 0) {
240-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/new/albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
249+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/new/albums?countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
241250
return $this->request();
242251
}
243252

244253
function getFeaturedRecommended($limit = 100, $offset = 0) {
245-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/recommended/albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
254+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/recommended/albums?countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
246255
return $this->request();
247256
}
248257

249258
function getFeaturedTop($limit = 100, $offset = 0) {
250-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/top/albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
259+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/top/albums?countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
251260
return $this->request();
252261
}
253262

254263
function getFeaturedLocal($limit = 100, $offset = 0) {
255-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/local/albums?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
264+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "featured/local/albums?countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
256265
return $this->request();
257266
}
258267

@@ -343,33 +352,59 @@ function getSuggestedNewTracks($limit = 50, $offset = 0, $getMore = false) {
343352

344353
function getByApiPath($limit, $offset, $apiPath) {
345354
if ($limit > 50) $limit = 50; //Tidal API limitation
346-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . $apiPath ."?sessionId=" . $this->sessionId . "&locale=en_US&deviceType=BROWSER&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
355+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . $apiPath ."?locale=en_US&deviceType=BROWSER&countryCode=" . $this->countryCode . "&limit=" . $limit . "&offset=" . $offset);
347356
return $this->request();
348357
}
349358

350-
function getStreamURL($track_id) {
351-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "tracks/" . $track_id . "/streamUrl?soundQuality=" . $this->audioQuality . "&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
359+
function getStreamURL_old($track_id) {
360+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "tracks/" . $track_id . "/streamUrl?soundQuality=" . $this->audioQuality . "&countryCode=" . $this->countryCode);
352361
return $this->request();
353362
}
354363

364+
function getStreamURL($track_id) {
365+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "tracks/" . $track_id . "/playbackinfopostpaywall?audioquality=" . $this->audioQuality . "&countryCode=" . $this->countryCode . "&playbackmode=STREAM&assetpresentation=FULL");
366+
$res = $this->request();
367+
if (strpos($res['manifestMimeType'],"vnd.tidal.bt") !== false) {
368+
$manifest = json_decode(base64_decode($res['manifest']),true);
369+
$res['manifest_b64_decoded'] = $manifest;
370+
$res['url'] = $manifest['urls'][0];
371+
}
372+
return $res;
373+
}
374+
355375
function getUserPlaylists() {
356-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "users/" . $this->userId . "/playlists?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
376+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "users/" . $this->userId . "/playlists?countryCode=" . $this->countryCode . "&limit=" . $limit);
357377
return $this->request();
358378
}
359379

360380
function getUserPlaylistTracks($playlist_id, $limit = 1000) {
361-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "playlists/" . $playlist_id . "/tracks?sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode . "&limit=" . $limit);
381+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . "playlists/" . $playlist_id . "/tracks?countryCode=" . $this->countryCode . "&limit=" . $limit);
362382
return $this->request();
363383
}
364384

365385
function getHomePage() {
366-
//curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/home?locale=en_US&deviceType=DESKTOP&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
367-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/home?locale=en_US&deviceType=BROWSER&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
386+
//curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/home?locale=en_US&deviceType=DESKTOP&countryCode=" . $this->countryCode);
387+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/home?locale=en_US&deviceType=BROWSER&countryCode=" . $this->countryCode);
388+
return $this->request();
389+
}
390+
391+
function getUserClients() {
392+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " users/" . $this->userId . "/clients?countryCode=" . $this->countryCode);
393+
return $this->request();
394+
}
395+
396+
function getUserSubscription() {
397+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " users/" . $this->userId . "/subscription?countryCode=" . $this->countryCode);
398+
return $this->request();
399+
}
400+
401+
function getUserFeedActivities() {
402+
curl_setopt($this->curl, CURLOPT_URL, self::API_V2_URL . " feed/activities/?userId=" . $this->userId . "&countryCode=" . $this->countryCode . '&locale=en-us');
368403
return $this->request();
369404
}
370405

371406
function getExplorePage() {
372-
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/explore?locale=en_US&deviceType=BROWSER&sessionId=" . $this->sessionId . "&countryCode=" . $this->countryCode);
407+
curl_setopt($this->curl, CURLOPT_URL, self::API_URL . " pages/explore?locale=en_US&deviceType=BROWSER&countryCode=" . $this->countryCode);
373408
return $this->request();
374409
}
375410

@@ -404,7 +439,12 @@ static function albumCoverToURL($pic,$quality = 'hq') {
404439
function request() {
405440
curl_setopt($this->curl, CURLOPT_POST, 0);
406441
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('authorization: Bearer ' . $this->token));
407-
$server_output = curl_exec($this->curl);
442+
for ($i=0; $i<3; $i++) {
443+
$server_output = curl_exec($this->curl);
444+
if (curl_errno($this->curl) == 0 ) {
445+
break;
446+
}
447+
}
408448
$res_json = json_decode($server_output, true);
409449
if (isset($res_json['status']) && ($res_json['status']) != 200) {
410450
$res_json['return'] = 1;

config.php

+19-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
// | Config |
7777
// +------------------------------------------------------------------------+
7878
function config() {
79-
global $cfg, $db, $update;
79+
global $cfg, $db, $update, $t;
8080
authenticate('access_logged_in');
8181
require_once('include/play.inc.php');
8282

@@ -286,13 +286,28 @@ function config() {
286286
<td></td>
287287
</tr>
288288
<?php
289-
}
289+
}
290+
$query = mysqli_query($db, 'SELECT * FROM tidal_token LIMIT 1');
291+
if ($query) $tidal_token = mysqli_fetch_assoc($query);
292+
if ($tidal_token['time'] == 0) {
293+
$update_info = '<span class="update_info"><br>Not logged in</span>';
294+
}
295+
elseif (time() > $tidal_token['expires_after']) {
296+
$update_info = '<span class="update_info"><br>Token expired.</span>';
297+
}
298+
elseif (time() < $tidal_token['expires_after']) {
299+
$tokenStatus = $t->verifyAccessToken();
300+
if (isset($tokenStatus['sessionId'])) {
301+
$exDate = date('Y-m-d H:i',$tidal_token['expires_after']);
302+
$update_info = '<span class="update_info"><br>Logged in, token valid until ' . $exDate . '</span>';
303+
}
304+
}
290305
?>
291306
<tr class="<?php echo ($i++ & 1) ? 'even' : 'odd'; ?>">
292307
<td></td>
293308
<td class="nowrap"><a href="config.php?action=tidal"><i class="ux ico-tidal icon-small fa-fw"></i>Tidal</a></td>
294309
<td></td>
295-
<td>Tidal login and status</td>
310+
<td>Tidal login and status<?php echo $update_info?></td>
296311
<td></td>
297312
</tr>
298313
</table>
@@ -1460,6 +1475,7 @@ function editTidal() {
14601475
$('#loginTidal > i').removeClass('fa-exclamation-circle icon-nok').addClass('fa-sign-in');
14611476
}, 2000);
14621477
timeLeft = 0;
1478+
xhr.abort();
14631479
return;
14641480
}
14651481

include/library.inc.php

+10
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,16 @@ function showArtistBio($artist_name, $size) {
996996
$i++;
997997
}
998998
}
999+
$artist_links = $t->getArtistLinks($id);
1000+
$data['artist_links']['links_found'] = 0;
1001+
if (isset($artist_links['items'])) {
1002+
foreach($artist_links['items'] as $al){
1003+
if ($al['siteName'] == 'ALLMUSIC' || $al['siteName'] == 'DISCOGS' || $al['siteName'] == 'FACEBOOK' || $al['siteName'] == 'OFFICIAL_HOMEPAGE' || $al['siteName'] == 'WIKIPEDIA' || $al['siteName'] == 'YOUTUBE' || $al['siteName'] == 'MYSPACE' || $al['siteName'] == 'TWITTER') {
1004+
$data['artist_links']['links_found']++;
1005+
$data['artist_links']['items'][] = array('url' => $al['url'], 'siteName' => $al['siteName']);
1006+
}
1007+
}
1008+
}
9991009
$data['size'] = $size;
10001010
/* $data = $t->getArtistAll($id);
10011011
$data["picture"] = $t->getArtistPicture($data["rows"][0]["modules"][0]["artist"]["picture"]);

index-view2.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,15 @@
515515
});
516516
related_artists +='</div>';
517517
}
518-
artist_bio = artist_bio + related_artists;
518+
artist_links = '';
519+
if (data["artist_links"]['links_found'] > 0) {
520+
artist_links = '<div style="text-transform: uppercase;"><h1>More about artist:</h1></div><div class="artist_bio_text lh3">';
521+
$.each(data["artist_links"]["items"], function(index, value){
522+
artist_links += '<span class=""><a target="_BLANK" href="' + value["url"] + '">' + (value["siteName"]).replace("_","&nbsp;") + '</a></span>&nbsp;&nbsp;|&nbsp;&nbsp; ';
523+
});
524+
artist_links +='</div>';
525+
}
526+
artist_bio = artist_bio + artist_links + related_artists;
519527
$( "#searchResultsTB" ).html( artist_bio );
520528
}
521529
else {

index-view3.php

+9
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,16 @@
760760
album_id : '<?php echo $album_id; ?>',
761761
image_id : '<?php echo $image_id; ?>',
762762
total_time : '<?php echo $total_time["sum_miliseconds"]; ?>',
763+
<?php
764+
foreach ($tracks as &$str) {
765+
$str = str_replace('"', "'", $str);
766+
}
767+
foreach ($tracks as &$str) {
768+
$str = str_replace("\\", "", $str);
769+
}
770+
?>
763771
tracks : '<?php echo str_replace("'","\'",json_encode($tracks)); ?>'
772+
//tracks : '<?php echo json_encode($tracks,JSON_HEX_APOS|JSON_HEX_QUOT); ?>'
764773
},
765774
dataType: "html"
766775
});

0 commit comments

Comments
 (0)