NAS_USER='aescript' NAS_PASS='@5j15SduIhP7' NAS_IP='10.10.35.7' NAS_PORT='5001' NAS_FILE='/team-folders/nexrender/Anons.osheet' #XXX TOKEN='7830267871:AAHHDEGWxa2ZjGoCCBhIk0skWR6u3ISVRtg' GROUP_CHAT='-4576902221' import telebot import logging import logging.config 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' ##test #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танавливает нах!") 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']) try: d=logos.loc[team,sport]['LINK'] 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(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=[40,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: 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!') # Заканчиваем