naver.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  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. "query" => $search,
  227. "sm" => "tab_pge",
  228. "where" => "web",
  229. "start" => 1 // increment by number of results each time (16??)
  230. ];
  231. $options = [];
  232. if($get["sort"] != "relevance"){
  233. $options[] = "so:dd";
  234. }
  235. if($get["time"] != "any"){
  236. $options[] = "p:" . $get["time"];
  237. }
  238. if(count($options) !== 0){
  239. $filters["nso"] = implode(",", $options);
  240. }
  241. //$html = file_get_contents("scraper/naver.html");
  242. $proxy = $this->backend->get_ip();
  243. try{
  244. $html =
  245. $this->get(
  246. $proxy,
  247. "https://search.naver.com/search.naver",
  248. $filters
  249. );
  250. }catch(Exception $error){
  251. throw new Exception("Failed to fetch search page");
  252. }
  253. }
  254. $this->fuckhtml->load($html);
  255. $results =
  256. preg_split(
  257. '/entry\.bootstrap\(document\.getElementById\("[a-f0-9-r]+"\), ?/',
  258. $html
  259. );
  260. if(count($results) !== 2){
  261. // this is thrown when no results are found
  262. $nsfw_probe =
  263. $this->fuckhtml
  264. ->getElementsByClassName(
  265. "dsc_adult",
  266. "div"
  267. );
  268. if(count($nsfw_probe) !== 0){
  269. $out["answer"][] = [
  270. "title" => "NSFW results",
  271. "description" => [
  272. [
  273. "type" => "text",
  274. "value" => "Naver blocks logged-out NSFW searches."
  275. ]
  276. ],
  277. "url" => null,
  278. "thumb" => null,
  279. "table" => [],
  280. "sublink" => []
  281. ];
  282. }
  283. return $out;
  284. //throw new Exception("Failed to grep results entrypoint");
  285. }
  286. $json =
  287. json_decode(
  288. $this->fuckhtml
  289. ->extract_json(
  290. $results[1]
  291. ),
  292. true
  293. );
  294. if(!isset($json["body"]["props"]["children"][0]["props"]["children"])){
  295. throw new Exception("Failed to access nested children");
  296. }
  297. foreach($json["body"]["props"]["children"][0]["props"]["children"] as $result){
  298. if(
  299. !isset($result["templateId"]) ||
  300. $result["templateId"] != "webItem"
  301. ){
  302. // should not happen
  303. continue;
  304. }
  305. $result = $result["props"];
  306. // get sublinks
  307. $sublinks = [];
  308. if(isset($result["subLinks"])){
  309. foreach($result["subLinks"] as $s){
  310. $sublinks[] = [
  311. "title" => $s["text"],
  312. "description" => null,
  313. "url" => $s["href"],
  314. "date" => null
  315. ];
  316. }
  317. }
  318. if(isset($result["linkBtns"])){
  319. foreach($result["linkBtns"] as $s){
  320. $sublinks[] = [
  321. "title" => $s["text"],
  322. "description" => null,
  323. "url" => $s["href"],
  324. "date" => null
  325. ];
  326. }
  327. }
  328. // get image (thumbnail, i guess)
  329. if(isset($result["images"][0]["imageSrc"])){
  330. $thumb = [
  331. "ratio" => "16:9",
  332. "url" => $this->unshit_thumb($result["images"][0]["imageSrc"])
  333. ];
  334. }else{
  335. $thumb = [
  336. "ratio" => null,
  337. "url" => null
  338. ];
  339. }
  340. // get table elements
  341. $table = [];
  342. if(isset($result["keyValue"]["contents"])){
  343. foreach($result["keyValue"]["contents"] as $s){
  344. if(!isset($s["valueData"]["text"])){ continue; }
  345. $table[$s["key"]] = $s["valueData"]["text"];
  346. }
  347. }
  348. // get date
  349. $time = null;
  350. if(isset($result["bodyPrefixes"][0]["text"])){
  351. $date =
  352. strtotime(
  353. substr(
  354. $result["bodyPrefixes"][0]["text"],
  355. -1
  356. )
  357. );
  358. if($date !== false){
  359. $time = $date;
  360. }
  361. }
  362. $out["web"][] = [
  363. "title" => $this->decode_html($result["title"]),
  364. "description" => $this->decode_html($result["bodyText"]),
  365. "url" => $result["href"],
  366. "date" => $time,
  367. "type" => "web",
  368. "thumb" => $thumb,
  369. "sublink" => $sublinks,
  370. "table" => $table
  371. ];
  372. }
  373. // get next page
  374. $npt =
  375. $this->fuckhtml
  376. ->getElementsByClassName(
  377. "btn_next",
  378. "a"
  379. );
  380. if(count($npt) !== 0){
  381. $out["npt"] =
  382. $this->backend->store(
  383. $this->fuckhtml
  384. ->getTextContent(
  385. $npt[0]["attributes"]["href"]
  386. ),
  387. "web",
  388. $proxy
  389. );
  390. }
  391. return $out;
  392. }
  393. public function image($get){
  394. $search = $get["s"];
  395. if(strlen($search) === 0){
  396. throw new Exception("Search term is empty!");
  397. }
  398. $out = [
  399. "status" => "ok",
  400. "npt" => null,
  401. "image" => []
  402. ];
  403. if($get["npt"]){
  404. [$url, $proxy] = $this->backend->get($get["npt"], "images");
  405. try{
  406. $json =
  407. $this->get(
  408. $proxy,
  409. $url,
  410. [],
  411. true
  412. );
  413. }catch(Exception $error){
  414. throw new Exception("Failed to fetch search page");
  415. }
  416. }else{
  417. $filters = [
  418. "ac" => "0",
  419. "api_type" => "pc_tab_more",
  420. "aq" => "0",
  421. "display" => 100,
  422. "logStart" => 1,
  423. "mode" => "column",
  424. "nso" => "so:r,p:all",
  425. "nx_search_query" => $search,
  426. "query" => $search,
  427. "section" => "image",
  428. "sm" => "tab_opt",
  429. "ssc" => "tab.image.all",
  430. "start" => 1,
  431. "where" => "image"
  432. // no callback, returns raw json lol
  433. ];
  434. $options = [
  435. "so:r"
  436. ];
  437. if($get["time"] != "any"){
  438. $options[] = "p:" . $get["time"];
  439. }
  440. if(count($options) !== 0){
  441. $filters["nso"] = implode(",", $options);
  442. }
  443. if($get["size"] != "any"){
  444. $filters["res_fr"] = 786432;
  445. $filters["res_to"] = 100000000;
  446. }
  447. if($get["color"] != "any"){
  448. $filters["color"] = $get["color"];
  449. }
  450. if($get["license"] != "any"){
  451. $filters["ccl"] = $get["license"];
  452. }
  453. //$json = file_get_contents("scraper/naver.html");
  454. $proxy = $this->backend->get_ip();
  455. try{
  456. $json =
  457. $this->get(
  458. $proxy,
  459. "https://s.search.naver.com/p/c/image/46/search.naver",
  460. $filters,
  461. true
  462. );
  463. }catch(Exception $error){
  464. throw new Exception("Failed to fetch search page");
  465. }
  466. }
  467. $json = json_decode($json, true);
  468. if($json === null){
  469. throw new Exception("Failed to decode JSON");
  470. }
  471. if(!isset($json["items"])){
  472. // no results returned :(
  473. return $out;
  474. //throw new Exception("Naver did not return an items object");
  475. }
  476. foreach($json["items"] as $image){
  477. $out["image"][] = [
  478. "title" => trim($image["title"], "."),
  479. "source" => [
  480. [
  481. "url" => $image["originalUrl"],
  482. "width" => (int)$image["orgWidth"],
  483. "height" => (int)$image["orgHeight"]
  484. ],
  485. [
  486. "url" => $image["thumb"],
  487. "width" => (int)$image["thumbWidth"],
  488. "height" => (int)$image["thumbHeight"]
  489. ]
  490. ],
  491. "url" => $image["link"]
  492. ];
  493. }
  494. // get npt
  495. if(
  496. isset($json["url"]) &&
  497. $json["url"] != "" &&
  498. $json["url"] != null
  499. ){
  500. $out["npt"] =
  501. $this->backend->store(
  502. $json["url"],
  503. "images",
  504. $proxy
  505. );
  506. }
  507. return $out;
  508. }
  509. public function video($get){
  510. $search = $get["s"];
  511. if(strlen($search) === 0){
  512. throw new Exception("Search term is empty!");
  513. }
  514. $out = [
  515. "status" => "ok",
  516. "npt" => null,
  517. "video" => [],
  518. "author" => [],
  519. "livestream" => [],
  520. "playlist" => [],
  521. "reel" => []
  522. ];
  523. if($get["npt"]){
  524. [$url, $proxy] = $this->backend->get($get["npt"], "images");
  525. try{
  526. $json =
  527. $this->get(
  528. $proxy,
  529. $url,
  530. [],
  531. true
  532. );
  533. }catch(Exception $error){
  534. throw new Exception("Failed to fetch search page");
  535. }
  536. }else{
  537. // 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
  538. // https://s.search.naver.com/p/video/48/search.naver
  539. // ?ac=0
  540. // &aq=0
  541. // &crbase=63
  542. // &display=48
  543. // &dtype=
  544. // &last_block_type=recom
  545. // &nlu_query=
  546. // &nq=
  547. // &nqx_theme={"theme":{"main":{"name":"encyclopedia","source":"TOS"}}}
  548. // &nx_and_query=
  549. // &nx_search_hlquery=
  550. // &nx_search_query=
  551. // &nx_sub_query=
  552. // &page=2
  553. // &period=
  554. // &playtime=
  555. // &ptype=
  556. // &query=asmr
  557. // &selected_channel=
  558. // &selected_cp=
  559. // &sm=mtb_pge
  560. // &sort=rel
  561. // &ssc=tab.video.all
  562. // &start=49
  563. // &video_more=1
  564. $filters = [
  565. "ac" => "0",
  566. "aq" => "0",
  567. "crbase" => "78",
  568. "display" => 48,
  569. "dtype" => "",
  570. "last_block_type" => "recom",
  571. "nlu_query" => "",
  572. "nq" => "",
  573. "nx_and_query" => "",
  574. "nx_search_hlquery" => "",
  575. "nx_search_query" => "",
  576. "nx_sub_query" => "",
  577. "page" => 1,
  578. "period" => "",
  579. "playtime" => "",
  580. "ptype" => "",
  581. "query" => $search,
  582. "selected_channel" => "",
  583. "selected_cp" => "",
  584. "sm" => "mtb_pge",
  585. "sort" => "rel",
  586. "ssc" => "tab.video.all",
  587. "start" => 1,
  588. "video_more" => 1
  589. ];
  590. if($get["type"] != "any"){
  591. $filters["dtype"] = $get["type"];
  592. }
  593. if($get["time"] != "any"){
  594. $filters["period"] = $get["time"];
  595. }
  596. if($get["sort"] != "rel"){
  597. $filters["sort"] = $get["sort"];
  598. }
  599. if($get["duration"] != "any"){
  600. $filters["playtime"] = $get["duration"];
  601. }
  602. //$json = file_get_contents("scraper/naver.html");
  603. $proxy = $this->backend->get_ip();
  604. try{
  605. $json =
  606. $this->get(
  607. $proxy,
  608. "https://s.search.naver.com/p/video/48/search.naver",
  609. $filters,
  610. true
  611. );
  612. }catch(Exception $error){
  613. throw new Exception("Failed to fetch search page");
  614. }
  615. }
  616. $json = json_decode($json, true);
  617. if($json === null){
  618. throw new Exception("Failed to decode JSON");
  619. }
  620. if(!isset($json["collection"])){
  621. return $out;
  622. //throw new Exception("Naver did not return a collection HTML element");
  623. }
  624. foreach($json["collection"] as $snippet){
  625. if(!isset($snippet["html"])){ continue; }
  626. $this->fuckhtml->load($snippet["html"]);
  627. $div =
  628. $this->fuckhtml
  629. ->getElementsByTagName(
  630. "div"
  631. );
  632. $items =
  633. $this->fuckhtml
  634. ->getElementsByAttributeValue(
  635. "data-template-id",
  636. "videoItem",
  637. $div
  638. );
  639. // parse normal videos
  640. foreach($items as $item){
  641. if($item["level"] === 6){ continue; }
  642. $this->fuckhtml->load($item);
  643. // get url
  644. $as =
  645. $this->fuckhtml
  646. ->getElementsByAttributeName(
  647. "data-heatmap-target",
  648. "a"
  649. );
  650. if(count($as) === 0){
  651. // should not happen
  652. continue;
  653. }
  654. // get thumbnail
  655. $thumb =
  656. $this->fuckhtml
  657. ->getElementsByAttributeValue(
  658. "loading",
  659. "lazy",
  660. "img"
  661. );
  662. if(count($thumb) !== 0){
  663. $thumb = [
  664. "url" =>
  665. $this->unshit_thumb(
  666. $this->fuckhtml
  667. ->getTextContent(
  668. $thumb[0]["attributes"]["src"]
  669. )
  670. ),
  671. "ratio" => "16:9"
  672. ];
  673. }else{
  674. $thumb = [
  675. "url" => null,
  676. "ratio" => null
  677. ];
  678. }
  679. // get timestamp
  680. $timestamp_probe =
  681. $this->fuckhtml
  682. ->getElementsByClassName(
  683. "sds-comps-text-type-footnote",
  684. "span"
  685. );
  686. if(count($timestamp_probe) !== 0){
  687. $timestamp =
  688. $this->hms2int(
  689. $this->fuckhtml
  690. ->getTextContent(
  691. $timestamp_probe[0]
  692. )
  693. );
  694. }else{
  695. $timestamp = null;
  696. }
  697. $out["video"][] = [
  698. "title" =>
  699. $this->fuckhtml
  700. ->getTextContent(
  701. $as[0]
  702. ),
  703. "description" => null,
  704. "author" => [
  705. "name" =>
  706. isset($item["attributes"]["profileimagealt"]) ?
  707. $this->fuckhtml
  708. ->getTextContent(
  709. $item["attributes"]["profileimagealt"]
  710. ) : null,
  711. "url" =>
  712. isset($item["attributes"]["profileimagehref"]) ?
  713. $this->fuckhtml
  714. ->getTextContent(
  715. $item["attributes"]["profileimagehref"]
  716. ) : null,
  717. "avatar" =>
  718. isset($item["attributes"]["profileimagesrc"]) ?
  719. $this->fuckhtml
  720. ->getTextContent(
  721. $item["attributes"]["profileimagesrc"]
  722. ) : null
  723. ],
  724. "date" => null,
  725. "duration" => $timestamp,
  726. "views" => null,
  727. "thumb" => $thumb,
  728. "url" =>
  729. $this->fuckhtml
  730. ->getTextContent(
  731. $as[0]["attributes"]["href"]
  732. )
  733. ];
  734. }
  735. // reset
  736. $this->fuckhtml->load($snippet["html"]);
  737. // parse reels
  738. $carousels =
  739. array_merge(
  740. $this->fuckhtml // for the reels only tab
  741. ->getElementsByClassName(
  742. "fds-video-tab-shortform-desk-filter",
  743. $div
  744. ),
  745. $this->fuckhtml // for the normal tab with reels inbetween
  746. ->getElementsByClassName(
  747. "fds-video-tab-shortform-desk",
  748. $div
  749. )
  750. );
  751. foreach($carousels as $carousel){
  752. $this->fuckhtml->load($carousel);
  753. $as =
  754. $this->fuckhtml
  755. ->getElementsByTagName(
  756. "a"
  757. );
  758. foreach($as as $reel){
  759. $this->fuckhtml->load($reel);
  760. $spans =
  761. $this->fuckhtml
  762. ->getElementsByTagName(
  763. "span"
  764. );
  765. $title =
  766. $this->fuckhtml
  767. ->getTextContent(
  768. $spans[0]
  769. );
  770. // get thumbnail
  771. $thumb =
  772. $this->fuckhtml
  773. ->getElementsByAttributeValue(
  774. "loading",
  775. "lazy",
  776. "img"
  777. );
  778. if(count($thumb) !== 0){
  779. $thumb = [
  780. "url" =>
  781. $this->unshit_thumb(
  782. $this->fuckhtml
  783. ->getTextContent(
  784. $thumb[0]["attributes"]["src"]
  785. )
  786. ),
  787. "ratio" => "16:9"
  788. ];
  789. }else{
  790. $thumb = [
  791. "url" => null,
  792. "ratio" => null
  793. ];
  794. }
  795. $name =
  796. $this->fuckhtml
  797. ->getElementsByClassName(
  798. "sds-comps-profile-info-title-text",
  799. $spans
  800. );
  801. if(count($name) === 0){
  802. $name = null;
  803. }else{
  804. $name =
  805. $this->fuckhtml
  806. ->getTextContent(
  807. $name[0]
  808. );
  809. }
  810. $out["reel"][] = [
  811. "title" => $title,
  812. "description" => null,
  813. "author" => [
  814. "name" => $name,
  815. "url" => null,
  816. "avatar" => null
  817. ],
  818. "date" => null,
  819. "duration" => null,
  820. "views" => null,
  821. "thumb" => $thumb,
  822. "url" =>
  823. $this->fuckhtml
  824. ->getTextContent(
  825. $reel["attributes"]["href"]
  826. )
  827. ];
  828. }
  829. }
  830. }
  831. // get npt
  832. if(
  833. isset($json["url"]) &&
  834. $json["url"] != "" &&
  835. $json["url"] != null
  836. ){
  837. $out["npt"] =
  838. $this->backend->store(
  839. $json["url"],
  840. "images",
  841. $proxy
  842. );
  843. }
  844. return $out;
  845. }
  846. private function unshit_thumb($url){
  847. $parts = parse_url($url);
  848. if($parts["host"] == "search.pstatic.net"){
  849. parse_str($parts["query"], $str);
  850. if(isset($str["src"])){
  851. return $str["src"];
  852. }
  853. }
  854. return $url;
  855. }
  856. private function decode_html($html){
  857. return
  858. trim(
  859. html_entity_decode(
  860. strip_tags(
  861. $html
  862. )
  863. ),
  864. "."
  865. );
  866. }
  867. private function hms2int($time){
  868. $parts = explode(":", $time, 3);
  869. $time = 0;
  870. if(count($parts) === 3){
  871. // hours
  872. $time = $time + ((int)$parts[0] * 3600);
  873. array_shift($parts);
  874. }
  875. if(count($parts) === 2){
  876. // minutes
  877. $time = $time + ((int)$parts[0] * 60);
  878. array_shift($parts);
  879. }
  880. // seconds
  881. $time = $time + (int)$parts[0];
  882. return $time;
  883. }
  884. }