diff --git a/config/user.json b/config/user.json index 60b7811..df41643 100644 --- a/config/user.json +++ b/config/user.json @@ -1,9 +1,5 @@ [ - { - "tw_acc_pseudo": "foufure13", - "tw_acc_token": "oauth:nmpw9bypx9emht7hn5z3vlgbwitaz5", - "charactere": "Kappa" - }, + { "tw_acc_pseudo": "SnowLunaSoft", "tw_acc_token": "oauth:f9rt5mvhtjx3naiz1or9x7ims8ssm6", @@ -11,7 +7,7 @@ }, { "tw_acc_pseudo": "exoticnaturees", - "tw_acc_token": "oauth:57ht6937k5du8bex534eetd1epydvg", + "tw_acc_token": "oauth:9102fncctpjc44jxfkdvhzaywobhhi", "charactere": "Kappa" } diff --git a/debug/record_stream.py b/debug/record_stream.py new file mode 100644 index 0000000..829b30d --- /dev/null +++ b/debug/record_stream.py @@ -0,0 +1,238 @@ +import os +import signal +import sys +import argparse +import json +import time +import pprint +import random +import requests +import datetime +import glob +import threading +import traceback +# import keyboard +from pynput import keyboard +from threading import Thread, Semaphore +from streamlink import Streamlink +from fake_useragent import UserAgent +from rich.console import Console +from rich.live import Live +from rich.prompt import Prompt +from rich.spinner import Spinner +from rich.table import Table +from rich.text import Text +import subprocess +import pty + +console = Console() + +def hprint(color, texte): + timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") + console.print("[bold "+color+"] ["+timestamp+"] "+texte+" [/bold "+color+"]") + +def del_file(dossier, file): + motif = os.path.join(dossier, file) + for file in glob.glob(motif): + os.remove(file) + hprint("",f"file deleted : {file}") + +def get_value_json(var_name, config): + return config.get(var_name) + +def get_value_json_list(index, key, json_data): + try: + return json_data[index][key] + except (IndexError, KeyError, TypeError): + return None + + # Fonction pour obtenir l'heure actuelle sous forme de chaîne +def get_current_time(): + current_time = time.time() + return time.strftime('%H:%M:%S', time.localtime(current_time)) + # now = datetime.now() + # return now.strftime("%H:%M") + + + + + + + + + +class RecordTwitch: + def __init__(self, channel_name, record_time): + self.channel_name = channel_name + self.request_count = 0 + self.channel_url = "https://www.twitch.tv/" + self.channel_name + self.active_threads = 0 + self.record_time = record_time + self.max_timerecordfile = 60 + self.running = False + self.script_name = "twitch_record" + if (self.record_time == -1): + self.record_time = 9999 + + + def hprint(self,color, texte): + timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") + console.print("[bold "+color+"] ["+timestamp+"] ("+self.script_name+") "+texte+" [/bold "+color+"]") + + def stop(self, signum, frame): + print("\STOPING...") + self.running = False + + def del_mp3(self, dossier): + motif = os.path.join(dossier, '*.mp3') + for file in glob.glob(motif): + os.remove(file) + self.hprint("",f"file deleted : {file}") + + def clear_diretory(self, dir_inrecord="in_record", dir_record="record"): + # self.hprint('green', 'clear_diretory start') + if os.path.exists(dir_inrecord) and os.path.exists(dir_record): + self.hprint('green', f"dir {dir_inrecord} and {dir_record} exist clearing") + self.del_mp3(dir_inrecord) + self.del_mp3(dir_record) + + + + def create_session(self): + # Session creating for request + self.ua = UserAgent() + self.session = Streamlink() + self.session.set_option("http-headers", { + "Accept-Language": "en-US,en;q=0.5", + "Connection": "keep-alive", + "DNT": "1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": self.ua.random, + "Client-ID": "your_client_id", # Replace with your actual Client-ID + "Referer": "https://www.google.com/" + }) + + def get_url(self): + hprint("green","try to get url") + url = "" + self.create_session() + try: + streams = self.session.streams(self.channel_url) + url = streams['audio_only'].url if 'audio_only' in streams else streams['worst'].url + hprint("cyan","url generate : " + url) + except Exception as e: + hprint("red","Error on get url : "+str(e)) + # traceback.print_exc() # Affiche les détails de l'erreur + pass + return url + + + + def loop_run(self, intervalle): + + try: + while True: + self.hprint("green","Start scan files...") + self.verif_record_move() + # self.hprint("yellow",f"wait {intervalle}s for next scan file completed.") + time.sleep(intervalle) + except KeyboardInterrupt: + self.hprint("red","STOP LOOP.") + + + def verif_record_move(self, dir_inrecord="in_record", dir_record="record"): + if not os.path.exists(dir_record): + os.makedirs(dir_record) + + fichiers = [f for f in os.listdir(dir_inrecord) if os.path.isfile(os.path.join(dir_inrecord, f))] + if len(fichiers) > 1: + # sort file + sort_file = sorted(fichiers, key=lambda x: int(x.split('_')[-1].split('.')[0])) + fileto_move = sort_file[0] + + chemin_source = os.path.join(dir_inrecord, fileto_move) + chemin_destination = os.path.join(dir_record, fileto_move) + + # move file + shutil.move(chemin_source, chemin_destination) + self.hprint("green",f"File moved: {fileto_move}") + # else: + # self.hprint("yellow","Not enough files to compare.") + + def compteur(self ): + seconds = 0 + loop = 0 + self.running = True + while True: + time.sleep(1) # Attend une seconde + # self.hprint("magenta", f"self.running = {self.running}") + if (seconds < 10): + print(f"\033[94mRecording time: 0{seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + else: + print(f"\033[94mRecording time: {seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + + seconds += 1 + if seconds == self.max_timerecordfile: + loop +=1 + seconds = 0 # Réinitialise le compteur après 60 seconds + + + def record_audio(self): + output_directory = "record" + in_record_directory = "in_record" + os.makedirs(output_directory, exist_ok=True) + os.makedirs(in_record_directory, exist_ok=True) + + stream_url = self.get_url() + if not stream_url: + console.print("[bold red]Impossible de récupérer l'URL du flux[/bold red]") + return + + timestamp_complet = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + timestamp = datetime.datetime.now().strftime("%Y-%m-%d") + + output_file_path = os.path.join(in_record_directory, f"{timestamp}_%03d.mp3") + + self.hprint("green", f"start record") + thread_compteur = Thread(target=self.compteur, daemon=True) + thread_compteur.start() + + command = ['ffmpeg','-i', stream_url,'-vn','-acodec','libmp3lame','-ar','44100','-ac','2','-map','0:a','-f','segment','-segment_time',str(self.max_timerecordfile),'-segment_format','mp3',output_file_path,'-loglevel', 'error'] + # self.hprint('yellow',str(command)) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + output, error = process.communicate() + + # thread_compteur.do_run = False + thread_compteur.join() + + + def main(self): + self.running = True + self.clear_diretory() + record_thread = Thread(target=self.record_audio) + record_thread.start() + # record_thread.join() # Wait for the recording to finish + loop_run = Thread(target=self.loop_run, args=(10,), daemon=True) + loop_run.start() + loop_run.join() # Wait for the recording to finish + + console.print("[bold magenta]Enregistrement terminé, le programme va se terminer.[/bold magenta]") + + def start_recording(self): + """Lance main_record_twitch dans un thread pour ne pas bloquer le code principal.""" + self.thread = threading.Thread(target=self.main) + self.thread.start() # Démarre l'enregistrement dans un thread séparé + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-recordtime', type=int, default=60, help='Time to record') + parser.add_argument('-twitchname', type=str, required=True, help='Twitch channel name') + args = parser.parse_args() + + bot = RecordTwitch(channel_name=args.twitchname, record_time=args.recordtime) + try: + bot.main() + except KeyboardInterrupt: + console.print("[bold red]ERREUR RECORDING[/bold red]") diff --git a/debug/record_stream2.py b/debug/record_stream2.py new file mode 100644 index 0000000..e10da98 --- /dev/null +++ b/debug/record_stream2.py @@ -0,0 +1,232 @@ +import os +import signal +import sys +import shutil +import argparse +import json +import time +import pprint +import random +import requests +import datetime +import glob +import threading +import traceback +# import keyboard +from pynput import keyboard +from threading import Thread, Semaphore +from streamlink import Streamlink +from fake_useragent import UserAgent +from rich.console import Console +from rich.live import Live +from rich.prompt import Prompt +from rich.spinner import Spinner +from rich.table import Table +from rich.text import Text +import subprocess +import pty + +console = Console() + +def hprint(color, texte): + timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") + console.print("[bold "+color+"] ["+timestamp+"] "+texte+" [/bold "+color+"]") + +def del_file(dossier, file): + motif = os.path.join(dossier, file) + for file in glob.glob(motif): + os.remove(file) + hprint("",f"file deleted : {file}") + +def get_value_json(var_name, config): + return config.get(var_name) + +def get_value_json_list(index, key, json_data): + try: + return json_data[index][key] + except (IndexError, KeyError, TypeError): + return None + + # Fonction pour obtenir l'heure actuelle sous forme de chaîne +def get_current_time(): + current_time = time.time() + return time.strftime('%H:%M:%S', time.localtime(current_time)) + # now = datetime.now() + # return now.strftime("%H:%M") + + + + + + + + + +class RecordTwitch: + def __init__(self, channel_name, record_time): + self.channel_name = channel_name + self.channel_url = "https://www.twitch.tv/" + self.channel_name + self.record_time = record_time + self.max_timerecordfile = 60 + self.running = True + self.script_name = "twitch_record" + if (self.record_time == -1): + self.record_time = 9999 + + + def hprint(self,color, texte): + timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") + console.print("[bold "+color+"] ["+timestamp+"] ("+self.script_name+") "+texte+" [/bold "+color+"]") + + def stop(self): + hprint("magenta","STOPING RecordTwitch") + self.running = False + + def del_mp3(self, dossier): + motif = os.path.join(dossier, '*.mp3') + for file in glob.glob(motif): + os.remove(file) + hprint("",f"file deleted : {file}") + + def clear_diretory(self, dir_inrecord="in_record", dir_record="record"): + # hprint('green', 'clear_diretory start') + if os.path.exists(dir_inrecord) and os.path.exists(dir_record): + hprint('green', f"dir {dir_inrecord} and {dir_record} exist clearing") + self.del_mp3(dir_inrecord) + self.del_mp3(dir_record) + + + + def create_session(self): + # Session creating for request + self.ua = UserAgent() + self.session = Streamlink() + self.session.set_option("http-headers", { + "Accept-Language": "en-US,en;q=0.5", + "Connection": "keep-alive", + "DNT": "1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": self.ua.random, + "Client-ID": "your_client_id", # Replace with your actual Client-ID + "Referer": "https://www.google.com/" + }) + + def get_url(self): + hprint("green","try to get url") + url = "" + self.create_session() + try: + streams = self.session.streams(self.channel_url) + url = streams['audio_only'].url if 'audio_only' in streams else streams['worst'].url + hprint("cyan","url generate : " + url) + except Exception as e: + hprint("red","Error on get url : "+str(e)) + # traceback.print_exc() # Affiche les détails de l'erreur + pass + return url + + + + def loop_run(self, intervalle): + try: + while self.running: + self.hprint("green", "Start scan files...") + self.verif_record_move() + self.hprint("yellow", f"wait {intervalle}s for next scan file completed.") + time.sleep(intervalle) + except KeyboardInterrupt: + self.hprint("red", "STOP LOOP.") + finally: + self.running = False # Assurez-vous que le drapeau est désactivé + + + def verif_record_move(self, dir_inrecord="in_record", dir_record="record"): + hprint("green", "start verif_record_move") + if not os.path.exists(dir_record): + os.makedirs(dir_record) + hprint("green", "création du dossier : "+dir_record) + + fichiers = [f for f in os.listdir(dir_inrecord) if os.path.isfile(os.path.join(dir_inrecord, f))] + if len(fichiers) > 1: + # sort file + sort_file = sorted(fichiers, key=lambda x: int(x.split('_')[-1].split('.')[0])) + fileto_move = sort_file[0] + + chemin_source = os.path.join(dir_inrecord, fileto_move) + chemin_destination = os.path.join(dir_record, fileto_move) + + # move file + shutil.move(chemin_source, chemin_destination) + hprint("green",f"File moved: {fileto_move}") + # else: + # hprint("yellow","Not enough files to compare.") + + def compteur(self ): + seconds = 0 + loop = 0 + while self.running: + time.sleep(1) # Attend une seconde + # hprint("magenta", f"self.running = {self.running}") + if (seconds < 10): + print(f"\033[94mRecording time: 0{seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + else: + print(f"\033[94mRecording time: {seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + + seconds += 1 + if seconds == self.max_timerecordfile: + loop +=1 + seconds = 0 # Réinitialise le compteur après 60 seconds + + + def record_audio(self): + output_directory = "record" + in_record_directory = "in_record" + os.makedirs(output_directory, exist_ok=True) + os.makedirs(in_record_directory, exist_ok=True) + + stream_url = self.get_url() + if not stream_url: + hprint("red","Impossible de récupérer l'URL du flux") + return + + timestamp_complet = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + timestamp = datetime.datetime.now().strftime("%Y-%m-%d") + + output_file_path = os.path.join(in_record_directory, f"{timestamp}_%03d.mp3") + + hprint("green", f"start record") + thread_compteur = Thread(target=self.compteur, daemon=True) + thread_compteur.start() + + command = ['ffmpeg','-i', stream_url,'-vn','-acodec','libmp3lame','-ar','44100','-ac','2','-map','0:a','-f','segment','-segment_time',str(self.max_timerecordfile),'-segment_format','mp3',output_file_path,'-loglevel', 'error'] + # hprint('yellow',str(command)) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + output, error = process.communicate() + + # thread_compteur.do_run = False + thread_compteur.join() + + + def main(self): + self.running = True + self.clear_diretory() + record_thread = Thread(target=self.record_audio) + record_thread.start() + # record_thread.join() # Wait for the recording to finish + loop_run = Thread(target=self.loop_run, args=(10,), daemon=True) + loop_run.start() + loop_run.join() # Wait for the recording to finish + hprint("cyan","Enregistrement terminé, le programme va se terminer.") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-recordtime', type=int, default=60, help='Time to record') + parser.add_argument('-twitchname', type=str, required=True, help='Twitch channel name') + args = parser.parse_args() + + bot = RecordTwitch(channel_name=args.twitchname, record_time=args.recordtime) + try: + bot.main() + except KeyboardInterrupt: + console.print("[bold red]ERREUR RECORDING[/bold red]") diff --git a/fonction/first_class.py b/fonction/first_class.py index 90af480..8e2806f 100644 --- a/fonction/first_class.py +++ b/fonction/first_class.py @@ -7,6 +7,7 @@ import time import pprint import random import requests +import shutil import datetime import glob import threading @@ -30,6 +31,11 @@ def hprint(color, texte): timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") console.print("[bold "+color+"] ["+timestamp+"] "+texte+" [/bold "+color+"]") +def sprint(script_name,color, texte): + timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") + console.print("[bold "+color+"] ["+timestamp+"] ("+script_name+") "+texte+" [/bold "+color+"]") + + def del_file(dossier, file): motif = os.path.join(dossier, file) for file in glob.glob(motif): @@ -55,85 +61,162 @@ def get_current_time(): - - - - - - - - - - - - - - - - ################### RecordTwitch ######################## - class RecordTwitch: - def __init__(self, channel_name, recordtime): - + def __init__(self, channel_name, record_time): self.channel_name = channel_name - self.all_proxies = [] self.channel_url = "https://www.twitch.tv/" + self.channel_name - self.record_time = recordtime - self.dir_twitchrecord = "twitch-recordAudio" - self.process = None # Pour stocker le sous-processus en cours - - + self.record_time = record_time + self.max_timerecordfile = 60 + self.running = True + self.script_name = "twitch_record" if (self.record_time == -1): self.record_time = 9999 + def stop(self): - """Arrête le processus d'enregistrement s'il est en cours.""" - if self.process and self.process.poll() is None: # Vérifie si le processus est actif - hprint("yellow",f"Arrêt de l'enregistrement...") - self.process.terminate() # Envoie un signal de terminaison - try: - self.process.wait(timeout=5) # Attend la fin avec un délai de 5 secondes - except subprocess.TimeoutExpired: - hprint("RED",f"Le processus ne répond pas, forçage de l'arrêt.") - self.process.kill() # Forcer l'arrêt si le processus ne termine pas - hprint("yellow",f"Enregistrement arrêté.") - else: - hprint("green",f"Aucun enregistrement en cours.") + sprint(self.script_name,"magenta","STOPING RecordTwitch") + self.running = False + + def del_mp3(self, dossier): + motif = os.path.join(dossier, '*.mp3') + for file in glob.glob(motif): + os.remove(file) + sprint(self.script_name,"yellow",f"file deleted : {file}") - def hprint(self,color, texte): - timestamp = datetime.datetime.now().strftime("%Hh %Mm %Ss") - console.print("[bold "+color+"] ["+timestamp+"] "+texte+" [/bold "+color+"]") - - - # Fonction pour convertir l'heure en secondes - def time_to_seconds(time_str): - h, m, s = map(int, time_str.split(':')) - return h * 3600 + m * 60 + s + def clear_diretory(self, dir_inrecord="in_record", dir_record="record"): + #sprint(self.script_name,'green', 'clear_diretory start') + if os.path.exists(dir_inrecord) and os.path.exists(dir_record): + sprint(self.script_name,'green', f"dir {dir_inrecord} and {dir_record} exist clearing") + self.del_mp3(dir_inrecord) + self.del_mp3(dir_record) + - # Fonction pour rechercher dans le dictionnaire - def search_dict(d, key): - return d.get(key, "Key not found") + def create_session(self): + # Session creating for request + self.ua = UserAgent() + self.session = Streamlink() + self.session.set_option("http-headers", { + "Accept-Language": "en-US,en;q=0.5", + "Connection": "keep-alive", + "DNT": "1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": self.ua.random, + "Client-ID": "your_client_id", # Replace with your actual Client-ID + "Referer": "https://www.google.com/" + }) - - def main_record_twitch(self): - # Utiliser Popen à la place de run pour pouvoir arrêter le processus + def get_url(self): + sprint(self.script_name,"green","start get_url") + url = "" + self.create_session() try: - print(f"Lancement de l'enregistrement pour {self.channel_name} pendant {self.record_time} secondes.") - record_twitch = ['python', self.dir_twitchrecord+'/twitch_record_unlimited.py', '-twitchname', self.channel_name,'-recordtime',str(self.record_time)] - self.process = subprocess.Popen(record_twitch) - self.process.communicate() # Attend que le sous-processus termine + streams = self.session.streams(self.channel_url) + url = streams['audio_only'].url if 'audio_only' in streams else streams['worst'].url + sprint(self.script_name,"cyan","url generate : " + url) except Exception as e: - print(f"Erreur pendant l'enregistrement: {e}") - - def start_recording(self): - """Lance main_record_twitch dans un thread pour ne pas bloquer le code principal.""" - self.thread = threading.Thread(target=self.main_record_twitch) - self.thread.start() # Démarre l'enregistrement dans un thread séparé + sprint(self.script_name,"red","Error on get url : "+str(e)) + # traceback.print_exc() # Affiche les détails de l'erreur + pass + return url -################### RecordTwitch FIN ######################## + + def loop_run(self, intervalle):#boucle pour déplacer les fichier fini enregistrement + time.sleep(30) # attente début du script complet et enregistrement + try: + while self.running: + self.verif_record_move() + sprint(self.script_name,"yellow", f"wait {intervalle}s for next scan file completed.") + time.sleep(intervalle) + except KeyboardInterrupt: + sprint(self.script_name,"red", "STOP LOOP.") + finally: + self.running = False # Assurez-vous que le drapeau est désactivé + + + def verif_record_move(self, dir_inrecord="in_record", dir_record="record"): + sprint(self.script_name,"green", "start verif_record_move") + if not os.path.exists(dir_record): + os.makedirs(dir_record) + sprint(self.script_name,"green", "création du dossier : "+dir_record) + + fichiers = [f for f in os.listdir(dir_inrecord) if os.path.isfile(os.path.join(dir_inrecord, f))] + if len(fichiers) > 1: + # sort file + sort_file = sorted(fichiers, key=lambda x: int(x.split('_')[-1].split('.')[0])) + fileto_move = sort_file[0] + chemin_source = os.path.join(dir_inrecord, fileto_move) + chemin_destination = os.path.join(dir_record, fileto_move) + # move file + shutil.move(chemin_source, chemin_destination) + sprint(self.script_name,"green",f"File moved: {fileto_move}") + else: + sprint(self.script_name,"yellow","Not enough files to compare.") + + def compteur(self ): + seconds = 0 + loop = 0 + while self.running: + time.sleep(1) # Attend une seconde + if (seconds < 10): + print(f"\033[94mRecording time: 0{seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + else: + print(f"\033[94mRecording time: {seconds}s | file : {loop}\033[0m", end='\r', flush=True) # Réinitialise la ligne à chaque fois + + seconds += 1 + if seconds == self.max_timerecordfile: + loop +=1 + seconds = 0 # Réinitialise le compteur après 60 seconds + + + def record_audio(self): + output_directory = "record" + in_record_directory = "in_record" + os.makedirs(output_directory, exist_ok=True) + os.makedirs(in_record_directory, exist_ok=True) + + + + timestamp_complet = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + timestamp = datetime.datetime.now().strftime("%Y-%m-%d") + + output_file_path = os.path.join(in_record_directory, f"{timestamp}_%03d.mp3") + + sprint(self.script_name,"green", f"start record") + thread_compteur = Thread(target=self.compteur, daemon=True) + thread_compteur.start() + + command = ['ffmpeg','-i', self.stream_url,'-vn','-acodec','libmp3lame','-ar','44100','-ac','2','-map','0:a','-f','segment','-segment_time',str(self.max_timerecordfile),'-segment_format','mp3',output_file_path,'-loglevel', 'error'] + # sprint(self.script_name,'yellow',str(command)) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + output, error = process.communicate() + + # thread_compteur.do_run = False + thread_compteur.join() + + + def main(self): + self.running = True + self.clear_diretory() + + self.stream_url = self.get_url() + if not self.stream_url: + sprint(self.script_name,"red","Impossible de récupérer l'URL du flux") + return + + record_thread = Thread(target=self.record_audio) + record_thread.start() + # record_thread.join() # Wait for the recording to finish + loop_run = Thread(target=self.loop_run, args=(20,), daemon=True) + loop_run.start() + #loop_run.join() # Wait for the recording to finish + sprint(self.script_name,"cyan","Enregistrement terminé, le programme va se terminer.") + + + +################## RecordTwitch FIN ######################## @@ -355,10 +438,11 @@ class IA_generator: def change_prompt(self): - if self.index_prompt == len(self.list_prompt): - self.index_prompt = 0 - else : - self.index_prompt += 1 + self.index_prompt = len(self.list_prompt) -1 + # if self.index_prompt == len(self.list_prompt): + # self.index_prompt = 0 + # else : + # self.index_prompt += 1 def reload_json(self): @@ -506,8 +590,8 @@ class messageTwitch: def change_user(self): # commented for pausing - if (self.totaluser != 1): # si la liste ne fait que 1 de taille - if(self.totaluser+1 > self.indexuser): # si la taille de liste est plus grande que lindex + if (self.totaluser != 1): # si la liste ne fait pas que 1 de taille + if(self.totaluser > self.indexuser): # si la taille de liste est plus grande que lindex self.indexuser = self.indexuser + 1 else : self.indexuser = 0 @@ -543,7 +627,7 @@ class messageTwitch: message_tosend = 'python send_message.py '+command hprint("yellow",f"send message = "+str(message_tosend)) subprocess.run(message_tosend, shell=True) - hprint("yellow",f"Finnish send message") + hprint("yellow",f"Finnish send send_message_user index :" + str(index_user)) def send_message(self, Message_text): @@ -553,7 +637,7 @@ class messageTwitch: message_tosend = 'python send_message.py '+command hprint("yellow",f"send message = "+str(message_tosend)) subprocess.run(message_tosend, shell=True) - hprint("yellow",f"Finnish send message") + hprint("yellow",f"Finnish send_message message") diff --git a/main_auto_loop.py b/main_auto_loop.py index debd17d..85de28f 100644 --- a/main_auto_loop.py +++ b/main_auto_loop.py @@ -1,5 +1,4 @@ import os -import signal import sys import argparse import json @@ -35,42 +34,31 @@ from fonction.first_class import messageTwitch from fonction.second_fonction import * -def signal_handler(sig, frame): - os.system('killall python') - sys.exit(0) +# def signal_handler(): + # os.system('killall python') + # sys.exit(0) -signal.signal(signal.SIGINT, signal_handler) console = Console() -def send_message(tw_acc_pseudo, tw_acc_token, channel_name, Message_text): - hprint("green","start send_message") - - command = '-pseudo "'+tw_acc_pseudo+'" -token "'+tw_acc_token+'" -twitchname "'+channel_name+'" -message " Kappa '+Message_text+'"' - message_tosend = 'python send_message.py '+command - hprint("yellow",f"send message = "+str(message_tosend)) - #subprocess.run(message_tosend, shell=True) - hprint("yellow",f"Finnish send message") - - def stop_all(): hprint("blue", "Arrêt d'enregistrement twitch.") recordTw.stop() sb_translation.stop() + # signal_handler() def print_help(): + hprint("PURPLE", "Touche 'F5'BOT Active l'écoute clavier") + hprint("PURPLE", "Touche 'F6'BOT Désactive l'écoute clavier") hprint("PURPLE", "Touche h : pour afficher les commandes") hprint("PURPLE", "Touche q : pour quitter le sript") hprint("PURPLE", "Touche c : Clear le terminal") hprint("PURPLE", "Touche s : envoie un message dans le tchat twitch avec la derniere génération") - hprint("PURPLE", "Touche u : pour stopper lenregistrement twitch") # hprint("PURPLE", "Touche j : pour start lenregistrement twitch") # pas set - # hprint("PURPLE", "Touche i : pour start la traduction en text du record") # pas set hprint("PURPLE", "Touche p : pour stopper la traduction en text du record") hprint("PURPLE", "Touche o : liste tout les sous titre créé") - hprint("PURPLE", "Touche k : lancer une generation de reponse avec ia depuis les traduction") hprint("PURPLE", "Touche l : liste toute les génération") hprint("PURPLE", "Touche m : change le prompt a donner a l'ia") @@ -107,9 +95,9 @@ def on_press(key): if listening_keyboard: if key.char == 'q': # Si la touche 'q' est pressée, arrête l'écoute hprint("cyan", "Touche 'q' détectée. Fin du programme.") - main_loop = False stop_all() - return False # Cela arrêtera l'écouteur + main_loop = False + # return False # Cela arrêtera l'écouteur elif key.char == 'c': hprint("cyan", "Touche 'c' clear terminal") clear_screen() @@ -125,7 +113,7 @@ def on_press(key): elif key.char == 's': hprint("cyan", "Touche 's' Envoie du message") Message_text = ask_text.getlast_generation() - #send_message(tw_acc_pseudo, tw_acc_token, args.twitchname, Message_text) + controluser.send_message(Message_text) elif key.char == 'o': hprint("cyan", "Touche 'o'liste sous titre") sb_translation.print_allsubtitle() @@ -154,54 +142,59 @@ def generation_responce(): if __name__ == '__main__': main_loop = True + #configuration du dossier de travaille work_directory = "working_bot" + if not os.path.exists(work_directory): + os.makedirs(work_directory) + hprint("green", "création du dossier : "+work_directory) os.chdir(work_directory) + #récupération du fichier de configuration with open("../config/config.json", 'r') as file: config = json.load(file) - tw_acc_pseudo = get_value_json("tw_acc_pseudo", config) - tw_acc_token = get_value_json("tw_acc_token", config) + #récupération des arguments parser = argparse.ArgumentParser() parser.add_argument('-threads', type=int, default=10, help='Number of threads') parser.add_argument('-recordtime', type=int, default=60, help='Time to record') parser.add_argument('-twitchname', type=str, required=True, help='Twitch channel name') args = parser.parse_args() + #lancement de la class d'enregistrement audio du stream hprint("blue", "start loop RecordTwitch") - recordTw = RecordTwitch(channel_name=args.twitchname, recordtime=args.recordtime) - recordTw.start_recording() + recordTw = RecordTwitch(channel_name=args.twitchname, record_time=args.recordtime) + recordTw.main() hprint("blue", "start loop Subtitle_translation") sb_translation = Subtitle_translation("../config/config.json") sb_translation.start_main_loop() - ask_text = IA_generator("../config/config.json") - ask_text.start_main_loop() + #ask_text = IA_generator("../config/config.json") + #ask_text.start_main_loop() - controluser = messageTwitch(args.twitchname) + #controluser = messageTwitch(args.twitchname) print_help() listener_thread = threading.Thread(target=start_keyboard_listener) listener_thread.start() # mise en thread de l'écoute des appuye touche - time.sleep(25) - last_generaton = "" - while main_loop: - hprint("blue", "start main_loop main script") - text_streamer = sb_translation.get_lasttext() - ask_text.setnew_streamer_word_text(text_streamer) - new_genration = ask_text.getlast_generation() + #time.sleep(25) + #last_generaton = "" + #while main_loop: + #time.sleep(3) + #hprint("blue", "start main_loop main script") + #text_streamer = sb_translation.get_lasttext() + #ask_text.setnew_streamer_word_text(text_streamer) + #new_genration = ask_text.getlast_generation() - if new_genration != "" and new_genration != last_generaton: - hprint("blue", "Send message -> "+new_genration) - # send_message(tw_acc_pseudo, tw_acc_token, args.twitchname, new_genration) - controluser.send_message(new_genration) - controluser.change_user() - last_generaton = new_genration + #if new_genration != "" and new_genration != last_generaton: + #hprint("blue", "Send message -> "+new_genration) + #controluser.send_message(new_genration) + #controluser.change_user() + #last_generaton = new_genration - time.sleep(25) + #time.sleep(10) diff --git a/working_bot/2025-01-10_002.json b/working_bot/2025-01-10_002.json new file mode 100644 index 0000000..1456a62 --- /dev/null +++ b/working_bot/2025-01-10_002.json @@ -0,0 +1 @@ +{"text": " Arr\u00eate, en vrai ce fight \u00e0 part la fin qui est bizarre, mais... Je suis en 6-6-6, \u00e7a va, genre. 6-6-6, c'est donc toi le saboteur ! L\u00e0 ! Vous avez mal jou\u00e9. Par vous, tu veux dire qui ? L'enti\u00e8ret\u00e9 de la game ? Je suis d'accord. T'es bien toi mon salaud, en vrai. Vu quand je vois la Kalista, comment elle est dans la game. Oui, oui, oui. On va dire dans... 80% des games, je suis bien. Si on enl\u00e8ve la game Tariq, oui. Voil\u00e0, c'est pour \u00e7a que j'ai 80%. T'as compt\u00e9 le nombre des games qu'on a fait aujourd'hui. Soustrait par game de Tariq. Oh oh, je suis dans la... Merde. Je suis d'accord. Je suis d'accord. Je suis d'accord.", "segments": [{"id": 0, "seek": 0, "start": 0.0, "end": 3.18, "text": " Arr\u00eate, en vrai ce fight \u00e0 part la fin qui est bizarre, mais...", "tokens": [50365, 1587, 81, 12943, 11, 465, 17815, 1769, 2092, 1531, 644, 635, 962, 1956, 871, 18265, 11, 2420, 485, 50524], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 1, "seek": 0, "start": 4.18, "end": 6.24, "text": " Je suis en 6-6-6, \u00e7a va, genre.", "tokens": [50574, 2588, 7624, 465, 1386, 12, 21, 12, 21, 11, 2788, 2773, 11, 11022, 13, 50677], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 2, "seek": 0, "start": 10.56, "end": 13.24, "text": " 6-6-6, c'est donc toi le saboteur !", "tokens": [50893, 1386, 12, 21, 12, 21, 11, 269, 6, 377, 5926, 15648, 476, 5560, 1370, 374, 2298, 51027], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 3, "seek": 0, "start": 14.16, "end": 15.38, "text": " L\u00e0 !", "tokens": [51073, 22237, 2298, 51134], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 4, "seek": 0, "start": 19.080000000000002, "end": 21.36, "text": " Vous avez mal jou\u00e9. Par vous, tu veux dire qui ?", "tokens": [51319, 10802, 11766, 2806, 11110, 526, 13, 3457, 2630, 11, 2604, 16389, 1264, 1956, 2506, 51433], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 5, "seek": 0, "start": 21.36, "end": 23.38, "text": " L'enti\u00e8ret\u00e9 de la game ? Je suis d'accord.", "tokens": [51433, 441, 6, 23012, 1462, 1505, 526, 368, 635, 1216, 2506, 2588, 7624, 274, 6, 19947, 13, 51534], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 6, "seek": 0, "start": 25.96, "end": 27.98, "text": " T'es bien toi mon salaud, en vrai.", "tokens": [51663, 314, 6, 279, 3610, 15648, 1108, 1845, 3751, 11, 465, 17815, 13, 51764], "temperature": 0.0, "avg_logprob": -0.45952383677164715, "compression_ratio": 1.35, "no_speech_prob": 0.33728325366973877}, {"id": 7, "seek": 2798, "start": 27.98, "end": 30.88, "text": " Vu quand je vois la Kalista, comment elle est dans la game.", "tokens": [50365, 37703, 6932, 1506, 18297, 635, 12655, 5236, 11, 2871, 8404, 871, 2680, 635, 1216, 13, 50510], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 8, "seek": 2798, "start": 30.88, "end": 31.88, "text": " Oui, oui, oui.", "tokens": [50510, 14005, 11, 14367, 11, 14367, 13, 50560], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 9, "seek": 2798, "start": 33.38, "end": 36.52, "text": " On va dire dans... 80% des games, je suis bien.", "tokens": [50635, 1282, 2773, 1264, 2680, 485, 4688, 4, 730, 2813, 11, 1506, 7624, 3610, 13, 50792], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 10, "seek": 2798, "start": 37.38, "end": 39.38, "text": " Si on enl\u00e8ve la game Tariq, oui.", "tokens": [50835, 4909, 322, 465, 75, 31397, 635, 1216, 314, 3504, 80, 11, 14367, 13, 50935], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 11, "seek": 2798, "start": 39.38, "end": 41.38, "text": " Voil\u00e0, c'est pour \u00e7a que j'ai 80%.", "tokens": [50935, 18677, 11, 269, 6, 377, 2016, 2788, 631, 361, 6, 1301, 4688, 6856, 51035], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 12, "seek": 2798, "start": 41.38, "end": 43.38, "text": " T'as compt\u00e9 le nombre des games qu'on a fait aujourd'hui.", "tokens": [51035, 314, 6, 296, 15660, 526, 476, 13000, 730, 2813, 421, 6, 266, 257, 3887, 14023, 6, 10556, 13, 51135], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 13, "seek": 2798, "start": 43.38, "end": 45.38, "text": " Soustrait par game de Tariq.", "tokens": [51135, 318, 15849, 8645, 971, 1216, 368, 314, 3504, 80, 13, 51235], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 14, "seek": 2798, "start": 50.38, "end": 52.38, "text": " Oh oh, je suis dans la...", "tokens": [51485, 876, 1954, 11, 1506, 7624, 2680, 635, 485, 51585], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 15, "seek": 2798, "start": 52.38, "end": 54.38, "text": " Merde.", "tokens": [51585, 6124, 1479, 13, 51685], "temperature": 0.0, "avg_logprob": -0.4133269945780436, "compression_ratio": 1.5023923444976077, "no_speech_prob": 0.018655717372894287}, {"id": 16, "seek": 5438, "start": 54.38, "end": 56.38, "text": " Je suis d'accord.", "tokens": [50365, 2588, 7624, 274, 6, 19947, 13, 50465], "temperature": 0.0, "avg_logprob": -0.797804143693712, "compression_ratio": 1.206896551724138, "no_speech_prob": 0.3034641742706299}, {"id": 17, "seek": 5438, "start": 57.78, "end": 59.78, "text": " Je suis d'accord.", "tokens": [50535, 2588, 7624, 274, 6, 19947, 13, 50635], "temperature": 0.0, "avg_logprob": -0.797804143693712, "compression_ratio": 1.206896551724138, "no_speech_prob": 0.3034641742706299}, {"id": 18, "seek": 5978, "start": 59.78, "end": 60.78, "text": " Je suis d'accord.", "tokens": [50365, 2588, 7624, 274, 6, 19947, 13, 50415], "temperature": 0.0, "avg_logprob": -0.3928448094262017, "compression_ratio": 0.68, "no_speech_prob": 0.747857928276062}], "language": "fr"} \ No newline at end of file diff --git a/working_bot/2025-01-10_002.srt b/working_bot/2025-01-10_002.srt new file mode 100644 index 0000000..0093a23 --- /dev/null +++ b/working_bot/2025-01-10_002.srt @@ -0,0 +1,76 @@ +1 +00:00:00,000 --> 00:00:03,180 +Arrête, en vrai ce fight à part la fin qui est bizarre, mais... + +2 +00:00:04,180 --> 00:00:06,240 +Je suis en 6-6-6, ça va, genre. + +3 +00:00:10,560 --> 00:00:13,240 +6-6-6, c'est donc toi le saboteur ! + +4 +00:00:14,160 --> 00:00:15,380 +Là ! + +5 +00:00:19,080 --> 00:00:21,360 +Vous avez mal joué. Par vous, tu veux dire qui ? + +6 +00:00:21,360 --> 00:00:23,380 +L'entièreté de la game ? Je suis d'accord. + +7 +00:00:25,960 --> 00:00:27,980 +T'es bien toi mon salaud, en vrai. + +8 +00:00:27,980 --> 00:00:30,880 +Vu quand je vois la Kalista, comment elle est dans la game. + +9 +00:00:30,880 --> 00:00:31,880 +Oui, oui, oui. + +10 +00:00:33,380 --> 00:00:36,520 +On va dire dans... 80% des games, je suis bien. + +11 +00:00:37,380 --> 00:00:39,380 +Si on enlève la game Tariq, oui. + +12 +00:00:39,380 --> 00:00:41,380 +Voilà, c'est pour ça que j'ai 80%. + +13 +00:00:41,380 --> 00:00:43,380 +T'as compté le nombre des games qu'on a fait aujourd'hui. + +14 +00:00:43,380 --> 00:00:45,380 +Soustrait par game de Tariq. + +15 +00:00:50,380 --> 00:00:52,380 +Oh oh, je suis dans la... + +16 +00:00:52,380 --> 00:00:54,380 +Merde. + +17 +00:00:54,380 --> 00:00:56,380 +Je suis d'accord. + +18 +00:00:57,780 --> 00:00:59,780 +Je suis d'accord. + +19 +00:00:59,780 --> 00:01:00,780 +Je suis d'accord. + diff --git a/working_bot/2025-01-10_002.tsv b/working_bot/2025-01-10_002.tsv new file mode 100644 index 0000000..61a67a1 --- /dev/null +++ b/working_bot/2025-01-10_002.tsv @@ -0,0 +1,20 @@ +start end text +0 3180 Arrête, en vrai ce fight à part la fin qui est bizarre, mais... +4180 6240 Je suis en 6-6-6, ça va, genre. +10560 13240 6-6-6, c'est donc toi le saboteur ! +14160 15380 Là ! +19080 21360 Vous avez mal joué. Par vous, tu veux dire qui ? +21360 23380 L'entièreté de la game ? Je suis d'accord. +25960 27980 T'es bien toi mon salaud, en vrai. +27980 30880 Vu quand je vois la Kalista, comment elle est dans la game. +30880 31880 Oui, oui, oui. +33380 36520 On va dire dans... 80% des games, je suis bien. +37380 39380 Si on enlève la game Tariq, oui. +39380 41380 Voilà, c'est pour ça que j'ai 80%. +41380 43380 T'as compté le nombre des games qu'on a fait aujourd'hui. +43380 45380 Soustrait par game de Tariq. +50380 52380 Oh oh, je suis dans la... +52380 54380 Merde. +54380 56380 Je suis d'accord. +57780 59780 Je suis d'accord. +59780 60780 Je suis d'accord. diff --git a/working_bot/2025-01-10_002.txt b/working_bot/2025-01-10_002.txt new file mode 100644 index 0000000..db54e35 --- /dev/null +++ b/working_bot/2025-01-10_002.txt @@ -0,0 +1,19 @@ +Arrête, en vrai ce fight à part la fin qui est bizarre, mais... +Je suis en 6-6-6, ça va, genre. +6-6-6, c'est donc toi le saboteur ! +Là ! +Vous avez mal joué. Par vous, tu veux dire qui ? +L'entièreté de la game ? Je suis d'accord. +T'es bien toi mon salaud, en vrai. +Vu quand je vois la Kalista, comment elle est dans la game. +Oui, oui, oui. +On va dire dans... 80% des games, je suis bien. +Si on enlève la game Tariq, oui. +Voilà, c'est pour ça que j'ai 80%. +T'as compté le nombre des games qu'on a fait aujourd'hui. +Soustrait par game de Tariq. +Oh oh, je suis dans la... +Merde. +Je suis d'accord. +Je suis d'accord. +Je suis d'accord. diff --git a/working_bot/2025-01-10_002.vtt b/working_bot/2025-01-10_002.vtt new file mode 100644 index 0000000..1138cb8 --- /dev/null +++ b/working_bot/2025-01-10_002.vtt @@ -0,0 +1,59 @@ +WEBVTT + +00:00.000 --> 00:03.180 +Arrête, en vrai ce fight à part la fin qui est bizarre, mais... + +00:04.180 --> 00:06.240 +Je suis en 6-6-6, ça va, genre. + +00:10.560 --> 00:13.240 +6-6-6, c'est donc toi le saboteur ! + +00:14.160 --> 00:15.380 +Là ! + +00:19.080 --> 00:21.360 +Vous avez mal joué. Par vous, tu veux dire qui ? + +00:21.360 --> 00:23.380 +L'entièreté de la game ? Je suis d'accord. + +00:25.960 --> 00:27.980 +T'es bien toi mon salaud, en vrai. + +00:27.980 --> 00:30.880 +Vu quand je vois la Kalista, comment elle est dans la game. + +00:30.880 --> 00:31.880 +Oui, oui, oui. + +00:33.380 --> 00:36.520 +On va dire dans... 80% des games, je suis bien. + +00:37.380 --> 00:39.380 +Si on enlève la game Tariq, oui. + +00:39.380 --> 00:41.380 +Voilà, c'est pour ça que j'ai 80%. + +00:41.380 --> 00:43.380 +T'as compté le nombre des games qu'on a fait aujourd'hui. + +00:43.380 --> 00:45.380 +Soustrait par game de Tariq. + +00:50.380 --> 00:52.380 +Oh oh, je suis dans la... + +00:52.380 --> 00:54.380 +Merde. + +00:54.380 --> 00:56.380 +Je suis d'accord. + +00:57.780 --> 00:59.780 +Je suis d'accord. + +00:59.780 --> 01:00.780 +Je suis d'accord. + diff --git a/working_bot/record/2024-12-09_015.mp3 b/working_bot/record/2024-12-09_015.mp3 deleted file mode 100644 index 04fa1d2..0000000 Binary files a/working_bot/record/2024-12-09_015.mp3 and /dev/null differ diff --git a/working_bot/record/2024-12-09_016.mp3 b/working_bot/record/2024-12-09_016.mp3 deleted file mode 100644 index 4e0b65f..0000000 Binary files a/working_bot/record/2024-12-09_016.mp3 and /dev/null differ diff --git a/working_bot/send_message.py b/working_bot/send_message.py index 399517b..e76207b 100644 --- a/working_bot/send_message.py +++ b/working_bot/send_message.py @@ -3,14 +3,14 @@ import argparse from urllib.parse import urlparse from pytmi import Client # Assurez-vous que c'est le nom correct de votre module et qu'il est correctement installé. -async def send_message_to_twitch_stream(nick, token, stream_url, message): +async def send_message_to_twitch_stream(pseudo, token, stream_url, message): parsed_url = urlparse(stream_url) channel = parsed_url.path.lstrip('/') async with Client() as client: try: print("Tentative de login") - await client.login_oauth(token, nick) + await client.login_oauth(token, pseudo) print("Tentative de join") await client.join(channel) print("Tentative d'envoi de message") @@ -21,12 +21,7 @@ async def send_message_to_twitch_stream(nick, token, stream_url, message): except Exception as e: print(f"Erreur lors de l'interaction avec Twitch: {type(e).__name__}, {e}") -async def main(): - # nick = "foufure13" # Remplacez par votre pseudo Twitch - # token = "oauth:7mexqe9zcxrqpz1s0fji4oolr4mxn6" # Remplacez par votre token OAuth - # stream_url = "https://www.twitch.tv/shambiess" # Remplacez par l'URL du stream Twitch - # message = "yoo" # Message à envoyer - +async def main(): parser = argparse.ArgumentParser() parser.add_argument('-pseudo', type=str, required=True, help='Pseudo name account') parser.add_argument('-token', type=str, required=True, help='Token oauth') @@ -35,7 +30,8 @@ async def main(): args = parser.parse_args() stream_url = "https://www.twitch.tv/"+args.twitchname - await send_message_to_twitch_stream(nick=args.pseudo, token=args.token, stream_url=stream_url, message=args.message) + await send_message_to_twitch_stream(pseudo=args.pseudo, token=args.token, stream_url=stream_url, message=args.message) + if __name__ == "__main__": asyncio.run(main())