123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- <?php
- include "../data/config.php";
- new spotify();
- class spotify{
-
- public function __construct(){
-
- include "../lib/fuckhtml.php";
- $this->fuckhtml = new fuckhtml();
-
- if(
- !isset($_GET["s"]) ||
- !preg_match(
- '/^(track|episode)\.([A-Za-z0-9]{22})$/',
- $_GET["s"],
- $matches
- )
- ){
-
- $this->do404("The track ID(s) parameter is missing or invalid");
- }
-
- try{
-
- if($matches[1] == "episode"){
-
- $uri = "show";
- }else{
-
- $uri = $matches[1];
- }
-
- $embed =
- $this->get("https://embed.spotify.com/{$uri}/" . $matches[2]);
- }catch(Exception $error){
-
- $this->do404("Failed to fetch embed data");
- }
-
- $this->fuckhtml->load($embed);
-
- $json =
- $this->fuckhtml
- ->getElementById(
- "__NEXT_DATA__",
- "script"
- );
-
- if($json === null){
-
- $this->do404("Failed to extract JSON");
- }
-
- $json =
- json_decode($json["innerHTML"], true);
-
- if($json === null){
-
- $this->do404("Failed to decode JSON");
- }
-
- switch($matches[1]){
-
- case "track":
- if(
- isset(
- $json
- ["props"]
- ["pageProps"]
- ["state"]
- ["data"]
- ["entity"]
- ["audioPreview"]
- ["url"]
- )
- ){
-
- header("Content-type: audio/mpeg");
- header(
- "Location: /audio/linear?s=" .
- urlencode(
- $json
- ["props"]
- ["pageProps"]
- ["state"]
- ["data"]
- ["entity"]
- ["audioPreview"]
- ["url"]
- )
- );
- }else{
-
- $this->do404("Could not extract playback URL");
- }
- break;
-
- case "episode":
- if(
- isset(
- $json
- ["props"]
- ["pageProps"]
- ["state"]
- ["data"]
- ["entity"]
- ["id"]
- )
- ){
-
- try{
- $json =
- $this->get(
- "https://spclient.wg.spotify.com/soundfinder/v1/unauth/episode/" .
- $json
- ["props"]
- ["pageProps"]
- ["state"]
- ["data"]
- ["entity"]
- ["id"] .
- "/com.widevine.alpha"
- );
- }catch(Exception $error){
-
- $this->do404("Failed to fetch audio resource");
- }
-
- $json = json_decode($json, true);
-
- if($json === null){
-
- $this->do404("Failed to decode audio resource JSON");
- }
-
- if(
- isset($json["passthrough"]) &&
- $json["passthrough"] == "ALLOWED" &&
- isset($json["passthroughUrl"])
- ){
-
- header(
- "Location:" .
- "/audio/linear.php?s=" .
- urlencode(
- str_replace(
- "http://",
- "https://",
- $json["passthroughUrl"]
- )
- )
- );
- }else{
-
- $this->do404("Failed to find passthroughUrl");
- }
-
- }else{
-
- $this->do404("Failed to find episode ID");
- }
- break;
- }
- }
-
- private function get($url){
-
- $headers = [
- "User-Agent: " . config::USER_AGENT,
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
- "Accept-Language: en-US,en;q=0.5",
- "Accept-Encoding: gzip",
- "DNT: 1",
- "Connection: keep-alive",
- "Upgrade-Insecure-Requests: 1",
- "Sec-Fetch-Dest: document",
- "Sec-Fetch-Mode: navigate",
- "Sec-Fetch-Site: none",
- "Sec-Fetch-User: ?1"
- ];
-
- $curlproc = curl_init();
-
- curl_setopt($curlproc, CURLOPT_URL, $url);
-
- curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
- curl_setopt($curlproc, CURLOPT_HTTPHEADER, $headers);
-
- curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
- curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
- curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
- curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
-
- $data = curl_exec($curlproc);
-
- if(curl_errno($curlproc)){
- throw new Exception(curl_error($curlproc));
- }
-
- curl_close($curlproc);
- return $data;
- }
-
- private function do404($error){
-
- http_response_code(404);
- header("Content-Type: text/plain");
- header("X-Error: $error");
- die();
- }
- }
|