Spaces:
Sleeping
Sleeping
| import requests | |
| import re | |
| import random | |
| import json | |
| from fastapi import FastAPI, Query | |
| from fastapi.middleware.cors import CORSMiddleware | |
| app = FastAPI( | |
| title="ImageHub API", | |
| description="Search high-quality images from multiple sources.", | |
| version="3.2.0" | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ------------------------------------------------------------------ | |
| # BING IMAGES SCRAPER | |
| # ------------------------------------------------------------------ | |
| def scrape_bing(query: str, page: int = 1, per_page: int = 30): | |
| offset = (page - 1) * per_page + 1 | |
| url = f"https://www.bing.com/images/search?q={requests.utils.quote(query)}&first={offset}" | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" | |
| } | |
| try: | |
| resp = requests.get(url, headers=headers, timeout=10) | |
| if resp.status_code != 200: | |
| return [] | |
| html = resp.text | |
| pattern = r'm="\{([^"]*)\}"' | |
| matches = re.findall(pattern, html) | |
| images = [] | |
| for match in matches: | |
| json_str = '{"' + match.replace('"', '"') + '"}' | |
| try: | |
| data = json.loads(json_str) | |
| except: | |
| data = {} | |
| murl = re.search(r'murl":"([^"]+)"', json_str) | |
| if murl: | |
| data['murl'] = murl.group(1) | |
| turl = re.search(r'turl":"([^"]+)"', json_str) | |
| if turl: | |
| data['turl'] = turl.group(1) | |
| title = re.search(r't":"([^"]+)"', json_str) | |
| if title: | |
| data['t'] = title.group(1) | |
| w = re.search(r'w":"(\d+)"', json_str) | |
| if w: | |
| data['w'] = w.group(1) | |
| h = re.search(r'h":"(\d+)"', json_str) | |
| if h: | |
| data['h'] = h.group(1) | |
| img_id = re.search(r'id":"([^"]+)"', json_str) | |
| if img_id: | |
| data['id'] = img_id.group(1) | |
| if data.get('murl'): | |
| images.append({ | |
| "id": data.get('id', f"img_{len(images)}"), | |
| "url": data['murl'], | |
| "thumbnail": data.get('turl', data['murl']), | |
| "width": int(data.get('w', 0)), | |
| "height": int(data.get('h', 0)), | |
| "tags": data.get('t', query)[:200], | |
| "likes": 0 | |
| }) | |
| if len(images) >= per_page: | |
| break | |
| return images[:per_page] | |
| except Exception as e: | |
| print(f"Bing error: {e}") | |
| return [] | |
| # ------------------------------------------------------------------ | |
| # PINTEREST API 1 (Working - from bj-devs) | |
| # ------------------------------------------------------------------ | |
| def fetch_pinterest_api_1(query: str, per_page: int = 30): | |
| """Primary Pinterest API - https://pinterest-search.apis-bj-devs.workers.dev/""" | |
| url = f"https://pinterest-search.apis-bj-devs.workers.dev/?search={requests.utils.quote(query)}&limit={per_page}" | |
| try: | |
| resp = requests.get(url, timeout=10) | |
| if resp.status_code != 200: | |
| return [] | |
| data = resp.json() | |
| if not data.get("status"): | |
| return [] | |
| pins = data.get("result", {}).get("pins", []) | |
| images = [] | |
| for pin in pins: | |
| media = pin.get("media", {}) | |
| images_data = media.get("images", {}) | |
| img_url = images_data.get("orig") or images_data.get("large") or images_data.get("medium") or "" | |
| if img_url: | |
| images.append({ | |
| "id": pin.get("id", f"img_{len(images)}"), | |
| "url": img_url, | |
| "thumbnail": images_data.get("small", img_url), | |
| "width": 0, | |
| "height": 0, | |
| "tags": pin.get("title", query)[:200], | |
| "likes": 0 | |
| }) | |
| return images | |
| except Exception as e: | |
| print(f"Pinterest API 1 error: {e}") | |
| return [] | |
| # ------------------------------------------------------------------ | |
| # PINTEREST API 2 (Backup/Alternative) | |
| # ------------------------------------------------------------------ | |
| def fetch_pinterest_api_2(query: str, per_page: int = 30): | |
| """Secondary Pinterest scraper as backup""" | |
| url = f"https://www.pinterest.com/resource/BaseSearchResource/get/" | |
| params = { | |
| "source_url": f"/search/pins/?q={requests.utils.quote(query)}", | |
| "data": json.dumps({ | |
| "options": { | |
| "query": query, | |
| "page_size": per_page, | |
| "scope": "pins", | |
| "field_set_key": "unauth_react" | |
| } | |
| }) | |
| } | |
| headers = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", | |
| "Accept": "application/json" | |
| } | |
| try: | |
| resp = requests.get(url, params=params, headers=headers, timeout=10) | |
| if resp.status_code != 200: | |
| return [] | |
| data = resp.json() | |
| results = data.get("resource_response", {}).get("data", {}).get("results", []) | |
| images = [] | |
| for i, pin in enumerate(results[:per_page]): | |
| images_data = pin.get("images", {}) | |
| if images_data: | |
| best_quality = max(images_data.keys(), key=lambda x: images_data[x].get("width", 0)) | |
| img_url = images_data[best_quality].get("url") | |
| if img_url: | |
| images.append({ | |
| "id": f"img_{pin.get('id', i)}", | |
| "url": img_url, | |
| "thumbnail": img_url, | |
| "width": images_data[best_quality].get("width", 0), | |
| "height": images_data[best_quality].get("height", 0), | |
| "tags": pin.get("title", query)[:200], | |
| "likes": pin.get("like_count", 0) | |
| }) | |
| return images | |
| except Exception as e: | |
| print(f"Pinterest API 2 error: {e}") | |
| return [] | |
| # ------------------------------------------------------------------ | |
| # MAIN HANDLER (Bing + Both Pinterest APIs) | |
| # ------------------------------------------------------------------ | |
| def search_handler(q: str, per_page: int = 30, page: int = 1): | |
| all_results = [] | |
| # 1. Bing (with pagination) | |
| bing_images = scrape_bing(q, page, per_page) | |
| all_results.extend(bing_images) | |
| # 2. Primary Pinterest API (first page only) | |
| needed = per_page - len(all_results) | |
| if needed > 0 and page == 1: | |
| pinterest_images_1 = fetch_pinterest_api_1(q, needed) | |
| all_results.extend(pinterest_images_1) | |
| needed = per_page - len(all_results) | |
| # 3. Secondary Pinterest API (if still needed) | |
| if needed > 0 and page == 1: | |
| pinterest_images_2 = fetch_pinterest_api_2(q, needed) | |
| all_results.extend(pinterest_images_2) | |
| # Shuffle for variety | |
| random.shuffle(all_results) | |
| all_results = all_results[:per_page] | |
| return { | |
| "status": "success", | |
| "query": q, | |
| "page": page, | |
| "total": len(all_results), | |
| "results": all_results, | |
| "developer": { | |
| "name": "WASIF ALI", | |
| "telegram": "@THE_FREE_HACKS" | |
| } | |
| } | |
| # ------------------------------------------------------------------ | |
| # FASTAPI ENDPOINTS | |
| # ------------------------------------------------------------------ | |
| def search_json( | |
| q: str = Query(..., description="Search keyword"), | |
| per_page: int = Query(30, ge=1, le=100), | |
| page: int = Query(1, ge=1) | |
| ): | |
| return search_handler(q, per_page, page) | |
| def search( | |
| q: str = Query(...), | |
| per_page: int = Query(30, ge=1, le=100), | |
| page: int = Query(1, ge=1) | |
| ): | |
| return search_handler(q, per_page, page) | |
| def root(): | |
| return { | |
| "message": "ImageHub API is live. Use /search.json?q=keyword", | |
| "developer": { | |
| "name": "WASIF ALI", | |
| "telegram": "@THE_FREE_HACKS" | |
| } | |
| } |