vegaapi / app.py
sanch1tx's picture
Update app.py
0d9ac65 verified
import httpx
import logging
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Optional, Dict, Any
from pydantic import BaseModel
# --- Configuration ---
VEGA_API_BASE = "https://sanch1tx-vega-providers.hf.space"
MODFLIX_JSON_URL = "https://raw.githubusercontent.com/himanshu8443/providers/main/modflix.json"
# --- Provider ID Mappings (Critical Fix) ---
# Map 'name' or incorrect 'value' from JSON to the actual folder name on the server
PROVIDER_ID_MAP = {
"vegamovies": "vega",
"moviesmod": "mod",
"uhdmovies": "uhd",
"moviesdrive": "drive",
"luxmovies": "luxMovies", # Case sensitive? matches folder name
"topmovies": "topmovies", # matches folder
"nfmirror": "netflixMirror",
"primemirror": "primeMirror",
"tokyoinsider": "tokyoInsider",
"skymovieshd": "skyMovieHD",
"moviebox": "movieBox",
"cinevood": "1cinevood",
"kmmovies": "kmMovies",
"katmoviefix": "katMovieFix",
"joya9tv1": "Joya9tv",
"cinewood": "1cinevood"
}
# --- Hardcoded Fallback Catalogs ---
DEFAULT_CATALOGS = {
"drive": [
{"title": "Latest", "filter": ""},
{"title": "Anime", "filter": "category/anime/"},
{"title": "Netflix", "filter": "category/netflix/"},
{"title": "4K", "filter": "category/2160p-4k/"},
],
"vega": [
{"title": "New", "filter": ""},
{"title": "Netflix", "filter": "web-series/netflix"},
{"title": "Amazon Prime", "filter": "web-series/amazon-prime-video"},
],
"default": [
{"title": "Latest", "filter": ""},
{"title": "Trending", "filter": "trending"},
]
}
# Fallback providers
FALLBACK_PROVIDERS = [
{"name": "Vega", "value": "vega", "baseUrl": VEGA_API_BASE, "isActive": True},
{"name": "UHD", "value": "uhd", "baseUrl": VEGA_API_BASE, "isActive": True},
{"name": "Drive", "value": "drive", "baseUrl": VEGA_API_BASE, "isActive": True},
{"name": "Movies4u", "value": "movies4u", "baseUrl": VEGA_API_BASE, "isActive": True},
]
app = FastAPI(title="Vega Providers Gateway")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("vega_gateway")
class ProviderModel(BaseModel):
name: str
value: str
baseUrl: str
isActive: bool
@app.get("/")
async def root():
return {"status": "ok", "message": "Vega Python Gateway Active"}
@app.get("/providers", response_model=List[ProviderModel])
async def get_providers():
async with httpx.AsyncClient() as client:
try:
response = await client.get(MODFLIX_JSON_URL, timeout=4.0)
if response.status_code == 200:
data = response.json()
providers = []
raw_list = data if isinstance(data, list) else data.get("providers", [])
for p in raw_list:
if isinstance(p, dict):
name = p.get("name") or "Unknown"
raw_val = p.get("value") or p.get("id") or name
# Apply mapping to ensure valid backend ID
val = PROVIDER_ID_MAP.get(raw_val.lower(), raw_val)
if val:
providers.append({
"name": name,
"value": val,
"baseUrl": p.get("baseUrl") or VEGA_API_BASE,
"isActive": True
})
if providers: return providers
except Exception:
pass
return FALLBACK_PROVIDERS
@app.get("/{provider}/catalog")
async def get_catalog(provider: str):
# Remap provider if needed (double check)
provider_id = PROVIDER_ID_MAP.get(provider.lower(), provider)
url = f"{VEGA_API_BASE}/{provider_id}/catalog"
try:
async with httpx.AsyncClient() as client:
resp = await client.get(url, timeout=5.0)
if resp.status_code == 200:
data = resp.json()
if isinstance(data, list) and len(data) > 0:
return {"catalog": data}
if isinstance(data, dict) and "catalog" in data:
return data
except Exception:
pass
fallback = DEFAULT_CATALOGS.get(provider_id) or DEFAULT_CATALOGS.get("default")
return {"catalog": fallback}
@app.get("/{provider}/posts")
async def get_posts(provider: str, filter: str = "", page: int = 1):
provider_id = PROVIDER_ID_MAP.get(provider.lower(), provider)
url = f"{VEGA_API_BASE}/{provider_id}/posts"
params = {"filter": filter, "page": page}
async with httpx.AsyncClient() as client:
try:
resp = await client.get(url, params=params, timeout=12.0)
if resp.status_code == 200:
data = resp.json()
if isinstance(data, list): return data
# Handle error response from upstream like {"error": "..."}
if isinstance(data, dict) and "error" in data:
logger.error(f"Upstream error for {provider_id}: {data['error']}")
except Exception as e:
logger.error(f"Error posts {provider_id}: {e}")
pass
return []
@app.get("/{provider}/meta")
async def get_meta(provider: str, link: str):
provider_id = PROVIDER_ID_MAP.get(provider.lower(), provider)
url = f"{VEGA_API_BASE}/{provider_id}/meta"
params = {"link": link}
async with httpx.AsyncClient() as client:
try:
resp = await client.get(url, params=params, timeout=15.0)
if resp.status_code == 200:
return resp.json()
except Exception:
pass
raise HTTPException(status_code=404, detail="Meta not found")
@app.get("/{provider}/episodes")
async def get_episodes(provider: str, url: str):
provider_id = PROVIDER_ID_MAP.get(provider.lower(), provider)
api_url = f"{VEGA_API_BASE}/{provider_id}/episodes"
params = {"url": url}
async with httpx.AsyncClient() as client:
try:
resp = await client.get(api_url, params=params, timeout=15.0)
if resp.status_code == 200 and isinstance(resp.json(), list):
return resp.json()
except Exception:
pass
return []
@app.get("/{provider}/stream")
async def get_stream(provider: str, link: str, type: str = "movie"):
provider_id = PROVIDER_ID_MAP.get(provider.lower(), provider)
api_url = f"{VEGA_API_BASE}/{provider_id}/stream"
params = {"link": link, "type": type}
async with httpx.AsyncClient() as client:
try:
resp = await client.get(api_url, params=params, timeout=45.0)
if resp.status_code == 200 and isinstance(resp.json(), list):
return resp.json()
except:
pass
return []