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 # ------------------------------------------------------------------ @app.get("/search.json") 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) @app.get("/search") 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) @app.get("/") def root(): return { "message": "ImageHub API is live. Use /search.json?q=keyword", "developer": { "name": "WASIF ALI", "telegram": "@THE_FREE_HACKS" } }