1
0

vsco.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. class vsco{
  3. public function __construct(){
  4. include "lib/backend.php";
  5. $this->backend = new backend("vsco");
  6. }
  7. public function getfilters($page){
  8. return [];
  9. }
  10. private function get($proxy, $url, $get = [], $bearer = null){
  11. $curlproc = curl_init();
  12. if($get !== []){
  13. $get_tmp = http_build_query($get);
  14. $url .= "?" . $get_tmp;
  15. }
  16. curl_setopt($curlproc, CURLOPT_URL, $url);
  17. curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
  18. if($bearer === null){
  19. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  20. ["User-Agent: " . config::USER_AGENT,
  21. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
  22. "Accept-Language: en-US,en;q=0.5",
  23. "Accept-Encoding: gzip",
  24. "DNT: 1",
  25. "Sec-GPC: 1",
  26. "Connection: keep-alive",
  27. "Upgrade-Insecure-Requests: 1",
  28. "Sec-Fetch-Dest: document",
  29. "Sec-Fetch-Mode: navigate",
  30. "Sec-Fetch-Site: same-origin",
  31. "Sec-Fetch-User: ?1",
  32. "Priority: u=0, i",
  33. "TE: trailers"]
  34. );
  35. }else{
  36. curl_setopt($curlproc, CURLOPT_HTTPHEADER,
  37. ["User-Agent: " . config::USER_AGENT,
  38. "Accept: */*",
  39. "Accept-Language: en-US",
  40. "Accept-Encoding: gzip",
  41. "Referer: https://vsco.co/search/images/" . urlencode($get["query"]),
  42. "authorization: Bearer " . $bearer,
  43. "content-type: application/json",
  44. "x-client-build: 1",
  45. "x-client-platform: web",
  46. "DNT: 1",
  47. "Sec-GPC: 1",
  48. "Connection: keep-alive",
  49. "Sec-Fetch-Dest: empty",
  50. "Sec-Fetch-Mode: cors",
  51. "Sec-Fetch-Site: same-origin",
  52. "Priority: u=0",
  53. "TE: trailers"]
  54. );
  55. }
  56. curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
  57. curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
  58. curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
  59. curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
  60. curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
  61. // http2 bypass
  62. curl_setopt($curlproc, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
  63. $this->backend->assign_proxy($curlproc, $proxy);
  64. $data = curl_exec($curlproc);
  65. if(curl_errno($curlproc)){
  66. throw new Exception(curl_error($curlproc));
  67. }
  68. curl_close($curlproc);
  69. return $data;
  70. }
  71. public function image($get){
  72. if($get["npt"]){
  73. [$data, $proxy] =
  74. $this->backend->get(
  75. $get["npt"], "images"
  76. );
  77. $data = json_decode($data, true);
  78. }else{
  79. $search = $get["s"];
  80. if(strlen($search) === 0){
  81. throw new Exception("Search term is empty!");
  82. }
  83. $proxy = $this->backend->get_ip();
  84. // get bearer token
  85. try{
  86. $html =
  87. $this->get(
  88. $proxy,
  89. "https://vsco.co/feed"
  90. );
  91. }catch(Exception $error){
  92. throw new Exception("Failed to fetch feed page");
  93. }
  94. preg_match(
  95. '/"tkn":"([A-z0-9]+)"/',
  96. $html,
  97. $bearer
  98. );
  99. if(!isset($bearer[1])){
  100. throw new Exception("Failed to grep bearer token");
  101. }
  102. $data = [
  103. "pagination" => [
  104. "query" => $search,
  105. "page" => 0,
  106. "size" => 100
  107. ],
  108. "bearer" => $bearer[1]
  109. ];
  110. }
  111. try{
  112. $json =
  113. $this->get(
  114. $proxy,
  115. "https://vsco.co/api/2.0/search/images",
  116. $data["pagination"],
  117. $data["bearer"]
  118. );
  119. }catch(Exception $error){
  120. throw new Exception("Failed to fetch JSON");
  121. }
  122. $json = json_decode($json, true);
  123. if($json === null){
  124. throw new Exception("Failed to decode JSON");
  125. }
  126. $out = [
  127. "status" => "ok",
  128. "npt" => null,
  129. "image" => []
  130. ];
  131. if(!isset($json["results"])){
  132. throw new Exception("Failed to access results object");
  133. }
  134. foreach($json["results"] as $image){
  135. $image_domain = parse_url("https://" . $image["responsive_url"], PHP_URL_HOST);
  136. $thumbnail = explode($image_domain, $image["responsive_url"], 2)[1];
  137. if(substr($thumbnail, 0, 3) != "/1/"){
  138. $thumbnail =
  139. preg_replace(
  140. '/^\/[^\/]+/',
  141. "",
  142. $thumbnail
  143. );
  144. }
  145. $thumbnail = "https://img.vsco.co/cdn-cgi/image/width=480,height=360" . $thumbnail;
  146. $size =
  147. $this->image_ratio(
  148. (int)$image["dimensions"]["width"],
  149. (int)$image["dimensions"]["height"]
  150. );
  151. $out["image"][] = [
  152. "title" => $image["description"],
  153. "source" => [
  154. [
  155. "url" => "https://" . $image["responsive_url"],
  156. "width" => (int)$image["dimensions"]["width"],
  157. "height" => (int)$image["dimensions"]["height"]
  158. ],
  159. [
  160. "url" => $thumbnail,
  161. "width" => $size[0],
  162. "height" => $size[1]
  163. ]
  164. ],
  165. "url" => "https://" . $image["grid"]["domain"] . "/media/" . $image["imageId"]
  166. ];
  167. }
  168. // get NPT
  169. $max_page = ceil($json["total"] / 100);
  170. $data["pagination"]["page"]++;
  171. if($max_page > $data["pagination"]["page"]){
  172. $out["npt"] =
  173. $this->backend->store(
  174. json_encode($data),
  175. "images",
  176. $proxy
  177. );
  178. }
  179. return $out;
  180. }
  181. private function image_ratio($width, $height){
  182. $ratio = [
  183. 480 / $width,
  184. 360 / $height
  185. ];
  186. if($ratio[0] < $ratio[1]){
  187. $ratio = $ratio[0];
  188. }else{
  189. $ratio = $ratio[1];
  190. }
  191. return [
  192. floor($width * $ratio),
  193. floor($height * $ratio)
  194. ];
  195. }
  196. }