|
|
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 |
|
|
|
|
|
|
|
|
VEGA_API_BASE = "https://sanch1tx-vega-providers.hf.space" |
|
|
MODFLIX_JSON_URL = "https://raw.githubusercontent.com/himanshu8443/providers/main/modflix.json" |
|
|
|
|
|
|
|
|
|
|
|
PROVIDER_ID_MAP = { |
|
|
"vegamovies": "vega", |
|
|
"moviesmod": "mod", |
|
|
"uhdmovies": "uhd", |
|
|
"moviesdrive": "drive", |
|
|
"luxmovies": "luxMovies", |
|
|
"topmovies": "topmovies", |
|
|
"nfmirror": "netflixMirror", |
|
|
"primemirror": "primeMirror", |
|
|
"tokyoinsider": "tokyoInsider", |
|
|
"skymovieshd": "skyMovieHD", |
|
|
"moviebox": "movieBox", |
|
|
"cinevood": "1cinevood", |
|
|
"kmmovies": "kmMovies", |
|
|
"katmoviefix": "katMovieFix", |
|
|
"joya9tv1": "Joya9tv", |
|
|
"cinewood": "1cinevood" |
|
|
} |
|
|
|
|
|
|
|
|
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 = [ |
|
|
{"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 |
|
|
|
|
|
|
|
|
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): |
|
|
|
|
|
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 |
|
|
|
|
|
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 [] |