├── .github └── workflows │ └── php.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── examples └── Search.php └── src └── Tidal └── TidalAPI.php /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Validate composer.json and composer.lock 18 | run: composer validate 19 | 20 | - name: Install dependencies 21 | run: composer install --prefer-dist --no-progress --no-suggest 22 | 23 | # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" 24 | # Docs: https://getcomposer.org/doc/articles/scripts.md 25 | 26 | # - name: Run test suite 27 | # run: composer run-script test 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 H. Yusuf Usta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-tidal 2 | 3 | Unofficial PHP API for TIDAL music streaming service. 4 | 5 | ## Installation 6 | 7 | Install from [Composer](https://getcomposer.org/) using `composer`: 8 | 9 | ``` bash 10 | $ composer require quiec/php-tidal dev-master 11 | ``` 12 | Also you can install without composer (for shared hosts). [Click here](https://github.com/Quiec/php-tidal/releases/download/1.0.0/tidalphp.zip) for download zip. 13 | 14 | ## Example usage 15 | 16 | [+ Simple Downloader](https://github.com/Quiec/php-tidal/blob/master/examples/Downloader.php) 17 | 18 | ``` php 19 | logIn("user", "pass"); 26 | $ara = $tidal->search("istanbul"); 27 | 28 | foreach ($ara as $sonuc) { 29 | echo $sonuc["artist"]["name"] . " - " . $sonuc["title"] . "\n"; 30 | } 31 | ``` 32 | 33 | ## Documentation 34 | 35 | I will add. 36 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quiec/php-tidal", 3 | "description": "Unofficial PHP API for TIDAL music streaming service", 4 | "require": { 5 | "guzzlehttp/guzzle": "^6.5" 6 | }, 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Yusuf Usta", 11 | "email": "yusuf@quiec.tech" 12 | } 13 | ], 14 | "minimum-stability": "dev", 15 | "autoload":{ 16 | "psr-4" : { 17 | "Tidal\\": "src/Tidal/" 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /examples/Search.php: -------------------------------------------------------------------------------- 1 | logIn("user", "pass"); 8 | $ara = $tidal->search("istanbul"); 9 | 10 | foreach ($ara as $sonuc) { 11 | echo $sonuc["artist"]["name"] . " - " . $sonuc["title"] . "\n"; 12 | } 13 | -------------------------------------------------------------------------------- /src/Tidal/TidalAPI.php: -------------------------------------------------------------------------------- 1 | client = new Client(); 22 | } 23 | 24 | public function logIn($username, $password) { 25 | $url = $this->urlCreate("login/username" . "?token=kgsOOmYk3zShYrNP"); 26 | $logIn = $this->client->post($url, [ 27 | 'form_params' => [ 28 | 'username' => $username, 29 | 'password' => $password 30 | ], 31 | 'headers' => [ 32 | 'Content-Type' => 'application/x-www-form-urlencoded' 33 | ] 34 | ]); 35 | 36 | $StatusCode = $logIn->getStatusCode(); 37 | if ($StatusCode !== 400) { 38 | $logInJson = json_decode($logIn->getBody(), true); 39 | $this->sessionId = $logInJson["sessionId"]; 40 | $this->countryCode = $logInJson["countryCode"]; 41 | 42 | echo "[i] Succesfully Logined.\n"; 43 | } 44 | } 45 | 46 | public function search($field = "track", $query = NULL) { 47 | return json_decode($this->sendRequest("search/" . $field, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "limit" => 999, "query" => $query]), true)["items"]; 48 | } 49 | 50 | public function getTrackUrl ($TrackId, $Quality = "HIGH") { 51 | return $this->sendRequest("tracks/" . $TrackId . "/streamUrl", ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "soundQuality" => $Quality]); 52 | } 53 | 54 | public function getVideoUrl ($VideoId, $Quality = "MEDIUM") { 55 | return $this->sendRequest("videos/" . $VideoId . "/urlpostpaywall", ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "urlusagemode" => "STREAM", "assetpresentation" => "FULL", "videoquality" => $Quality]); 56 | } 57 | 58 | public function getVideo ($VideoId) { 59 | return $this->sendRequest("videos/" . $VideoId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 60 | } 61 | 62 | public function getTrack ($TrackId) { 63 | return $this->sendRequest("tracks/" . $TrackId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 64 | } 65 | 66 | public function getTrackRadio ($TrackId, $Limit = 100) { 67 | return $this->sendRequest('tracks/' . $TrackId . '/radio', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "limit" => $Limit]); 68 | } 69 | 70 | public function getGenres () { 71 | return $this->sendRequest('genres', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 72 | } 73 | 74 | public function getGenreItems ($GenreId, $ContentType) { 75 | return $this->sendRequest('genres/' . $GenreId . '/' . $ContentType, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 76 | } 77 | 78 | public function getMoods () { 79 | return $this->sendRequest('moods', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 80 | } 81 | 82 | public function getMoodPlaylist ($MoodId) { 83 | return $this->sendRequest('moods/' . $MoodId . '/playlists', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 84 | } 85 | 86 | public function getFeatured () { 87 | return json_decode($this->sendRequest('promotions', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]), true)["items"]; 88 | } 89 | 90 | public function getFeaturedItems ($Group, $ContentType) { 91 | return $this->sendRequest('featured/' . $Group . '/' . $ContentType, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 92 | } 93 | 94 | public function getUser ($UserId) { 95 | return $this->sendRequest('users/' . $UserId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 96 | } 97 | 98 | public function getUserPlaylist ($UserId) { 99 | return $this->sendRequest('users/' . $UserId . '/playlists', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 100 | } 101 | 102 | public function getPlaylist ($PlaylistId) { 103 | return $this->sendRequest('playlists/' . $PlaylistId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 104 | } 105 | 106 | public function getPlaylistTracks ($PlaylistId) { 107 | // need parse because getting tracks and videos 108 | return $this->sendRequest('playlists/' . $PlaylistId . '/tracks', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 109 | } 110 | 111 | public function getPlaylistVideos ($PlaylistId) { 112 | return $this->sendRequest('playlists/' . $PlaylistId . '/items', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 113 | } 114 | 115 | public function getPlaylistItems ($PlaylistId) { 116 | return $this->sendRequest('playlists/' . $PlaylistId . '/items', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 117 | } 118 | 119 | public function getAlbum ($AlbumId) { 120 | return $this->sendRequest('albums/' . $AlbumId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 121 | } 122 | 123 | public function getAlbumTracks ($AlbumId) { 124 | return $this->sendRequest('albums/' . $AlbumId . '/tracks', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 125 | } 126 | 127 | public function getAlbumVideos ($AlbumId) { 128 | // need parse because getting tracks and videos 129 | return $this->sendRequest('albums/' . $AlbumId . '/items', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 130 | } 131 | 132 | public function getAlbumItems ($AlbumId) { 133 | return $this->sendRequest('albums/' . $AlbumId . '/items', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 134 | } 135 | 136 | public function getArtist ($ArtistId) { 137 | return $this->sendRequest('artists/' . $ArtistId, ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 138 | } 139 | 140 | public function getArtistAlbums ($ArtistId) { 141 | return $this->sendRequest('artists/' . $ArtistId . '/albums', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 142 | } 143 | 144 | public function getArtistAlbums_Singles ($ArtistId) { 145 | return $this->sendRequest('artists/' . $ArtistId . '/albums', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "filter" => "EPSANDSINGLES"]); 146 | } 147 | 148 | public function getArtistAlbums_Other ($ArtistId) { 149 | return $this->sendRequest('artists/' . $ArtistId . '/albums', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode, "filter" => "COMPILATIONS"]); 150 | } 151 | 152 | public function getArtistTopTracks ($ArtistId) { 153 | return $this->sendRequest('artists/' . $ArtistId . '/toptracks', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 154 | } 155 | 156 | public function getArtistVideos ($ArtistId) { 157 | return $this->sendRequest('artists/' . $ArtistId . '/videos', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 158 | } 159 | 160 | public function getArtistBio ($ArtistId) { 161 | return $this->sendRequest('artists/' . $ArtistId . '/bio', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 162 | } 163 | 164 | public function getArtistSimilar ($ArtistId) { 165 | return $this->sendRequest('artists/' . $ArtistId . '/similar', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 166 | } 167 | 168 | public function getArtistRadio ($ArtistId) { 169 | return $this->sendRequest('artists/' . $ArtistId . '/radio', ["sessionId" => $this->sessionId, "countryCode" => $this->countryCode]); 170 | } 171 | 172 | public function getAlbumPhoto ($AlbumPhotoId, $Size = 1080) { 173 | return "https://resources.tidal.com/images/" . $AlbumPhotoId . "/" . $Size . "x" . $Size . ".jpg"; 174 | } 175 | 176 | 177 | 178 | private function sendRequest($Method, $Params, $Headers = NULL) { 179 | if (!isset($this->sessionId, $this->countryCode)) { 180 | echo "Please first log in, You Didnt Login\n"; 181 | } else { 182 | $url = $this->urlCreate($Method); 183 | return $sendReq = $this->client->get($url, 184 | [ 185 | 'query' => $Params, 186 | 'headers' => $Headers 187 | ])->getBody(); 188 | } 189 | } 190 | 191 | private function urlCreate($method) { 192 | return self::TIDAL_API_URL . $method; 193 | } 194 | } 195 | --------------------------------------------------------------------------------