1
0

flickr.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <?php
  2. class flickr{
  3. const req_web = 0;
  4. const req_xhr = 1;
  5. public function __construct(){
  6. include "lib/backend.php";
  7. $this->backend = new backend("flickr");
  8. include "lib/fuckhtml.php";
  9. $this->fuckhtml = new fuckhtml();
  10. }
  11. public function getfilters($page){
  12. return [
  13. "nsfw" => [
  14. "display" => "NSFW",
  15. "option" => [
  16. "yes" => "Yes",
  17. "maybe" => "Maybe",
  18. "no" => "No",
  19. ]
  20. ],
  21. "sort" => [
  22. "display" => "Sort by",
  23. "option" => [
  24. "relevance" => "Relevance",
  25. "date-posted-desc" => "Newest uploads",
  26. "date-posted-asc" => "Oldest uploads",
  27. "date-taken-desc" => "Newest taken",
  28. "date-taken-asc" => "Oldest taken",
  29. "interestingness-desc" => "Interesting"
  30. ]
  31. ],
  32. "color" => [
  33. "display" => "Color",
  34. "option" => [
  35. "any" => "Any color",
  36. // color_codes=
  37. "0" => "Red",
  38. "1" => "Brown",
  39. "2" => "Orange",
  40. "b" => "Pink",
  41. "4" => "Yellow",
  42. "3" => "Golden",
  43. "5" => "Lime",
  44. "6" => "Green",
  45. "7" => "Sky blue",
  46. "8" => "Blue",
  47. "9" => "Purple",
  48. "a" => "Hot pink",
  49. "c" => "White",
  50. "d" => "Gray",
  51. "e" => "Black",
  52. // styles= override
  53. "blackandwhite" => "Black & white",
  54. ]
  55. ],
  56. "style" => [ // styles=
  57. "display" => "Style",
  58. "option" => [
  59. "any" => "Any style",
  60. "depthoffield" => "Depth of field",
  61. "minimalism" => "Minimalism",
  62. "pattern" => "Patterns"
  63. ]
  64. ],
  65. "license" => [
  66. "display" => "License",
  67. "option" => [
  68. "any" => "Any license",
  69. "1,2,3,4,5,6,9,11,12,13,14,15,16" => "All creative commons",
  70. "4,5,6,9,10,11,12,13" => "Commercial use allowed",
  71. "1,2,4,5,9,10,11,12,14,15" => "Modifications allowed",
  72. "4,5,9,10,11,12" => "Commercial use & mods allowed",
  73. "7,9,10" => "No known copyright restrictions",
  74. "8" => "U.S Government works"
  75. ]
  76. ]
  77. ];
  78. }
  79. private function get($proxy, $url, $get = [], $reqtype){
  80. $curlproc = curl_init();
  81. if($get !== []){
  82. $get = http_build_query($get);
  83. $url .= "?" . $get;
  84. }
  85. curl_setopt($curlproc, CURLOPT_URL, $url);
  86. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  87. if($reqtype === flickr::req_web){
  88. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  89. ["User-Agent: " . config::USER_AGENT,
  90. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
  91. "Accept-Language: en-US,en;q=0.5",
  92. "Accept-Encoding: gzip",
  93. "DNT: 1",
  94. "Sec-GPC: 1",
  95. "Connection: keep-alive",
  96. "Upgrade-Insecure-Requests: 1",
  97. "Sec-Fetch-Dest: document",
  98. "Sec-Fetch-Mode: navigate",
  99. "Sec-Fetch-Site: same-origin",
  100. "Sec-Fetch-User: ?1",
  101. "Priority: u=0, i",
  102. "TE: trailers"]
  103. );
  104. }else{
  105. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  106. ["User-Agent: " . config::USER_AGENT,
  107. "Accept: */*",
  108. "Accept-Language: en-US,en;q=0.5",
  109. "Accept-Encoding: gzip",
  110. "Origin: https://www.flickr.com",
  111. "DNT: 1",
  112. "Sec-GPC: 1",
  113. "Connection: keep-alive",
  114. "Referer: https://www.flickr.com/",
  115. // Cookie:
  116. "Sec-Fetch-Dest: empty",
  117. "Sec-Fetch-Mode: cors",
  118. "Sec-Fetch-Site: same-site",
  119. "TE: trailers"]
  120. );
  121. }
  122. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  123. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  124. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  125. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  126. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  127. // http2 bypass
  128. curl_setopt($curlproc, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  129. $this->backend->assign_proxy($curlproc, $proxy);
  130. $data = curl_exec($curlproc);
  131. if(curl_errno($curlproc)){
  132. throw new Exception(curl_error($curlproc));
  133. }
  134. curl_close($curlproc);
  135. return $data;
  136. }
  137. public function image($get){
  138. if($get["npt"]){
  139. [$filters, $proxy] =
  140. $this->backend->get(
  141. $get["npt"], "images"
  142. );
  143. $filters = json_decode($filters, true);
  144. // Workaround for the future, if flickr deprecates &page argument on html page
  145. /*
  146. try{
  147. $json =
  148. $this->get(
  149. $proxy,
  150. "https://api.flickr.com/services/rest",
  151. [
  152. "sort" => $data["sort"],
  153. "parse_tags" => 1,
  154. // url_s,url_n,url_w,url_m,url_z,url_c,url_l,url_h,url_k,url_3k,url_4k,url_5k,url_6k,url_o
  155. "extras" => "can_comment,can_print,count_comments,count_faves,description,isfavorite,license,media,needs_interstitial,owner_name,path_alias,realname,rotation,url_sq,url_q,url_t,url_s,url_n,url_w,url_m,url_z,url_c,url_l",
  156. "per_page" => 100,
  157. "page" => $data["page"],
  158. "lang" => "en-US",
  159. "text" => $data["search"],
  160. "viewerNSID" => "",
  161. "method" => "flickr.photos.search",
  162. "csrf" => "",
  163. "api_key" => $data["api_key"],
  164. "format" => "json",
  165. "hermes" => 1,
  166. "hermesClient" => 1,
  167. "reqId" => $data["reqId"],
  168. "nojsoncallback" => 1
  169. ]
  170. );
  171. }catch(Exception $error){
  172. throw new Exception("Failed to fetch JSON");
  173. }*/
  174. }else{
  175. if(strlen($get["s"]) === 0){
  176. throw new Exception("Search term is empty!");
  177. }
  178. $proxy = $this->backend->get_ip();
  179. // compute filters
  180. $filters = [
  181. "page" => 1,
  182. "sort" => $get["sort"]
  183. ];
  184. if($get["style"] != "any"){
  185. $filters["styles"] = $get["style"];
  186. }
  187. if($get["color"] != "any"){
  188. if($get["color"] != "blackandwhite"){
  189. $filters["color_codes"] = $get["color"];
  190. }else{
  191. $filters["styles"] = "blackandwhite";
  192. }
  193. }
  194. if($get["license"] != "any"){
  195. $filters["license"] = $get["license"];
  196. }
  197. switch($get["nsfw"]){
  198. case "yes": $filters["safe_search"] = 0; break;
  199. case "maybe": $filters["safe_search"] = 2; break;
  200. case "no": $filters["safe_search"] = 1; break;
  201. }
  202. }
  203. $get_params = [
  204. "text" => $get["s"],
  205. "per_page" => 50,
  206. // scrape highest resolution
  207. "extras" => "url_s,url_n,url_w,url_m,url_z,url_c,url_l,url_h,url_k,url_3k,url_4k,url_5k,url_6k,url_o",
  208. "view_all" => 1
  209. ];
  210. $get_params = array_merge($get_params, $filters);
  211. $html =
  212. $this->get(
  213. $proxy,
  214. "https://www.flickr.com/search/",
  215. $get_params,
  216. flickr::req_web
  217. );
  218. // @TODO
  219. // get api_key and reqId, if flickr deprecates &page
  220. $this->fuckhtml->load($html);
  221. //
  222. // get response JSON
  223. //
  224. $scripts =
  225. $this->fuckhtml
  226. ->getElementsByClassName(
  227. "modelExport",
  228. "script"
  229. );
  230. $found = false;
  231. foreach($scripts as $script){
  232. $json =
  233. preg_split(
  234. '/modelExport: ?/',
  235. $script["innerHTML"],
  236. 2
  237. );
  238. if(count($json) !== 0){
  239. $found = true;
  240. $json = $json[1];
  241. break;
  242. }
  243. }
  244. if($found === false){
  245. throw new Exception("Failed to grep JSON");
  246. }
  247. $json =
  248. json_decode(
  249. $this->fuckhtml
  250. ->extract_json(
  251. $json
  252. ),
  253. true
  254. );
  255. if($json === null){
  256. throw new Exception("Failed to decode JSON");
  257. }
  258. $out = [
  259. "status" => "ok",
  260. "npt" => null,
  261. "image" => []
  262. ];
  263. if(!isset($json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["_data"])){
  264. throw new Exception("Failed to access data object");
  265. }
  266. foreach($json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["_data"] as $image){
  267. if(!isset($image["data"])){
  268. // flickr likes to gives us empty array objects
  269. continue;
  270. }
  271. $image = $image["data"];
  272. $title = [];
  273. if(isset($image["title"])){
  274. $title[] =
  275. $this->fuckhtml
  276. ->getTextContent(
  277. $image["title"]
  278. );
  279. }
  280. if(isset($image["description"])){
  281. $title[] =
  282. $this->fuckhtml
  283. ->getTextContent(
  284. str_replace(
  285. "\n",
  286. " ",
  287. $image["description"]
  288. )
  289. );
  290. }
  291. $title = implode(": ", $title);
  292. $sources = array_values($image["sizes"]["data"]);
  293. $suitable_sizes = ["n", "m", "w", "s"];
  294. $thumb = &$sources[0]["data"];
  295. foreach($suitable_sizes as $testing_size){
  296. if(isset($image["sizes"]["data"][$testing_size])){
  297. $thumb = &$image["sizes"]["data"][$testing_size]["data"];
  298. break;
  299. }
  300. }
  301. $og = &$sources[count($sources) - 1]["data"];
  302. $out["image"][] = [
  303. "title" => $title,
  304. "source" => [
  305. [
  306. "url" => "https:" . $og["displayUrl"],
  307. "width" => (int)$og["width"],
  308. "height" => (int)$og["height"]
  309. ],
  310. [
  311. "url" => "https:" . $thumb["displayUrl"],
  312. "width" => (int)$thumb["width"],
  313. "height" => (int)$thumb["height"]
  314. ]
  315. ],
  316. "url" => "https://www.flickr.com/photos/" . $image["ownerNsid"] . "/" . $image["id"] . "/"
  317. ];
  318. }
  319. $total_items = (int)$json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["totalItems"];
  320. if(($filters["page"]) * 50 < $total_items){
  321. $filters["page"]++;
  322. $out["npt"] =
  323. $this->backend->store(
  324. json_encode($filters),
  325. "images",
  326. $proxy
  327. );
  328. }
  329. return $out;
  330. }
  331. }