From 346ba10643dfb91f71da21ffedb569c9390074d2 Mon Sep 17 00:00:00 2001 From: Alexey Barabanov Date: Mon, 11 Aug 2025 16:15:51 +0300 Subject: [PATCH] remove OLD --- AF_script_test_1.py | 400 ------------------ AF_script_test_2.py | 506 ----------------------- AF_script_test_3.5.py | 584 -------------------------- AF_script_test_3.py | 555 ------------------------- AF_script_test_5.1.py | 927 ------------------------------------------ AF_script_test_5.py | 716 -------------------------------- 6 files changed, 3688 deletions(-) delete mode 100644 AF_script_test_1.py delete mode 100644 AF_script_test_2.py delete mode 100644 AF_script_test_3.5.py delete mode 100644 AF_script_test_3.py delete mode 100644 AF_script_test_5.1.py delete mode 100644 AF_script_test_5.py diff --git a/AF_script_test_1.py b/AF_script_test_1.py deleted file mode 100644 index da92e0e..0000000 --- a/AF_script_test_1.py +++ /dev/null @@ -1,400 +0,0 @@ -# NAS_IP='walle.barabanov.tv' -# NAS_PORT='443' -# NAS_FILE='/mydrive/Drive/Anons.osheet' - -NAS_USER='aescript' -NAS_PASS='@5j15SduIhP7' -NAS_IP='edit.tvstart.ru' -NAS_PORT='443' -NAS_FILE='/team-folders/nexrender/Anons.osheet' - -import logging -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 - -logger = logging.getLogger(__name__) - -logging.basicConfig(filename='AF_script.log', level=logging.INFO,format='%(asctime)s %(levelname)s %(message)s') - -def load_osheet(): - logger.info('Get data') - synd = SynologyDrive(NAS_USER, NAS_PASS, NAS_IP,NAS_PORT,https=True,dsm_version='7') - - try: - logger.info(synd.login()) # Проверка что ссеия установлена. - try: - logger.debug('Try to download sheet') - bio = synd.download_synology_office_file(NAS_FILE) - logger.debug(bio) - logger.info('Download Success') - return bio - except: - logger.warning('Download fails') - except: - logger.warning('Login error') - -def get_start(osheet): - logger.info('Read Start page') - try: - sheet = pd.read_excel(osheet, sheet_name='Start',header=1) - sheet=sheet[sheet['STATE']==False] # Проверка "первая" - logger.debug('Проверка 1') - logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'DATA','TIME','SPORT','LEAGUE'") - sheet.dropna(subset=['DATA','TIME','SPORT','LEAGUE'], inplace=True) - logger.debug(sheet) - logger.info('Parsing OK') - return sheet - except: - logger.warning('error while read excel sheet') - -def get_packs(osheet): - logger.info('Read SPORT page') - try: - sheet = pd.read_excel(osheet, sheet_name='SPORT',header=0,index_col='SPORT') - logger.debug(sheet) - logger.info('Parsing OK') - return sheet[sheet.index.notna()] - except: - logger.warning('error while read excel sheet') - raise - -def get_logos(osheet): - logger.info('Read TEAMS page') - try: - sheet = pd.read_excel(osheet, sheet_name='TEAMS',header=0,index_col=[0,1]) - logger.debug('Проверка "первая"') - logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'TEAM','LINK'") - sheet.dropna(subset=['LINK'], inplace=True) - logger.debug(sheet) - logger.info('Parsing OK') - return sheet - except: - logger.warning('error while read excel sheet') - -def get_sport_logo(sport,pack): - logger.info('Get '+sport+' pack') - 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 Exception as inst: - logger.warning("Couldn't get "+sport+" pack") - logger.warning(inst) - return '' - -def get_team_logo(team,sport,logos): - logger.info(f'Get {team}/{sport} logo') - try: - d=logos.loc[team,sport]['LINK'] - logger.debug(d) - return d - except KeyError as inst: - logger.warning(f"There is no LINK for sport {team}/{sport}") - return '' - -def make_name(ds,pack,logos): - logger.info('Start make name') - - fn='' - data={} - empty_sport=pack.iloc[0].name - if isinstance(ds['DATA'],str): - fn+=f"{ds['DATA'][6:]}{ds['DATA'][3:5]}{ds['DATA'][0:2]}" - elif isinstance(ds['DATA'],datetime.date): - fn+=f"{ds['DATA'].year}{ds['DATA'].month:02}{ds['DATA'].day:02}" - - #Если нет оформления - if ds['SPORT']!=empty_sport: - fn+=f"_{ds['SPORT']}" - data['sport']=ds['SPORT'] - data['pack']=unc2uri(get_sport_logo(ds['SPORT'],pack)) - else: - data['sport']='' - data['pack']='' - fn+=f'_{ds["LEAGUE"]}' - - #Если нет команд - if pd.isna(ds['TEAM A']): - logger.info('No Team A present') - data['team_a']='' - data['team_a_logo']='' - else: - fn+=f"_{ds['TEAM A']}" - data['team_a']=ds['TEAM A'] - data['team_a_logo']=unc2uri(get_team_logo(ds['TEAM A'],ds['SPORT'],logos)) - - if pd.isna(ds['TEAM B']): - logger.info('No Team B present') - data['team_b']='' - data['team_b_logo']='' - else: - fn+=f"_{ds['TEAM B']}" - data['team_b']=ds['TEAM B'] - data['team_b_logo']=unc2uri(get_team_logo(ds['TEAM B'],ds['SPORT'],logos)) - - fn=translit(fn,reversed=True) - fn=fn.replace(' ','-') - fn=fn.replace("'",'') - - data['outfile_name']=fn - data['league']=ds['LEAGUE'] - if isinstance(ds['TIME'],str): - t=ds['TIME'].split(':') - # data['time']=':'.join(t[0:2]) - data['time_h']= t[0] - data['time_m']= t[1] - elif isinstance(ds['TIME'],datetime.time): - data['time_h']= str(ds['TIME'].hour) - data['time_m']= str(ds['TIME'].minute) - - if isinstance(ds['DATA'],str): - d=ds['DATA'].split('.') - d=f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(ds['DATA'],datetime.date): - d=f"{ds['DATA'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][ds['DATA'].month]}" - data['data']=d - - logger.debug(data) - logger.debug(fn) - logger.info("End make name") - - watch_list=[] - watch_list.append(send_job(data)) - if ds['TRIPPLE']: - data['data']='сегодня' - data['outfile_name']=fn+'_Today' - watch_list.append(send_job(data)) - data['data']='завтра' - data['outfile_name']=fn+'_Tomorrow' - watch_list.append(send_job(data)) - pprint(watch_list) - return list(filter(None,watch_list)) - -def send_job(data): - 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'] == 'сегодня': - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": "95" - }) - logger.info('For "'+data['data']+'" font set to 95') - - #Размер текста - elif data['data'] == 'завтра': - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": "109" - }) - logger.info('For "'+data['data']+'" font set to 109') - - payload['assets'].append({ - "type": "data", - "layerName": "DATA", - "property": "Source Text", - "value": data['data'] - }) - - #Время - if len(data['time_h'])<2: - payload['assets'].append({ - "layerName": "TIME_H", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - payload['assets'].append({ - "layerName": "TIME_M", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - payload['assets'].append({ - "layerName": "TIME", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - logger.info('Shifting the "Time" by 37 pixels') - - 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: - payload['assets'].append({ - "layerName": "LEAGUE", - "property": "Source Text.fontSize", - "type": "data", - "value": "73" - }) - logger.info('For "'+data['league']+'" font set to 73') - - #Спорт - 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_b_logo']: - payload['assets'].append({ - "src": data['team_b_logo'], - "type": "image", - "layerName": "TEAM_B_LOGO" - }) - - #Верхнее оформление - 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): - if unc[:2]=='\\\\': - uri=f"file:{unc.replace('\\','/')}" - else: - uri=unc - return uri - -logger.info('Start!') # Начинаем - -osheet=load_osheet() -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']}") -watch_list=[] -for row in start.iterrows(): - row=row[1] - watch_list+=make_name(row,pack,logos) -logger.info(f"Queued {len(watch_list)} jobs") - -while watch_list: - sleep(60) - for job in watch_list: - r=requests.get(f"http://10.10.2.20:3000/api/v1/jobs/{job['uid']}") - if r.status_code==200 and r.json()['state'] in ('finished', 'error'): - watch_list.remove(job) - logger.info(f"{job}, {r.json()['state']}, {len(watch_list)} to go") - print('.',end="") - -logger.info('End!') # Заканчиваем - - -# with open('myjob.json') as myjob: -# headers={'content-type':'application/json'} -# print('start request') -# r=requests.post('http://10.10.2.20:3000/api/v1/jobs', -# headers=headers, data=myjob.read()) -# print('end request') -# print(r.status_code) - -#curl http://10.10.2.20:3000/api/v1/jobs >jobs.json -# import json -# with open('jobs.json') as f: -# jobs=json.load(f) -# s=[(i['uid'],i['state']) for i in jobs] -# pprint(s) \ No newline at end of file diff --git a/AF_script_test_2.py b/AF_script_test_2.py deleted file mode 100644 index abccbd5..0000000 --- a/AF_script_test_2.py +++ /dev/null @@ -1,506 +0,0 @@ -NAS_USER='aescript' -NAS_PASS='@5j15SduIhP7' -NAS_IP='edit.tvstart.ru' -NAS_PORT='443' -NAS_FILE='/team-folders/nexrender/Anons.osheet' #XXX - -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' - -#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': '7830267871:AAHHDEGWxa2ZjGoCCBhIk0skWR6u3ISVRtg', - 'chat_id': '-4576902221', - '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' - }, - }, - 'loggers': { - __name__: { - 'handlers': ['console','file','telegram'], - '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__) - -def load_osheet(): - 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(bio) - logger.debug('Download Success') - return bio - except: - logger.exception('Download fails') - except: - logger.exception('Login error') - -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('Проверка 1') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'DATA','TIME','SPORT','LEAGUE'") - # sheet.dropna(subset=['DATA','TIME','SPORT','LEAGUE'], inplace=True) - # logger.debug(sheet) - 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(sheet) - 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('Проверка "первая"') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'TEAM','LINK'") - # sheet.dropna(subset=['LINK'], inplace=True) - # logger.debug(sheet) - logger.debug('Parsing OK') - return sheet - except: - logger.exception('error while read excel sheet') - -def get_sport_logo(sport,pack): - logger.info('Get '+sport+' pack') - 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 Exception as inst: - logger.exception("Couldn't get "+sport+" pack") - # logger.exception(inst) - return '' - -def get_team_logo(team,sport,logos): - logger.info(f'Get {team}/{sport} logo') - try: - d=logos.loc[team,sport]['LINK'] - logger.debug(d) - return d - except KeyError as inst: - logger.exception(f"There is no LINK for sport {team}/{sport}") - return '' - -def make_name(ds,pack,logos): - logger.debug('Start make name') - - fn='' - data={} - empty_sport=pack.iloc[0].name - if isinstance(ds['DATA'],str): - fn+=f"{ds['DATA'][6:]}{ds['DATA'][3:5]}{ds['DATA'][0:2]}" - elif isinstance(ds['DATA'],datetime.date): - fn+=f"{ds['DATA'].year}{ds['DATA'].month:02}{ds['DATA'].day:02}" - - #Если нет оформления - if ds['SPORT']!=empty_sport: - fn+=f"_{ds['SPORT']}" - data['sport']=ds['SPORT'] - data['pack']=unc2uri(get_sport_logo(ds['SPORT'],pack)) - else: - data['sport']='' - data['pack']='' - fn+=f'_{ds["LEAGUE"]}' - - #Если нет команд - if pd.isna(ds['TEAM A']): - logger.info('No Team A present') - data['team_a']='' - data['team_a_logo']='' - data['team_a_logo_res']='' - else: - name = ds['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(ds['TEAM A'],ds['SPORT'],logos)) - data['team_a_logo_res']='' - - if pd.isna(ds['TEAM B']): - logger.info('No Team B present') - data['team_b']='' - data['team_b_logo']='' - data['team_b_logo_res']='' - else: - name = ds['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(ds['TEAM B'],ds['SPORT'],logos)) - - fn=translit(fn,reversed=True) - fn=fn.replace(' ','-') - fn=fn.replace("'",'') - - data['outfile_name']=fn - data['league']=ds['LEAGUE'] - if isinstance(ds['TIME'],str): - t=ds['TIME'].split(':') - # data['time']=':'.join(t[0:2]) - data['time_h']= t[0] - data['time_m']= t[1] - elif isinstance(ds['TIME'],datetime.time): - data['time_h']= str(ds['TIME'].hour) - data['time_m']= str(ds['TIME'].minute) - - if isinstance(ds['DATA'],str): - d=ds['DATA'].split('.') - d=f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(ds['DATA'],datetime.date): - d=f"{ds['DATA'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][ds['DATA'].month]}" - data['data']=d - - # logger.debug(data) - # logger.debug(fn) - logger.debug("End make name") - - watch_list=[] - watch_list.append(send_job(data)) - if ds['TRIPPLE']: - data['data']='сегодня' - data['outfile_name']=fn+'_Today' - watch_list.append(send_job(data)) - data['data']='завтра' - data['outfile_name']=fn+'_Tomorrow' - watch_list.append(send_job(data)) - pprint(watch_list) - return list(filter(None,watch_list)) - -def send_job(data): - 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'] == 'сегодня': - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": "95" - }) - logger.info('For "'+data['data']+'" font set to 95') - - #Размер текста - elif data['data'] == 'завтра': - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": "109" - }) - logger.info('For "'+data['data']+'" font set to 109') - - payload['assets'].append({ - "type": "data", - "layerName": "DATA", - "property": "Source Text", - "value": data['data'] - }) - - #Время - if len(data['time_h'])<2: - payload['assets'].append({ - "layerName": "TIME_H", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - payload['assets'].append({ - "layerName": "TIME_M", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - payload['assets'].append({ - "layerName": "TIME", - "property": "transform.anchorPoint", - "type": "data", - "value": [37,0] - }) - logger.info('Shifting the "Time" by 37 pixels') - - 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: - payload['assets'].append({ - "layerName": "LEAGUE", - "property": "Source Text.fontSize", - "type": "data", - "value": "73" - }) - logger.info('For "'+data['league']+'" font set to 73') - - #Спорт - 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('Team A logo was resized to '+data['team_a_logo_res'][0]) - - - #Логотип Б - 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('Team B logo was resized to '+data['team_b_logo_res'][0]) - - #Верхнее оформлени - 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): - - from urllib.parse import urlparse - from pathlib import PureWindowsPath - - p= urlparse(unc) - if len(p.scheme)>2: - return unc - else: - p=PureWindowsPath(unc) - return p.as_uri() - - # if unc[:2]=='\\\\': - # uri=f"file:{unc.replace('\\','/')}" - # else: - # uri=unc - # return uri - - -#XXX -if PLACEHOLDER: - send_job=send_job_dumb - -logger.info('Start!') # Начинаем - -osheet=load_osheet() -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']}") - -watch_list=[] -for row in start.iterrows(): - row=row[1] - watch_list+=make_name(row,pack,logos) -logger.info(f"Queued {len(watch_list)} jobs") - -while watch_list: - sleep(60) - 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']}") - - 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") - 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") - print('.',end="") - -logger.info('End!') # Заканчиваем diff --git a/AF_script_test_3.5.py b/AF_script_test_3.5.py deleted file mode 100644 index 3639401..0000000 --- a/AF_script_test_3.5.py +++ /dev/null @@ -1,584 +0,0 @@ -NAS_USER='aescript' -NAS_PASS='@5j15SduIhP7' -NAS_IP='edit.tvstart.ru' -NAS_PORT='443' -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' - -#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': '7830267871:AAHHDEGWxa2ZjGoCCBhIk0skWR6u3ISVRtg', - 'chat_id': '-4576902221', - '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' - }, - }, - 'loggers': { - __name__: { - 'handlers': ['console','file','telegram'], - '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) -@bot.message_handler(commands=['help', 'start']) -def send_welcome(message): - bot.send_chat_action(message.chat.id,'typing') - if message.from_user.username: - user=message.from_user.username - else: - user='!' - sleep(1) - bot.reply_to(message, "Привет "+user+"\n Я помогу тебе сделать Анонсы!\n Вот список команд которые я могу выполнить:\n /ибаш - наибашу обработаку и рендер!\n") - -def load_osheet(): - 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(bio) - logger.debug('Download Success') - return bio - except: - logger.exception('Download fails') - except: - logger.exception('Login error') - -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('Проверка 1') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'DATA','TIME','SPORT','LEAGUE'") - # sheet.dropna(subset=['DATA','TIME','SPORT','LEAGUE'], inplace=True) - # logger.debug(sheet) - 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(sheet) - 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('Проверка "первая"') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'TEAM','LINK'") - # sheet.dropna(subset=['LINK'], inplace=True) - # logger.debug(sheet) - logger.debug('Parsing OK') - return sheet - except: - logger.exception('error while read excel sheet') - -def get_sport_logo(sport,pack): - logger.info('Get '+sport+' pack') - 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 Exception as inst: - logger.exception("Couldn't get "+sport+" pack") - # logger.exception(inst) - return '' - -def get_team_logo(team,sport,logos): - logger.info(f'Get {team}/{sport} logo') - 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 '' - -def make_name(ds,pack,logos): - logger.debug('Start make name') - - fn='' - data={} - empty_sport=pack.iloc[0].name - if isinstance(ds['DATA'],str): - fn+=f"{ds['DATA'][6:]}{ds['DATA'][3:5]}{ds['DATA'][0:2]}" - elif isinstance(ds['DATA'],datetime.date): - fn+=f"{ds['DATA'].year}{ds['DATA'].month:02}{ds['DATA'].day:02}" - - #Если нет оформления - if ds['SPORT']!=empty_sport: - fn+=f"_{ds['SPORT']}" - data['sport']=ds['SPORT'] - data['pack']=unc2uri(get_sport_logo(ds['SPORT'],pack)) - else: - data['sport']='' - data['pack']='' - fn+=f'_{ds["LEAGUE"]}' - - #Если нет команд - if pd.isna(ds['TEAM A']): - logger.info('No Team A present') - data['team_a']='' - data['team_a_logo']='' - data['team_a_logo_res']='' - else: - name = ds['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(ds['TEAM A'],ds['SPORT'],logos)) - - - if pd.isna(ds['TEAM B']): - logger.info('No Team B present') - data['team_b']='' - data['team_b_logo']='' - data['team_b_logo_res']='' - else: - name = ds['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(ds['TEAM B'],ds['SPORT'],logos)) - - #CHANEL -> START/TRIUMPH - if pd.isna(ds['CHANEL']): - logger.debug('No Chanel is set') - pass - else: - logger.debug('Chanel is set '+ds['CHANEL']) - fn+=f"_{ds['CHANEL']}" - - - fn=translit(fn,reversed=True) - fn=fn.replace(' ','-') - fn=fn.replace("'",'') - - data['outfile_name']=fn - data['league']=ds['LEAGUE'] - if isinstance(ds['TIME'],str): - t=ds['TIME'].split(':') - # data['time']=':'.join(t[0:2]) - data['time_h']= t[0] - data['time_m']= t[1] - elif isinstance(ds['TIME'],datetime.time): - data['time_h']= str(ds['TIME'].hour) - data['time_m']= str(ds['TIME'].minute) - logger.debug('time '+data['time_h']+':'+data['time_m']) - if isinstance(ds['DATA'],str): - d=ds['DATA'].split('.') - d=f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(ds['DATA'],datetime.date): - d=f"{ds['DATA'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][ds['DATA'].month]}" - data['data']=d - - # logger.debug(data) - # logger.debug(fn) - logger.debug("End make name") - - watch_list=[] - watch_list.append(send_job(data)) - if ds['TRIPPLE']: - data['data']='сегодня' - data['outfile_name']=fn+'_Today' - watch_list.append(send_job(data)) - data['data']='завтра' - data['outfile_name']=fn+'_Tomorrow' - watch_list.append(send_job(data)) - pprint(watch_list) - return list(filter(None,watch_list)) - -def send_job(data): - 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('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - # Размер и положение текста "Завтра" - elif data['data'] == 'завтра': - fontSize="115" - anchorPoint=[0,25] - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": fontSize - }) - logger.info('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - # Размер и положение текста "Даты" - 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('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - #Время - 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('Shifting the "'+data['time_h']+':'+data['time_m']+'" by '+str(anchorPoint)+' pixels') - - 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('For "'+data['league']+'" font set to '+fontSize+'') - - #Спорт - 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(''+data['team_a']+' logo was resized to '+data['team_a_logo_res'][0]+'') - - - #Логотип Б - 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(''+data['team_b']+' logo was resized to '+data['team_b_logo_res'][0]+'') - - #Верхнее оформлени - 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): - - from urllib.parse import urlparse - from pathlib import PureWindowsPath - - p= urlparse(unc) - if len(p.scheme)>2 or not unc: - return unc - else: - p=PureWindowsPath(unc) - return p.as_uri() - - # if unc[:2]=='\\\\': - # uri=f"file:{unc.replace('\\','/')}" - # else: - # uri=unc - # return uri - - -#XXX -if PLACEHOLDER: - send_job=send_job_dumb - -logger.info('Start!') # Начинаем - -@bot.message_handler(commands=['ибаш','ibash']) -def ibash(message): - bot.send_chat_action(message.chat.id,'typing') - if message.from_user.username: - user=message.from_user.username - else: - user='!' - bot.reply_to(message, "Ну что ж "+user+", давай попробуем НАИБАШИТЬ!") - - bot.send_chat_action(message.chat.id,'upload_document') - - osheet=load_osheet() - 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 row in start.iterrows(): - row=row[1] - watch_list+=make_name(row,pack,logos) - logger.info(f"Queued {len(watch_list)} jobs") - - 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']}") - - 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") - 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") - print('.',end="") - -bot.infinity_polling() - -logger.info('End!') # Заканчиваем diff --git a/AF_script_test_3.py b/AF_script_test_3.py deleted file mode 100644 index fa48141..0000000 --- a/AF_script_test_3.py +++ /dev/null @@ -1,555 +0,0 @@ -NAS_USER='aescript' -NAS_PASS='@5j15SduIhP7' -NAS_IP='edit.tvstart.ru' -NAS_PORT='443' -NAS_FILE='/team-folders/nexrender/Anons.osheet' #XXX - -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' - -#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': '7830267871:AAHHDEGWxa2ZjGoCCBhIk0skWR6u3ISVRtg', - 'chat_id': '-4576902221', - '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' - }, - }, - 'loggers': { - __name__: { - 'handlers': ['console','file','telegram'], - '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 - -def load_osheet(): - 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(bio) - logger.debug('Download Success') - return bio - except: - logger.exception('Download fails') - except: - logger.exception('Login error') - -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('Проверка 1') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'DATA','TIME','SPORT','LEAGUE'") - # sheet.dropna(subset=['DATA','TIME','SPORT','LEAGUE'], inplace=True) - # logger.debug(sheet) - 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(sheet) - 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('Проверка "первая"') - # logger.debug(sheet) - logger.debug("Удаление строк с отсутствием 'TEAM','LINK'") - # sheet.dropna(subset=['LINK'], inplace=True) - # logger.debug(sheet) - logger.debug('Parsing OK') - return sheet - except: - logger.exception('error while read excel sheet') - -def get_sport_logo(sport,pack): - logger.info('Get '+sport+' pack') - 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 Exception as inst: - logger.exception("Couldn't get "+sport+" pack") - # logger.exception(inst) - return '' - -def get_team_logo(team,sport,logos): - logger.info(f'Get {team}/{sport} logo') - 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 '' - -def make_name(ds,pack,logos): - logger.debug('Start make name') - - fn='' - data={} - empty_sport=pack.iloc[0].name - if isinstance(ds['DATA'],str): - fn+=f"{ds['DATA'][6:]}{ds['DATA'][3:5]}{ds['DATA'][0:2]}" - elif isinstance(ds['DATA'],datetime.date): - fn+=f"{ds['DATA'].year}{ds['DATA'].month:02}{ds['DATA'].day:02}" - - #Если нет оформления - if ds['SPORT']!=empty_sport: - fn+=f"_{ds['SPORT']}" - data['sport']=ds['SPORT'] - data['pack']=unc2uri(get_sport_logo(ds['SPORT'],pack)) - else: - data['sport']='' - data['pack']='' - fn+=f'_{ds["LEAGUE"]}' - - #Если нет команд - if pd.isna(ds['TEAM A']): - logger.info('No Team A present') - data['team_a']='' - data['team_a_logo']='' - data['team_a_logo_res']='' - else: - name = ds['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(ds['TEAM A'],ds['SPORT'],logos)) - - - if pd.isna(ds['TEAM B']): - logger.info('No Team B present') - data['team_b']='' - data['team_b_logo']='' - data['team_b_logo_res']='' - else: - name = ds['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(ds['TEAM B'],ds['SPORT'],logos)) - - #CHANEL -> START/TRIUMPH - if pd.isna(ds['CHANEL']): - logger.debug('No Chanel is set') - pass - else: - logger.debug('Chanel is set '+ds['CHANEL']) - fn+=f"_{ds['CHANEL']}" - - - fn=translit(fn,reversed=True) - fn=fn.replace(' ','-') - fn=fn.replace("'",'') - - data['outfile_name']=fn - data['league']=ds['LEAGUE'] - if isinstance(ds['TIME'],str): - t=ds['TIME'].split(':') - # data['time']=':'.join(t[0:2]) - data['time_h']= t[0] - data['time_m']= t[1] - elif isinstance(ds['TIME'],datetime.time): - data['time_h']= str(ds['TIME'].hour) - data['time_m']= str(ds['TIME'].minute) - logger.debug('time '+data['time_h']+':'+data['time_m']) - if isinstance(ds['DATA'],str): - d=ds['DATA'].split('.') - d=f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(ds['DATA'],datetime.date): - d=f"{ds['DATA'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][ds['DATA'].month]}" - data['data']=d - - # logger.debug(data) - # logger.debug(fn) - logger.debug("End make name") - - watch_list=[] - watch_list.append(send_job(data)) - if ds['TRIPPLE']: - data['data']='сегодня' - data['outfile_name']=fn+'_Today' - watch_list.append(send_job(data)) - data['data']='завтра' - data['outfile_name']=fn+'_Tomorrow' - watch_list.append(send_job(data)) - pprint(watch_list) - return list(filter(None,watch_list)) - -def send_job(data): - 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('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - # Размер и положение текста "Завтра" - elif data['data'] == 'завтра': - fontSize="115" - anchorPoint=[0,25] - payload['assets'].append({ - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": fontSize - }) - logger.info('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - # Размер и положение текста "Даты" - 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('For "'+data['data']+'" font set to '+fontSize+'') - payload['assets'].append({ - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchorPoint - }) - logger.info('Shifting the "'+data['data']+'" by '+str(anchorPoint)+' pixels') - - #Время - 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('Shifting the "'+data['time_h']+':'+data['time_m']+'" by '+str(anchorPoint)+' pixels') - - 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('For "'+data['league']+'" font set to '+fontSize+'') - - #Спорт - 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(''+data['team_a']+' logo was resized to '+data['team_a_logo_res'][0]+'') - - - #Логотип Б - 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(''+data['team_b']+' logo was resized to '+data['team_b_logo_res'][0]+'') - - #Верхнее оформлени - 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): - - from urllib.parse import urlparse - from pathlib import PureWindowsPath - - p= urlparse(unc) - if len(p.scheme)>2 or not unc: - return unc - else: - p=PureWindowsPath(unc) - return p.as_uri() - - # if unc[:2]=='\\\\': - # uri=f"file:{unc.replace('\\','/')}" - # else: - # uri=unc - # return uri - - -#XXX -if PLACEHOLDER: - send_job=send_job_dumb - -logger.info('Start!') # Начинаем - -osheet=load_osheet() -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']}") - -watch_list=[] -for row in start.iterrows(): - row=row[1] - watch_list+=make_name(row,pack,logos) -logger.info(f"Queued {len(watch_list)} jobs") - -while watch_list: - 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']}") - - 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") - 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") - print('.',end="") - -logger.info('End!') # Заканчиваем diff --git a/AF_script_test_5.1.py b/AF_script_test_5.1.py deleted file mode 100644 index 66eeaf3..0000000 --- a/AF_script_test_5.1.py +++ /dev/null @@ -1,927 +0,0 @@ -import os -from dotenv import load_dotenv -import logging -import logging.config -from pprint import pprint -import pandas as pd -from transliterate import translit -import requests -from time import sleep -import datetime -import sys -from urllib.parse import urlparse -from pathlib import PureWindowsPath -import telebot -from telebot import types -from synology_drive_api.drive import SynologyDrive -from flask import Flask, jsonify -import threading -from functools import wraps - -# Инициализация Flask приложения для панели мониторинга -flask_app = Flask(__name__) -flask_app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET', 'default-secret-key') - -# Загрузка переменных окружения -load_dotenv('AF_environment.env') - -class Monitoring: - """Класс для сбора статистики и мониторинга""" - def __init__(self): - self.jobs_history = [] - self.system_stats = { - 'total_jobs': 0, - 'successful_jobs': 0, - 'failed_jobs': 0, - 'active_jobs': 0, - 'users': {} - } - - def add_job(self, job_data): - """Добавление информации о новой задаче""" - self.jobs_history.append(job_data) - self.system_stats['total_jobs'] += 1 - self.system_stats['active_jobs'] += 1 - - user_id = job_data.get('user_id') - if user_id: - if user_id not in self.system_stats['users']: - self.system_stats['users'][user_id] = { - 'total_jobs': 0, - 'successful_jobs': 0, - 'failed_jobs': 0 - } - self.system_stats['users'][user_id]['total_jobs'] += 1 - - def job_completed(self, job_id, success=True, user_id=None): - """Обновление статуса завершенной задачи""" - self.system_stats['active_jobs'] -= 1 - - if success: - self.system_stats['successful_jobs'] += 1 - else: - self.system_stats['failed_jobs'] += 1 - - if user_id and user_id in self.system_stats['users']: - if success: - self.system_stats['users'][user_id]['successful_jobs'] += 1 - else: - self.system_stats['users'][user_id]['failed_jobs'] += 1 - - # Обновляем статус в истории - for job in self.jobs_history: - if job.get('job_id') == job_id: - job['status'] = 'completed' if success else 'failed' - job['completed_at'] = datetime.datetime.now() - break - - def get_stats(self): - """Получение текущей статистики""" - return self.system_stats - - def get_recent_jobs(self, limit=10): - """Получение последних задач""" - return self.jobs_history[-limit:] if self.jobs_history else [] - - def get_user_stats(self, user_id): - """Получение статистики по конкретному пользователю""" - return self.system_stats['users'].get(user_id, { - 'total_jobs': 0, - 'successful_jobs': 0, - 'failed_jobs': 0 - }) - -class Config: - """Класс для работы с конфигурацией приложения""" - def __init__(self): - self.nas_user = os.getenv('NAS_USER') - self.nas_pass = os.getenv('NAS_PASS') - self.nas_ip = os.getenv('NAS_IP') - self.nas_port = os.getenv('NAS_PORT') - self.nas_file = os.getenv('NAS_FILE') - self.token = os.getenv('TELEGRAM_TOKEN') - self.group_chat = os.getenv('TELEGRAM_GROUP_CHAT') - self.nexrender_url = os.getenv('NEXRENDER_URL') - self.admin_password = os.getenv('ADMIN_PASSWORD', 'admin123') - self._validate_config() - - def _validate_config(self): - """Проверка наличия обязательных переменных окружения""" - required_vars = { - 'NAS_USER': self.nas_user, - 'NAS_PASS': self.nas_pass, - 'NAS_IP': self.nas_ip, - 'TELEGRAM_TOKEN': self.token, - 'NEXRENDER_URL': self.nexrender_url - } - missing = [k for k, v in required_vars.items() if not v] - if missing: - raise ValueError(f"Отсутствуют обязательные переменные окружения: {', '.join(missing)}") - -class JobManager: - """Основной класс для управления задачами рендеринга""" - def __init__(self, config, monitoring): - self.config = config - self.monitoring = monitoring - self.bot = telebot.TeleBot(config.token) - self.PLACEHOLDER = sys.platform == 'win32' - self.setup_logging() - self.setup_handlers() - - if self.PLACEHOLDER: - self._init_placeholders() - - def _init_placeholders(self): - """Инициализация заглушек для тестирования""" - 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']} - return None - - class FakeResp: - def __init__(self, state='queued', *args, **kwargs): - self.state = state - self.status_code = 200 - - def json(self): - return {'state': self.state} - - def fake_get(*args, **kwargs): - rand = random() - if rand < 0.8: - return FakeResp() - elif rand < 0.95: - return FakeResp('finished') - else: - return FakeResp('error') - - self._send_job_real = self.send_job - self.send_job = send_job_dumb - self._fake_get = fake_get - - def setup_logging(self): - """Настройка системы логирования""" - LOG_CONFIG = { - 'version': 1, - 'formatters': { - 'detailed': { - 'format': '%(asctime)s %(levelname)-8s %(name)-15s %(message)s', - 'datefmt': '%Y-%m-%d %H:%M:%S' - } - }, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - 'level': 'INFO', - 'formatter': 'detailed' - }, - 'file': { - 'class': 'logging.FileHandler', - 'filename': 'af_bot.log', - 'mode': 'a', - 'level': 'DEBUG', - 'formatter': 'detailed' - } - }, - 'loggers': { - '': { - 'handlers': ['console', 'file'], - 'level': 'DEBUG', - 'propagate': True - } - } - } - logging.config.dictConfig(LOG_CONFIG) - self.logger = logging.getLogger(__name__) - - def setup_handlers(self): - """Настройка обработчиков команд Telegram""" - @self.bot.message_handler(commands=['start', 'help', 'menu']) - def send_welcome(message): - self.show_main_menu(message) - - @self.bot.message_handler(func=lambda message: True) - def handle_text(message): - if message.text == '📊 Статистика': - self.show_stats(message) - elif message.text == '🔄 Создать анонс': - self.start_ibash(message) - elif message.text == '❌ Отменить задачи': - self.cancel_jobs(message) - elif message.text == '👤 Моя статистика': - self.show_user_stats(message) - else: - self.bot.reply_to(message, "Используйте меню для навигации") - - @self.bot.callback_query_handler(func=lambda call: True) - def handle_callback(call): - if call.data == 'ibash_all': - self.process_ibash(call.message, all_announcements=True) - elif call.data == 'ibash_new': - self.process_ibash(call.message, all_announcements=False) - elif call.data == 'cancel': - self.bot.edit_message_text( - "Действие отменено", - call.message.chat.id, - call.message.message_id - ) - self.show_main_menu(call.message) - - def show_main_menu(self, message): - """Отображение главного меню с кнопками""" - markup = types.ReplyKeyboardMarkup( - row_width=2, - resize_keyboard=True, - one_time_keyboard=False - ) - - buttons = [ - types.KeyboardButton('🔄 Создать анонс'), - types.KeyboardButton('📊 Статистика'), - types.KeyboardButton('👤 Моя статистика'), - types.KeyboardButton('❌ Отменить задачи') - ] - - markup.add(*buttons) - - self.bot.send_message( - message.chat.id, - "📱 *Главное меню*:\nВыберите действие:", - reply_markup=markup, - parse_mode='Markdown' - ) - - def show_stats(self, message): - """Отображение статистики системы""" - stats = self.monitoring.get_stats() - recent_jobs = self.monitoring.get_recent_jobs(5) - - stats_text = ( - "📈 *Статистика системы*\n\n" - f"• Всего задач: {stats['total_jobs']}\n" - f"• Успешных: {stats['successful_jobs']}\n" - f"• Неудачных: {stats['failed_jobs']}\n" - f"• Активных: {stats['active_jobs']}\n\n" - "⏱ *Последние задачи*:\n" - ) - - for job in recent_jobs: - status_icon = '✅' if job.get('status') == 'completed' else '❌' if job.get('status') == 'failed' else '🔄' - stats_text += f"{status_icon} {job.get('name', 'N/A')} ({job.get('user', 'system')})\n" - - self.bot.send_message( - message.chat.id, - stats_text, - parse_mode='Markdown' - ) - - def show_user_stats(self, message): - """Отображение статистики пользователя""" - user_id = message.from_user.id - username = message.from_user.username or message.from_user.first_name - user_stats = self.monitoring.get_user_stats(user_id) - - stats_text = ( - f"👤 *Ваша статистика* ({username})\n\n" - f"• Всего задач: {user_stats['total_jobs']}\n" - f"• Успешных: {user_stats['successful_jobs']}\n" - f"• Неудачных: {user_stats['failed_jobs']}\n" - f"• Процент успеха: {user_stats['successful_jobs'] / user_stats['total_jobs'] * 100:.1f}%" - if user_stats['total_jobs'] > 0 else "0%" - ) - - self.bot.send_message( - message.chat.id, - stats_text, - parse_mode='Markdown' - ) - - def start_ibash(self, message): - """Начало процесса создания анонсов с интерактивным меню""" - self.logger.info(f"Start ibash requested by {message.from_user.username}") - - markup = types.InlineKeyboardMarkup() - markup.row( - types.InlineKeyboardButton("Все анонсы", callback_data="ibash_all"), - types.InlineKeyboardButton("Только новые", callback_data="ibash_new") - ) - markup.row(types.InlineKeyboardButton("Отмена", callback_data="cancel")) - - self.bot.send_message( - message.chat.id, - "🔧 *Создание анонсов*\n\nВыберите тип обработки:", - reply_markup=markup, - parse_mode='Markdown' - ) - - def process_ibash(self, message, all_announcements=False): - """Обработка создания анонсов""" - user_id = message.from_user.id - username = message.from_user.username or message.from_user.first_name - - self.bot.send_chat_action(message.chat.id, 'typing') - - try: - # Загрузка данных - osheet = self.load_osheet(message) - start = self.get_sheet_data(osheet, 'Start', header=1) - - if not all_announcements: - start = start[start['STATE'] == False] # Только новые анонсы - - pack = self.get_sheet_data(osheet, 'SPORT', header=0, index_col='SPORT') - pack = pack[pack.index.notna()] - logos = self.get_sheet_data(osheet, 'TEAMS', header=0, index_col=[0, 1]) - - # Очистка старых задач - self.cleanup_old_jobs() - - # Создание задач - self.bot.send_chat_action(message.chat.id, 'record_video') - watch_list = [] - - for i, row in start.iterrows(): - dd = self.make_data_dict(row) - jobs = self.make_job_dicts(dd, pack, logos, message) - - for job in jobs: - if job: - job_data = { - 'job_id': job['uid'], - 'name': job['outname'], - 'user_id': user_id, - 'user': username, - 'status': 'started', - 'started_at': datetime.datetime.now() - } - self.monitoring.add_job(job_data) - watch_list.append(job) - - self.logger.info(f"В очереди {len(watch_list)} задач") - self.bot.send_message( - message.chat.id, - f"🚀 Запущено {len(watch_list)} задач на рендеринг", - parse_mode='Markdown' - ) - - # Отслеживание выполнения - self.track_jobs(message, watch_list, user_id) - - except Exception as e: - self.logger.exception("Ошибка в process_ibash") - self.bot.send_message( - message.chat.id, - f"❌ Ошибка при создании анонсов: {str(e)}", - parse_mode='Markdown' - ) - - def track_jobs(self, message, watch_list, user_id): - """Отслеживание выполнения задач""" - while watch_list: - self.bot.send_chat_action(message.chat.id, 'record_video') - sleep(25) - - for job in watch_list[:]: - try: - if self.PLACEHOLDER: - r = self._fake_get() - else: - r = requests.get(f"{self.config.nexrender_url}/{job['uid']}") - - if r.status_code == 200: - state = r.json()['state'] - if state == 'finished': - watch_list.remove(job) - self.monitoring.job_completed(job['uid'], True, user_id) - - self.logger.info(f"{job['outname']} готов, осталось {len(watch_list)}") - self.bot.send_message( - message.chat.id, - f"✅ *{job['outname']}* готов\nОсталось задач: {len(watch_list)}", - parse_mode='Markdown' - ) - - elif state == 'error': - watch_list.remove(job) - self.monitoring.job_completed(job['uid'], False, user_id) - - self.logger.warning(f"{job['outname']} завершился с ошибкой") - self.bot.send_message( - message.chat.id, - f"❌ *{job['outname']}* завершился с ошибкой", - parse_mode='Markdown' - ) - - except Exception as e: - self.logger.error(f"Ошибка проверки статуса задачи {job['uid']}: {e}") - - self.bot.send_message( - message.chat.id, - "🎉 Все задачи завершены!", - reply_markup=types.ReplyKeyboardRemove(), - parse_mode='Markdown' - ) - self.show_main_menu(message) - - def cleanup_old_jobs(self): - """Очистка завершенных задач""" - try: - r = requests.get(self.config.nexrender_url) - if r.status_code == 200: - jobs = r.json() - for job in jobs: - if job['state'] in ('finished', 'error'): - requests.delete(f"{self.config.nexrender_url}/{job['uid']}") - except Exception as e: - self.logger.error(f"Ошибка очистки старых задач: {e}") - - def cancel_jobs(self, message): - """Отмена всех активных задач""" - try: - r = requests.get(self.config.nexrender_url) - if r.status_code == 200: - jobs = r.json() - cancelled = 0 - - for job in jobs: - if job['state'] in ('queued', 'picked'): - requests.delete(f"{self.config.nexrender_url}/{job['uid']}") - cancelled += 1 - - self.logger.info(f"Отменено {cancelled} задач") - self.bot.send_message( - message.chat.id, - f"⏹ Отменено {cancelled} активных задач", - parse_mode='Markdown' - ) - else: - self.bot.send_message( - message.chat.id, - "⚠ Не удалось получить список задач для отмены", - parse_mode='Markdown' - ) - except Exception as e: - self.logger.error(f"Ошибка отмены задач: {e}") - self.bot.send_message( - message.chat.id, - f"❌ Ошибка при отмене задач: {str(e)}", - parse_mode='Markdown' - ) - - def load_osheet(self, message): - """Загрузка файла с Synology Drive""" - self.logger.debug('Получение данных') - try: - synd = SynologyDrive( - self.config.nas_user, - self.config.nas_pass, - self.config.nas_ip, - self.config.nas_port, - https=True, - dsm_version='7' - ) - - self.logger.debug(synd.login()) # Проверка сессии - try: - self.logger.debug('Попытка загрузки таблицы') - bio = synd.download_synology_office_file(self.config.nas_file) - self.logger.debug('Успешная загрузка') - return bio - except Exception as e: - self.logger.exception('Ошибка загрузки') - self.bot.send_message( - message.chat.id, - 'Не удалось скачать таблицу', - parse_mode='html' - ) - raise - except Exception as e: - self.logger.exception('Ошибка авторизации') - self.bot.send_message( - message.chat.id, - 'Не удалось авторизоваться', - parse_mode='html' - ) - raise - - def get_sheet_data(self, osheet, sheet_name, **kwargs): - """Получение данных из листа Excel""" - self.logger.debug(f'Чтение листа {sheet_name}') - try: - sheet = pd.read_excel(osheet, sheet_name=sheet_name, **kwargs) - self.logger.debug('Успешное чтение') - return sheet - except Exception as e: - self.logger.exception(f'Ошибка чтения листа {sheet_name}') - raise - - def get_sport_logo(self, sport, pack, message): - """Получение логотипа вида спорта""" - self.logger.info(f'Получение оформления для {sport}') - self.bot.send_message( - message.chat.id, - f'Ищем оформления для {sport}', - parse_mode='html' - ) - try: - d = pack.loc[sport]['LINK'] - self.logger.debug(d) - if pd.isna(d): - self.logger.warning(f'Нет LINK для вида спорта "{sport}"') - return '' - return d - except Exception as e: - self.logger.exception(f"Не удалось получить оформление для {sport}") - return '' - - def get_team_logo(self, team, sport, logos, message): - """Получение логотипа команды""" - self.logger.info(f'Получение логотипа {team}/{sport}') - self.bot.send_message( - message.chat.id, - f'Поиск логотипа {sport}-{team}', - parse_mode='html' - ) - try: - d = logos.loc[team, sport]['LINK'] - self.logger.debug(d) - return d - except KeyError: - self.logger.warning(f"Нет LINK для {team}/{sport}") - return '' - except Exception as e: - self.logger.exception(f"Ошибка при получении логотипа {sport}") - return '' - - def make_data_dict(self, ds): - """Создание словаря с данными""" - return { - 'date': ds['DATA'], - 'time': ds['TIME'], - 'channel': ds['CHANEL'], - 'sport': ds['SPORT'], - 'league': ds['LEAGUE'], - 'team_a': ds['TEAM A'], - 'team_b': ds['TEAM B'], - 'index': ds.name - } - - def unc2uri(self, unc): - """Преобразование UNC пути в URI""" - self.logger.debug('Преобразование пути') - try: - p = urlparse(unc) - if len(p.scheme) > 2 or not unc: - return unc - else: - p = PureWindowsPath(unc) - return p.as_uri() - except Exception as e: - self.logger.exception('Ошибка преобразования пути') - return unc - - def send_job(self, data, message): - """Отправка задачи на рендеринг""" - if self.PLACEHOLDER: - return self._send_job_dumb(data) - - payload = { - "template": { - "src": "file:///c:/users/virtVmix-2/Downloads/PackShot_Sborka_eng.aepx", - "composition": "pack", - "outputModule": "Start_h264", - "outputExt": "mp4" - }, - "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" - } - ] - }, - "assets": [] - } - - # Добавление данных в payload - self._add_data_to_payload(payload, data, message) - - url = self.config.nexrender_url - try: - r = requests.post(url, json=payload) - if r.status_code == 200: - res = r.json() - uid = res['uid'] - return {'uid': uid, 'outname': data['outfile_name']} - except Exception as e: - self.logger.exception('Ошибка отправки задачи') - return None - - def _add_data_to_payload(self, payload, data, message): - """Добавление данных в payload""" - # Добавление даты - self._add_date_data(payload, data, message) - - # Добавление времени - self._add_time_data(payload, data, message) - - # Добавление лиги - payload['assets'].append({ - "type": "data", - "layerName": "LEAGUE", - "property": "Source Text", - "value": data['league'] - }) - - # Добавление спорта - if data['sport']: - payload['assets'].append({ - "type": "data", - "layerName": "SPORT", - "property": "Source Text", - "value": data['sport'] - }) - - # Добавление команд и логотипов - self._add_team_data(payload, data, message, 'A') - self._add_team_data(payload, data, message, 'B') - - # Добавление оформления - if data['pack']: - payload['assets'].append({ - "src": data['pack'], - "type": "video", - "layerName": "TOP" - }) - - def _add_date_data(self, payload, data, message): - """Добавление данных о дате""" - if data['data'] == 'сегодня': - self._add_specific_date_style(payload, data, message, "105", [0, 5]) - elif data['data'] == 'завтра': - self._add_specific_date_style(payload, data, message, "115", [0, 25]) - elif len(data['data']) < 6: - self._add_specific_date_style(payload, data, message, "120", [0, 20]) - - payload['assets'].append({ - "type": "data", - "layerName": "DATA", - "property": "Source Text", - "value": data['data'] - }) - - def _add_specific_date_style(self, payload, data, message, font_size, anchor_point): - """Добавление стилей для конкретной даты""" - payload['assets'].extend([ - { - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": font_size - }, - { - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchor_point - } - ]) - self.logger.info(f'Для "{data["data"]}" шрифт установлен {font_size}') - self.bot.send_message( - message.chat.id, - f'Для "{data["data"]}" размер шрифта установлен {font_size}', - parse_mode='html' - ) - self.logger.info(f'Сдвиг "{data["data"]}" на {anchor_point} пикселей') - self.bot.send_message( - message.chat.id, - f'Сдвигаем "{data["data"]}" на {anchor_point} пикселей', - parse_mode='html' - ) - - def _add_time_data(self, payload, data, message): - """Добавление данных о времени""" - if len(data['time_h']) < 2: - anchor_point = [40, 0] - for layer in ["TIME_H", "TIME_M", "TIME"]: - payload['assets'].append({ - "layerName": layer, - "property": "transform.anchorPoint", - "type": "data", - "value": anchor_point - }) - self.logger.info(f'Сдвиг "{data["time_h"]}:{data["time_m"]}" на {anchor_point} пикселей') - self.bot.send_message( - message.chat.id, - f'Сдвигаем "{data["time_h"]}:{data["time_m"]}" на {anchor_point} пикседей', - parse_mode='html' - ) - - payload['assets'].extend([ - { - "type": "data", - "layerName": "TIME_H", - "property": "Source Text", - "value": data['time_h'] - }, - { - "type": "data", - "layerName": "TIME_M", - "property": "Source Text", - "value": data['time_m'] - } - ]) - - def _add_team_data(self, payload, data, message, team): - """Добавление данных о команде""" - team_key = f'team_{team.lower()}' - if data[team_key]: - payload['assets'].append({ - "type": "data", - "layerName": f"TEAM_{team}", - "property": "Source Text", - "value": data[team_key] - }) - - logo_key = f'{team_key}_logo' - if data[logo_key]: - payload['assets'].append({ - "src": data[logo_key], - "type": "image", - "layerName": f"TEAM_{team}_LOGO" - }) - - logo_res_key = f'{team_key}_logo_res' - if data.get(logo_res_key): - payload['assets'].append({ - "property": "scale", - "type": "data", - "expression": f"if (width > height) {{max_size = width;}} else {{max_size = height;}} var real_size = {data[logo_res_key][0]}/max_size*100;[real_size,real_size]", - "layerName": f"TEAM_{team}_LOGO" - }) - self.logger.info(f'{data[team_key]} логотип изменен до {data[logo_res_key][0]}') - self.bot.send_message( - message.chat.id, - f'{data[team_key]} масштабирован под {data[logo_res_key][0]} пикселей', - parse_mode='html' - ) - - def make_job_dicts(self, dd, pack, logos, message): - """Создание задач рендеринга""" - self.logger.debug('Начало создания имени') - 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]}" - d = dd['date'].split('.') - data['data'] = f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(dd['date'], datetime.date): - fn += f"{dd['date'].year}{dd['date'].month:02}{dd['date'].day:02}" - data['data'] = f"{dd['date'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][dd['date'].month]}" - - # Вид спорта и оформление - if dd['sport'] != empty_sport: - fn += f"_{dd['sport']}" - data['sport'] = dd['sport'] - data['pack'] = self.unc2uri(self.get_sport_logo(dd['sport'], pack, message)) - else: - data['sport'] = '' - data['pack'] = '' - - # Лига - if dd["league"][-1] == '.': - self.logger.debug('Точка в названии лиги!') - fn += f'_{dd["league"][:-1]}' - data['league'] = dd['league'][:-1] - else: - data['league'] = dd['league'] - fn += f'_{dd["league"]}' - - # Команды - self._process_team_data(dd, data, fn, 'A', logos, message) - self._process_team_data(dd, data, fn, 'B', logos, message) - - # Канал - if not pd.isna(dd['channel']): - self.logger.debug('Канал установлен ' + dd['channel']) - fn += f"_{dd['channel']}" - - # Финальное форматирование имени файла - fn = translit(fn, reversed=True) - fn = fn.replace(' ', '-').replace("'", '') - data['outfile_name'] = fn - - # Время - if isinstance(dd['time'], str): - t = dd['time'].split(':') - 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) - - self.logger.debug('Время ' + data['time_h'] + ':' + data['time_m']) - self.logger.debug("Конец создания имени") - - # Создание задач - watch_list = [] - watch_list.append(self.send_job(data, message)) - - if True: # TODO: Заменить на условие, если нужно - data['data'] = 'сегодня' - data['outfile_name'] = fn + '_Today' - watch_list.append(self.send_job(data, message)) - data['data'] = 'завтра' - data['outfile_name'] = fn + '_Tomorrow' - watch_list.append(self.send_job(data, message)) - - pprint(watch_list) - return list(filter(None, watch_list)) - - def _process_team_data(self, dd, data, fn, team, logos, message): - """Обработка данных команды""" - team_key = f'team_{team.lower()}' - if pd.isna(dd[f'TEAM {team}']): - self.logger.info(f'Нет команды {team}') - self.bot.send_message( - message.chat.id, - f'Нет команды {team}', - parse_mode='html' - ) - data[team_key] = '' - data[f'{team_key}_logo'] = '' - data[f'{team_key}_logo_res'] = '' - else: - name = dd[f'TEAM {team}'].split('#') - fn += f"_{name[0]}" - data[f'{team_key}_logo_res'] = name[2:] - data[team_key] = name[0] - data[f'{team_key}_logo'] = self.unc2uri( - self.get_team_logo(dd[f'TEAM {team}'], dd['sport'], logos, message) - ) - -def run_flask(): - """Запуск Flask сервера для панели мониторинга""" - flask_app.run(host='0.0.0.0', port=5000) - -@flask_app.route('/admin/stats') -def admin_stats(): - """API endpoint для получения статистики""" - stats = monitoring.get_stats() - return jsonify({ - 'status': 'success', - 'data': stats - }) - -@flask_app.route('/admin/jobs') -def admin_jobs(): - """API endpoint для получения списка задач""" - jobs = monitoring.get_recent_jobs(50) - return jsonify({ - 'status': 'success', - 'data': jobs - }) - -@flask_app.route('/admin/users') -def admin_users(): - """API endpoint для получения статистики по пользователям""" - stats = monitoring.get_stats() - return jsonify({ - 'status': 'success', - 'data': stats.get('users', {}) - }) - -if __name__ == '__main__': - try: - # Проверяем наличие файла окружения - if not os.path.exists('AF_environment.env'): - raise FileNotFoundError( - "Файл окружения AF_environment.env не найден. " - "Создайте его по образцу AF_environment.example.env" - ) - - # Инициализация компонентов - config = Config() - monitoring = Monitoring() - job_manager = JobManager(config, monitoring) - - # Запуск Flask в отдельном потоке - flask_thread = threading.Thread(target=run_flask, daemon=True) - flask_thread.start() - - # Запуск Telegram бота - job_manager.bot.infinity_polling() - - # except FileNotFoundError \ No newline at end of file diff --git a/AF_script_test_5.py b/AF_script_test_5.py deleted file mode 100644 index 3c5b754..0000000 --- a/AF_script_test_5.py +++ /dev/null @@ -1,716 +0,0 @@ -import os -from dotenv import load_dotenv -import logging -import logging.config -from pprint import pprint -import pandas as pd -from transliterate import translit -import requests -from time import sleep -import datetime -import sys -from urllib.parse import urlparse -from pathlib import PureWindowsPath -import telebot -from synology_drive_api.drive import SynologyDrive - -# Загрузка переменных окружения из файла -load_dotenv('AF_environment.env') - -class Config: - """Класс для хранения конфигурации""" - def __init__(self): - # Обязательные переменные окружения - self.nas_user = os.getenv('NAS_USER') - self.nas_pass = os.getenv('NAS_PASS') - self.nas_ip = os.getenv('NAS_IP') - self.nas_port = os.getenv('NAS_PORT') - self.nas_file = os.getenv('NAS_FILE') - self.token = os.getenv('TELEGRAM_TOKEN') - self.group_chat = os.getenv('TELEGRAM_GROUP_CHAT') - self.nexrender_url = os.getenv('NEXRENDER_URL') - - # Валидация конфигурации - self._validate_config() - - def _validate_config(self): - """Проверяет, что все обязательные переменные окружения установлены""" - missing_vars = [] - for var, value in vars(self).items(): - if value is None: - missing_vars.append(var.upper()) - - if missing_vars: - raise ValueError( - f"Отсутствуют обязательные переменные окружения: {', '.join(missing_vars)}. " - "Пожалуйста, проверьте файл AF_environment.env" - ) - -class JobManager: - """Класс для управления задачами рендеринга""" - def __init__(self, config): - self.config = config - self.bot = telebot.TeleBot(config.token) - self.PLACEHOLDER = sys.platform == 'win32' - - if self.PLACEHOLDER: - self._init_placeholders() - - def _init_placeholders(self): - """Инициализация заглушек для тестирования""" - 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']} - return None - - class FakeResp: - def __init__(self, state='queued', *args, **kwargs): - self.state = state - self.status_code = 200 - - def json(self): - return {'state': self.state} - - def fake_get(*args, **kwargs): - rand = random() - if rand < 0.8: - return FakeResp() - elif rand < 0.95: - return FakeResp('finished') - else: - return FakeResp('error') - - self._send_job_real = self.send_job - self.send_job = send_job_dumb - self._fake_get = fake_get - - def setup_logging(self): - """Настройка логирования""" - LOG_CONFIG = { - 'version': 1, - 'handlers': { - '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' - }, - }, - 'loggers': { - __name__: { - 'handlers': ['console', 'file'], - 'level': 'DEBUG' - } - }, - 'formatters': { - '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) - self.logger = logging.getLogger(__name__) - telebot.logger.addHandler(self.logger.handlers[0]) - - def load_osheet(self, message): - """Загрузка файла с Synology Drive""" - self.logger.debug('Получение данных') - try: - synd = SynologyDrive( - self.config.nas_user, - self.config.nas_pass, - self.config.nas_ip, - self.config.nas_port, - https=True, - dsm_version='7' - ) - - self.logger.debug(synd.login()) # Проверка сессии - try: - self.logger.debug('Попытка загрузки таблицы') - bio = synd.download_synology_office_file(self.config.nas_file) - self.logger.debug('Успешная загрузка') - return bio - except Exception as e: - self.logger.exception('Ошибка загрузки') - self.bot.send_message( - message.chat.id, - 'Не удалось скачать таблицу', - parse_mode='html' - ) - raise - except Exception as e: - self.logger.exception('Ошибка авторизации') - self.bot.send_message( - message.chat.id, - 'Не удалось авторизоваться', - parse_mode='html' - ) - raise - - def get_sheet_data(self, osheet, sheet_name, **kwargs): - """Получение данных из листа Excel""" - self.logger.debug(f'Чтение листа {sheet_name}') - try: - sheet = pd.read_excel(osheet, sheet_name=sheet_name, **kwargs) - self.logger.debug('Успешное чтение') - return sheet - except Exception as e: - self.logger.exception(f'Ошибка чтения листа {sheet_name}') - raise - - def get_sport_logo(self, sport, pack, message): - """Получение логотипа вида спорта""" - self.logger.info(f'Получение оформления для {sport}') - self.bot.send_message( - message.chat.id, - f'Ищем оформления для {sport}', - parse_mode='html' - ) - try: - d = pack.loc[sport]['LINK'] - self.logger.debug(d) - if pd.isna(d): - self.logger.warning(f'Нет LINK для вида спорта "{sport}"') - return '' - return d - except Exception as e: - self.logger.exception(f"Не удалось получить оформление для {sport}") - return '' - - def get_team_logo(self, team, sport, logos, message): - """Получение логотипа команды""" - self.logger.info(f'Получение логотипа {team}/{sport}') - self.bot.send_message( - message.chat.id, - f'Поиск логотипа {sport}-{team}', - parse_mode='html' - ) - try: - d = logos.loc[team, sport]['LINK'] - self.logger.debug(d) - return d - except KeyError: - self.logger.warning(f"Нет LINK для {team}/{sport}") - return '' - except Exception as e: - self.logger.exception(f"Ошибка при получении логотипа {sport}") - return '' - - def make_data_dict(self, ds): - """Создание словаря с данными""" - return { - 'date': ds['DATA'], - 'time': ds['TIME'], - 'channel': ds['CHANEL'], - 'sport': ds['SPORT'], - 'league': ds['LEAGUE'], - 'TEAM A': ds['TEAM A'], - 'TEAM B': ds['TEAM B'], - 'index': ds.name - } - - def unc2uri(self, unc): - """Преобразование UNC пути в URI""" - self.logger.debug('Преобразование пути') - try: - p = urlparse(unc) - if len(p.scheme) > 2 or not unc: - return unc - else: - p = PureWindowsPath(unc) - return p.as_uri() - except Exception as e: - self.logger.exception('Ошибка преобразования пути') - return unc - - def send_job(self, data, message): - """Отправка задачи на рендеринг""" - if self.PLACEHOLDER: - return self.send_job_dumb(data) - - payload = { - "template": { - "src": "file:///c:/users/virtVmix-2/Downloads/PackShot_Sborka_eng.aepx", - "composition": "pack", - "outputModule": "Start_h264", - "outputExt": "mp4" - }, - "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" - } - ] - }, - "assets": [] - } - - # Добавление данных в payload - self._add_data_to_payload(payload, data, message) - - url = self.config.nexrender_url - try: - r = requests.post(url, json=payload) - if r.status_code == 200: - res = r.json() - uid = res['uid'] - return {'uid': uid, 'outname': data['outfile_name']} - except Exception as e: - self.logger.exception('Ошибка отправки задачи') - return None - - def _add_data_to_payload(self, payload, data, message): - """Добавление данных в payload""" - # Добавление даты - self._add_date_data(payload, data, message) - - # Добавление времени - self._add_time_data(payload, data, message) - - # Добавление лиги - payload['assets'].append({ - "type": "data", - "layerName": "LEAGUE", - "property": "Source Text", - "value": data['league'] - }) - - # Добавление спорта - if data['sport']: - payload['assets'].append({ - "type": "data", - "layerName": "SPORT", - "property": "Source Text", - "value": data['sport'] - }) - - # Добавление команд и логотипов - self._add_team_data(payload, data, message, 'A') - self._add_team_data(payload, data, message, 'B') - - # Добавление оформления - if data['pack']: - payload['assets'].append({ - "src": data['pack'], - "type": "video", - "layerName": "TOP" - }) - - def _add_date_data(self, payload, data, message): - """Добавление данных о дате""" - if data['data'] == 'сегодня': - self._add_specific_date_style(payload, data, message, "105", [0, 5]) - elif data['data'] == 'завтра': - self._add_specific_date_style(payload, data, message, "115", [0, 25]) - elif len(data['data']) < 6: - self._add_specific_date_style(payload, data, message, "120", [0, 20]) - - payload['assets'].append({ - "type": "data", - "layerName": "DATA", - "property": "Source Text", - "value": data['data'] - }) - - def _add_specific_date_style(self, payload, data, message, font_size, anchor_point): - """Добавление стилей для конкретной даты""" - payload['assets'].extend([ - { - "layerName": "DATA", - "property": "Source Text.fontSize", - "type": "data", - "value": font_size - }, - { - "layerName": "DATA", - "property": "transform.anchorPoint", - "type": "data", - "value": anchor_point - } - ]) - self.logger.info(f'Для "{data["data"]}" шрифт установлен {font_size}') - self.bot.send_message( - message.chat.id, - f'Для "{data["data"]}" размер шрифта установлен {font_size}', - parse_mode='html' - ) - self.logger.info(f'Сдвиг "{data["data"]}" на {anchor_point} пикселей') - self.bot.send_message( - message.chat.id, - f'Сдвигаем "{data["data"]}" на {anchor_point} пикселей', - parse_mode='html' - ) - - def _add_time_data(self, payload, data, message): - """Добавление данных о времени""" - if len(data['time_h']) < 2: - anchor_point = [40, 0] - for layer in ["TIME_H", "TIME_M", "TIME"]: - payload['assets'].append({ - "layerName": layer, - "property": "transform.anchorPoint", - "type": "data", - "value": anchor_point - }) - self.logger.info(f'Сдвиг "{data["time_h"]}:{data["time_m"]}" на {anchor_point} пикселей') - self.bot.send_message( - message.chat.id, - f'Сдвигаем "{data["time_h"]}:{data["time_m"]}" на {anchor_point} пикседей', - parse_mode='html' - ) - - payload['assets'].extend([ - { - "type": "data", - "layerName": "TIME_H", - "property": "Source Text", - "value": data['time_h'] - }, - { - "type": "data", - "layerName": "TIME_M", - "property": "Source Text", - "value": data['time_m'] - } - ]) - - def _add_team_data(self, payload, data, message, team): - """Добавление данных о команде""" - team_key = f'team_{team.lower()}' - if data[team_key]: - payload['assets'].append({ - "type": "data", - "layerName": f"TEAM_{team}", - "property": "Source Text", - "value": data[team_key] - }) - - logo_key = f'{team_key}_logo' - if data[logo_key]: - payload['assets'].append({ - "src": data[logo_key], - "type": "image", - "layerName": f"TEAM_{team}_LOGO" - }) - - logo_res_key = f'{team_key}_logo_res' - if data.get(logo_res_key): - payload['assets'].append({ - "property": "scale", - "type": "data", - "expression": f"if (width > height) {{max_size = width;}} else {{max_size = height;}} var real_size = {data[logo_res_key][0]}/max_size*100;[real_size,real_size]", - "layerName": f"TEAM_{team}_LOGO" - }) - self.logger.info(f'{data[team_key]} логотип изменен до {data[logo_res_key][0]}') - self.bot.send_message( - message.chat.id, - f'{data[team_key]} масштабирован под {data[logo_res_key][0]} пикселей', - parse_mode='html' - ) - - def make_job_dicts(self, dd, pack, logos, message): - """Создание задач рендеринга""" - self.logger.debug('Начало создания имени') - 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]}" - d = dd['date'].split('.') - data['data'] = f"{int(d[0])} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][int(d[1])]}" - elif isinstance(dd['date'], datetime.date): - fn += f"{dd['date'].year}{dd['date'].month:02}{dd['date'].day:02}" - data['data'] = f"{dd['date'].day} {['','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'][dd['date'].month]}" - - # Вид спорта и оформление - if dd['sport'] != empty_sport: - fn += f"_{dd['sport']}" - data['sport'] = dd['sport'] - data['pack'] = self.unc2uri(self.get_sport_logo(dd['sport'], pack, message)) - else: - data['sport'] = '' - data['pack'] = '' - - # Лига - if dd["league"][-1] == '.': - self.logger.debug('Точка в названии лиги!') - fn += f'_{dd["league"][:-1]}' - data['league'] = dd['league'][:-1] - else: - data['league'] = dd['league'] - fn += f'_{dd["league"]}' - - # Команды - self._process_team_data(dd, data, fn, 'A', logos, message) - self._process_team_data(dd, data, fn, 'B', logos, message) - - # Канал - if not pd.isna(dd['channel']): - self.logger.debug('Канал установлен ' + dd['channel']) - fn += f"_{dd['channel']}" - - # Финальное форматирование имени файла - fn = translit(fn, reversed=True) - fn = fn.replace(' ', '-').replace("'", '') - data['outfile_name'] = fn - - # Время - if isinstance(dd['time'], str): - t = dd['time'].split(':') - 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) - - self.logger.debug('Время ' + data['time_h'] + ':' + data['time_m']) - self.logger.debug("Конец создания имени") - - # Создание задач - watch_list = [] - watch_list.append(self.send_job(data, message)) - - if True: # TODO: Заменить на условие, если нужно - data['data'] = 'сегодня' - data['outfile_name'] = fn + '_Today' - watch_list.append(self.send_job(data, message)) - data['data'] = 'завтра' - data['outfile_name'] = fn + '_Tomorrow' - watch_list.append(self.send_job(data, message)) - - pprint(watch_list) - return list(filter(None, watch_list)) - - def _process_team_data(self, dd, data, fn, team, logos, message): - """Обработка данных команды""" - team_key = f'team_{team.lower()}' - if pd.isna(dd[f'TEAM {team}']): - self.logger.info(f'Нет команды {team}') - self.bot.send_message( - message.chat.id, - f'Нет команды {team}', - parse_mode='html' - ) - data[team_key] = '' - data[f'{team_key}_logo'] = '' - data[f'{team_key}_logo_res'] = '' - else: - name = dd[f'TEAM {team}'].split('#') - fn += f"_{name[0]}" - data[f'{team_key}_logo_res'] = name[2:] - data[team_key] = name[0] - data[f'{team_key}_logo'] = self.unc2uri( - self.get_team_logo(dd[f'TEAM {team}'], dd['sport'], logos, message) - ) - - def run(self): - """Запуск бота""" - @self.bot.message_handler(commands=['help', 'start']) - def send_welcome(message): - self.bot.send_chat_action(message.chat.id, 'typing') - user = f" {message.from_user.username}" if message.from_user.username else '!' - sleep(1) - self.bot.reply_to( - message, - f"Привет{user}\nЯ помогу тебе сделать Анонсы!\nВот список команд которые я могу выполнить:\n/ибаш - наибашу обработку и рендер!\n/харе - остановит нах!" - ) - - @self.bot.message_handler(commands=['чёкак', 'status']) - def status(message): - self.logger.info(f'Статус запрошен {message.from_user.username}') - try: - r = requests.get(self.config.nexrender_url) - if r.status_code == 200: - jobs = r.json() - s = [{'uid': i['uid'], 'state': i['state']} for i in jobs] - queued = sum(1 for job in s if job['state'] in ('queued', 'picked')) - - if s: - self.logger.info(f"{queued} в очереди") - self.bot.send_message( - message.chat.id, - f"В очереди {queued}" - ) - else: - self.logger.info("Нет задач в очереди") - self.bot.send_message( - message.chat.id, - "Нет задач в очереди" - ) - except Exception as e: - self.logger.exception("Ошибка получения статуса") - self.bot.send_message( - message.chat.id, - "Ошибка получения статуса" - ) - - @self.bot.message_handler(commands=['харе', 'stop']) - def stop(message): - try: - r = requests.get(self.config.nexrender_url) - if r.status_code == 200: - jobs = r.json() - s = [{'uid': i['uid'], 'state': i['state']} for i in jobs] - cancelled = 0 - - if s: - for job in s: - requests.delete(f"{self.config.nexrender_url}/{job['uid']}") - cancelled += 1 - - self.logger.info(f"Отменено {cancelled} задач пользователем {message.from_user.username}") - self.bot.send_message( - message.chat.id, - f"Отменено {cancelled}" - ) - else: - self.logger.info(f"{message.from_user.username} запросил отмену, но нет задач для отмены") - self.bot.send_message( - message.chat.id, - "Нет задач для отмены" - ) - except Exception as e: - self.logger.exception("Ошибка отмены задач") - self.bot.send_message( - message.chat.id, - "Ошибка отмены задач" - ) - - @self.bot.message_handler(commands=['ибаш', 'ibash']) - def ibash(message): - self.logger.info(f'Запуск задач для {message.from_user.username}') - self.bot.send_chat_action(message.chat.id, 'typing') - - user = message.from_user.username if message.from_user.username else '!' - self.bot.send_message( - message.chat.id, - f"Ну что ж {user}, давай попробуем \nНАИБАШИТЬ!!!", - parse_mode='html' - ) - - self.bot.send_chat_action(message.chat.id, 'upload_document') - - try: - osheet = self.load_osheet(message) - start = self.get_sheet_data(osheet, 'Start', header=1) - start = start[start['STATE'] == False] # Проверка "первая" - pack = self.get_sheet_data(osheet, 'SPORT', header=0, index_col='SPORT') - pack = pack[pack.index.notna()] - logos = self.get_sheet_data(osheet, 'TEAMS', header=0, index_col=[0, 1]) - - # Очистка старых задач - try: - r = requests.get(self.config.nexrender_url) - if r.status_code == 200: - jobs = r.json() - for job in jobs: - if job['state'] in ('finished', 'error'): - requests.delete(f"{self.config.nexrender_url}/{job['uid']}") - except Exception as e: - self.logger.exception("Ошибка очистки старых задач") - - self.bot.send_chat_action(message.chat.id, 'record_video') - - watch_list = [] - for i, row in start.iterrows(): - dd = self.make_data_dict(row) - watch_list += self.make_job_dicts(dd, pack, logos, message) - - self.logger.info(f"В очереди {len(watch_list)} задач") - self.bot.send_message( - message.chat.id, - f"В очереди {len(watch_list)} задач" - ) - - while watch_list: - self.bot.send_chat_action(message.chat.id, 'record_video') - sleep(25) - - for job in watch_list[:]: # Копия списка для итерации - try: - if self.PLACEHOLDER: - r = self._fake_get() - else: - r = requests.get(f"{self.config.nexrender_url}/{job['uid']}") - - if r.status_code == 200: - state = r.json()['state'] - if state == 'finished': - watch_list.remove(job) - self.logger.info(f"{job['outname']}, {state}, {len(watch_list)} осталось") - self.bot.send_message( - message.chat.id, - f"{job['outname']}, готов, {len(watch_list)} осталось выполнить", - parse_mode='html' - ) - elif state == 'error': - watch_list.remove(job) - self.logger.warning(f"{job}, {state}, {len(watch_list)} осталось") - self.bot.send_message( - message.chat.id, - f"!!!{job}, {state}, {len(watch_list)} осталось выполнить", - parse_mode='html' - ) - except Exception as e: - self.logger.exception(f"Ошибка проверки статуса задачи {job['uid']}") - - self.bot.send_message(message.chat.id, 'Пойду спать :)') - - except Exception as e: - self.logger.exception("Ошибка выполнения команды ибаш") - self.bot.send_message( - message.chat.id, - "Произошла ошибка при обработке команды" - ) - - self.logger.info('Запуск бота') - self.bot.infinity_polling() - self.logger.info('Завершение работы бота') - -if __name__ == '__main__': - try: - # Проверяем, что файл окружения существует - if not os.path.exists('AF_environment.env'): - raise FileNotFoundError( - "Файл окружения AF_environment.env не найден. " - ) - - config = Config() - job_manager = JobManager(config) - job_manager.setup_logging() - job_manager.run() - - except FileNotFoundError as e: - logging.error(str(e)) - print(str(e)) - sys.exit(1) - except ValueError as e: - logging.error(f"Ошибка конфигурации: {e}") - print(f"Ошибка конфигурации: {e}") - sys.exit(1) - except Exception as e: - logging.error(f"Неожиданная ошибка: {e}", exc_info=True) - print(f"Неожиданная ошибка: {e}") - sys.exit(1) \ No newline at end of file