ac.php 5.5 KB

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