1
0

solofield.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. <?php
  2. class solofield{
  3. public function __construct(){
  4. include "lib/backend.php";
  5. $this->backend = new backend("solofield");
  6. include "lib/fuckhtml.php";
  7. $this->fuckhtml = new fuckhtml();
  8. }
  9. public function getfilters($page){
  10. return [
  11. "nsfw" => [
  12. "display" => "NSFW",
  13. "option" => [
  14. "yes" => "Yes",
  15. "no" => "No",
  16. ]
  17. ]
  18. ];
  19. }
  20. private function get($proxy, $url, $get = []){
  21. $curlproc = curl_init();
  22. if($get !== []){
  23. $get = http_build_query($get);
  24. $url .= "?" . $get;
  25. }
  26. curl_setopt($curlproc, CURLOPT_URL, $url);
  27. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  28. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  29. ["User-Agent: " . config::USER_AGENT,
  30. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
  31. "Accept-Language: en-US,en;q=0.5",
  32. "Accept-Encoding: gzip",
  33. "Referer: https://solofield.net",
  34. "DNT: 1",
  35. "Connection: keep-alive",
  36. "Cookie: cross-site-cookie=name; lno=35842050",
  37. "Upgrade-Insecure-Requests: 1",
  38. "Sec-Fetch-Dest: document",
  39. "Sec-Fetch-Mode: navigate",
  40. "Sec-Fetch-Site: same-origin",
  41. "Sec-Fetch-User: ?1"]
  42. );
  43. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  44. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  45. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  46. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  47. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  48. $this->backend->assign_proxy($curlproc, $proxy);
  49. $data = curl_exec($curlproc);
  50. if(curl_errno($curlproc)){
  51. throw new Exception(curl_error($curlproc));
  52. }
  53. curl_close($curlproc);
  54. return $data;
  55. }
  56. public function web($get){
  57. if($get["npt"]){
  58. [$query, $proxy] = $this->backend->get($get["npt"], "web");
  59. try{
  60. $html =
  61. $this->get(
  62. $proxy,
  63. "https://solofield.net/search?" . $query,
  64. []
  65. );
  66. }catch(Exception $error){
  67. throw new Exception("Failed to fetch search page");
  68. }
  69. }else{
  70. $proxy = $this->backend->get_ip();
  71. try{
  72. $html =
  73. $this->get(
  74. $proxy,
  75. "https://solofield.net/search",
  76. [
  77. "q" => $get["s"],
  78. "ie" => "UTF-8",
  79. "oe" => "UTF-8",
  80. "hl" => "ja", // changing this doesnt do anything
  81. "lr" => "lang_ja", // same here
  82. //"ls" => "", // ??
  83. "f" => ($get["nsfw"] == "yes" ? "off" : "on")
  84. ]
  85. );
  86. }catch(Exception $error){
  87. throw new Exception("Failed to fetch search page");
  88. }
  89. }
  90. $out = [
  91. "status" => "ok",
  92. "spelling" => [
  93. "type" => "no_correction",
  94. "using" => null,
  95. "correction" => null
  96. ],
  97. "npt" => null,
  98. "answer" => [],
  99. "web" => [],
  100. "image" => [],
  101. "video" => [],
  102. "news" => [],
  103. "related" => []
  104. ];
  105. // check for errors and load the result div
  106. $this->error_and_load($html);
  107. $items =
  108. $this->fuckhtml
  109. ->getElementsByClassName(
  110. "g0",
  111. "li"
  112. );
  113. foreach($items as $item){
  114. $this->fuckhtml->load($item);
  115. $title_tag =
  116. $this->fuckhtml
  117. ->getElementsByClassName(
  118. "r",
  119. "h3"
  120. );
  121. if(count($title_tag) === 0){
  122. continue;
  123. }
  124. $this->fuckhtml->load($title_tag[0]);
  125. $link =
  126. $this->fuckhtml
  127. ->getTextContent(
  128. $this->fuckhtml
  129. ->getElementsByTagName(
  130. "a"
  131. )[0]
  132. ["attributes"]
  133. ["href"]
  134. );
  135. $this->fuckhtml->load($item);
  136. $thumb =
  137. $this->fuckhtml
  138. ->getElementsByClassName(
  139. "webshot",
  140. "img"
  141. );
  142. if(count($thumb) !== 0){
  143. $thumb = [
  144. "ratio" => "1:1",
  145. "url" =>
  146. "https://solofield.net" .
  147. $this->fuckhtml
  148. ->getTextContent(
  149. $thumb[0]
  150. ["attributes"]
  151. ["src"]
  152. )
  153. ];
  154. }else{
  155. $thumb = [
  156. "ratio" => null,
  157. "url" => null
  158. ];
  159. }
  160. $out["web"][] = [
  161. "title" =>
  162. $this->fuckhtml
  163. ->getTextContent(
  164. $title_tag[0]
  165. ),
  166. "description" =>
  167. $this->fuckhtml
  168. ->getTextContent(
  169. $this->fuckhtml
  170. ->getElementsByClassName(
  171. "s",
  172. "div"
  173. )[0]
  174. ),
  175. "url" => $link,
  176. "date" => null,
  177. "type" => "web",
  178. "thumb" => $thumb,
  179. "sublink" => [],
  180. "table" => []
  181. ];
  182. }
  183. // get next page
  184. $this->get_npt($html, $proxy, $out, "web");
  185. return $out;
  186. }
  187. public function image($get){
  188. // no pagination
  189. $html =
  190. $this->get(
  191. $this->backend->get_ip(),
  192. "https://solofield.net/isearch",
  193. [
  194. "q" => $get["s"],
  195. "ie" => "UTF-8",
  196. "oe" => "UTF-8",
  197. "hl" => "ja", // changing this doesnt do anything
  198. //"lr" => "lang_ja", // same here
  199. "ls" => "", // ??
  200. "f" => ($get["nsfw"] == "yes" ? "off" : "on")
  201. ]
  202. );
  203. $out = [
  204. "status" => "ok",
  205. "npt" => null,
  206. "image" => []
  207. ];
  208. // check for errors and load the result div
  209. $this->error_and_load($html);
  210. $images =
  211. $this->fuckhtml
  212. ->getElementsByTagName(
  213. "li"
  214. );
  215. foreach($images as $image){
  216. $this->fuckhtml->load($image);
  217. $img =
  218. $this->fuckhtml
  219. ->getElementsByTagName(
  220. "img"
  221. );
  222. if(count($img) === 0){
  223. // ?? invalid
  224. continue;
  225. }
  226. $img = $img[0];
  227. $size =
  228. explode(
  229. "x",
  230. $this->fuckhtml
  231. ->getTextContent(
  232. $image
  233. ),
  234. 2
  235. );
  236. $size = [
  237. (int)trim($size[0]), // width
  238. (int)trim($size[1]) // height
  239. ];
  240. $out["image"][] = [
  241. "title" => null,
  242. "source" => [
  243. [
  244. "url" =>
  245. "https://solofield.net/" .
  246. $this->fuckhtml
  247. ->getTextContent(
  248. $img["attributes"]["src"]
  249. ),
  250. "width" => $size[0],
  251. "height" => $size[1]
  252. ]
  253. ],
  254. "url" =>
  255. $this->fuckhtml
  256. ->getTextContent(
  257. $this->fuckhtml
  258. ->getElementsByTagName(
  259. "a"
  260. )[0]
  261. ["attributes"]
  262. ["href"]
  263. )
  264. ];
  265. }
  266. return $out;
  267. }
  268. public function video($get){
  269. if($get["npt"]){
  270. [$query, $proxy] = $this->backend->get($get["npt"], "videos");
  271. try{
  272. $html =
  273. $this->get(
  274. $proxy,
  275. "https://solofield.net/vsearch?" . $query,
  276. []
  277. );
  278. }catch(Exception $error){
  279. throw new Exception("Failed to fetch search page");
  280. }
  281. }else{
  282. $proxy = $this->backend->get_ip();
  283. try{
  284. $html =
  285. $this->get(
  286. $proxy,
  287. "https://solofield.net/vsearch",
  288. [
  289. "q" => $get["s"],
  290. "ie" => "UTF-8",
  291. "oe" => "UTF-8",
  292. "hl" => "ja", // changing this doesnt do anything
  293. //"lr" => "lang_ja", // same here
  294. "ls" => "", // ??
  295. "f" => ($get["nsfw"] == "yes" ? "off" : "on")
  296. ]
  297. );
  298. }catch(Exception $error){
  299. throw new Exception("Failed to fetch search page");
  300. }
  301. }
  302. $out = [
  303. "status" => "ok",
  304. "npt" => null,
  305. "video" => [],
  306. "author" => [],
  307. "livestream" => [],
  308. "playlist" => [],
  309. "reel" => []
  310. ];
  311. // check for errors and load the result div
  312. $this->error_and_load($html);
  313. $items =
  314. $this->fuckhtml
  315. ->getElementsByTagName(
  316. "li"
  317. );
  318. foreach($items as $item){
  319. $this->fuckhtml->load($item);
  320. $as =
  321. $this->fuckhtml
  322. ->getElementsByTagName(
  323. "a"
  324. );
  325. if(count($as) === 0){
  326. continue;
  327. }
  328. $thumb =
  329. $this->fuckhtml
  330. ->getElementsByTagName(
  331. "img"
  332. );
  333. if(count($thumb) !== 0){
  334. $thumb = [
  335. "ratio" => "16:9",
  336. "url" =>
  337. "https://solofield.net/" .
  338. $thumb[0]
  339. ["attributes"]
  340. ["src"]
  341. ];
  342. }else{
  343. $thumb = [
  344. "ratio" => null,
  345. "url" => null
  346. ];
  347. }
  348. $date =
  349. $this->fuckhtml
  350. ->getElementsByAttributeValue(
  351. "style",
  352. "font-size: 10px;",
  353. "span"
  354. );
  355. if(count($date) !== 0){
  356. $date =
  357. $this->unfuckdate(
  358. $this->fuckhtml
  359. ->getTextContent(
  360. $date[0]
  361. )
  362. );
  363. }else{
  364. $date = null;
  365. }
  366. $center_td =
  367. $this->fuckhtml
  368. ->getElementsByAttributeValue(
  369. "align",
  370. "center",
  371. "td"
  372. );
  373. if(count($center_td) === 2){
  374. $duration =
  375. $this->fuckhtml
  376. ->getTextContent(
  377. $this->hms2int(
  378. $center_td[0]
  379. )
  380. );
  381. }else{
  382. $duration = null;
  383. }
  384. $out["video"][] = [
  385. "title" =>
  386. $this->fuckhtml
  387. ->getTextContent(
  388. $as[1]
  389. ),
  390. "description" => null,
  391. "author" => [
  392. "name" => null,
  393. "url" => null,
  394. "avatar" => null
  395. ],
  396. "date" => $date,
  397. "duration" => $duration,
  398. "views" => null,
  399. "thumb" => $thumb,
  400. "url" =>
  401. $this->fuckhtml
  402. ->getTextContent(
  403. $as[0]
  404. ["attributes"]
  405. ["href"]
  406. )
  407. ];
  408. }
  409. // get next page
  410. $this->get_npt($html, $proxy, $out, "videos");
  411. return $out;
  412. }
  413. private function get_npt($html, $proxy, &$out, $type){
  414. // get next page
  415. $this->fuckhtml->load($html);
  416. $pjs =
  417. $this->fuckhtml
  418. ->getElementById(
  419. "pjs"
  420. );
  421. if($pjs){
  422. $alnk =
  423. $this->fuckhtml
  424. ->getElementsByClassName(
  425. "alnk",
  426. "span"
  427. );
  428. foreach($alnk as $lnk){
  429. if(
  430. stripos(
  431. $this->fuckhtml
  432. ->getTextContent(
  433. $lnk
  434. ),
  435. "Next"
  436. ) !== false
  437. ){
  438. $this->fuckhtml->load($lnk);
  439. $out["npt"] =
  440. $this->backend->store(
  441. parse_url(
  442. $this->fuckhtml
  443. ->getElementsByTagName(
  444. "a"
  445. )[0]
  446. ["attributes"]
  447. ["href"],
  448. PHP_URL_QUERY
  449. ),
  450. $type,
  451. $proxy
  452. );
  453. }
  454. }
  455. }
  456. }
  457. private function error_and_load($html){
  458. if(strlen($html) === 0){
  459. throw new Exception("Solofield blocked the request IP");
  460. }
  461. $this->fuckhtml->load($html);
  462. $list =
  463. $this->fuckhtml
  464. ->getElementById(
  465. "list",
  466. "div"
  467. );
  468. if($list === false){
  469. $nosearch =
  470. $this->fuckhtml
  471. ->getElementById(
  472. "nosearch",
  473. "div"
  474. );
  475. if($nosearch){
  476. return $out;
  477. }
  478. throw new Exception("Failed to grep search list");
  479. }
  480. $this->fuckhtml->load($list);
  481. }
  482. private function unfuckdate($date){
  483. return
  484. strtotime(
  485. rtrim(
  486. preg_replace(
  487. '/[^0-9]+/',
  488. "-",
  489. explode(
  490. ":",
  491. $date,
  492. 2
  493. )[1]
  494. ),
  495. "-"
  496. )
  497. );
  498. }
  499. private function hms2int($time){
  500. $parts = explode(":", $time, 3);
  501. $time = 0;
  502. if(count($parts) === 3){
  503. // hours
  504. $time = $time + ((int)$parts[0] * 3600);
  505. array_shift($parts);
  506. }
  507. if(count($parts) === 2){
  508. // minutes
  509. $time = $time + ((int)$parts[0] * 60);
  510. array_shift($parts);
  511. }
  512. // seconds
  513. $time = $time + (int)$parts[0];
  514. return $time;
  515. }
  516. }