From addc5a14a93547f630f23e5b6a79cffa2e37d71a Mon Sep 17 00:00:00 2001 From: lolcat Date: Sat, 17 Feb 2024 23:22:19 -0500 Subject: [PATCH] boobs --- api.txt | 31 +- audio/linear.php | 20 + audio/sc.php | 223 ++++++ audio/seekable.php | 20 + audio/spotify.php | 214 ++++++ captcha.php | 128 +++- data/config.php | 27 +- images.php | 5 +- lib/{captcha_gen.php => bot_protection.php} | 145 ++-- lib/classic.png | Bin 358 -> 0 bytes lib/frontend.php | 13 +- lib/fuckhtml.php | 25 +- music.php | 47 +- news.php | 5 +- opensearch.php | 2 +- scraper/mojeek.php | 27 +- scraper/sc.php | 11 +- scraper/spotify.json | 1 + scraper/spotify.php | 726 ++++++++++++++++++++ settings.php | 2 +- static/style.css | 43 +- template/header.html | 5 + template/home.html | 2 +- template/images.html | 1 + template/search.html | 1 + videos.php | 5 +- web.php | 7 +- 27 files changed, 1521 insertions(+), 215 deletions(-) create mode 100644 audio/linear.php create mode 100644 audio/sc.php create mode 100644 audio/seekable.php create mode 100644 audio/spotify.php rename lib/{captcha_gen.php => bot_protection.php} (68%) delete mode 100644 lib/classic.png create mode 100644 scraper/spotify.json create mode 100644 scraper/spotify.php diff --git a/api.txt b/api.txt index bc8ed05..a64873e 100644 --- a/api.txt +++ b/api.txt @@ -267,20 +267,23 @@ Each entry under "song" contains a array index called "stream" that looks like this :: - endpoint: audio_sc + endpoint: sc url: https://api-v2.soundcloud <...> - When the endpoint is "audio_sc", you MUST use 4get's audio_sc - endpoint, for example, if you want an audio stream back. Otherwise, - you are free to handle the json+m3u8 crap yourself. If the endpoint - is equal to "audio", that URL SHOULD return a valid HTTP audio - stream, and using the "audio" endpoint becomes optional again. + When the endpoint is something else than "linear", you MUST use + the specified endpoint. Otherwise, you are free to handle that + json+m3u8 crap yourself. If the endpoint is equal to "linear", the + URL should return a valid HTTP audio stream. To access the endpoint, + you must add the following prefix in your request, like so: + + https://4get.ca/audio/?s= + /favicon Get the favicon for a website. The only parameter is "s", and must - include the protocol. + include the protocol for fetching in case the favicon is not cached + yet. Example :: @@ -313,14 +316,14 @@ is set. -+ /audio ++ /audio/linear Get a proxied audio file. Does not support "Range" headers, as it's - only used to proxy small files. + only used to proxy small files (hence why it's called linear DUH) The parameter is "s" for the audio link. -+ /audio_sc ++ /audio/sc Get a proxied audio file for SoundCloud. Does not support downloads trough WGET or CURL, since it returns 30kb~160kb "206 Partial Content" parts, due to technical limitations that comes with @@ -334,6 +337,14 @@ does not support "normal" SoundCloud URLs at this time. ++ /audio/spotify + Get a proxied Spotify audio file. Accepts a track ID for the "s" + parameter. Will only allow you to fetch the 30 second preview since + I don't feel like fucking with cookies and accounts every fucking + living moment of my life. You must handle the initial 302 redirect + to the /audio/linear endpoint. + + + Appendix If you have any questions or need clarifications, please send an email my way to will at lolcat.ca diff --git a/audio/linear.php b/audio/linear.php new file mode 100644 index 0000000..b6a848f --- /dev/null +++ b/audio/linear.php @@ -0,0 +1,20 @@ +stream_linear_audio($_GET["s"]); +}catch(Exception $error){ + + header("X-Error: " . $error->getMessage()); +} diff --git a/audio/sc.php b/audio/sc.php new file mode 100644 index 0000000..53d8164 --- /dev/null +++ b/audio/sc.php @@ -0,0 +1,223 @@ +proxy = new proxy(); + + if(isset($_GET["u"])){ + + /* + we're now proxying audio + */ + $viewkey = $_GET["u"]; + + if(!isset($_GET["r"])){ + + $this->do404("Ranges(r) are missing"); + } + + $ranges = explode(",", $_GET["r"]); + + // sanitize ranges + foreach($ranges as &$range){ + + if(!is_numeric($range)){ + + $this->do404("Invalid range specified"); + } + + $range = (int)$range; + } + + // sort ranges (just to make sure) + sort($ranges); + + // convert ranges to pairs + $last = -1; + foreach($ranges as &$r){ + + $tmp = $r; + $r = [$last + 1, $r]; + + $last = $tmp; + } + + $browser_headers = getallheaders(); + + // get the requested range from client + $client_range = 0; + foreach($browser_headers as $key => $value){ + + if(strtolower($key) == "range"){ + + preg_match( + '/bytes=([0-9]+)/', + $value, + $client_regex + ); + + if(isset($client_regex[1])){ + + $client_range = (int)$client_regex[1]; + }else{ + + $client_range = 0; + } + break; + } + } + + if( + $client_range < 0 || + $client_range > $ranges[count($ranges) - 1][1] + ){ + + // range is not satisfiable + http_response_code(416); + header("Content-Type: text/plain"); + die(); + } + + $rng = null; + for($i=0; $iproxy->stream_linear_audio( + $viewkey + ); + }catch(Exception $error){ + + $this->do404("Could not read stream"); + } + + die(); + } + + /* + redirect user to correct resource + we need to scrape and store the byte positions in the result URL + */ + if(!isset($_GET["s"])){ + + $this->do404("The URL(s) parameter is missing"); + } + + $viewkey = $_GET["s"]; + + if( + preg_match( + '/soundcloud\.com$/', + parse_url($viewkey, PHP_URL_HOST) + ) === false + ){ + + $this->do404("This endpoint can only be used for soundcloud streams"); + } + + try{ + + $json = $this->proxy->get($viewkey)["body"]; + }catch(Exception $error){ + + $this->do404("Curl error: " . $error->getMessage()); + } + + $json = json_decode($json, true); + + if(!isset($json["url"])){ + + $this->do404("Could not get URL from JSON"); + } + + $viewkey = $json["url"]; + + $m3u8 = $this->proxy->get($viewkey)["body"]; + + $m3u8 = explode("\n", $m3u8); + + $lineout = null; + $streampos_arr = []; + foreach($m3u8 as $line){ + + $line = trim($line); + if($line[0] == "#"){ + + continue; + } + + if($lineout === null){ + $lineout = $line; + } + + preg_match( + '/\/media\/[0-9]+\/([0-9]+)\/([0-9]+)/', + $line, + $matches + ); + + if(isset($matches[0])){ + + $streampos_arr[] = [ + (int)$matches[1], + (int)$matches[2] + ]; + } + } + + if($lineout === null){ + + $this->do404("Could not get stream URL"); + } + + $lineout = + preg_replace( + '/\/media\/([0-9]+)\/[0-9]+\/[0-9]+/', + '/media/$1/0/0', + $lineout + ); + + $streampos = []; + + foreach($streampos_arr as $pos){ + + $streampos[] = $pos[1]; + } + + $streampos = implode(",", $streampos); + + header("Location: /audio/sc?u=" . urlencode($lineout) . "&r=$streampos"); + header("Accept-Ranges: bytes"); + } + + private function do404($error){ + + http_response_code(404); + header("Content-Type: text/plain"); + header("X-Error: $error"); + die(); + } +} diff --git a/audio/seekable.php b/audio/seekable.php new file mode 100644 index 0000000..b6a848f --- /dev/null +++ b/audio/seekable.php @@ -0,0 +1,20 @@ +stream_linear_audio($_GET["s"]); +}catch(Exception $error){ + + header("X-Error: " . $error->getMessage()); +} 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 @@ +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(); + } +} diff --git a/captcha.php b/captcha.php index 21da034..a92b0ee 100755 --- a/captcha.php +++ b/captcha.php @@ -1,47 +1,104 @@ newImage(400, 400, $theme["bg"]); +$im->newImage(400, 427, $theme["bg"]); $im->setImageBackgroundColor($theme["bg"]); $im->setImageFormat("jpg"); @@ -76,12 +133,18 @@ for($y=0; $y<4; $y++){ for($x=0; $x<4; $x++){ - $tmp = new Imagick("./data/captcha/" . $grid[0][$i][0] . "/" . random_int(1, $grid[0][$i][1]) . ".png"); + $tmp = new Imagick("./data/captcha/" . $grid[$i][0] . "/" . random_int(1, $grid[$i][1]) . ".png"); // convert transparency correctly $tmp->setImageBackgroundColor("black"); $tmp->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE); - + + // randomly mirror + if(random_int(0,1) === 1){ + + $tmp->flopImage(); + } + // distort $tmp $tmp->distortImage( $distort[random_int(0,1)], @@ -101,21 +164,15 @@ for($y=0; $y<4; $y++){ false ); + $tmp->addNoiseImage($noise[random_int(0, 1)]); + // append image - $im->compositeImage($tmp->getImage(), Imagick::COMPOSITE_DEFAULT, $x * 100, $y * 100); + $im->compositeImage($tmp->getImage(), Imagick::COMPOSITE_DEFAULT, $x * 100, ($y * 100) + 27); $i++; } } -// add noise -$im->addNoiseImage($noise[random_int(0, 1)]); - -// expand top of image -$im->setImageGravity(Imagick::GRAVITY_SOUTH); -$im->chopImage(0, -27, 400, 400); -$im->extentImage(0, 0, 0, -27); - // add text $draw = new ImagickDraw(); $draw->setFontSize(20); @@ -123,7 +180,7 @@ $draw->setFillColor($theme["fg"]); //$draw->setTextAntialias(false); $draw->setFont("./data/captcha/font.ttf"); -$text = "Pick " . $grid[1] . " images of " . str_replace("_", " ", $grid[2]); +$text = "Pick " . $picks . " images of " . str_replace("_", " ", $choosen[0]); $pos = 200 - ($im->queryFontMetrics($draw, $text)["textWidth"] / 2); @@ -143,5 +200,4 @@ for($i=0; $isetFormat("jpeg"); $im->setImageCompressionQuality(90); -$im->setImageCompression(Imagick::COMPRESSION_JPEG2000); echo $im->getImageBlob(); diff --git a/data/config.php b/data/config.php index dd0f3a7..6327ba9 100644 --- a/data/config.php +++ b/data/config.php @@ -5,7 +5,7 @@ class config{ // any parameters. // 4get version. Please keep this updated - const VERSION = 6; + const VERSION = 7; // Will be shown pretty much everywhere. const SERVER_NAME = "4get"; @@ -24,10 +24,10 @@ class config{ const API_ENABLED = true; // Bot protection - // 4get.ca has been hit with 250k bot reqs every single day for months + // 4get.ca has been hit with 500k bot reqs every single day for months // you probably want to enable this if your instance is public... // 0 = disabled - // 1 = ask for image captcha (requires image dataset & imagick 6.9.11-60) + // 1 = ask for image captcha (requires imagemagick v6 or higher) // @TODO: 2 = invite only (users needs a pass) const BOT_PROTECTION = 0; @@ -62,20 +62,27 @@ class config{ "https://4get.zzls.xyz", "https://4getus.zzls.xyz", "https://4get.silly.computer", - "https://4g.opnxng.com", "https://4get.konakona.moe", "https://4get.lvkaszus.pl", "https://4g.ggtyler.dev", "https://4get.perennialte.ch", - "https://4get.sihj.net", + "https://4get.sijh.net", "https://4get.hbubli.cc", "https://4get.plunked.party", - "https://4get.seitan-ayoub.lol" + "https://4get.seitan-ayoub.lol", + "https://4get.etenie.pl", + "https://4get.lunar.icu", + "https://4get.dcs0.hu", + "https://4get.kizuki.lol", + "https://4get.psily.garden", + "https://search.milivojevic.in.rs", + "https://4get.snine.nl", + "https://4get.datura.network" ]; // Default user agent to use for scraper requests. Sometimes ignored to get specific webpages // Changing this might break things. - const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0"; + const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0"; // Proxy pool assignments for each scraper // false = Use server's raw IP @@ -94,6 +101,8 @@ class config{ const PROXY_YT = false; // youtube const PROXY_YEP = false; const PROXY_PINTEREST = false; + const PROXY_SEZNAM = false; + const PROXY_NAVER = false; const PROXY_FTM = false; // findthatmeme const PROXY_IMGUR = false; const PROXY_YANDEX_W = false; // yandex web @@ -107,8 +116,8 @@ class config{ // SOUNDCLOUD // Get these parameters by making a search on soundcloud with network // tab open, then filter URLs using "search?q=". (No need to login) - const SC_USER_ID = "361066-632137-891392-693457"; - const SC_CLIENT_TOKEN = "nUB9ZvnjRiqKF43CkKf3iu69D8bboyKY"; + const SC_USER_ID = "59333-426459-717969-168008"; + const SC_CLIENT_TOKEN = "8BBZpqUP1KSN4W6YB64xog2PX4Dw98b1"; // MARGINALIA // Get an API key by contacting the Marginalia.nu maintainer. The "public" key diff --git a/images.php b/images.php index d9dbecf..3c4df15 100644 --- a/images.php +++ b/images.php @@ -15,10 +15,11 @@ $get = $frontend->parsegetfilters($_GET, $filters); /* Captcha */ -include "lib/captcha_gen.php"; -new captcha($frontend, $get, $filters, "images", true); +include "lib/bot_protection.php"; +new bot_protection($frontend, $get, $filters, "images", true); $payload = [ + "timetaken" => microtime(true), "images" => "", "nextpage" => "" ]; diff --git a/lib/captcha_gen.php b/lib/bot_protection.php similarity index 68% rename from lib/captcha_gen.php rename to lib/bot_protection.php index abcab7a..82de54c 100644 --- a/lib/captcha_gen.php +++ b/lib/bot_protection.php @@ -1,6 +1,6 @@ = 102){ + if($inc >= config::MAX_SEARCHES + 2){ // reached limit, delete and give captcha apcu_delete($_COOKIE["pass"]); @@ -62,7 +62,7 @@ class captcha{ if($output === false){ - http_response_code(429); // too many reqs + http_response_code(401); // forbidden echo json_encode([ "status" => "The \"pass\" token in your cookies is missing or has expired!!" ]); @@ -104,10 +104,13 @@ class captcha{ !isset($regex[0][1]) ){ - // check if its k + // check if its the v key if( - $line[0] == "k" && - strpos($line[1], "c.") === 0 + $line[0] == "v" && + preg_match( + '/^c[0-9]+\.[A-Za-z0-9_]{20}$/', + $line[1] + ) ){ $key = apcu_fetch($line[1]); @@ -129,27 +132,21 @@ class captcha{ $answers[] = $regex; } - + if( !$invalid && - $key !== false + $key !== false // has captcha been gen'd? ){ - $check = $key[1]; + $check = count($key); // validate answer - for($i=0; $irandomchars(); apcu_inc($key, 1, $stupid, 86400); @@ -203,84 +187,23 @@ class captcha{ } } - // get the positions for the answers - // will return between 3 and 6 answer positions - $range = range(0, 15); - $answer_pos = []; - - array_splice($range, 0, 1); - - for($i=0; $irandomchars(); $payload = [ + "timetaken" => microtime(true), "class" => "", "right-left" => "", "right-right" => "", "left" => '
' . '

IQ test

' . - 'Due to getting hit with 20,000 bot requests per day, I had to put this up. Sorry.

' . - 'Solving this captcha will allow you to make 100 searches today. I will add a way for legit users to bypass the captcha later. Sorry /g/tards!!' . + 'IQ test has been enabled due to bot abuse on the network.
' . + 'Solving this IQ test will let you make 100 searches today. I will add an invite system to bypass this soon...' . $error . '
' . '
' . '
' . - 'Captcha image' . + 'Captcha image' . '
' . '' . '' . @@ -317,13 +240,12 @@ class captcha{ '
' . '
' . '
' . - '' . + '' . '' . '
' . '
' ]; - http_response_code(429); // too many reqs $frontend->loadheader( $get, $filters, @@ -333,4 +255,27 @@ class captcha{ echo $frontend->load("search.html", $payload); die(); } + + private function randomchars(){ + + $chars = + array_merge( + range("A", "Z"), + range("a", "z"), + range(0, 9) + ); + + $chars[] = "_"; + + $c = count($chars) - 1; + + $key = ""; + + for($i=0; $i<20; $i++){ + + $key .= $chars[random_int(0, $c)]; + } + + return $key; + } } diff --git a/lib/classic.png b/lib/classic.png deleted file mode 100644 index d2c9609e7606c2e3008bc9344e35ecfe84f1a8d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^Q-C;_g&9b8|2KXOq$C1-LR>X8G>i=Odm9T^%xtMC zN}V^MHpJiE*}?k4g;*a321ZU#7srqa#<$lQ+l(Cr+8*k2N-g-q!|+*J=fJD-+YBu+ z3b_Iewuf%qnIEdeln^TT;yXh>|1Qnmdsj0|ejQ)@pKJSv6|aP@R;bNd8u-O#Riu>b z`NcSyX9`~(T3kGb>-gsPCaD&@tlp;G{VFK3CTh;D*ru$+ zRj)QY_-e5A7032X7j(SN?rIJ(d#159yHU?~O`sQR#xf_~VE1*i&qr|ttA9J0e%Dw- zw&t2<>eQOBQ>$*K$8NVMO_{2;;8>qUz`~j5lX~Y)tFf$}>}Q~Theba1bM8Yv={SGu mC95?T&);AFVe!R`FWilet9W}h_tyghj=|H_&t;ucLK6TJO`Jji diff --git a/lib/frontend.php b/lib/frontend.php index b002ee9..738ad83 100644 --- a/lib/frontend.php +++ b/lib/frontend.php @@ -39,6 +39,14 @@ class frontend{ $replacements["ac"] = ''; } + if( + isset($replacements["timetaken"]) && + $replacements["timetaken"] !== null + ){ + + $replacements["timetaken"] = '
Took ' . substr(microtime(true) - $replacements["timetaken"], 0, 4) . 's
'; + } + $handle = fopen("template/{$template}", "r"); $data = fread($handle, filesize("template/{$template}")); fclose($handle); @@ -68,7 +76,7 @@ class frontend{ echo $this->load("header.html", [ - "title" => trim($get["s"] . " ({$page})"), + "title" => trim(htmlspecialchars($get["s"]) . " ({$page})"), "description" => ucfirst($page) . ' search results for "' . htmlspecialchars($get["s"]) . '"', "index" => "no", "search" => htmlspecialchars($get["s"]), @@ -88,7 +96,7 @@ class frontend{ $this->drawerror( "Tshh, blocked!", - 'You were blocked from viewing this page. If you wish to scrape data from 4get, please consider running your own 4get instance or using the API.', + 'You were blocked from viewing this page. If you wish to scrape data from 4get, please consider running your own 4get instance.', ); die(); } @@ -98,6 +106,7 @@ class frontend{ echo $this->load("search.html", [ + "timetaken" => null, "class" => "", "right-left" => "", "right-right" => "", diff --git a/lib/fuckhtml.php b/lib/fuckhtml.php index 2f9d3aa..ed1252c 100644 --- a/lib/fuckhtml.php +++ b/lib/fuckhtml.php @@ -466,19 +466,26 @@ class fuckhtml{ return preg_replace_callback( - '/\\\u[A-Fa-f0-9]{4}|\\\x[A-Fa-f0-9]{2}/', + '/\\\u[A-Fa-f0-9]{4}|\\\x[A-Fa-f0-9]{2}|\\\n|\\\r/', function($match){ - if($match[0][1] == "u"){ + switch($match[0][1]){ - return json_decode('"' . $match[0] . '"'); - }else{ + case "u": + return json_decode('"' . $match[0] . '"'); + break; - return mb_convert_encoding( - stripcslashes($match[0]), - "utf-8", - "windows-1252" - ); + case "x": + return mb_convert_encoding( + stripcslashes($match[0]), + "utf-8", + "windows-1252" + ); + break; + + default: + return " "; + break; } }, $string diff --git a/music.php b/music.php index 5bc3e5f..0162d4c 100644 --- a/music.php +++ b/music.php @@ -15,10 +15,11 @@ $get = $frontend->parsegetfilters($_GET, $filters); /* Captcha */ -include "lib/captcha_gen.php"; -new captcha($frontend, $get, $filters, "music", true); +include "lib/bot_protection.php"; +new bot_protection($frontend, $get, $filters, "music", true); $payload = [ + "timetaken" => microtime(true), "class" => "", "right-left" => "", "right-right" => "", @@ -36,7 +37,10 @@ try{ $categories = [ "song" => "", "author" => "", - "playlist" => "" + "playlist" => "", + "album" => "", + "podcast" => "", + "user" => "" ]; /* @@ -48,14 +52,26 @@ if(count($results["song"]) !== 0){ $main = "song"; -}elseif(count($results["author"]) !== 0){ +}elseif(count($results["album"]) !== 0){ - $main = "author"; + $main = "album"; }elseif(count($results["playlist"]) !== 0){ $main = "playlist"; +}elseif(count($results["podcast"]) !== 0){ + + $main = "podcast"; + +}elseif(count($results["author"]) !== 0){ + + $main = "author"; + +}elseif(count($results["user"]) !== 0){ + + $main = "user"; + }else{ // No results found! @@ -133,12 +149,15 @@ foreach($categories as $name => $data){ $customhtml = null; if( - $name == "song" && + ( + $name == "song" || + $name == "podcast" + ) && $item["stream"]["endpoint"] !== null ){ $customhtml = - '