1. добавил в gitigove .env
2. /vmix - генерируется проект vMix с нужными линками для виртуальных машин
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
/TestJson
|
/TestJson
|
||||||
/logs/*
|
/logs/*
|
||||||
*.venv
|
*.venv
|
||||||
|
*.env
|
||||||
116
get_data.py
116
get_data.py
@@ -1,22 +1,20 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI, HTTPException, Request
|
||||||
from fastapi.responses import Response, HTMLResponse
|
from fastapi.responses import Response, HTMLResponse, FileResponse, StreamingResponse
|
||||||
from fastapi import HTTPException
|
from typing import Dict, Any
|
||||||
from fastapi import Request
|
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import requests
|
import requests, uvicorn, json
|
||||||
import threading
|
import threading, queue
|
||||||
import time
|
|
||||||
import queue
|
|
||||||
import argparse
|
import argparse
|
||||||
import uvicorn
|
|
||||||
import os
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import json
|
|
||||||
from datetime import datetime, time as dtime, timedelta
|
from datetime import datetime, time as dtime, timedelta
|
||||||
from fastapi.responses import Response
|
from fastapi.responses import Response
|
||||||
import logging
|
import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
import platform
|
from dotenv import load_dotenv
|
||||||
|
from pprint import pprint
|
||||||
|
import nasio
|
||||||
|
import io, os, platform, time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
@@ -30,10 +28,8 @@ MYHOST = platform.node()
|
|||||||
if not os.path.exists("logs"):
|
if not os.path.exists("logs"):
|
||||||
os.makedirs("logs")
|
os.makedirs("logs")
|
||||||
|
|
||||||
telegram_bot_token = "7639240596:AAH0YtdQoWZSC-_R_EW4wKAHHNLIA0F_ARY"
|
telegram_bot_token = os.getenv("TELEGRAM_TOKEN")
|
||||||
# telegram_chat_id = 228977654
|
telegram_chat_id = os.getenv("TELEGRAM_CHAT_ID")
|
||||||
# telegram_chat_id = -4803699526
|
|
||||||
telegram_chat_id = -1003388354193
|
|
||||||
log_config = {
|
log_config = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"handlers": {
|
"handlers": {
|
||||||
@@ -79,11 +75,19 @@ logging.config.dictConfig(log_config)
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.handlers[2].formatter.use_emoji = True
|
logger.handlers[2].formatter.use_emoji = True
|
||||||
|
|
||||||
|
pprint(f"Локальный файл окружения ={load_dotenv(verbose=True)}")
|
||||||
|
|
||||||
LEAGUE = args.league
|
LEAGUE = args.league
|
||||||
TEAM = args.team
|
TEAM = args.team
|
||||||
LANG = args.lang
|
LANG = args.lang
|
||||||
HOST = "https://pro.russiabasket.org"
|
HOST = os.getenv("API_BASE_URL")
|
||||||
|
SYNO_PATH = f'{os.getenv("SYNO_PATH")}MATCH INFO.xlsx'
|
||||||
|
SYNO_URL = os.getenv("SYNO_URL")
|
||||||
|
SYNO_USERNAME = os.getenv("SYNO_USERNAME")
|
||||||
|
SYNO_PASSWORD = os.getenv("SYNO_PASSWORD")
|
||||||
|
SYNO_PATH_МVMIX = os.getenv("SYNO_PATH_МVMIX")
|
||||||
|
|
||||||
|
|
||||||
STATUS = False
|
STATUS = False
|
||||||
GAME_ID = None
|
GAME_ID = None
|
||||||
SEASON = None
|
SEASON = None
|
||||||
@@ -2773,7 +2777,6 @@ async def play_by_play():
|
|||||||
team1_name = data["team1"]["name"]
|
team1_name = data["team1"]["name"]
|
||||||
team2_name = data["team2"]["name"]
|
team2_name = data["team2"]["name"]
|
||||||
|
|
||||||
|
|
||||||
team1_startnum = [
|
team1_startnum = [
|
||||||
i["startNum"]
|
i["startNum"]
|
||||||
for i in next(
|
for i in next(
|
||||||
@@ -2800,7 +2803,10 @@ async def play_by_play():
|
|||||||
if "play" not in df_data_pbp:
|
if "play" not in df_data_pbp:
|
||||||
return maybe_clear_for_vmix([])
|
return maybe_clear_for_vmix([])
|
||||||
|
|
||||||
if "live-status" in latest_data and latest_data["live-status"]["data"] != "Not Found":
|
if (
|
||||||
|
"live-status" in latest_data
|
||||||
|
and latest_data["live-status"]["data"] != "Not Found"
|
||||||
|
):
|
||||||
json_quarter = latest_data["live-status"]["data"]["result"]["period"]
|
json_quarter = latest_data["live-status"]["data"]["result"]["period"]
|
||||||
json_second = latest_data["live-status"]["data"]["result"]["second"]
|
json_second = latest_data["live-status"]["data"]["result"]["second"]
|
||||||
else:
|
else:
|
||||||
@@ -2899,9 +2905,81 @@ async def play_by_play():
|
|||||||
return maybe_clear_for_vmix(payload)
|
return maybe_clear_for_vmix(payload)
|
||||||
|
|
||||||
|
|
||||||
|
def change_vmix_datasource_urls(xml_data, new_base_url: str) -> bytes:
|
||||||
|
"""
|
||||||
|
Ищет все <datasource friendlyName="JSON"> и меняет <url> внутри на new_base_url + endpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 1. Приводим вход к bytes
|
||||||
|
if isinstance(xml_data, (bytes, bytearray)):
|
||||||
|
raw_bytes = bytes(xml_data)
|
||||||
|
elif isinstance(xml_data, str):
|
||||||
|
raw_bytes = xml_data.encode("utf-8")
|
||||||
|
elif isinstance(xml_data, io.IOBase) or hasattr(xml_data, "read"):
|
||||||
|
# nasio.load_bio, скорее всего, возвращает BytesIO
|
||||||
|
raw_bytes = xml_data.read()
|
||||||
|
try:
|
||||||
|
xml_data.seek(0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise TypeError(f"Unsupported xml_data type: {type(xml_data)}")
|
||||||
|
|
||||||
|
# 2. Декодируем
|
||||||
|
text = raw_bytes.decode("utf-8", errors="replace")
|
||||||
|
|
||||||
|
# 3. Парсим XML
|
||||||
|
root = ET.fromstring(text)
|
||||||
|
|
||||||
|
# 4. Меняем URL
|
||||||
|
for ds in root.findall(".//datasource[@friendlyName='JSON']"):
|
||||||
|
for inst in ds.findall(".//instance"):
|
||||||
|
url_tag = inst.find(".//state/xml/url")
|
||||||
|
if url_tag is not None and url_tag.text:
|
||||||
|
old_url = url_tag.text.strip()
|
||||||
|
|
||||||
|
# аккуратно выделяем endpoint
|
||||||
|
# http://127.0.0.1:8000/team1 -> /team1
|
||||||
|
after_scheme = old_url.split("://", 1)[-1]
|
||||||
|
after_host = (
|
||||||
|
after_scheme.split("/", 1)[-1] if "/" in after_scheme else ""
|
||||||
|
)
|
||||||
|
endpoint = "/" + after_host if after_host else ""
|
||||||
|
|
||||||
|
new_url = new_base_url.rstrip("/") + endpoint
|
||||||
|
url_tag.text = new_url
|
||||||
|
|
||||||
|
# 5. Сериализуем обратно в bytes
|
||||||
|
new_xml = ET.tostring(root, encoding="utf-8", method="xml")
|
||||||
|
return new_xml
|
||||||
|
|
||||||
|
|
||||||
@app.get("/vmix")
|
@app.get("/vmix")
|
||||||
async def vmix_project():
|
async def vmix_project():
|
||||||
|
vmix_bio = nasio.load_bio(
|
||||||
|
user=SYNO_USERNAME,
|
||||||
|
password=SYNO_PASSWORD,
|
||||||
|
nas_ip=SYNO_URL,
|
||||||
|
nas_port="443",
|
||||||
|
path=SYNO_PATH_МVMIX,
|
||||||
|
)
|
||||||
|
system_name = platform.system()
|
||||||
|
if system_name == "Windows":
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
# ❗ На Linux/Synology/Docker — заменяем URL
|
||||||
|
edited_vmix = change_vmix_datasource_urls(
|
||||||
|
vmix_bio, f"https://{MYHOST}.tvstart.ru"
|
||||||
|
)
|
||||||
|
# 2. гарантируем, что это bytes
|
||||||
|
if isinstance(edited_vmix, str):
|
||||||
|
edited_vmix = edited_vmix.encode("utf-8")
|
||||||
|
|
||||||
|
return StreamingResponse(
|
||||||
|
io.BytesIO(edited_vmix),
|
||||||
|
media_type="application/octet-stream",
|
||||||
|
headers={"Content-Disposition": f'attachment; filename="VTB_{MYHOST}.vmix"'},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user