diff options
author | lolcat <will@lolcat.ca> | 2024-02-17 23:22:19 -0500 |
---|---|---|
committer | lolcat <will@lolcat.ca> | 2024-02-17 23:22:19 -0500 |
commit | addc5a14a93547f630f23e5b6a79cffa2e37d71a (patch) | |
tree | a9163ba3a2e24c3c493cdde95e506c0e7e8a772d /audio/spotify.php | |
parent | edc917f5ee984160a0eef436dabd51696d675964 (diff) |
boobs
Diffstat (limited to 'audio/spotify.php')
-rw-r--r-- | audio/spotify.php | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/audio/spotify.php b/audio/spotify.php new file mode 100644 index 0000000..dc8fae6 --- /dev/null +++ b/audio/spotify.php @@ -0,0 +1,214 @@ +<?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(); + } +} |