flickr.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. }
  198. $get_params = [
  199. "text" => $get["s"],
  200. "per_page" => 50,
  201. // scrape highest resolution
  202. "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",
  203. "view_all" => 1
  204. ];
  205. $get_params = array_merge($get_params, $filters);
  206. $html =
  207. $this->get(
  208. $proxy,
  209. "https://www.flickr.com/search/",
  210. $get_params,
  211. flickr::req_web
  212. );
  213. // @TODO
  214. // get api_key and reqId, if flickr deprecates &page
  215. $this->fuckhtml->load($html);
  216. //
  217. // get response JSON
  218. //
  219. $scripts =
  220. $this->fuckhtml
  221. ->getElementsByClassName(
  222. "modelExport",
  223. "script"
  224. );
  225. $found = false;
  226. foreach($scripts as $script){
  227. $json =
  228. preg_split(
  229. '/modelExport: ?/',
  230. $script["innerHTML"],
  231. 2
  232. );
  233. if(count($json) !== 0){
  234. $found = true;
  235. $json = $json[1];
  236. break;
  237. }
  238. }
  239. if($found === false){
  240. throw new Exception("Failed to grep JSON");
  241. }
  242. $json =
  243. json_decode(
  244. $this->fuckhtml
  245. ->extract_json(
  246. $json
  247. ),
  248. true
  249. );
  250. if($json === null){
  251. throw new Exception("Failed to decode JSON");
  252. }
  253. $out = [
  254. "status" => "ok",
  255. "npt" => null,
  256. "image" => []
  257. ];
  258. if(!isset($json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["_data"])){
  259. throw new Exception("Failed to access data object");
  260. }
  261. foreach($json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["_data"] as $image){
  262. if(!isset($image["data"])){
  263. // flickr likes to gives us empty array objects
  264. continue;
  265. }
  266. $image = $image["data"];
  267. $title = [];
  268. if(isset($image["title"])){
  269. $title[] =
  270. $this->fuckhtml
  271. ->getTextContent(
  272. $image["title"]
  273. );
  274. }
  275. if(isset($image["description"])){
  276. $title[] =
  277. $this->fuckhtml
  278. ->getTextContent(
  279. str_replace(
  280. "\n",
  281. " ",
  282. $image["description"]
  283. )
  284. );
  285. }
  286. $title = implode(": ", $title);
  287. $sources = array_values($image["sizes"]["data"]);
  288. $suitable_sizes = ["n", "m", "w", "s"];
  289. $thumb = &$sources[0]["data"];
  290. foreach($suitable_sizes as $testing_size){
  291. if(isset($image["sizes"]["data"][$testing_size])){
  292. $thumb = &$image["sizes"]["data"][$testing_size]["data"];
  293. break;
  294. }
  295. }
  296. $og = &$sources[count($sources) - 1]["data"];
  297. $out["image"][] = [
  298. "title" => $title,
  299. "source" => [
  300. [
  301. "url" => "https:" . $og["displayUrl"],
  302. "width" => (int)$og["width"],
  303. "height" => (int)$og["height"]
  304. ],
  305. [
  306. "url" => "https:" . $thumb["displayUrl"],
  307. "width" => (int)$thumb["width"],
  308. "height" => (int)$thumb["height"]
  309. ]
  310. ],
  311. "url" => "https://www.flickr.com/photos/" . $image["ownerNsid"] . "/" . $image["id"] . "/"
  312. ];
  313. }
  314. $total_items = (int)$json["main"]["search-photos-lite-models"][0]["data"]["photos"]["data"]["totalItems"];
  315. if(($filters["page"]) * 50 < $total_items){
  316. $filters["page"]++;
  317. $out["npt"] =
  318. $this->backend->store(
  319. json_encode($filters),
  320. "images",
  321. $proxy
  322. );
  323. }
  324. return $out;
  325. }
  326. }