ac.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. include "../../data/config.php";
  3. new autocomplete();
  4. class autocomplete{
  5. public function __construct(){
  6. header("Content-Type: application/json");
  7. $this->scrapers = [
  8. "brave" => "https://search.brave.com/api/suggest?q={searchTerms}",
  9. "ddg" => "https://duckduckgo.com/ac/?q={searchTerms}&type=list",
  10. "yandex" => "https://suggest.yandex.com/suggest-ff.cgi?part={searchTerms}&uil=en&v=3&sn=5&lr=21276&yu=4861394161661655015",
  11. "google" => "https://www.google.com/complete/search?client=mobile-gws-lite&q={searchTerms}",
  12. "qwant" => "https://api.qwant.com/v3/suggest/?q={searchTerms}&client=opensearch",
  13. "yep" => "https://api.yep.com/ac/?query={searchTerms}",
  14. "marginalia" => "https://search.marginalia.nu/suggest/?partial={searchTerms}",
  15. "yt" => "https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&q={searchTerms}",
  16. "sc" => "",
  17. "startpage" => "https://www.startpage.com/suggestions?q={searchTerms}&format=opensearch&segment=startpage.defaultffx&lui=english"
  18. ];
  19. /*
  20. Sanitize input
  21. */
  22. if(!isset($_GET["s"])){
  23. $this->do404("Missing search(s) parameter");
  24. }
  25. if(is_string($_GET["s"]) === false){
  26. $this->do404("Invalid search(s) parameter");
  27. }
  28. if(strlen($_GET["s"]) > 500){
  29. $this->do404("Search(s) exceeds the 500 char length");
  30. }
  31. /*
  32. Get $scraper
  33. */
  34. if(!isset($_GET["scraper"])){
  35. if(isset($_COOKIE["scraper_ac"])){
  36. $scraper = $_COOKIE["scraper_ac"];
  37. }else{
  38. $scraper = "brave"; // default option
  39. }
  40. }else{
  41. $scraper = $_GET["scraper"];
  42. }
  43. if($scraper == "disabled"){
  44. // this shouldnt happen, but let's handle it anyways
  45. $this->doempty();
  46. }
  47. // make sure it exists
  48. if(!isset($this->scrapers[$scraper])){
  49. $scraper = "brave"; // default option
  50. }
  51. // return results
  52. switch($scraper){
  53. case "google":
  54. case "yt":
  55. // handle google cause they want to be a special snowflake :(
  56. $js = $this->get($this->scrapers[$scraper], $_GET["s"]);
  57. preg_match(
  58. '/\((\[.*\])\)/',
  59. $js,
  60. $js
  61. );
  62. if(!isset($js[1])){
  63. $this->doempty();
  64. }
  65. $js = json_decode($js[1]);
  66. $json = [];
  67. foreach($js[1] as $item){
  68. $json[] = htmlspecialchars_decode(strip_tags($item[0]));
  69. }
  70. echo json_encode(
  71. [
  72. $_GET["s"],
  73. $json
  74. ],
  75. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  76. );
  77. break;
  78. case "sc":
  79. // soundcloud
  80. chdir("../../");
  81. include "scraper/sc.php";
  82. $sc = new sc();
  83. $token = $sc->get_token("raw_ip::::");
  84. $js = $this->get(
  85. "https://api-v2.soundcloud.com/search/queries?q={searchTerms}&client_id=" . $token . "&limit=10&offset=0&linked_partitioning=1&app_version=1693487844&app_locale=en",
  86. $_GET["s"]
  87. );
  88. $js = json_decode($js, true);
  89. if(!isset($js["collection"])){
  90. $this->doempty();
  91. }
  92. $json = [];
  93. foreach($js["collection"] as $item){
  94. $json[] = $item["query"];
  95. }
  96. echo json_encode(
  97. [
  98. $_GET["s"],
  99. $json
  100. ],
  101. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  102. );
  103. break;
  104. case "marginalia":
  105. $json = $this->get($this->scrapers[$scraper], $_GET["s"]);
  106. $json = json_decode($json, true);
  107. if($json === null){
  108. $this->doempty();
  109. }
  110. echo json_encode(
  111. [
  112. $_GET["s"],
  113. $json
  114. ],
  115. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  116. );
  117. break;
  118. default:
  119. // if it respects the openSearch protocol
  120. $json = json_decode($this->get($this->scrapers[$scraper], $_GET["s"]), true);
  121. echo json_encode(
  122. [
  123. $_GET["s"],
  124. $json[1] // ensure it contains valid key 0
  125. ],
  126. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  127. );
  128. break;
  129. }
  130. }
  131. private function get($url, $query){
  132. try{
  133. $curlproc = curl_init();
  134. $url = str_replace("{searchTerms}", urlencode($query), $url);
  135. curl_setopt($curlproc, CURLOPT_URL, $url);
  136. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  137. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  138. ["User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0",
  139. "Accept: application/json, text/javascript, */*; q=0.01",
  140. "Accept-Language: en-US,en;q=0.5",
  141. "Accept-Encoding: gzip",
  142. "DNT: 1",
  143. "Connection: keep-alive",
  144. "Sec-Fetch-Dest: empty",
  145. "Sec-Fetch-Mode: cors",
  146. "Sec-Fetch-Site: same-site"]
  147. );
  148. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  149. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  150. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  151. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  152. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  153. $data = curl_exec($curlproc);
  154. if(curl_errno($curlproc)){
  155. throw new Exception(curl_error($curlproc));
  156. }
  157. curl_close($curlproc);
  158. return $data;
  159. }catch(Exception $error){
  160. do404("Curl error: " . $error->getMessage());
  161. }
  162. }
  163. private function do404($error){
  164. echo json_encode(
  165. ["error" => $error],
  166. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  167. );
  168. die();
  169. }
  170. private function doempty(){
  171. echo json_encode(
  172. [
  173. $_GET["s"],
  174. []
  175. ],
  176. JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE
  177. );
  178. die();
  179. }
  180. }