###############################################################
PORT = 4323
LANGUAGE = "de"
REGION = "DE"
###############################################################
import json
import gzip
import requests
from io import BytesIO
import uuid
from flask import Flask, request, Response, abort
import time
import os
import socket
GEOIP_URL = "https://www.vavoo.tv/geoip"
PING_URL = "https://www.vavoo.tv/api/app/ping"
CATALOG_URL = "https://vavoo.to/mediahubmx-catalog.json"
RESOLVE_URL = "https://vavoo.to/mediahubmx-resolve.json"
HEADERS = {
"accept": "*/*",
"user-agent": "electron-fetch/1.0 electron (+https://github.com/arantes555/electron-fetch)",
"Accept-Language": LANGUAGE,
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
}
def decode_response(resp):
if resp.content[:2] == b'\x1f\x8b':
return json.loads(gzip.decompress(resp.content))
else:
return resp.json()
session = requests.Session()
session.headers.update(HEADERS)
r_geo = session.get(GEOIP_URL)
r_geo.raise_for_status()
geo_data = decode_response(r_geo)
unique_id = str(uuid.uuid4())
current_timestamp = int(time.time() * 1000)
initial_payload = {
"reason": "app-focus",
"locale": LANGUAGE,
"theme": "dark",
"metadata": {
"device": {"type": "desktop", "uniqueId": unique_id},
"os": {"name": "win32", "version": "Windows 10 Pro", "abis": ["x64"], "host": "Lenovo"},
"app": {"platform": "electron"},
"version": {"package": "tv.vavoo.app", "binary": "3.1.8", "js": "3.1.8"},
},
"appFocusTime": 0,
"playerActive": False,
"playDuration": 0,
"devMode": False,
"hasAddon": True,
"castConnected": False,
"package": "tv.vavoo.app",
"version": "3.1.8",
"process": "app",
"firstAppStart": current_timestamp,
"lastAppStart": current_timestamp,
"ipLocation": None,
"adblockEnabled": True,
"proxy": {"supported": ["ss"], "engine": "Mu", "enabled": False, "autoServer": True},
"iap": {"supported": False},
}
r1 = session.post(PING_URL, json=initial_payload)
r1.raise_for_status()
data1 = decode_response(r1)
initial_token = data1.get("token")
initial_addon_sig = data1.get("addonSig")
#print(f"[+] Initial token received: {initial_token}")
#print(f"[+] Initial addonSig received: {initial_addon_sig}")
catalog_headers = {
"content-type": "application/json; charset=utf-8",
"mediahubmx-signature": initial_addon_sig,
"user-agent": "MediaHubMX/2",
"accept": "*/*",
"Accept-Language": LANGUAGE,
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
}
all_filtered_items = []
cursor = None
while True:
catalog_payload = {
"language": LANGUAGE,
"region": REGION,
"catalogId": "iptv",
"id": "iptv",
"adult": False,
"search": "",
"sort": "",
"filter": {},
"cursor": cursor,
"clientVersion": "3.0.2"
}
r_catalog = session.post(CATALOG_URL, json=catalog_payload, headers=catalog_headers)
r_catalog.raise_for_status()
catalog_data = decode_response(r_catalog)
for item in catalog_data.get("items", []):
if item.get("type") == "iptv":
filtered_item = {
"id": item["ids"]["id"],
"url": item["url"],
"name": item["name"],
"group": item["group"],
"logo": item["logo"]
}
all_filtered_items.append(filtered_item)
cursor = catalog_data.get("nextCursor")
if cursor is None:
break
def save_m3u_file():
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
if local_ip.startswith("127."):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
except Exception:
local_ip = "127.0.0.1"
finally:
s.close()
m3u_content = "#EXTM3U\n"
for item in all_filtered_items:
m3u_content += f'#EXTINF:-1 tvg-id="{item["id"]}" tvg-name="{item["name"]}" tvg-logo="{item["logo"]}" group-title="{item["group"]}",{item["name"]}\n'
m3u_content += f'http://{local_ip}:{PORT}/vavoo?channel={item["id"]}\n'
with open("vavoo_playlist.m3u", "w", encoding="utf-8") as f:
f.write(m3u_content)
print("[✓] Local M3U playlist saved to vavoo_playlist.m3u")
save_m3u_file()
app = Flask(__name__)
@app.route('/vavoo')
def stream_proxy():
channel_id = request.args.get('channel')
if not channel_id:
abort(400)
channel = next((item for item in all_filtered_items if item["id"] == channel_id), None)
if not channel:
abort(404)
resolve_headers = {
"content-type": "application/json; charset=utf-8",
"mediahubmx-signature": initial_addon_sig,
"user-agent": "MediaHubMX/2",
"accept": "*/*",
"Accept-Language": LANGUAGE,
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
}
resolve_payload = {
"language": LANGUAGE,
"region": REGION,
"url": channel["url"],
"clientVersion": "3.0.2"
}
r_resolve = session.post(RESOLVE_URL, json=resolve_payload, headers=resolve_headers)
r_resolve.raise_for_status()
resolve_result = decode_response(r_resolve)
if resolve_result and len(resolve_result) > 0:
stream_url = resolve_result[0]["url"]
return Response(status=302, headers={"Location": stream_url})
else:
abort(404)
@app.route('/playlist.m3u')
def playlist():
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
if local_ip.startswith("127."):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(("8.8.8.8", 80))
local_ip = s.getsockname()[0]
except Exception:
local_ip = "127.0.0.1"
finally:
s.close()
m3u_content = "#EXTM3U\n"
for item in all_filtered_items:
m3u_content += f'#EXTINF:-1 tvg-id="{item["id"]}" tvg-name="{item["name"]}" tvg-logo="{item["logo"]}" group-title="{item["group"]}",{item["name"]}\n'
m3u_content += f'http://{local_ip}:{PORT}/vavoo?channel={item["id"]}\n'
return Response(m3u_content, mimetype='application/x-mpegURL')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=PORT)