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") pprint(f"Загрузка файла окружения = {load_dotenv(dotenv_path="/mnt/aescript/.env",verbose=True)}",) load_dotenv(dotenv_path="/mnt/aescript/.env") NAS_USER = os.getenv("NAS_USER") NAS_PASS = os.getenv("NAS_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") 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танавливает нах!", ) 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!") # Заканчиваем