import telebot
import logging
import logging.config
from dotenv import load_dotenv
import os
from pprint import pprint
from synology_drive_api.drive import SynologyDrive
import pandas as pd
from transliterate import translit
import requests
from time import sleep
import datetime
import sys
PLACEHOLDER = sys.platform == "win32"
# XXX
if PLACEHOLDER:
from random import random, choices
def send_job_dumb(data):
if random() < 0.8:
uid = "".join(choices("abcdefghijklmnopqrstuvwxyz_", k=8))
return {"uid": uid, "outname": data["outfile_name"]}
class fake_resp:
def __init__(self, state="queured", *kargs, **kwargs):
self.state = state
self.status_code == 200
def json(self):
return {"state": self.state}
def fake_get():
if random < 0.8:
return fake_resp()
elif random < 0.8:
return fake_resp("finished")
else:
return fake_resp("error")
LOG_CONFIG = {
"version": 1,
"handlers": {
"telegram": {
"class": "telegram_handler.TelegramHandler",
"level": "INFO",
"token": TOKEN,
"chat_id": GROUP_CHAT,
"formatter": "telegram",
},
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "simple",
"stream": "ext://sys.stdout",
},
"file": {
"class": "logging.FileHandler",
"level": "DEBUG",
"formatter": "simple",
"encoding": "utf-8",
"filename": "AF_script.log",
},
},
# ,'telegram'
"loggers": {__name__: {"handlers": ["console", "file"], "level": "DEBUG"}},
"formatters": {
"telegram": {
"class": "telegram_handler.HtmlFormatter",
"format": "%(levelname)s %(message)s",
"use_emoji": "True",
},
"simple": {
"class": "logging.Formatter",
"format": "%(asctime)s %(levelname)-8s %(funcName)12s() - %(message)s",
"datefmt": "%d.%m.%Y %H:%M:%S",
},
},
}
logging.config.dictConfig(LOG_CONFIG)
logger = logging.getLogger(__name__)
# logger.handlers[2].formatter.use_emoji=True
bot = telebot.TeleBot(TOKEN)
telebot.logger.addHandler(logger.handlers[1])
@bot.message_handler(commands=["help", "start"])
def send_welcome(message):
bot.send_chat_action(message.chat.id, "typing")
if message.from_user.username:
user = f" {message.from_user.username}"
else:
user = "!"
sleep(1)
bot.reply_to(
message,
f"Привет{user}\n Я помогу тебе сделать Анонсы!\n Вот список команд которые я могу выполнить:\n /ибаш - наибашу обработку и рендер!\n /харе - оcтанавливает нах!",
)
logger.debug(load_dotenv(dotenv_path="/mnt/aescript/.env",verbose=True))
NAS_USER = os.getenv("NAS_USER")
NASS_PASS = os.getenv("NASS_PASS")
NAS_IP = os.getenv("NAS_IP")
NAS_PORT = os.getenv("NAS_PORT")
NAS_FILE = os.getenv("NAS_FILE")
TOKEN = os.getenv("TOKEN")
GROUP_CHAT = os.getenv("GROUP_CHAT")
def load_osheet(message):
logger.debug("Get data")
synd = SynologyDrive(
NAS_USER, NAS_PASS, NAS_IP, NAS_PORT, https=True, dsm_version="7"
)
try:
logger.debug(synd.login()) # Проверка что ссеия установлена.
try:
logger.debug("Try to download sheet")
bio = synd.download_synology_office_file(NAS_FILE)
logger.debug("Download Success")
return bio
except:
logger.exception("Download fails")
bot.send_message(
message.chat.id,
f"Не удалось скачать таблицу",
parse_mode=["html"],
)
except:
logger.exception("Login error")
bot.send_message(
message.chat.id, f"Не удалось авторизоватся", parse_mode=["html"]
)
def get_start(osheet):
logger.debug("Read Start page")
try:
sheet = pd.read_excel(osheet, sheet_name="Start", header=1)
sheet = sheet[sheet["STATE"] == False] # Проверка "первая"
logger.debug("Parsing OK")
return sheet
except:
logger.exception("error while read excel sheet")
def get_packs(osheet):
logger.debug("Read SPORT page")
try:
sheet = pd.read_excel(osheet, sheet_name="SPORT", header=0, index_col="SPORT")
logger.debug("Parsing OK")
return sheet[sheet.index.notna()]
except:
logger.exception("error while read excel sheet")
raise
def get_logos(osheet):
logger.debug("Read TEAMS page")
try:
sheet = pd.read_excel(osheet, sheet_name="TEAMS", header=0, index_col=[0, 1])
logger.debug("Parsing OK")
return sheet
except:
logger.exception("error while read excel sheet")
def get_sport_logo(sport, pack, message):
logger.info(f"Get {sport} pack")
bot.send_message(
message.chat.id, f"Ищем оформления для {sport}", parse_mode=["html"]
)
try:
d = pack.loc[sport]["LINK"]
logger.debug(d)
if pd.isna(d):
logger.warning(f'There is no LINK for sport "{sport}"')
return ""
return d
except:
logger.exception("Couldn't get " + sport + " pack")
return ""
def get_team_logo(team, sport, logos, message):
logger.info(f"Get {team}/{sport} logo")
bot.send_message(
message.chat.id, f"Поиск логотипа {sport}-{team}", parse_mode=["html"]
)
logger.debug(team, sport)
logger.info(logos)
bot.send_message(message.chat.id, logos)
try:
d = logos.loc[team, sport]["LINK"][0] ##проверить!!!
logger.debug(d)
return d
except KeyError as inst:
logger.warning(f"There is no LINK for {team}/{sport}")
return ""
except Exception:
logger.exception(f"Error while get {sport} pack")
return ""
def make_data_dict(ds):
dd = {}
dd["date"] = ds["DATA"]
dd["time"] = ds["TIME"]
dd["channel"] = ds["CHANEL"]
dd["sport"] = ds["SPORT"]
dd["league"] = ds["LEAGUE"]
dd["team_a"] = ds["TEAM A"]
dd["team_b"] = ds["TEAM B"]
dd["index"] = ds.name
return dd
def make_job_dicts(dd, pack, logos, message):
# def make_name(ds,pack,logos):
logger.debug("Start make name")
fn = ""
data = {}
empty_sport = pack.iloc[0].name
# Дата и Время
if isinstance(dd["date"], str):
fn += f"{dd['date'][6:]}{dd['date'][3:5]}{dd['date'][0:2]}"
elif isinstance(dd["date"], datetime.date):
fn += f"{dd['date'].year}{dd['date'].month:02}{dd['date'].day:02}"
# Вид спорта и оформление
if dd["sport"] != empty_sport:
fn += f"_{dd['sport']}"
data["sport"] = dd["sport"]
data["pack"] = unc2uri(get_sport_logo(dd["sport"], pack, message))
else:
data["sport"] = ""
data["pack"] = ""
# Лига
if dd["league"][-1] == ".":
logger.debug("dot in league name!")
fn += f'_{dd["league"][:-1]}'
data["league"] = dd["league"][:-1]
else:
data["league"] = dd["league"]
fn += f'_{dd["league"]}'
# Команды А и Б
if pd.isna(dd["team_a"]):
logger.info("No Team A present")
bot.send_message(message.chat.id, f"Нет команды А", parse_mode=["html"])
data["team_a"] = ""
data["team_a_logo"] = ""
data["team_a_logo_res"] = ""
else:
name = dd["team_a"].split("#")
fn += f"_{name[0]}"
data["team_a_logo_res"] = name[2:]
data["team_a"] = name[0]
data["team_a_logo"] = unc2uri(
get_team_logo(dd["team_a"], dd["sport"], logos, message)
)
if pd.isna(dd["team_b"]):
logger.info("No Team B present")
bot.send_message(message.chat.id, f"Нет команды Б", parse_mode=["html"])
data["team_b"] = ""
data["team_b_logo"] = ""
data["team_b_logo_res"] = ""
else:
name = dd["team_b"].split("#")
fn += f"_{name[0]}"
data["team_b_logo_res"] = name[2:]
data["team_b"] = name[0]
data["team_b_logo"] = unc2uri(
get_team_logo(dd["team_b"], dd["sport"], logos, message)
)
# CHANEL -> START/TRIUMPH
if pd.isna(dd["channel"]):
logger.debug("No Channel is set")
pass
else:
logger.debug("Channel is set " + dd["channel"])
fn += f"_{dd['channel']}"
fn = translit(fn, reversed=True)
fn = fn.replace(" ", "-")
fn = fn.replace("'", "")
data["outfile_name"] = fn
if isinstance(dd["time"], str):
t = dd["time"].split(":")
# data['time']=':'.join(t[0:2])
data["time_h"] = t[0]
data["time_m"] = t[1]
elif isinstance(dd["time"], datetime.time):
data["time_h"] = str(dd["time"].hour)
data["time_m"] = str(dd["time"].minute)
logger.debug("time " + data["time_h"] + ":" + data["time_m"])
if isinstance(dd["date"], str):
d = dd["date"].split(".")
d = f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}"
elif isinstance(dd["date"], datetime.date):
d = f"{dd['date'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][dd['date'].month]}"
data["data"] = d
logger.debug(data)
logger.debug(data["outfile_name"])
logger.debug(fn)
logger.debug("End make name")
watch_list = []
watch_list.append(send_job(data, message))
if True:
data["data"] = "сегодня"
data["outfile_name"] = fn + "_Today"
watch_list.append(send_job(data, message))
data["data"] = "завтра"
data["outfile_name"] = fn + "_Tomorrow"
watch_list.append(send_job(data, message))
pprint(watch_list)
return list(filter(None, watch_list))
def send_job(data, message):
payload = {}
payload["template"] = {
"src": "file:///c:/users/virtVmix-2/Downloads/PackShot_Sborka_eng.aepx",
"composition": "pack",
"outputModule": "Start_h264",
"outputExt": "mp4",
}
payload["actions"] = {
"postrender": [
{
"module": "@nexrender/action-encode",
"preset": "mp4",
"output": "encoded.mp4",
},
{
"module": "@nexrender/action-copy",
"input": "encoded.mp4",
"output": f"//10.10.35.3/edit/Auto_Anons/{data['outfile_name']}.mp4",
},
]
}
payload["assets"] = []
# ДАТА из файла и "сегодня"/"завтра"
# Размер и положение текста "Сегодня"
if data["data"] == "сегодня":
fontSize = "105"
anchorPoint = [0, 5]
payload["assets"].append(
{
"layerName": "DATA",
"property": "Source Text.fontSize",
"type": "data",
"value": fontSize,
}
)
logger.info(f'For "{data['data']}" font set to {fontSize}')
bot.send_message(
message.chat.id,
f'Для "{data['data']}" размер шрифта установлен {fontSize}',
parse_mode=["html"],
)
payload["assets"].append(
{
"layerName": "DATA",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
logger.info(f'Shifting the "{data['data']}" by {anchorPoint} pixels')
bot.send_message(
message.chat.id,
f'Сдвигаем "{data['data']}" на {anchorPoint} пикселей',
parse_mode=["html"],
)
# Размер и положение текста "Завтра"
elif data["data"] == "завтра":
fontSize = "115"
anchorPoint = [0, 25]
payload["assets"].append(
{
"layerName": "DATA",
"property": "Source Text.fontSize",
"type": "data",
"value": fontSize,
}
)
logger.info(f'For "{data['data']}" font set to {fontSize}')
bot.send_message(
message.chat.id,
f'Для "{data['data']}" размер шрифта установлен {fontSize}',
parse_mode=["html"],
)
payload["assets"].append(
{
"layerName": "DATA",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
logger.info(f'Shifting the "{data['data']}" by {anchorPoint} pixels')
bot.send_message(
message.chat.id,
f'Сдвигаем "{data['data']}" на {anchorPoint} пикселей',
parse_mode=["html"],
)
# Размер и положение текста "Даты"
payload["assets"].append(
{
"type": "data",
"layerName": "DATA",
"property": "Source Text",
"value": data["data"],
}
)
if len(data["data"]) < 6:
fontSize = "120"
anchorPoint = [0, 20]
payload["assets"].append(
{
"layerName": "DATA",
"property": "Source Text.fontSize",
"type": "data",
"value": fontSize,
}
)
logger.info(f'For "{data['data']}" font set to {fontSize}')
bot.send_message(
message.chat.id,
f'Для "{data['data']}" размер шрифта установлен {fontSize}',
parse_mode=["html"],
)
payload["assets"].append(
{
"layerName": "DATA",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
logger.info(f'Shifting the "{data['data']}" by {anchorPoint} pixels')
bot.send_message(
message.chat.id,
f'Сдвигаем "{data['data']}" на {anchorPoint} пикселей',
parse_mode=["html"],
)
# Время
if len(data["time_h"]) < 2:
anchorPoint = [60, 0]
payload["assets"].append(
{
"layerName": "TIME_H",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
payload["assets"].append(
{
"layerName": "TIME_M",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
payload["assets"].append(
{
"layerName": "TIME",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
logger.info(
f'Shifting the "{data['time_h']}:{data['time_m']}" by {anchorPoint} pixels'
)
bot.send_message(
message.chat.id,
f'Сдвигаем "{data['time_h']}:{data['time_m']}" на {anchorPoint} пикседей',
parse_mode=["html"],
)
elif len(data["time_h"]) == 2 and int(data["time_h"]) < 20:
anchorPoint = [20, 0]
payload["assets"].append(
{
"layerName": "TIME_H",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
payload["assets"].append(
{
"layerName": "TIME_M",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
payload["assets"].append(
{
"layerName": "TIME",
"property": "transform.anchorPoint",
"type": "data",
"value": anchorPoint,
}
)
logger.info(
f'Shifting the "{data['time_h']}:{data['time_m']}" by {anchorPoint} pixels'
)
bot.send_message(
message.chat.id,
f'Сдвигаем "{data['time_h']}:{data['time_m']}" на {anchorPoint} пикседей',
parse_mode=["html"],
)
payload["assets"].append(
{
"type": "data",
"layerName": "TIME_H",
"property": "Source Text",
"value": data["time_h"],
}
)
payload["assets"].append(
{
"type": "data",
"layerName": "TIME_M",
"property": "Source Text",
"value": data["time_m"],
}
)
# Лига
payload["assets"].append(
{
"type": "data",
"layerName": "LEAGUE",
"property": "Source Text",
"value": data["league"],
}
)
# Размер текста "Лиги"
if len(data["league"]) > 16:
fontSize = "73"
payload["assets"].append(
{
"layerName": "LEAGUE",
"property": "Source Text.fontSize",
"type": "data",
"value": fontSize,
}
)
logger.info(f'For "{data['league']}" font set to {fontSize}')
bot.send_message(
message.chat.id,
f'Для "{data['league']}" размер шрифта установлен {fontSize}',
parse_mode=["html"],
)
# Спорт
if data["sport"]:
payload["assets"].append(
{
"type": "data",
"layerName": "SPORT",
"property": "Source Text",
"value": data["sport"],
}
)
# Команда А
if data["team_a"]:
payload["assets"].append(
{
"type": "data",
"layerName": "TEAM_A",
"property": "Source Text",
"value": data["team_a"],
}
)
# Команда Б
if data["team_b"]:
payload["assets"].append(
{
"type": "data",
"layerName": "TEAM_B",
"property": "Source Text",
"value": data["team_b"],
}
)
# Логотип А
if data["team_a_logo"]:
payload["assets"].append(
{"src": data["team_a_logo"], "type": "image", "layerName": "TEAM_A_LOGO"}
)
if data["team_a_logo_res"]:
payload["assets"].append(
{
"property": "scale",
"type": "data",
"expression": "if (width > height) {max_size = width;} else {max_size = height;} var real_size = "
+ data["team_a_logo_res"][0]
+ "/max_size*100;[real_size,real_size]",
"layerName": "TEAM_A_LOGO",
}
)
logger.info(
f"{data['team_a']} logo was resized to {data['team_a_logo_res'][0]}"
)
bot.send_message(
message.chat.id,
f"{data['team_a']} маштабирован под {data['team_a_logo_res'][0]} пикселей",
parse_mode=["html"],
)
# Логотип Б
if data["team_b_logo"]:
payload["assets"].append(
{"src": data["team_b_logo"], "type": "image", "layerName": "TEAM_B_LOGO"}
)
if data["team_b_logo_res"]:
payload["assets"].append(
{
"property": "scale",
"type": "data",
"expression": "if (width > height) {max_size = width;} else {max_size = height;} var real_size = "
+ data["team_b_logo_res"][0]
+ "/max_size*100;[real_size,real_size]",
"layerName": "TEAM_B_LOGO",
}
)
logger.info(
f"{data['team_b']} logo was resized to {data['team_b_logo_res'][0]}"
)
bot.send_message(
message.chat.id,
f"{data['team_b']} маштабирован под {data['team_b_logo_res'][0]} пикселей",
parse_mode=["html"],
)
# Верхнее оформлени
if data["pack"]:
payload["assets"].append(
{"src": data["pack"], "type": "video", "layerName": "TOP"}
)
url = "http://10.10.2.20:3000/api/v1/jobs"
r = requests.post(url, json=payload)
if r.status_code == 200:
res = r.json()
# pprint(res)
uid = res["uid"]
return {"uid": uid, "outname": data["outfile_name"]}
def unc2uri(unc):
logger.debug("Start")
from urllib.parse import urlparse
from pathlib import PureWindowsPath
try:
print(unc)
p = urlparse(unc)
if len(p.scheme) > 2 or not unc:
return unc
else:
p = PureWindowsPath(unc)
return p.as_uri()
except:
logger.exception("erro wile prasing url")
# XXX
if PLACEHOLDER:
send_job = send_job_dumb
logger.info("Start!") # Начинаем
@bot.message_handler(commands=["чёкак", "status"])
def status(message):
logger.info(f"Staus requested by {message.from_user.username}")
r = requests.get("http://10.10.2.20:3000/api/v1/jobs")
if r.status_code == 200:
jobs = r.json()
s = [{"uid": i["uid"], "state": i["state"]} for i in jobs]
queued = 0
if s:
for job in s:
if job["state"] in ("queued"):
queued += 1
t = requests.get(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}")
# bot.send_message(message.chat.id,f'{job['uid']} - {t.json()['state']}')
pprint(t)
logger.info(f"{queued} queud")
bot.send_message(message.chat.id, f"В очереди {queued}")
else:
logger.info(f"no queued jobs")
bot.send_message(message.chat.id, "Нет задач в очереди")
@bot.message_handler(commands=["харе", "stop"])
def stop(message):
r = requests.get("http://10.10.2.20:3000/api/v1/jobs")
if r.status_code == 200:
jobs = r.json()
s = [{"uid": i["uid"], "state": i["state"]} for i in jobs]
queued = 0
if s:
for job in s:
if job["state"] in ("queued", "picked"):
requests.delete(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}")
queued += 1
else:
requests.delete(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}")
logger.info(f"Cancelled {queued} jobs by {message.from_user.username}")
bot.send_message(message.chat.id, f"Отменяно {queued}")
else:
logger.info(
f"{message.from_user.username} requested job cancel but No jobs to cancel"
)
bot.send_message(message.chat.id, "Нет задач для отмены")
@bot.message_handler(commands=["ибаш", "ibash"])
def ibash(message):
logger.info(f"Starting jobs for {message.from_user.username}")
bot.send_chat_action(message.chat.id, "typing")
if message.from_user.username:
user = message.from_user.username
else:
user = "!"
bot.send_message(
message.chat.id,
f"Ну что ж {user}, давай попробуем \nНАИБАШИТЬ!!!",
parse_mode=["html"],
)
bot.send_chat_action(message.chat.id, "upload_document")
osheet = load_osheet(message)
start = get_start(osheet)
pack = get_packs(osheet)
logos = get_logos(osheet)
# Удаляем прошлые задания которые закончились или с оштбкой
r = requests.get("http://10.10.2.20:3000/api/v1/jobs")
if r.status_code == 200:
jobs = r.json()
s = [{"uid": i["uid"], "state": i["state"]} for i in jobs]
for job in s:
if job["state"] in ("finished", "error"):
requests.delete(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}")
bot.send_chat_action(message.chat.id, "record_video")
watch_list = []
for i, row in start.iterrows():
dd = make_data_dict(row)
watch_list += make_job_dicts(dd, pack, logos, message)
logger.info(f"Queued {len(watch_list)} jobs")
bot.send_message(message.chat.id, f"В очереди {len(watch_list)} задач")
while watch_list:
bot.send_chat_action(message.chat.id, "record_video")
sleep(25)
for job in watch_list:
# XXX
if PLACEHOLDER:
r = fake_get()
else:
r = requests.get(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}")
logger.debug(r.text)
if r.status_code == 200 and r.json()["state"] == "finished":
watch_list.remove(job)
logger.info(
f"{job['outname']}, {r.json()['state']}, {len(watch_list)} to go"
)
bot.send_message(
message.chat.id,
f"{job['outname']}, готов, {len(watch_list)} осталось выполнить",
parse_mode=["html"],
)
logger.debug(f"{job['uid']} - {r.json()['state']}")
elif r.status_code == 200 and r.json()["state"] == "error":
watch_list.remove(job)
logger.warning(f"{job}, {r.json()['state']}, {len(watch_list)} to go")
bot.send_message(
message.chat.id,
f"!!!{job}, {r.json()['state']}, {len(watch_list)} осталось выполнить",
parse_mode=["html"],
)
# print('.',end="")
bot.send_message("Пойду спать :)")
bot.infinity_polling()
logger.info("End!") # Заканчиваем