Switch GIF API from Klipy to GIPHY
This commit is contained in:
parent
7c21fb35ff
commit
1b71c63919
|
|
@ -1,120 +1,87 @@
|
|||
"""
|
||||
controllers/tenor.py — Klipy GIF API proxy (requests-based) with Tenor fallback.
|
||||
controllers/tenor.py — GIPHY API proxy (requests-based).
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import requests
|
||||
from bottle import route, request, response
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_klipy_key: str = "aw3wqJXDc2LXcyL0zRg0v7LvXQCh69hciOxRMk23V1mWYxfql4NhKglzArCEHwBs"
|
||||
_tenor_keys = [
|
||||
"AIzaSyBi0xcrRsFkWV6TvG5udT71OVqSh_vuCQc",
|
||||
"AIzaSyDe5BdI5kQ6YLsTE_Dd8E5tLgJ4j7hYsWs",
|
||||
"AIzaSyCb2Cw5i9nFZzG5b7GdDf7e5f6h7j8k9l0",
|
||||
]
|
||||
_timeout = 25
|
||||
_giphy_key: str = "GIPHY_API_KEY"
|
||||
_session = requests.Session()
|
||||
_session.headers.update({'User-Agent': 'GIPHY-Proxy/1.0'})
|
||||
|
||||
GIPHY_BASE = "https://api.giphy.com/v1/gifs"
|
||||
|
||||
|
||||
def init(tenor_cfg):
|
||||
global _klipy_key
|
||||
global _giphy_key
|
||||
if hasattr(tenor_cfg, 'api_key') and tenor_cfg.api_key:
|
||||
_klipy_key = tenor_cfg.api_key
|
||||
logger.info(f"Klipy API key initialized: {_klipy_key[:10]}...")
|
||||
_giphy_key = tenor_cfg.api_key
|
||||
logger.info(f"GIPHY API key initialized: {_giphy_key[:10]}...")
|
||||
else:
|
||||
logger.warning("No Klipy API key provided, using default key")
|
||||
logger.warning("No GIPHY API key configured, using default placeholder")
|
||||
|
||||
|
||||
def _build_params(query_params, extra=None):
|
||||
params = {
|
||||
"page": query_params.get("page", "1"),
|
||||
"per_page": query_params.get("limit", "24"),
|
||||
"content_filter": query_params.get("content_filter", "off"),
|
||||
"locale": query_params.get("locale", "us"),
|
||||
"api_key": _giphy_key,
|
||||
"limit": query_params.get("limit", "20"),
|
||||
"rating": query_params.get("rating", "g"),
|
||||
"lang": query_params.get("lang", "en"),
|
||||
}
|
||||
if query_params.get("customer_id"):
|
||||
params["customer_id"] = query_params["customer_id"]
|
||||
if query_params.get("format_filter"):
|
||||
params["format_filter"] = query_params["format_filter"]
|
||||
if query_params.get("offset"):
|
||||
params["offset"] = query_params["offset"]
|
||||
if extra:
|
||||
params.update(extra)
|
||||
return params
|
||||
|
||||
|
||||
def _fetch_tenor_fallback(endpoint, params):
|
||||
"""Fallback to original Tenor API if Klipy fails."""
|
||||
tenor_key = random.choice(_tenor_keys)
|
||||
base = "https://tenor.googleapis.com/v2"
|
||||
path = "featured" if "trending" in endpoint else "search"
|
||||
p = {
|
||||
"key": tenor_key,
|
||||
"limit": params.get("per_page", 24),
|
||||
}
|
||||
if "q" in params:
|
||||
p["q"] = params["q"]
|
||||
url = f"{base}/{path}"
|
||||
logger.info(f"Tenor fallback: GET {url}")
|
||||
try:
|
||||
resp = requests.get(url, params=p, timeout=15)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
results = data.get("results", [])
|
||||
# Transform Tenor format -> Klipy-like format
|
||||
transformed = []
|
||||
for gif in results:
|
||||
mf = gif.get("media_formats", {})
|
||||
tf = {
|
||||
def _transform_giphy_result(gif):
|
||||
"""Convert GIPHY format -> unified {id, title, file: {hd, md, sm, xs}}."""
|
||||
images = gif.get("images", {})
|
||||
return {
|
||||
"id": gif.get("id"),
|
||||
"title": gif.get("title", ""),
|
||||
"slug": gif.get("h1_title", ""),
|
||||
"slug": gif.get("slug", gif.get("id", "")),
|
||||
"file": {
|
||||
"hd": {"gif": {"url": mf.get("gif", {}).get("url", "")}},
|
||||
"md": {"gif": {"url": mf.get("mediumgif", {}).get("url", "") or mf.get("gif", {}).get("url", "")}},
|
||||
"sm": {"gif": {"url": mf.get("tinygif", {}).get("url", "")}},
|
||||
"xs": {"gif": {"url": mf.get("nanogif", {}).get("url", "")}},
|
||||
"hd": {"gif": {"url": images.get("original", {}).get("url", "")}},
|
||||
"md": {"gif": {"url": images.get("downsized_large", {}).get("url", "") or images.get("downsized", {}).get("url", "")}},
|
||||
"sm": {"gif": {"url": images.get("fixed_width_downsampled", {}).get("url", "") or images.get("fixed_width", {}).get("url", "")}},
|
||||
"xs": {"gif": {"url": images.get("fixed_width_small", {}).get("url", "")}},
|
||||
},
|
||||
"blur_preview": mf.get("tinygif", {}).get("url", ""),
|
||||
"blur_preview": images.get("preview_gif", {}).get("url", ""),
|
||||
}
|
||||
transformed.append(tf)
|
||||
logger.info(f"Tenor fallback returned {len(transformed)} results")
|
||||
|
||||
|
||||
def _fetch_giphy(endpoint, params):
|
||||
url = f"{GIPHY_BASE}/{endpoint}"
|
||||
logger.debug(f"GET {url}")
|
||||
try:
|
||||
resp = _session.get(url, params=params, timeout=15)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
results = data.get("data", [])
|
||||
if isinstance(results, dict):
|
||||
results = [results]
|
||||
transformed = [_transform_giphy_result(g) for g in results]
|
||||
return {
|
||||
"success": True,
|
||||
"results": transformed,
|
||||
"fallback": "tenor",
|
||||
"pagination": {
|
||||
"current_page": (int(params.get("offset", 0)) // max(int(params.get("limit", 20)), 1)) + 1,
|
||||
"per_page": params.get("limit", 20),
|
||||
"has_next": len(transformed) >= int(params.get("limit", 20)),
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
error_msg = f"Tenor fallback also failed: {str(e)}"
|
||||
except requests.exceptions.RequestException as e:
|
||||
error_msg = f"GIPHY error: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
response.status = 502
|
||||
return {"success": False, "error": error_msg}
|
||||
|
||||
|
||||
def _fetch_klipy(endpoint, params):
|
||||
url = f"https://api.klipy.com/api/v1/{_klipy_key}/{endpoint}"
|
||||
logger.debug(f"GET {url} params={params}")
|
||||
try:
|
||||
resp = requests.get(url, params=params, timeout=_timeout)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
return {
|
||||
"success": data.get("result", False),
|
||||
"results": data.get("data", {}).get("data", []),
|
||||
"pagination": {
|
||||
"current_page": data.get("data", {}).get("current_page", 1),
|
||||
"per_page": data.get("data", {}).get("per_page", 24),
|
||||
"has_next": data.get("data", {}).get("has_next", False),
|
||||
},
|
||||
}
|
||||
except requests.exceptions.Timeout:
|
||||
logger.warning("Klipy timeout, falling back to Tenor...")
|
||||
return _fetch_tenor_fallback(endpoint, params)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.warning(f"Klipy error ({str(e)[:80]}), falling back to Tenor...")
|
||||
return _fetch_tenor_fallback(endpoint, params)
|
||||
except Exception as e:
|
||||
error_msg = f"Unexpected error: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
|
|
@ -127,7 +94,7 @@ def register_routes(app):
|
|||
def gifs_trending():
|
||||
logger.debug(f"Trending request: {dict(request.query)}")
|
||||
params = _build_params(request.query)
|
||||
return _fetch_klipy("gifs/trending", params)
|
||||
return _fetch_giphy("trending", params)
|
||||
|
||||
@app.route("/api/gifs/search", method="GET")
|
||||
def gifs_search():
|
||||
|
|
@ -137,4 +104,4 @@ def register_routes(app):
|
|||
response.status = 400
|
||||
return {"success": False, "error": "Missing query"}
|
||||
params = _build_params(request.query, extra={"q": q})
|
||||
return _fetch_klipy("gifs/search", params)
|
||||
return _fetch_giphy("search", params)
|
||||
|
|
|
|||
Loading…
Reference in New Issue