ac.php 5.2 KB

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