naver.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. <?php
  2. class naver{
  3. public function __construct(){
  4. include "lib/backend.php";
  5. $this->backend = new backend("naver");
  6. include "lib/fuckhtml.php";
  7. $this->fuckhtml = new fuckhtml();
  8. }
  9. public function getfilters($page){
  10. $base = [
  11. "time" => [
  12. "display" => "Time",
  13. "option" => [
  14. "any" => "Any time",
  15. "1h" => "Last hour",
  16. "1d" => "Last day",
  17. "1w" => "Last week",
  18. "1m" => "Last month",
  19. "3m" => "Last 3 months",
  20. "6m" => "Last 6 months",
  21. "1y" => "Last year",
  22. ]
  23. ]
  24. ];
  25. switch($page){
  26. case "web":
  27. return
  28. array_merge([
  29. "sort" => [
  30. "display" => "Sort by",
  31. "option" => [
  32. "relevance" => "Relevance", // r
  33. "most_recent" => "Most recent" // dd
  34. ]
  35. ]
  36. ], $base);
  37. break;
  38. case "images":
  39. return
  40. array_merge(
  41. $base,
  42. [
  43. "size" => [
  44. "display" => "Size",
  45. "option" => [
  46. "any" => "Any size",
  47. "highdef" => "High definition" // &res_fr=786432&res_to=100000000
  48. ]
  49. ],
  50. "color" => [ // &color=
  51. "display" => "Color",
  52. "option" => [
  53. "any" => "Any color",
  54. "orange" => "Orange",
  55. "yellow" => "Yellow",
  56. "lime" => "Lime",
  57. "green" => "Green",
  58. "cyan" => "Cyan",
  59. "blue" => "Blue",
  60. "purple" => "Purple",
  61. "pink" => "Pink",
  62. "apricot" => "Apricot",
  63. "ocher" => "Ocher",
  64. "sepia" => "Sepia",
  65. "black" => "Black",
  66. "gray" => "Gray",
  67. "white" => "White"
  68. ]
  69. ],
  70. "license" => [ // &ccl=
  71. "display" => "License",
  72. "option" => [
  73. "any" => "Any license",
  74. "1" => "CCL Total",
  75. "2" => "Commercial use",
  76. "4" => "Modifications permitted"
  77. ]
  78. ]
  79. ]
  80. );
  81. break;
  82. case "videos":
  83. return
  84. [
  85. "time" => [ // done
  86. "display" => "Time",
  87. "option" => [
  88. "any" => "Any time",
  89. "1day" => "Last day",
  90. "1week" => "Last week",
  91. "1month" => "Last month",
  92. "3month" => "Last 3 months",
  93. "6month" => "Last 6 months",
  94. "1year" => "Last year"
  95. ]
  96. ],
  97. "sort" => [ // done
  98. "display" => "Sort by",
  99. "option" => [
  100. "rel" => "Relevance",
  101. "date" => "Most recent", // &sort=date
  102. "playcount" => "Most views", // &sort=playcount
  103. ]
  104. ],
  105. "type" => [ // done
  106. "display" => "Type",
  107. "option" => [
  108. "any" => "Any videos",
  109. "shorts" => "Shorts" // dtype=shorts
  110. ]
  111. ],
  112. "duration" => [
  113. "display" => "Duration", // &playtime=
  114. "option" => [
  115. "any" => "Any duration",
  116. "0:600" => "10 minutes",
  117. "601:1800" => "10-30 minutes",
  118. "1801:3600" => "30-60 minutes",
  119. "3601:65535" => "More than 1 hour"
  120. ]
  121. ]
  122. ];
  123. break;
  124. }
  125. }
  126. private function get($proxy, $url, $get = [], $is_xhr = false){
  127. $curlproc = curl_init();
  128. if($get !== []){
  129. $get = http_build_query($get);
  130. $url .= "?" . $get;
  131. }
  132. curl_setopt($curlproc, CURLOPT_URL, $url);
  133. // use http2
  134. curl_setopt($curlproc, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  135. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  136. if($is_xhr === false){
  137. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  138. ["User-Agent: " . config::USER_AGENT,
  139. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
  140. "Accept-Language: en-US,en;q=0.5",
  141. "Accept-Encoding: gzip",
  142. "DNT: 1",
  143. "Sec-GPC: 1",
  144. "Connection: keep-alive",
  145. "Upgrade-Insecure-Requests: 1",
  146. "Sec-Fetch-Dest: document",
  147. "Sec-Fetch-Mode: navigate",
  148. "Sec-Fetch-Site: same-origin",
  149. "Priority: u=0, i",
  150. "Sec-Fetch-User: ?1"]
  151. );
  152. }else{
  153. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  154. ["User-Agent: " . config::USER_AGENT,
  155. "Accept: */*",
  156. "Accept-Language: en-US,en;q=0.9",
  157. "Accept-Encoding: gzip, deflate, br, zstd",
  158. "Referer: https://search.naver.com/",
  159. "DNT: 1",
  160. "Sec-GPC: 1",
  161. "Alt-Used: s.search.naver.com",
  162. "Connection: keep-alive",
  163. "Sec-Fetch-Dest: script",
  164. "Sec-Fetch-Mode: no-cors",
  165. "Sec-Fetch-Site: same-site",
  166. "TE: trailers"]
  167. );
  168. }
  169. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  170. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  171. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  172. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  173. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  174. $this->backend->assign_proxy($curlproc, $proxy);
  175. $data = curl_exec($curlproc);
  176. if(curl_errno($curlproc)){
  177. throw new Exception(curl_error($curlproc));
  178. }
  179. curl_close($curlproc);
  180. return $data;
  181. }
  182. public function web($get){
  183. $search = $get["s"];
  184. if(strlen($search) === 0){
  185. throw new Exception("Search term is empty!");
  186. }
  187. $out = [
  188. "status" => "ok",
  189. "spelling" => [
  190. "type" => "no_correction",
  191. "using" => null,
  192. "correction" => null
  193. ],
  194. "npt" => null,
  195. "answer" => [],
  196. "web" => [],
  197. "image" => [],
  198. "video" => [],
  199. "news" => [],
  200. "related" => []
  201. ];
  202. if($get["npt"]){
  203. [$d, $proxy] = $this->backend->get($get["npt"], "web");
  204. try{
  205. $html =
  206. $this->get(
  207. $proxy,
  208. "https://search.naver.com/search.naver" . $d,
  209. []
  210. );
  211. }catch(Exception $error){
  212. throw new Exception("Failed to fetch search page");
  213. }
  214. }else{
  215. // parse filters
  216. // https://search.naver.com
  217. // /search.naver
  218. // ?nso=
  219. // &page=1
  220. // &query=nisekoi
  221. // &sm=tab_pge
  222. // &start=1
  223. // &where=web
  224. $filters = [
  225. "nso" => "",
  226. "page" => 2, // page 2 is repeat of page 1
  227. "query" => $search,
  228. "sm" => "tab_pge",
  229. "ssc" => "tab.ur.all",
  230. "start" => 1 // increment by number of results each time (16??)
  231. ];
  232. $options = [];
  233. if($get["sort"] != "relevance"){
  234. $options[] = "so:dd";
  235. }
  236. if($get["time"] != "any"){
  237. $options[] = "p:" . $get["time"];
  238. }
  239. if(count($options) !== 0){
  240. $filters["nso"] = implode(",", $options);
  241. }
  242. //$html = file_get_contents("scraper/naver.html");
  243. $proxy = $this->backend->get_ip();
  244. try{
  245. $html =
  246. $this->get(
  247. $proxy,
  248. "https://search.naver.com/search.naver",
  249. $filters
  250. );
  251. }catch(Exception $error){
  252. throw new Exception("Failed to fetch search page");
  253. }
  254. }
  255. $this->fuckhtml->load($html);
  256. $jsons =
  257. preg_split(
  258. '/entry\.bootstrap\(document\.getElementById\("[a-f0-9-r]+"\), ?/',
  259. $html
  260. );
  261. if(count($jsons) <= 1){
  262. // this is thrown when no results are found
  263. $nsfw_probe =
  264. $this->fuckhtml
  265. ->getElementsByClassName(
  266. "dsc_adult",
  267. "div"
  268. );
  269. if(count($nsfw_probe) !== 0){
  270. $out["answer"][] = [
  271. "title" => "NSFW results",
  272. "description" => [
  273. [
  274. "type" => "text",
  275. "value" => "Naver blocks logged-out NSFW searches."
  276. ]
  277. ],
  278. "url" => null,
  279. "thumb" => null,
  280. "table" => [],
  281. "sublink" => []
  282. ];
  283. }
  284. return $out;
  285. //throw new Exception("Failed to grep results entrypoint");
  286. }
  287. foreach($jsons as $json){
  288. $json =
  289. json_decode(
  290. $this->fuckhtml
  291. ->extract_json(
  292. $json
  293. ),
  294. true
  295. );
  296. if($json === null){
  297. continue;
  298. }
  299. if(!isset($json["data"]["state"]["items"])){
  300. //throw new Exception("Failed to access nested children");
  301. continue;
  302. }
  303. foreach($json["data"]["state"]["items"] as $result){
  304. // get sublinks
  305. $sublinks = [];
  306. if(isset($result["subLinks"])){
  307. foreach($result["subLinks"] as $s){
  308. $sublinks[] = [
  309. "title" => $s["text"],
  310. "description" => null,
  311. "url" => $s["href"],
  312. "date" => null
  313. ];
  314. }
  315. }
  316. if(isset($result["linkBtns"])){
  317. foreach($result["linkBtns"] as $s){
  318. $sublinks[] = [
  319. "title" => $s["text"],
  320. "description" => null,
  321. "url" => $s["href"],
  322. "date" => null
  323. ];
  324. }
  325. }
  326. // get image (thumbnail, i guess)
  327. if(isset($result["images"][0]["imageSrc"])){
  328. $thumb = [
  329. "ratio" => "16:9",
  330. "url" => $this->unshit_thumb($result["images"][0]["imageSrc"])
  331. ];
  332. }else{
  333. $thumb = [
  334. "ratio" => null,
  335. "url" => null
  336. ];
  337. }
  338. // get table elements
  339. $table = [];
  340. if(isset($result["keyValue"]["contents"])){
  341. foreach($result["keyValue"]["contents"] as $s){
  342. if(!isset($s["valueData"]["text"])){ continue; }
  343. $table[$s["key"]] = $s["valueData"]["text"];
  344. }
  345. }
  346. // get date
  347. $time = null;
  348. if(isset($result["profile"]["createdDate"])){
  349. $time = $result["profile"]["createdDate"];
  350. }elseif(isset($result["sourceProfile"]["createdDate"])){
  351. $time = $result["sourceProfile"]["createdDate"];
  352. }
  353. if($time !== null){
  354. $date =
  355. strtotime(
  356. substr(
  357. $time,
  358. -1
  359. )
  360. );
  361. if($date !== false){
  362. $time = $date;
  363. }else{
  364. $time = null;
  365. }
  366. }
  367. // get title
  368. if(isset($result["title"])){
  369. $title = $result["title"];
  370. }elseif(isset($result["questionTitle"])){
  371. $title = $result["questionTitle"];
  372. }else{
  373. continue;
  374. }
  375. // get url
  376. if(isset($result["titleHref"])){
  377. $href = $result["titleHref"];
  378. }elseif(isset($result["href"])){
  379. $href = $result["href"];
  380. }elseif(isset($result["answerHref"])){
  381. $href = $result["answerHref"];
  382. }else{
  383. continue;
  384. }
  385. // get description
  386. if(isset($result["bodyText"])){
  387. $description = $result["bodyText"];
  388. }elseif(isset($result["content"])){
  389. $description = $result["content"];
  390. }elseif(isset($result["questionContent"])){
  391. $description = $result["questionContent"];
  392. }else{
  393. $description = null;
  394. }
  395. $out["web"][] = [
  396. "title" => $this->decode_html($title),
  397. "description" => $this->decode_html($description),
  398. "url" => $href,
  399. "date" => $time,
  400. "type" => "web",
  401. "thumb" => $thumb,
  402. "sublink" => $sublinks,
  403. "table" => $table
  404. ];
  405. }
  406. }
  407. // get next page
  408. $npt =
  409. $this->fuckhtml
  410. ->getElementsByClassName(
  411. "btn_next",
  412. "a"
  413. );
  414. if(count($npt) !== 0){
  415. $out["npt"] =
  416. $this->backend->store(
  417. $this->fuckhtml
  418. ->getTextContent(
  419. $npt[0]["attributes"]["href"]
  420. ),
  421. "web",
  422. $proxy
  423. );
  424. }
  425. return $out;
  426. }
  427. public function image($get){
  428. $search = $get["s"];
  429. if(strlen($search) === 0){
  430. throw new Exception("Search term is empty!");
  431. }
  432. $out = [
  433. "status" => "ok",
  434. "npt" => null,
  435. "image" => []
  436. ];
  437. if($get["npt"]){
  438. [$url, $proxy] = $this->backend->get($get["npt"], "images");
  439. try{
  440. $json =
  441. $this->get(
  442. $proxy,
  443. $url,
  444. [],
  445. true
  446. );
  447. }catch(Exception $error){
  448. throw new Exception("Failed to fetch search page");
  449. }
  450. }else{
  451. $filters = [
  452. "ac" => "0",
  453. "api_type" => "pc_tab_more",
  454. "aq" => "0",
  455. "display" => 100,
  456. "logStart" => 1,
  457. "mode" => "column",
  458. "nso" => "so:r,p:all",
  459. "nx_search_query" => $search,
  460. "query" => $search,
  461. "section" => "image",
  462. "sm" => "tab_opt",
  463. "ssc" => "tab.image.all",
  464. "start" => 1,
  465. "where" => "image"
  466. // no callback, returns raw json lol
  467. ];
  468. $options = [
  469. "so:r"
  470. ];
  471. if($get["time"] != "any"){
  472. $options[] = "p:" . $get["time"];
  473. }
  474. if(count($options) !== 0){
  475. $filters["nso"] = implode(",", $options);
  476. }
  477. if($get["size"] != "any"){
  478. $filters["res_fr"] = 786432;
  479. $filters["res_to"] = 100000000;
  480. }
  481. if($get["color"] != "any"){
  482. $filters["color"] = $get["color"];
  483. }
  484. if($get["license"] != "any"){
  485. $filters["ccl"] = $get["license"];
  486. }
  487. //$json = file_get_contents("scraper/naver.html");
  488. $proxy = $this->backend->get_ip();
  489. try{
  490. $json =
  491. $this->get(
  492. $proxy,
  493. "https://s.search.naver.com/p/c/image/46/search.naver",
  494. $filters,
  495. true
  496. );
  497. }catch(Exception $error){
  498. throw new Exception("Failed to fetch search page");
  499. }
  500. }
  501. $json = json_decode($json, true);
  502. if($json === null){
  503. throw new Exception("Failed to decode JSON");
  504. }
  505. if(!isset($json["items"])){
  506. // no results returned :(
  507. return $out;
  508. //throw new Exception("Naver did not return an items object");
  509. }
  510. foreach($json["items"] as $image){
  511. // why does it fucking do that
  512. if($image["orgWidth"] === 0){ continue; }
  513. $out["image"][] = [
  514. "title" => trim($image["title"], "."),
  515. "source" => [
  516. [
  517. "url" => $image["originalUrl"],
  518. "width" => (int)$image["orgWidth"],
  519. "height" => (int)$image["orgHeight"]
  520. ],
  521. [
  522. "url" => $image["thumb"],
  523. "width" => (int)$image["thumbWidth"],
  524. "height" => (int)$image["thumbHeight"]
  525. ]
  526. ],
  527. "url" => $image["link"]
  528. ];
  529. }
  530. // get npt
  531. if(
  532. isset($json["url"]) &&
  533. $json["url"] != "" &&
  534. $json["url"] != null
  535. ){
  536. $out["npt"] =
  537. $this->backend->store(
  538. $json["url"],
  539. "images",
  540. $proxy
  541. );
  542. }
  543. return $out;
  544. }
  545. public function video($get){
  546. $search = $get["s"];
  547. if(strlen($search) === 0){
  548. throw new Exception("Search term is empty!");
  549. }
  550. $out = [
  551. "status" => "ok",
  552. "npt" => null,
  553. "video" => [],
  554. "author" => [],
  555. "livestream" => [],
  556. "playlist" => [],
  557. "reel" => []
  558. ];
  559. if($get["npt"]){
  560. [$url, $proxy] = $this->backend->get($get["npt"], "images");
  561. try{
  562. $json =
  563. $this->get(
  564. $proxy,
  565. $url,
  566. [],
  567. true
  568. );
  569. }catch(Exception $error){
  570. throw new Exception("Failed to fetch search page");
  571. }
  572. }else{
  573. // https://s.search.naver.com/p/video/48/search.naver?ac=0&aq=0&crbase=63&display=48&dtype=&last_block_type=recom&nlu_query=&nq=&nqx_theme={"theme":{"main":{"name":"encyclopedia","source":"TOS"}}}&nx_and_query=&nx_search_hlquery=&nx_search_query=&nx_sub_query=&page=2&period=&playtime=&ptype=&query=asmr&selected_channel=&selected_cp=&sm=mtb_pge&sort=rel&ssc=tab.video.all&start=49&video_more=1
  574. // https://s.search.naver.com/p/video/48/search.naver
  575. // ?ac=0
  576. // &aq=0
  577. // &crbase=63
  578. // &display=48
  579. // &dtype=
  580. // &last_block_type=recom
  581. // &nlu_query=
  582. // &nq=
  583. // &nqx_theme={"theme":{"main":{"name":"encyclopedia","source":"TOS"}}}
  584. // &nx_and_query=
  585. // &nx_search_hlquery=
  586. // &nx_search_query=
  587. // &nx_sub_query=
  588. // &page=2
  589. // &period=
  590. // &playtime=
  591. // &ptype=
  592. // &query=asmr
  593. // &selected_channel=
  594. // &selected_cp=
  595. // &sm=mtb_pge
  596. // &sort=rel
  597. // &ssc=tab.video.all
  598. // &start=49
  599. // &video_more=1
  600. $filters = [
  601. "ac" => "0",
  602. "aq" => "0",
  603. "crbase" => "78",
  604. "display" => 48,
  605. "dtype" => "",
  606. "last_block_type" => "recom",
  607. "nlu_query" => "",
  608. "nq" => "",
  609. "nx_and_query" => "",
  610. "nx_search_hlquery" => "",
  611. "nx_search_query" => "",
  612. "nx_sub_query" => "",
  613. "page" => 1,
  614. "period" => "",
  615. "playtime" => "",
  616. "ptype" => "",
  617. "query" => $search,
  618. "selected_channel" => "",
  619. "selected_cp" => "",
  620. "sm" => "mtb_pge",
  621. "sort" => "rel",
  622. "ssc" => "tab.video.all",
  623. "start" => 1,
  624. "video_more" => 1
  625. ];
  626. if($get["type"] != "any"){
  627. $filters["dtype"] = $get["type"];
  628. }
  629. if($get["time"] != "any"){
  630. $filters["period"] = $get["time"];
  631. }
  632. if($get["sort"] != "rel"){
  633. $filters["sort"] = $get["sort"];
  634. }
  635. if($get["duration"] != "any"){
  636. $filters["playtime"] = $get["duration"];
  637. }
  638. //$json = file_get_contents("scraper/naver.html");
  639. $proxy = $this->backend->get_ip();
  640. try{
  641. $json =
  642. $this->get(
  643. $proxy,
  644. "https://s.search.naver.com/p/video/48/search.naver",
  645. $filters,
  646. true
  647. );
  648. }catch(Exception $error){
  649. throw new Exception("Failed to fetch search page");
  650. }
  651. }
  652. $json = json_decode($json, true);
  653. if($json === null){
  654. throw new Exception("Failed to decode JSON");
  655. }
  656. if(!isset($json["collection"])){
  657. return $out;
  658. //throw new Exception("Naver did not return a collection HTML element");
  659. }
  660. foreach($json["collection"] as $snippet){
  661. if(!isset($snippet["html"])){ continue; }
  662. $this->fuckhtml->load($snippet["html"]);
  663. $div =
  664. $this->fuckhtml
  665. ->getElementsByTagName(
  666. "div"
  667. );
  668. $items =
  669. $this->fuckhtml
  670. ->getElementsByAttributeValue(
  671. "data-template-id",
  672. "videoItem",
  673. $div
  674. );
  675. // parse normal videos
  676. foreach($items as $item){
  677. if($item["level"] === 6){ continue; }
  678. $this->fuckhtml->load($item);
  679. // get url
  680. $as =
  681. $this->fuckhtml
  682. ->getElementsByAttributeName(
  683. "data-heatmap-target",
  684. "a"
  685. );
  686. if(count($as) === 0){
  687. // should not happen
  688. continue;
  689. }
  690. // get thumbnail
  691. $thumb =
  692. $this->fuckhtml
  693. ->getElementsByAttributeValue(
  694. "loading",
  695. "lazy",
  696. "img"
  697. );
  698. if(count($thumb) !== 0){
  699. $thumb = [
  700. "url" =>
  701. $this->unshit_thumb(
  702. $this->fuckhtml
  703. ->getTextContent(
  704. $thumb[0]["attributes"]["src"]
  705. )
  706. ),
  707. "ratio" => "16:9"
  708. ];
  709. }else{
  710. $thumb = [
  711. "url" => null,
  712. "ratio" => null
  713. ];
  714. }
  715. // get timestamp
  716. $timestamp_probe =
  717. $this->fuckhtml
  718. ->getElementsByClassName(
  719. "sds-comps-text-type-footnote",
  720. "span"
  721. );
  722. if(count($timestamp_probe) !== 0){
  723. $timestamp =
  724. $this->hms2int(
  725. $this->fuckhtml
  726. ->getTextContent(
  727. $timestamp_probe[0]
  728. )
  729. );
  730. }else{
  731. $timestamp = null;
  732. }
  733. $out["video"][] = [
  734. "title" =>
  735. $this->fuckhtml
  736. ->getTextContent(
  737. $as[0]
  738. ),
  739. "description" => null,
  740. "author" => [
  741. "name" =>
  742. isset($item["attributes"]["profileimagealt"]) ?
  743. $this->fuckhtml
  744. ->getTextContent(
  745. $item["attributes"]["profileimagealt"]
  746. ) : null,
  747. "url" =>
  748. isset($item["attributes"]["profileimagehref"]) ?
  749. $this->fuckhtml
  750. ->getTextContent(
  751. $item["attributes"]["profileimagehref"]
  752. ) : null,
  753. "avatar" =>
  754. isset($item["attributes"]["profileimagesrc"]) ?
  755. $this->fuckhtml
  756. ->getTextContent(
  757. $item["attributes"]["profileimagesrc"]
  758. ) : null
  759. ],
  760. "date" => null,
  761. "duration" => $timestamp,
  762. "views" => null,
  763. "thumb" => $thumb,
  764. "url" =>
  765. $this->fuckhtml
  766. ->getTextContent(
  767. $as[0]["attributes"]["href"]
  768. )
  769. ];
  770. }
  771. // reset
  772. $this->fuckhtml->load($snippet["html"]);
  773. // parse reels
  774. $carousels =
  775. array_merge(
  776. $this->fuckhtml // for the reels only tab
  777. ->getElementsByClassName(
  778. "fds-video-tab-shortform-desk-filter",
  779. $div
  780. ),
  781. $this->fuckhtml // for the normal tab with reels inbetween
  782. ->getElementsByClassName(
  783. "fds-video-tab-shortform-desk",
  784. $div
  785. )
  786. );
  787. foreach($carousels as $carousel){
  788. $this->fuckhtml->load($carousel);
  789. $as =
  790. $this->fuckhtml
  791. ->getElementsByTagName(
  792. "a"
  793. );
  794. foreach($as as $reel){
  795. $this->fuckhtml->load($reel);
  796. $spans =
  797. $this->fuckhtml
  798. ->getElementsByTagName(
  799. "span"
  800. );
  801. $title =
  802. $this->fuckhtml
  803. ->getTextContent(
  804. $spans[0]
  805. );
  806. // get thumbnail
  807. $thumb =
  808. $this->fuckhtml
  809. ->getElementsByAttributeValue(
  810. "loading",
  811. "lazy",
  812. "img"
  813. );
  814. if(count($thumb) !== 0){
  815. $thumb = [
  816. "url" =>
  817. $this->unshit_thumb(
  818. $this->fuckhtml
  819. ->getTextContent(
  820. $thumb[0]["attributes"]["src"]
  821. )
  822. ),
  823. "ratio" => "16:9"
  824. ];
  825. }else{
  826. $thumb = [
  827. "url" => null,
  828. "ratio" => null
  829. ];
  830. }
  831. $name =
  832. $this->fuckhtml
  833. ->getElementsByClassName(
  834. "sds-comps-profile-info-title-text",
  835. $spans
  836. );
  837. if(count($name) === 0){
  838. $name = null;
  839. }else{
  840. $name =
  841. $this->fuckhtml
  842. ->getTextContent(
  843. $name[0]
  844. );
  845. }
  846. $out["reel"][] = [
  847. "title" => $title,
  848. "description" => null,
  849. "author" => [
  850. "name" => $name,
  851. "url" => null,
  852. "avatar" => null
  853. ],
  854. "date" => null,
  855. "duration" => null,
  856. "views" => null,
  857. "thumb" => $thumb,
  858. "url" =>
  859. $this->fuckhtml
  860. ->getTextContent(
  861. $reel["attributes"]["href"]
  862. )
  863. ];
  864. }
  865. }
  866. }
  867. // get npt
  868. if(
  869. isset($json["url"]) &&
  870. $json["url"] != "" &&
  871. $json["url"] != null
  872. ){
  873. $out["npt"] =
  874. $this->backend->store(
  875. $json["url"],
  876. "images",
  877. $proxy
  878. );
  879. }
  880. return $out;
  881. }
  882. private function unshit_thumb($url){
  883. $parts = parse_url($url);
  884. if($parts["host"] == "search.pstatic.net"){
  885. parse_str($parts["query"], $str);
  886. if(isset($str["src"])){
  887. return $str["src"];
  888. }
  889. }
  890. return $url;
  891. }
  892. private function decode_html($html){
  893. return
  894. trim(
  895. html_entity_decode(
  896. strip_tags(
  897. $html
  898. )
  899. ),
  900. "."
  901. );
  902. }
  903. private function hms2int($time){
  904. $parts = explode(":", $time, 3);
  905. $time = 0;
  906. if(count($parts) === 3){
  907. // hours
  908. $time = $time + ((int)$parts[0] * 3600);
  909. array_shift($parts);
  910. }
  911. if(count($parts) === 2){
  912. // minutes
  913. $time = $time + ((int)$parts[0] * 60);
  914. array_shift($parts);
  915. }
  916. // seconds
  917. $time = $time + (int)$parts[0];
  918. return $time;
  919. }
  920. }