soundcloud lolllllll
This commit is contained in:
		
							parent
							
								
									cfd44438ae
								
							
						
					
					
						commit
						c8ab934b10
					
				
							
								
								
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | lib/test.html | ||||||
|  | lib/postdata.json | ||||||
|  | lib/nextpage.json | ||||||
|  | scraper/brave.html | ||||||
|  | scraper/yandex.json | ||||||
|  | scraper/marginalia.json | ||||||
|  | banner_og/ | ||||||
|  | scraper/mojeek.html | ||||||
|  | scraper/google.html | ||||||
|  | scraper/google-img.html | ||||||
|  | scraper/google-video.html | ||||||
|  | scraper/google-news.html | ||||||
|  | scraper/google-img-nextpage.html | ||||||
|  | scraper/brave-image.html | ||||||
|  | scraper/brave-video.html | ||||||
|  | scraper/facebook.html | ||||||
|  | scraper/facebook-nextpage.json | ||||||
|  | scraper/yandex-video.json | ||||||
|  | scraper/yandex.html | ||||||
|  | scraper/soundcloud.json | ||||||
|  | scraper/mp3-pm.html | ||||||
|  | banner/* | ||||||
|  | !banner/*default* | ||||||
							
								
								
									
										29
									
								
								api.txt
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								api.txt
									
									
									
									
									
								
							| @ -242,6 +242,21 @@ | |||||||
|     the endpoint above. |     the endpoint above. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | + /api/v1/music | ||||||
|  |     Each entry under "song" contains a array index called "stream" that | ||||||
|  |     looks like this :: | ||||||
|  |      | ||||||
|  |         endpoint: audio_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. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| + /favicon | + /favicon | ||||||
|     Get the favicon for a website. The only parameter is "s", and must |     Get the favicon for a website. The only parameter is "s", and must | ||||||
|     include the protocol. |     include the protocol. | ||||||
| @ -284,6 +299,20 @@ | |||||||
|     The parameter is "s" for the audio link. |     The parameter is "s" for the audio link. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | + /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 | ||||||
|  |     converting m3u8 playlists to seekable audio files. If you use this | ||||||
|  |     endpoint, you must support these 206 codes and also handle the | ||||||
|  |     initial 302 HTTP redirect. I used this method as I didn't want to | ||||||
|  |     store information about your request needlessly. This method also | ||||||
|  |     allows noJS users to access the files. | ||||||
|  |      | ||||||
|  |     The parameter is "s" for the SoundCloud JSON m3u8 abomination. It | ||||||
|  |     does not support "normal" SoundCloud URLs at this time. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| + Appendix | + Appendix | ||||||
|     If you have any questions or need clarifications, please send an |     If you have any questions or need clarifications, please send an | ||||||
|     email my way to will at lolcat.ca |     email my way to will at lolcat.ca | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								api/v1/music.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								api/v1/music.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | header("Content-Type: application/json"); | ||||||
|  | 
 | ||||||
|  | chdir("../../"); | ||||||
|  | 
 | ||||||
|  | include "lib/frontend.php"; | ||||||
|  | $frontend = new frontend(); | ||||||
|  | 
 | ||||||
|  | [$scraper, $filters] = $frontend->getscraperfilters( | ||||||
|  | 	"music", | ||||||
|  | 	isset($_GET["scraper"]) ? $_GET["scraper"] : null | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | $get = $frontend->parsegetfilters($_GET, $filters); | ||||||
|  | 
 | ||||||
|  | try{ | ||||||
|  | 	echo json_encode( | ||||||
|  | 		$scraper->music($get), | ||||||
|  | 		JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | ||||||
|  | 	); | ||||||
|  | 	 | ||||||
|  | }catch(Exception $e){ | ||||||
|  | 	 | ||||||
|  | 	echo json_encode(["status" => $e->getMessage()]); | ||||||
|  | } | ||||||
							
								
								
									
										223
									
								
								audio_sc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								audio_sc.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,223 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | new sc_audio(); | ||||||
|  | 
 | ||||||
|  | class sc_audio{ | ||||||
|  | 	 | ||||||
|  | 	public function __construct(){ | ||||||
|  | 		 | ||||||
|  | 		include "lib/curlproxy.php"; | ||||||
|  | 		$this->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; $i<count($ranges); $i++){ | ||||||
|  | 				 | ||||||
|  | 				if($ranges[$i][0] <= $client_range){ | ||||||
|  | 					 | ||||||
|  | 					$rng = $ranges[$i]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			// proxy data!
 | ||||||
|  | 			http_response_code(206); // partial content
 | ||||||
|  | 			header("Accept-Ranges: bytes"); | ||||||
|  | 			header("Content-Range: bytes {$rng[0]}-{$rng[1]}/" . ($ranges[count($ranges) - 1][1] + 1)); | ||||||
|  | 			 | ||||||
|  | 			$viewkey = | ||||||
|  | 				preg_replace( | ||||||
|  | 					'/\/media\/([0-9]+)\/[0-9]+\/[0-9]+/', | ||||||
|  | 					'/media/$1/' . $rng[0] . '/' . $rng[1], | ||||||
|  | 					$viewkey | ||||||
|  | 				); | ||||||
|  | 			 | ||||||
|  | 			try{ | ||||||
|  | 				 | ||||||
|  | 				$this->proxy->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(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -150,7 +150,7 @@ class proxy{ | |||||||
| 					$curl, | 					$curl, | ||||||
| 					CURLOPT_HTTPHEADER, | 					CURLOPT_HTTPHEADER, | ||||||
| 					[ | 					[ | ||||||
| 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/110.0", | 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", | ||||||
| 						"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | 						"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-Language: en-US,en;q=0.5", | ||||||
| 						"Accept-Encoding: gzip, deflate", | 						"Accept-Encoding: gzip, deflate", | ||||||
| @ -178,7 +178,7 @@ class proxy{ | |||||||
| 					$curl, | 					$curl, | ||||||
| 					CURLOPT_HTTPHEADER, | 					CURLOPT_HTTPHEADER, | ||||||
| 					[ | 					[ | ||||||
| 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0", | 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", | ||||||
| 						"Accept: image/avif,image/webp,*/*", | 						"Accept: image/avif,image/webp,*/*", | ||||||
| 						"Accept-Language: en-US,en;q=0.5", | 						"Accept-Language: en-US,en;q=0.5", | ||||||
| 						"Accept-Encoding: gzip, deflate", | 						"Accept-Encoding: gzip, deflate", | ||||||
| @ -380,7 +380,7 @@ class proxy{ | |||||||
| 					$curl, | 					$curl, | ||||||
| 					CURLOPT_HTTPHEADER, | 					CURLOPT_HTTPHEADER, | ||||||
| 					[ | 					[ | ||||||
| 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/110.0", | 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", | ||||||
| 						"Accept: image/avif,image/webp,*/*", | 						"Accept: image/avif,image/webp,*/*", | ||||||
| 						"Accept-Language: en-US,en;q=0.5", | 						"Accept-Language: en-US,en;q=0.5", | ||||||
| 						"Accept-Encoding: gzip, deflate, br", | 						"Accept-Encoding: gzip, deflate, br", | ||||||
| @ -396,7 +396,7 @@ class proxy{ | |||||||
| 					$curl, | 					$curl, | ||||||
| 					CURLOPT_HTTPHEADER, | 					CURLOPT_HTTPHEADER, | ||||||
| 					[ | 					[ | ||||||
| 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/110.0", | 						"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", | ||||||
| 						"Accept: audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5", | 						"Accept: audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5", | ||||||
| 						"Accept-Language: en-US,en;q=0.5", | 						"Accept-Language: en-US,en;q=0.5", | ||||||
| 						"Accept-Encoding: gzip, deflate, br", | 						"Accept-Encoding: gzip, deflate, br", | ||||||
|  | |||||||
| @ -98,7 +98,7 @@ class frontend{ | |||||||
| 			]); | 			]); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public function drawtextresult($site, $greentext = null, $duration = null, $keywords, $tabindex = true){ | 	public function drawtextresult($site, $greentext = null, $duration = null, $keywords, $tabindex = true, $customhtml = null){ | ||||||
| 		 | 		 | ||||||
| 		$payload = | 		$payload = | ||||||
| 			'<div class="text-result">'; | 			'<div class="text-result">'; | ||||||
| @ -187,7 +187,9 @@ class frontend{ | |||||||
| 					$this->highlighttext($keywords, $site["description"]) . | 					$this->highlighttext($keywords, $site["description"]) . | ||||||
| 				'</div>'; | 				'</div>'; | ||||||
| 		} | 		} | ||||||
| 			 | 		 | ||||||
|  | 		$payload .= $customhtml; | ||||||
|  | 		 | ||||||
| 		$payload .= '</a>'; | 		$payload .= '</a>'; | ||||||
| 		 | 		 | ||||||
| 		/* | 		/* | ||||||
| @ -764,6 +766,7 @@ class frontend{ | |||||||
| 				'<a href="https://webcache.googleusercontent.com/search?q=cache:' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://google.com" alt="go">Google cache</a>' . | 				'<a href="https://webcache.googleusercontent.com/search?q=cache:' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://google.com" alt="go">Google cache</a>' . | ||||||
| 				'<a href="https://web.archive.org/web/' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://archive.org" alt="ar">Archive.org</a>' . | 				'<a href="https://web.archive.org/web/' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://archive.org" alt="ar">Archive.org</a>' . | ||||||
| 				'<a href="https://archive.is/newest/' . htmlspecialchars($link) . '" class="list" target="_BLANK"><img src="/favicon?s=https://archive.is" alt="ar">Archive.is</a>' . | 				'<a href="https://archive.is/newest/' . htmlspecialchars($link) . '" class="list" target="_BLANK"><img src="/favicon?s=https://archive.is" alt="ar">Archive.is</a>' . | ||||||
|  | 				'<a href="https://ghostarchive.org/search?term=' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://ghostarchive.org" alt="gh">Ghostarchive</a>' . | ||||||
| 				'<a href="https://www.bing.com/search?q=url%3A' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://bing.com" alt="bi">Bing cache</a>' . | 				'<a href="https://www.bing.com/search?q=url%3A' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://bing.com" alt="bi">Bing cache</a>' . | ||||||
| 				'<a href="https://megalodon.jp/?url=' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://megalodon.jp" alt="me">Megalodon</a>' . | 				'<a href="https://megalodon.jp/?url=' . $urlencode . '" class="list" target="_BLANK"><img src="/favicon?s=https://megalodon.jp" alt="me">Megalodon</a>' . | ||||||
| 			'</div>'; | 			'</div>'; | ||||||
| @ -835,6 +838,10 @@ class frontend{ | |||||||
| 			case "news": | 			case "news": | ||||||
| 				$get_scraper = isset($_COOKIE["scraper_news"]) ? $_COOKIE["scraper_news"] : null; | 				$get_scraper = isset($_COOKIE["scraper_news"]) ? $_COOKIE["scraper_news"] : null; | ||||||
| 				break; | 				break; | ||||||
|  | 			 | ||||||
|  | 			case "music": | ||||||
|  | 				$get_scraper = isset($_COOKIE["scraper_news"]) ? $_COOKIE["scraper_news"] : null; | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if( | 		if( | ||||||
| @ -923,6 +930,14 @@ class frontend{ | |||||||
| 						"mojeek" => "Mojeek" | 						"mojeek" => "Mojeek" | ||||||
| 					] | 					] | ||||||
| 				]; | 				]; | ||||||
|  | 			 | ||||||
|  | 			case "music": | ||||||
|  | 				$filters["scraper"] = [ | ||||||
|  | 					"display" => "Scraper", | ||||||
|  | 					"option" => [ | ||||||
|  | 						"sc" => "SoundCloud" | ||||||
|  | 					] | ||||||
|  | 				]; | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| @ -994,6 +1009,11 @@ class frontend{ | |||||||
| 				include "scraper/wiby.php"; | 				include "scraper/wiby.php"; | ||||||
| 				$lib = new wiby(); | 				$lib = new wiby(); | ||||||
| 				break; | 				break; | ||||||
|  | 			 | ||||||
|  | 			case "sc": | ||||||
|  | 				include "scraper/sc.php"; | ||||||
|  | 				$lib = new sc(); | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		// set scraper on $_GET
 | 		// set scraper on $_GET
 | ||||||
| @ -1169,7 +1189,7 @@ class frontend{ | |||||||
| 		 | 		 | ||||||
| 		$html = null; | 		$html = null; | ||||||
| 		 | 		 | ||||||
| 		foreach(["web", "images", "videos", "news"] as $type){ | 		foreach(["web", "images", "videos", "news", "music"] as $type){ | ||||||
| 			 | 			 | ||||||
| 			$html .= '<a href="/' . $type . '?s=' . urlencode($query); | 			$html .= '<a href="/' . $type . '?s=' . urlencode($query); | ||||||
| 			 | 			 | ||||||
| @ -1303,7 +1323,7 @@ class frontend{ | |||||||
| 			return htmlspecialchars($image); | 			return htmlspecialchars($image); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		return "/proxy?i=" . urlencode($image) . "&s=" . $format; | 		return "/proxy.php?i=" . urlencode($image) . "&s=" . $format; | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	public function htmlnextpage($gets, $npt, $page){ | 	public function htmlnextpage($gets, $npt, $page){ | ||||||
|  | |||||||
							
								
								
									
										224
									
								
								music.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								music.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,224 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | 	Initialize random shit | ||||||
|  | */ | ||||||
|  | include "lib/frontend.php"; | ||||||
|  | $frontend = new frontend(); | ||||||
|  | 
 | ||||||
|  | [$scraper, $filters] = $frontend->getscraperfilters("music"); | ||||||
|  | 
 | ||||||
|  | $get = $frontend->parsegetfilters($_GET, $filters); | ||||||
|  | 
 | ||||||
|  | $frontend->loadheader( | ||||||
|  | 	$get, | ||||||
|  | 	$filters, | ||||||
|  | 	"music" | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | $payload = [ | ||||||
|  | 	"class" => "", | ||||||
|  | 	"right-left" => "", | ||||||
|  | 	"right-right" => "", | ||||||
|  | 	"left" => "" | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | try{ | ||||||
|  | 	$results = $scraper->music($get); | ||||||
|  | 	 | ||||||
|  | }catch(Exception $error){ | ||||||
|  | 	 | ||||||
|  | 	echo | ||||||
|  | 		$frontend->drawerror( | ||||||
|  | 			"Shit", | ||||||
|  | 			'This scraper returned an error:' . | ||||||
|  | 			'<div class="code">' . htmlspecialchars($error->getMessage()) . '</div>' . | ||||||
|  | 			'Things you can try:' . | ||||||
|  | 			'<ul>' .  | ||||||
|  | 				'<li>Use a different scraper</li>' . | ||||||
|  | 				'<li>Remove keywords that could cause errors</li>' . | ||||||
|  | 				'<li>Use another 4get instance</li>' . | ||||||
|  | 			'</ul><br>' . | ||||||
|  | 			'If the error persists, please <a href="/about">contact the administrator</a>.' | ||||||
|  | 		); | ||||||
|  | 	die(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | $categories = [ | ||||||
|  | 	"song" => "", | ||||||
|  | 	"author" => "", | ||||||
|  | 	"playlist" => "" | ||||||
|  | ]; | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | 	Set the main container | ||||||
|  | */ | ||||||
|  | $main = null; | ||||||
|  | 
 | ||||||
|  | if(count($results["song"]) !== 0){ | ||||||
|  | 	 | ||||||
|  | 	$main = "song"; | ||||||
|  | 	 | ||||||
|  | }elseif(count($results["author"]) !== 0){ | ||||||
|  | 	 | ||||||
|  | 	$main = "author"; | ||||||
|  | 	 | ||||||
|  | }elseif(count($results["playlist"]) !== 0){ | ||||||
|  | 	 | ||||||
|  | 	$main = "playlist"; | ||||||
|  | 	 | ||||||
|  | }else{ | ||||||
|  | 	 | ||||||
|  | 	// No results found!
 | ||||||
|  | 	echo | ||||||
|  | 		$frontend->drawerror( | ||||||
|  | 			"Nobody here but us chickens!", | ||||||
|  | 			'Have you tried:' . | ||||||
|  | 				'<ul>' . | ||||||
|  | 					'<li>Using a different scraper</li>' . | ||||||
|  | 					'<li>Using fewer keywords</li>' . | ||||||
|  | 					'<li>Defining broader filters (Is NSFW turned off?)</li>' . | ||||||
|  | 				'</ul>' . | ||||||
|  | 			'</div>' | ||||||
|  | 		); | ||||||
|  | 	die(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | 	Generate list of songs | ||||||
|  | */ | ||||||
|  | foreach($categories as $name => $data){ | ||||||
|  | 	 | ||||||
|  | 	foreach($results[$name] as $item){ | ||||||
|  | 		 | ||||||
|  | 		$greentext = []; | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			isset($item["date"]) && | ||||||
|  | 			$item["date"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$greentext[] = date("jS M y @ g:ia", $item["date"]); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			isset($item["views"]) && | ||||||
|  | 			$item["views"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$views = number_format($item["views"]) . " views"; | ||||||
|  | 			$greentext[] = $views; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			isset($item["followers"]) && | ||||||
|  | 			$item["followers"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$greentext[] = number_format($item["followers"]) . " followers"; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			isset($item["author"]["name"]) && | ||||||
|  | 			$item["author"]["name"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$greentext[] = $item["author"]["name"]; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		$greentext = implode(" • ", $greentext); | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			isset($item["duration"]) && | ||||||
|  | 			$item["duration"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$duration = $frontend->s_to_timestamp($item["duration"]); | ||||||
|  | 		}else{ | ||||||
|  | 			 | ||||||
|  | 			$duration = null; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		$tabindex = $name == $main ? true : false; | ||||||
|  | 		 | ||||||
|  | 		$customhtml = null; | ||||||
|  | 		 | ||||||
|  | 		if( | ||||||
|  | 			$name == "song" && | ||||||
|  | 			$item["stream"]["endpoint"] !== null | ||||||
|  | 		){ | ||||||
|  | 			 | ||||||
|  | 			$customhtml = | ||||||
|  | 				'<audio src="' . $item["stream"]["endpoint"] . '?s=' . urlencode($item["stream"]["url"]) . '" controls autostart="false" preload="none">'; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		$categories[$name] .= $frontend->drawtextresult($item, $greentext, $duration, $get["s"], $tabindex, $customhtml); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | $payload["left"] = $categories[$main]; | ||||||
|  | 
 | ||||||
|  | // dont re-draw the category
 | ||||||
|  | unset($categories[$main]); | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | 	Populate right handside | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | $i = 1; | ||||||
|  | foreach($categories as $name => $value){ | ||||||
|  | 	 | ||||||
|  | 	if($value == ""){ | ||||||
|  | 		 | ||||||
|  | 		continue; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if($i % 2 === 1){ | ||||||
|  | 		 | ||||||
|  | 		$write = "right-left"; | ||||||
|  | 	}else{ | ||||||
|  | 		 | ||||||
|  | 		$write = "right-right"; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	$payload[$write] .= | ||||||
|  | 		'<div class="answer-wrapper">' . | ||||||
|  | 		'<input id="answer' . $i . '" class="spoiler" type="checkbox">' . | ||||||
|  | 		'<div class="answer">' . | ||||||
|  | 			'<div class="answer-title">' . | ||||||
|  | 				'<a class="answer-title" href="?s=' . urlencode($get["s"]); | ||||||
|  | 	 | ||||||
|  | 	switch($name){ | ||||||
|  | 		 | ||||||
|  | 		case "playlist": | ||||||
|  | 			$payload[$write] .= | ||||||
|  | 				'&type=playlist"><h2>Playlists</h2></a>'; | ||||||
|  | 			break; | ||||||
|  | 		 | ||||||
|  | 		case "author": | ||||||
|  | 			$payload[$write] .= | ||||||
|  | 				'&type=people"><h2>Authors</h2></a>'; | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	$payload[$write] .= | ||||||
|  | 			'</div>' . | ||||||
|  | 			$categories[$name] . | ||||||
|  | 		'</div>' . | ||||||
|  | 		'<label class="spoiler-button" for="answer' . $i . '"></label></div>'; | ||||||
|  | 	 | ||||||
|  | 	$i++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | if($i !== 1){ | ||||||
|  | 	 | ||||||
|  | 	$payload["class"] = " has-answer"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | if($results["npt"] !== null){ | ||||||
|  | 	 | ||||||
|  | 	$payload["left"] .= | ||||||
|  | 		'<a href="' . $frontend->htmlnextpage($get, $results["npt"], "music") . '" class="nextpage">Next page ></a>'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | echo $frontend->load("search.html", $payload); | ||||||
							
								
								
									
										397
									
								
								scraper/sc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								scraper/sc.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,397 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | class sc{ | ||||||
|  | 	 | ||||||
|  | 	public function __construct(){ | ||||||
|  | 		 | ||||||
|  | 		include "lib/nextpage.php"; | ||||||
|  | 		$this->nextpage = new nextpage("sc"); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public function getfilters($page){ | ||||||
|  | 		 | ||||||
|  | 		return [ | ||||||
|  | 			"type" => [ | ||||||
|  | 				"display" => "Type", | ||||||
|  | 				"option" => [ | ||||||
|  | 					"any" => "Any type", | ||||||
|  | 					"track" => "Tracks", | ||||||
|  | 					"people" => "People", | ||||||
|  | 					"album" => "Albums", | ||||||
|  | 					"playlist" => "Playlists", | ||||||
|  | 					"goplus" => "Go+ Tracks" | ||||||
|  | 				] | ||||||
|  | 			] | ||||||
|  | 		]; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private function get($url, $get = []){ | ||||||
|  | 		 | ||||||
|  | 		$curlproc = curl_init(); | ||||||
|  | 		 | ||||||
|  | 		if($get !== []){ | ||||||
|  | 			$get = http_build_query($get); | ||||||
|  | 			$url .= "?" . $get; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		curl_setopt($curlproc, CURLOPT_URL, $url); | ||||||
|  | 		 | ||||||
|  | 		curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
 | ||||||
|  | 		curl_setopt($curlproc, CURLOPT_HTTPHEADER, | ||||||
|  | 			["User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", | ||||||
|  | 			"Accept: application/json, text/javascript, */*; q=0.01", | ||||||
|  | 			"Accept-Language: en-US,en;q=0.5", | ||||||
|  | 			"Accept-Encoding: gzip", | ||||||
|  | 			"Referer: https://soundcloud.com/", | ||||||
|  | 			"Origin: https://soundcloud.com", | ||||||
|  | 			"DNT: 1", | ||||||
|  | 			"Connection: keep-alive", | ||||||
|  | 			"Sec-Fetch-Dest: empty", | ||||||
|  | 			"Sec-Fetch-Mode: cors", | ||||||
|  | 			"Sec-Fetch-Site: same-site"] | ||||||
|  | 		); | ||||||
|  | 		 | ||||||
|  | 		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; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	public function music($get){ | ||||||
|  | 		 | ||||||
|  | 		if($get["npt"]){ | ||||||
|  | 			 | ||||||
|  | 			$params = $this->nextpage->get($get["npt"], "music"); | ||||||
|  | 			$params = json_decode($params, true); | ||||||
|  | 			 | ||||||
|  | 			$url = $params["url"]; | ||||||
|  | 			unset($params["url"]); | ||||||
|  | 			 | ||||||
|  | 		}else{ | ||||||
|  | 			 | ||||||
|  | 			// normal search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search?q=freddie%20dredd&variant_ids=&facet=model&user_id=351062-302234-707916-795081&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			// soundcloud go+ search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search/tracks?q=freddie%20dredd&variant_ids=&filter.content_tier=SUB_HIGH_TIER&facet=genre&user_id=630591-269800-703400-765403&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			// tracks search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search/tracks?q=freddie%20dredd&variant_ids=&facet=genre&user_id=630591-269800-703400-765403&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			// users search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search/users?q=freddie%20dredd&variant_ids=&facet=place&user_id=630591-269800-703400-765403&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			// albums search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search/albums?q=freddie%20dredd&variant_ids=&facet=genre&user_id=630591-269800-703400-765403&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			// playlists search:
 | ||||||
|  | 			// https://api-v2.soundcloud.com/search/playlists_without_albums?q=freddie%20dredd&variant_ids=&facet=genre&user_id=630591-269800-703400-765403&client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E&limit=20&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en
 | ||||||
|  | 			 | ||||||
|  | 			$search = $get["s"]; | ||||||
|  | 			$type = $get["type"]; | ||||||
|  | 			 | ||||||
|  | 			switch($type){ | ||||||
|  | 				 | ||||||
|  | 				case "any": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"facet" => "model", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "track": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search/tracks"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"facet_genre" => "", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "people": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search/users"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"facet" => "place", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "album": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search/albums"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"facet" => "genre", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "playlist": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search/playlists_without_albums"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"facet" => "genre", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "goplus": | ||||||
|  | 					$url = "https://api-v2.soundcloud.com/search/tracks"; | ||||||
|  | 					$params = [ | ||||||
|  | 						"q" => $search, | ||||||
|  | 						"variant_ids" => "", | ||||||
|  | 						"filter.content_tier" => "SUB_HIGH_TIER", | ||||||
|  | 						"facet" => "genre", | ||||||
|  | 						"user_id" => "351062-302234-707916-795081", | ||||||
|  | 						"client_id" => "iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E", | ||||||
|  | 						"limit" => 20, | ||||||
|  | 						"offset" => 0, | ||||||
|  | 						"linked_partitioning" => 1, | ||||||
|  | 						"app_version" => 1693487844, | ||||||
|  | 						"app_locale" => "en" | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 			 | ||||||
|  | 		try{ | ||||||
|  | 			 | ||||||
|  | 			$json = $this->get($url, $params); | ||||||
|  | 			 | ||||||
|  | 		}catch(Exception $error){ | ||||||
|  | 			 | ||||||
|  | 			throw new Exception("Failed to fetch JSON"); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		/* | ||||||
|  | 		$handle = fopen("scraper/soundcloud.json", "r"); | ||||||
|  | 		$json = fread($handle, filesize("scraper/soundcloud.json")); | ||||||
|  | 		fclose($handle); | ||||||
|  | 		*/ | ||||||
|  | 		 | ||||||
|  | 		$json = json_decode($json, true); | ||||||
|  | 		 | ||||||
|  | 		if($json === null){ | ||||||
|  | 			 | ||||||
|  | 			throw new Exception("Failed to decode JSON"); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		$out = [ | ||||||
|  | 			"status" => "ok", | ||||||
|  | 			"npt" => null, | ||||||
|  | 			"song" => [], | ||||||
|  | 			"playlist" => [], | ||||||
|  | 			"author" => [] | ||||||
|  | 		]; | ||||||
|  | 		 | ||||||
|  | 		/* | ||||||
|  | 			Get next page | ||||||
|  | 		*/ | ||||||
|  | 		if(isset($json["next_href"])){ | ||||||
|  | 			 | ||||||
|  | 			$params["query_urn"] = $json["query_urn"]; | ||||||
|  | 			$params["offset"] = $params["offset"] + 20; | ||||||
|  | 			$params["url"] = $url; // we will remove this later
 | ||||||
|  | 			 | ||||||
|  | 			$out["npt"] = | ||||||
|  | 				$this->nextpage->store( | ||||||
|  | 					json_encode($params), | ||||||
|  | 					"music" | ||||||
|  | 				); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		/* | ||||||
|  | 			Scrape items | ||||||
|  | 		*/ | ||||||
|  | 		foreach($json["collection"] as $item){ | ||||||
|  | 			 | ||||||
|  | 			switch($item["kind"]){ | ||||||
|  | 				 | ||||||
|  | 				case "user": | ||||||
|  | 					// parse author
 | ||||||
|  | 					$out["author"][] = [ | ||||||
|  | 						"title" => $item["username"], | ||||||
|  | 						"followers" => $item["followers_count"], | ||||||
|  | 						"description" => $item["track_count"] . " songs. " . $this->limitstrlen($item["description"]), | ||||||
|  | 						"thumb" => [ | ||||||
|  | 							"url" => $item["avatar_url"], | ||||||
|  | 							"ratio" => "1:1" | ||||||
|  | 						], | ||||||
|  | 						"url" => $item["permalink_url"] | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "playlist": | ||||||
|  | 					// parse playlist
 | ||||||
|  | 					$description = []; | ||||||
|  | 					$count = 0; | ||||||
|  | 					 | ||||||
|  | 					foreach($item["tracks"] as $song){ | ||||||
|  | 						 | ||||||
|  | 						$count++; | ||||||
|  | 						 | ||||||
|  | 						if(!isset($song["title"])){ | ||||||
|  | 							 | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 						 | ||||||
|  | 						$description[] = $song["title"]; | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					if(count($description) != 0){ | ||||||
|  | 						 | ||||||
|  | 						$description = $count . " songs. " . implode(", ", $description); | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					if( | ||||||
|  | 						isset($item["artwork_url"]) && | ||||||
|  | 						!empty($item["artwork_url"]) | ||||||
|  | 					){ | ||||||
|  | 						 | ||||||
|  | 						$thumb = [ | ||||||
|  | 							"ratio" => "1:1", | ||||||
|  | 							"url" => $item["artwork_url"] | ||||||
|  | 						]; | ||||||
|  | 						 | ||||||
|  | 					}elseif( | ||||||
|  | 						isset($item["tracks"][0]["artwork_url"]) && | ||||||
|  | 						!empty($item["tracks"][0]["artwork_url"]) | ||||||
|  | 					){ | ||||||
|  | 						 | ||||||
|  | 						$thumb = [ | ||||||
|  | 							"ratio" => "1:1", | ||||||
|  | 							"url" => $item["tracks"][0]["artwork_url"] | ||||||
|  | 						]; | ||||||
|  | 					}else{ | ||||||
|  | 						 | ||||||
|  | 						$thumb = [ | ||||||
|  | 							"ratio" => null, | ||||||
|  | 							"url" => null | ||||||
|  | 						]; | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					$out["playlist"][] = [ | ||||||
|  | 						"title" => $item["title"], | ||||||
|  | 						"description" => $description, | ||||||
|  | 						"author" => [ | ||||||
|  | 							"name" => $item["user"]["username"], | ||||||
|  | 							"url" => $item["user"]["permalink_url"], | ||||||
|  | 							"avatar" => $item["user"]["avatar_url"] | ||||||
|  | 						], | ||||||
|  | 						"thumb" => $thumb, | ||||||
|  | 						"date" => strtotime($item["created_at"]), | ||||||
|  | 						"duration" => $item["duration"] / 1000, | ||||||
|  | 						"url" => $item["permalink_url"] | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 				 | ||||||
|  | 				case "track": | ||||||
|  | 					if(stripos($item["monetization_model"], "TIER") === false){ | ||||||
|  | 						 | ||||||
|  | 						$stream = [ | ||||||
|  | 							"endpoint" => "audio_sc", | ||||||
|  | 							"url" => | ||||||
|  | 								$item["media"]["transcodings"][0]["url"] . | ||||||
|  | 								"?client_id=iMxZgT5mfGstBj8GWJbYMvpzelS8ne0E" . | ||||||
|  | 								"&track_authorization=" . | ||||||
|  | 								$item["track_authorization"] | ||||||
|  | 						]; | ||||||
|  | 					}else{ | ||||||
|  | 						 | ||||||
|  | 						$stream = [ | ||||||
|  | 							"endpoint" => null, | ||||||
|  | 							"url" => null | ||||||
|  | 						]; | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					// parse track
 | ||||||
|  | 					$out["song"][] = [ | ||||||
|  | 						"title" => $item["title"], | ||||||
|  | 						"description" => $item["description"] == "" ? null : $this->limitstrlen($item["description"]), | ||||||
|  | 						"url" => $item["permalink_url"], | ||||||
|  | 						"views" => $item["playback_count"], | ||||||
|  | 						"author" => [ | ||||||
|  | 							"name" => $item["user"]["username"], | ||||||
|  | 							"url" => $item["user"]["permalink_url"], | ||||||
|  | 							"avatar" => $item["user"]["avatar_url"] | ||||||
|  | 						], | ||||||
|  | 						"thumb" => [ | ||||||
|  | 							"ratio" => "1:1", | ||||||
|  | 							"url" => $item["artwork_url"] | ||||||
|  | 						], | ||||||
|  | 						"date" => strtotime($item["created_at"]), | ||||||
|  | 						"duration" => (int)$item["full_duration"] / 1000, | ||||||
|  | 						"stream" => $stream | ||||||
|  | 					]; | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return $out; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private function limitstrlen($text){ | ||||||
|  | 		 | ||||||
|  | 		return | ||||||
|  | 			explode( | ||||||
|  | 				"\n", | ||||||
|  | 				wordwrap( | ||||||
|  | 					str_replace( | ||||||
|  | 						"\n", | ||||||
|  | 						" ", | ||||||
|  | 						$text | ||||||
|  | 					), | ||||||
|  | 					300, | ||||||
|  | 					"\n" | ||||||
|  | 				) | ||||||
|  | 			)[0]; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -959,6 +959,7 @@ class yandex{ | |||||||
| 					"img" | 					"img" | ||||||
| 				); | 				); | ||||||
| 			 | 			 | ||||||
|  | 			$c = 1; | ||||||
| 			if(count($thumb) === 0){ | 			if(count($thumb) === 0){ | ||||||
| 				 | 				 | ||||||
| 				$thumb = [ | 				$thumb = [ | ||||||
| @ -967,7 +968,6 @@ class yandex{ | |||||||
| 				]; | 				]; | ||||||
| 			}else{ | 			}else{ | ||||||
| 				 | 				 | ||||||
| 				$c = 1; |  | ||||||
| 				$thumb = [ | 				$thumb = [ | ||||||
| 					"url" => | 					"url" => | ||||||
| 						str_replace( | 						str_replace( | ||||||
| @ -1065,12 +1065,17 @@ class yandex{ | |||||||
| 				"views" => $views, | 				"views" => $views, | ||||||
| 				"thumb" => $thumb, | 				"thumb" => $thumb, | ||||||
| 				"url" => | 				"url" => | ||||||
| 					$this->fuckhtml | 					str_replace( | ||||||
| 					->getTextContent( | 						"http://", | ||||||
| 						$data["counters"] | 						"https://", | ||||||
| 						["toHostingLoaded"] | 						$this->fuckhtml | ||||||
| 						["postfix"] | 						->getTextContent( | ||||||
| 						["href"] | 							$data["counters"] | ||||||
|  | 							["toHostingLoaded"] | ||||||
|  | 							["postfix"] | ||||||
|  | 							["href"] | ||||||
|  | 						), | ||||||
|  | 						$c | ||||||
| 					) | 					) | ||||||
| 			]; | 			]; | ||||||
| 		} | 		} | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								settings.php
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								settings.php
									
									
									
									
									
								
							| @ -161,6 +161,16 @@ $settings = [ | |||||||
| 						"text" => "Mojeek" | 						"text" => "Mojeek" | ||||||
| 					] | 					] | ||||||
| 				] | 				] | ||||||
|  | 			], | ||||||
|  | 			[ | ||||||
|  | 				"description" => "Music", | ||||||
|  | 				"parameter" => "scraper_music", | ||||||
|  | 				"options" => [ | ||||||
|  | 					[ | ||||||
|  | 						"value" => "sc", | ||||||
|  | 						"text" => "SoundCloud" | ||||||
|  | 					] | ||||||
|  | 				] | ||||||
| 			] | 			] | ||||||
| 		] | 		] | ||||||
| 	] | 	] | ||||||
| @ -235,7 +245,7 @@ echo | |||||||
| 		'<head>' . | 		'<head>' . | ||||||
| 			'<meta http-equiv="Content-Type" content="text/html;charset=utf-8">' . | 			'<meta http-equiv="Content-Type" content="text/html;charset=utf-8">' . | ||||||
| 			'<title>Settings</title>' . | 			'<title>Settings</title>' . | ||||||
| 			'<link rel="stylesheet" href="/static/style.css">' . | 			'<link rel="stylesheet" href="/static/style.css?v3">' . | ||||||
| 			'<meta name="viewport" content="width=device-width,initial-scale=1">' . | 			'<meta name="viewport" content="width=device-width,initial-scale=1">' . | ||||||
| 			'<meta name="robots" content="index,follow">' . | 			'<meta name="robots" content="index,follow">' . | ||||||
| 			'<link rel="icon" type="image/x-icon" href="/favicon.ico">' . | 			'<link rel="icon" type="image/x-icon" href="/favicon.ico">' . | ||||||
|  | |||||||
| @ -51,6 +51,13 @@ | |||||||
| audio{ | audio{ | ||||||
| 	max-width:100%; | 	max-width:100%; | ||||||
| 	display:block; | 	display:block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .left audio{ | ||||||
|  | 	margin-top:7px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .right-wrapper audio{ | ||||||
| 	margin-bottom:17px; | 	margin-bottom:17px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| 	<head> | 	<head> | ||||||
| 		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | 		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | ||||||
| 		<title>{%title%}</title> | 		<title>{%title%}</title> | ||||||
| 		<link rel="stylesheet" href="/static/style.css?v2"> | 		<link rel="stylesheet" href="/static/style.css?v3"> | ||||||
| 		<meta name="viewport" content="width=device-width,initial-scale=1"> | 		<meta name="viewport" content="width=device-width,initial-scale=1"> | ||||||
| 		<meta name="robots" content="{%index%}index,{%index%}follow"> | 		<meta name="robots" content="{%index%}index,{%index%}follow"> | ||||||
| 		<link rel="icon" type="image/x-icon" href="/favicon.ico"> | 		<link rel="icon" type="image/x-icon" href="/favicon.ico"> | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| 		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | 		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | ||||||
| 		<title>4get</title> | 		<title>4get</title> | ||||||
| 		<meta name="viewport" content="width=device-width,initial-scale=1"> | 		<meta name="viewport" content="width=device-width,initial-scale=1"> | ||||||
| 		<link rel="stylesheet" href="/static/style.css?v2"> | 		<link rel="stylesheet" href="/static/style.css?v3"> | ||||||
| 		<meta name="robots" content="index,follow"> | 		<meta name="robots" content="index,follow"> | ||||||
| 		<link rel="icon" type="image/x-icon" href="/favicon.ico"> | 		<link rel="icon" type="image/x-icon" href="/favicon.ico"> | ||||||
| 		<meta name="description" content="4get.ca: They live in our walls!"> | 		<meta name="description" content="4get.ca: They live in our walls!"> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 lolcat
						lolcat