diff --git a/README.md b/README.md index b1f79ca..3116673 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,11 @@ Python script to check, download live stream, VOD, chat and upload them to any c ```.env CLIENT-ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx CLIENT-SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -OAUTH-PRIVATE-TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +OAUTH-PRIVATE-TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # optional to record without ADS or download sub-only VODS ``` 8. if you want to enable/disable more available options, edit `twitch-archive.py` 9. run `Python twitch-archive.py` or for multiple streamers `Python twitch-archive.py -u streamer` + \ No newline at end of file diff --git a/bin/upload.bat b/bin/upload.bat index 5c2fb8b..b562f1c 100644 --- a/bin/upload.bat +++ b/bin/upload.bat @@ -5,4 +5,4 @@ if "%root_path:~-1%" == "\" set "root_path_1=%root_path:~0,-1%" for %%f in ("%root_path_1%") do set "root_path_name=%%~nxf" FOR /F "eol=# tokens=*" %%i in (%~dp0\..\.env) do SET %%i CD %~dp0 -rclone.exe copy %root_path%/%user% %remote%/%root_path_name%/%user% --progress \ No newline at end of file +rclone.exe copy %root_path%/%user% %remote%/%root_path_name%/%user% --progress --include-from %~dp0/temp/upload.txt \ No newline at end of file diff --git a/bin/upload.sh b/bin/upload.sh index 67d216e..83afebf 100644 --- a/bin/upload.sh +++ b/bin/upload.sh @@ -1,2 +1,2 @@ #!/bin/sh -rclone copy $1/$2 gd:VODS/$(basename $1)/$2 --progress \ No newline at end of file +rclone copy $1/$2 gd:VODS/$(basename $1)/$2 --progress --include-from $(dirname "$0")/temp/upload.txt \ No newline at end of file diff --git a/only-vod-chat.py b/only-vod-chat.py index 71eac10..3f950b4 100644 --- a/only-vod-chat.py +++ b/only-vod-chat.py @@ -1,6 +1,7 @@ -import requests, os, time, json, sys, subprocess, getopt, pathlib +import requests, os, time, json, sys, subprocess, getopt, pathlib, locale from colorama import Fore, Style -from datetime import datetime +from datetime import datetime, timedelta +locale.setlocale(locale.LC_TIME, "es_ES") from pytz import timezone from dotenv import load_dotenv, find_dotenv @@ -13,10 +14,10 @@ class TwitchArchive: # global configuration self.root_path = r"archive" # Path where this script saves everything (livestream,VODs,chat,metadata) self.refresh = 60 # Time between checking (5.0 is recommended), avoid less than 1.0 - self.downloadVOD = 0 # 0 - disable VOD downloading after stream finished, 1 - enable VOD downloading after stream finished (this option downloads the latest public vod) + self.downloadVOD = 1 # 0 - disable VOD downloading after stream finished, 1 - enable VOD downloading after stream finished (this option downloads the latest public vod) self.downloadCHAT = 1 # 0 - disable chat downloading and rendering, 1 - enable chat downloading and rendering self.uploadCloud = 1 # 0 - disable upload to remote cloud, 1 - enable upload to remote cloud - self.deleteFiles = 1 # 0 - disable the deleting of files from current seccion after being uploaded to the cloud, 1 - enable the deleting files of files from current seccion after being uploaded to the cloud (BE CAREFUL WITH THIS OPTION) + self.deleteFiles = 0 # 0 - disable the deleting of files from current seccion after being uploaded to the cloud, 1 - enable the deleting files of files from current seccion after being uploaded to the cloud (BE CAREFUL WITH THIS OPTION) self.hls_segmentsVOD = 10 # 1-10 for downloading vod, it's possible to use multiple threads to potentially increase the throughput def run(self): @@ -38,18 +39,18 @@ class TwitchArchive: self.oauth_token = self.get_oauth_token() self.channel_id = self.get_channel_id() - self.temp_path = str(pathlib.Path(os.path.join(self.root_path,self.username,"vod", "temp")).absolute()) - self.vod_path = str(pathlib.Path(os.path.join(self.root_path, self.username, "vod")).absolute()) - self.json_path = str(pathlib.Path(os.path.join(self.root_path, self.username, "chat", "json")).absolute()) - self.chat_path = str(pathlib.Path(os.path.join(self.root_path, self.username, "chat")).absolute()) + self.temp_path = str(pathlib.Path(os.path.join("VODS",self.root_path,self.username,"vod", "temp")).absolute()) + self.vod_path = str(pathlib.Path(os.path.join("VODS",self.root_path, self.username, "vod")).absolute()) + self.json_path = str(pathlib.Path(os.path.join("VODS",self.root_path, self.username, "chat", "json")).absolute()) + self.chat_path = str(pathlib.Path(os.path.join("VODS",self.root_path, self.username, "chat")).absolute()) if(os.path.isdir(self.temp_path) is False): os.makedirs(self.temp_path) if(os.path.isdir(self.vod_path) is False): os.makedirs(self.vod_path) if(os.path.isdir(self.json_path) is False): os.makedirs(self.json_path) if(os.path.isdir(self.chat_path) is False): os.makedirs(self.chat_path) - if not os.path.exists(os.path.join(self.root_path, ".log")): - with open(os.path.join(self.root_path, ".log"), 'w'): pass + if not os.path.exists(os.path.join('VODS',self.root_path, ".log")): + with open(os.path.join('VODS',self.root_path, ".log"), 'w'): pass print(f"Checking for {Fore.GREEN}{self.username}{Style.RESET_ALL} every {Fore.GREEN}{self.refresh}{Style.RESET_ALL} seconds to download VOD/CHAT") self.loopcheck() @@ -63,123 +64,161 @@ class TwitchArchive: print('OS no supported') return - def get_oauth_token(self): - try: - return requests.post(f"https://id.twitch.tv/oauth2/token?client_id={os.getenv('CLIENT-ID')}&client_secret={os.getenv('CLIENT-SECRET')}&grant_type=client_credentials").json()['access_token'] - except: - return None - def get_channel_id(self): - try: - r = requests.get(f'https://api.twitch.tv/helix/users?login={self.username}', headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.getenv('CLIENT-ID')}, timeout = 15) - r.raise_for_status() - info = r.json() - if info["data"] != []: - return info["data"][0]["id"] - else: - return None - except requests.exceptions.RequestException as e: - print(e) def check_user(self): - try: - url = 'https://api.twitch.tv/helix/streams?user_id=' + self.channel_id - live = requests.get(url, headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.environ.get('CLIENT-ID')}, timeout = 30) - stream_data = live.json() - if len(stream_data['data']) == 1: - self.live_info = stream_data['data'][0] - return True - else: - return False - except Exception as e: - print("API request ERROR") - print(e) - return False + client_id = "kimne78kx3ncx6brgo4mv6wki5h1ko" + query = ''' + query { + user(login: "''' + self.username + '''") { + stream { + archiveVideo{ + id + } + title + createdAt + } + } + } + ''' + url = 'https://gql.twitch.tv/gql' + response = requests.post(url,json={'query': query},headers={"Client-ID": client_id}) + return json.loads(response.text) + def get_vod(self): + client_id = "kimne78kx3ncx6brgo4mv6wki5h1ko" + query = ''' + query { + user(login: "''' + self.username + '''") { + videos(first: 1) { + edges { + node { + id + scope + title + description + recordedAt + lengthSeconds + animatedPreviewURL + previewThumbnailURL(height: 1280, width: 720) + thumbnailURLs(height: 1280, width: 720) + } + } + } + } + } + ''' + url = 'https://gql.twitch.tv/gql' + response = requests.post(url, json={'query': query}, headers={"Client-ID": client_id}) + return json.loads(response.text) def loopcheck(self): while True: - if self.check_user() is True: - live_temp_path = os.path.join(self.temp_path, "live_temp.ts") - with open(os.path.join(self.root_path, ".log")) as logs: - logs = logs.read() - log_id = self.live_info["started_at"] + " - " + self.username + " - " + self.live_info["title"] - if log_id in logs: - time.sleep(self.refresh) - with open(os.path.join(self.root_path, ".log"), "r+") as logs: - log_id = self.live_info["started_at"] + " - " + self.username + " - " + self.live_info["title"] - for line in logs: - if log_id in line: - break - else: - logs.write(self.live_info["started_at"] + " - " + self.username + " - " + self.live_info["title"] + "\n") + is_live = self.check_user()['data']['user']['stream'] + if is_live is not None: + is_live_ready = self.check_user()['data']['user']['stream']['title'] + if is_live_ready is not None: + live_date = datetime.strptime(is_live["createdAt"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) + live_temp_path = os.path.join(self.temp_path, "live_temp.ts") + + with open(os.path.join(self.root_path, ".log")) as logs: + logs = logs.read() + log_id = is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] + if log_id in logs: + time.sleep(self.refresh) - subprocess.call(['streamlink', 'twitch.tv/'+ self.username, 'worst', '--hls-segment-threads', '3', '--retry-streams', str(self.refresh), '--twitch-disable-reruns', '-o', live_temp_path]) - try: - vodurl = f'https://api.twitch.tv/helix/videos?user_id={str(self.channel_id)}&period=day&type=archive' - vods = requests.get(vodurl, headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.getenv('CLIENT-ID')}, timeout = 30) - vodsinfo = json.loads(vods.text) - if vodsinfo["data"][0] != []: - vod_date = datetime.strptime(vodsinfo["data"][0]["created_at"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) - vod_raw_filename = datetime.strftime(vod_date,'%Y%m%d_%Hh%Mm%Ss') - if self.live_info["id"] == vodsinfo["data"][0]["stream_id"]: - print('VOD AND CHAT AVAILABLE') - current_vod = vodsinfo["data"][0] - vod_raw_path = os.path.join(self.temp_path, "vod_temp.ts") - vod_proc_path = os.path.join(self.vod_path, vod_raw_filename + ".mp4") - chat_json_path = os.path.join(self.json_path, vod_raw_filename + ".json") - chat_video_path = os.path.join(self.chat_path, vod_raw_filename + ".mp4") - - if self.downloadVOD == 1: - print('Downloading VOD: ' + current_vod["title"]) - try: - subprocess.call(['streamlink', 'twitch.tv/videos/' + current_vod["id"], self.quality, "--hls-segment-threads", str(self.hls_segmentsVOD), "-o", vod_raw_path]) - if(os.path.exists(vod_raw_path) is True): - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - else: - print("Skip fixing. File not found.") - except Exception as e: - print('Error', 'A ERROR has ocurred and the VOD will not be downloaded.\n') - if self.downloadCHAT == 1: - print('Downloading and rendering CHAT: ' + current_vod["title"]) - try: - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.bat", current_vod["id"], chat_json_path, chat_video_path]) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.sh", current_vod["id"], chat_json_path, chat_video_path]) - except Exception as e: - print("A ERROR has ocurred and chat will need to be downloaded and rendered manually\n") - - if self.uploadCloud == 1: - if self.os == 'windows': - tree = subprocess.run(['powershell.exe','tree', f'{self.root_path}/{self.username}', '/f'], capture_output=True, text=True).stdout.split("\n",2)[2] - elif self.os == 'linux': - tree = subprocess.check_output(['tree', str(pathlib.Path(self.root_path).resolve())+'/'+self.username]).decode(sys.stdout.encoding) - print('Uploading the following files:\n' + tree) - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.bat', str(pathlib.Path(self.root_path).resolve()),self.username]) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.sh', str(pathlib.Path(self.root_path).resolve()),self.username]) - - if self.deleteFiles == 1: - print(f'{Fore.RED}DELETING FILES{Style.RESET_ALL}') - if self.downloadVOD == 1: - if(os.path.exists(vod_raw_path) is True): - print(f'{Fore.RED}Deleting ' + vod_raw_path + f'{Style.RESET_ALL}') - os.remove(vod_raw_path) - if(os.path.exists(vod_proc_path) is True): - print(f'{Fore.RED}Deleting ' + vod_proc_path + f'{Style.RESET_ALL}') - os.remove(vod_proc_path) - if self.downloadCHAT == 1: - if(os.path.exists(chat_json_path) is True): - print(f'{Fore.RED}Deleting ' + chat_json_path + f'{Style.RESET_ALL}') - os.remove(chat_json_path) - if(os.path.exists(chat_video_path) is True): - print(f'{Fore.RED}Deleting ' + chat_video_path + f'{Style.RESET_ALL}') - os.remove(chat_video_path) + with open(os.path.join(self.root_path, ".log"), "r+") as logs: + log_id = is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] + for line in logs: + if log_id in line: + break else: - print('THE VOD/CHAT FOR CURRENT LIVESTREAM IS NOT AVAILABLE\nThe current livestream date: ' + self.live_info['started_at'] + '\nThe VOD date: ' + vodsinfo["data"][0]["created_at"]) - except Exception as e: - print('API request error.') - print(e) + logs.write(is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] +"\n") - print('CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') - time.sleep(self.refresh) + subprocess.call(['streamlink', 'twitch.tv/'+ self.username, self.quality, '--twitch-api-header', 'Authorization=OAuth ' + os.getenv('OAUTH-PRIVATE-TOKEN'), '--hls-segment-threads', str(self.hls_segments), '--hls-live-restart', '--retry-streams', str(self.refresh), '--twitch-disable-reruns', '-o', live_temp_path]) + os.remove(live_temp_path) + + current_vod = self.get_vod()['data']['user']['videos']['edges'][0]['node'] + vod_date = datetime.strptime(current_vod["recordedAt"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) + vod_raw_filename = datetime.strftime(vod_date,'%Y%m%d_%Hh%Mm%Ss') + live_date_min = live_date - timedelta(minutes=1) + live_date_max = live_date + timedelta(minutes=1) + + if live_date_min <= vod_date <= live_date_max: + print('VOD AND CHAT AVAILABLE') + vod_raw_path = os.path.join(self.temp_path, "vod_temp.ts") + vod_proc_path = os.path.join(self.vod_path, vod_raw_filename + ".mp4") + chat_json_path = os.path.join(self.json_path, vod_raw_filename + ".json") + chat_video_path = os.path.join(self.chat_path, vod_raw_filename + ".mp4") + if self.username == 'KalathrasLolweapon': + file_date = datetime.strptime(vod_raw_filename, '%Y%m%d_%Hh%Mm%Ss').date() + + week_first = file_date - timedelta(days=file_date.weekday()) + week_last = week_first + timedelta(days=6) + + vod_year = 'VOD - ' + str(file_date.year) + vod_month = f'{file_date.month:02d} - ' + file_date.strftime("%B").upper() + vod_week = file_date.strftime("%B").capitalize() + ' ' + str(week_first.day) + '-' + str(week_last.day) + + chat_year = 'Chat - ' + str(file_date.year) + chat_month = f'{file_date.month:02d} - ' + file_date.strftime("%B") + + vod_path = str(pathlib.Path(os.path.join("VODS",vod_year,vod_month,vod_week)).absolute()) + chat_path = str(pathlib.Path(os.path.join("Chat",chat_year,chat_month)).absolute()) + if(os.path.isdir(vod_path) is False): os.makedirs(vod_path) + if(os.path.isdir(chat_path) is False): os.makedirs(chat_path) + chat_video_path = os.path.join(chat_path, vod_raw_filename + ".mp4") + vod_proc_path = os.path.join(vod_path, vod_raw_filename + ".mp4") + + if self.downloadVOD == 1: + print('Downloading VOD: ' + current_vod["title"]) + try: + subprocess.call(['streamlink', 'twitch.tv/videos/' + current_vod["id"], self.quality, "--hls-segment-threads", str(self.hls_segmentsVOD), "-o", vod_raw_path]) + if(os.path.exists(vod_raw_path) is True): + if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + os.remove(vod_raw_path) + else: + print("Skip fixing. File not found.") + except Exception as e: + print('Error', 'A ERROR has ocurred and the VOD will not be downloaded.\n') + if self.downloadCHAT == 1: + print('Downloading and rendering CHAT: ' + current_vod["title"]) + try: + if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.bat", current_vod["id"], chat_json_path, chat_video_path]) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.sh", current_vod["id"], chat_json_path, chat_video_path]) + except Exception as e: + print("A ERROR has ocurred and chat will need to be downloaded and rendered manually\n") + + if self.uploadCloud == 1: + print('Uploading files:') + if self.os == 'windows': + if self.username == 'KalathrasLolweapon': + subprocess.call(['rclone', 'copy', str(pathlib.Path(__file__).parent.resolve())+'/VODS', 'gd:VODS', '--progress']) + subprocess.call(['rclone', 'copy', str(pathlib.Path(__file__).parent.resolve())+'/Chat', 'gd:Chat', '--progress']) + else:subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.bat', str(pathlib.Path(self.root_path).resolve()),self.username]) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.sh', str(pathlib.Path(self.root_path).resolve()),self.username]) + + if self.deleteFiles == 1: + print(f'{Fore.RED}DELETING FILES{Style.RESET_ALL}') + if self.downloadVOD == 1: + if(os.path.exists(vod_raw_path) is True): + print(f'{Fore.RED}Deleting ' + vod_raw_path + f'{Style.RESET_ALL}') + os.remove(vod_raw_path) + if(os.path.exists(vod_proc_path) is True): + print(f'{Fore.RED}Deleting ' + vod_proc_path + f'{Style.RESET_ALL}') + os.remove(vod_proc_path) + if self.downloadCHAT == 1: + if(os.path.exists(chat_json_path) is True): + print(f'{Fore.RED}Deleting ' + chat_json_path + f'{Style.RESET_ALL}') + os.remove(chat_json_path) + if(os.path.exists(chat_video_path) is True): + print(f'{Fore.RED}Deleting ' + chat_video_path + f'{Style.RESET_ALL}') + os.remove(chat_video_path) + else: + print('THE VOD/CHAT FOR CURRENT LIVESTREAM IS NOT AVAILABLE\nThe current livestream date: ' + is_live["createdAt"] + '\nThe VOD date: ' + current_vod["recordedAt"]) + print('CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') + time.sleep(self.refresh) + else: time.sleep(self.refresh) + else: time.sleep(self.refresh) def main(argv): twitch_archive = TwitchArchive() help_msg = 'Twitch-Archive\nPython script to download the VOD and/or chat and render it, upload them to any cloud storage.\n -h, --help Display this information\n -u, --username Twitch channel username\n -q, --quality best/source high/720p medium/480p worst/360p\n -v, --vod <1/0> Download vod\n -c, --chat <1/0> Download chat and render it\n -r, --upload <1/0> Upload to cloud storage\n -d, --delete <1/0> Delete all files after upload (CAREFUL with this arg)\n' diff --git a/twitch-archive.py b/twitch-archive.py index 082f26e..815bab1 100644 --- a/twitch-archive.py +++ b/twitch-archive.py @@ -14,12 +14,12 @@ class TwitchArchive: # global configuration self.root_path = r"archive" # Path where this script saves everything (livestream,VODs,chat,metadata) self.refresh = 5.0 # Time between checking (5.0 is recommended), avoid less than 1.0 - self.notifications = 0 # 0 - disable email notification of current seccion, 1 - enable email notification of current seccion + self.notifications = 1 # 0 - disable email notification of current seccion, 1 - enable email notification of current seccion self.downloadMETADATA = 1 # 0 - disable metadata downloading, 1 - enable metadata downloading self.downloadVOD = 1 # 0 - disable VOD downloading after stream finished, 1 - enable VOD downloading after stream finished (this option downloads the latest public vod) self.downloadCHAT = 1 # 0 - disable chat downloading and rendering, 1 - enable chat downloading and rendering - self.uploadCloud = 0 # 0 - disable upload to remote cloud, 1 - enable upload to remote cloud - self.deleteFiles = 0 # 0 - disable the deleting of files from current seccion after being uploaded to the cloud, 1 - enable the deleting files of files from current seccion after being uploaded to the cloud (BE CAREFUL WITH THIS OPTION) + self.uploadCloud = 1 # 0 - disable upload to remote cloud, 1 - enable upload to remote cloud + self.deleteFiles = 1 # 0 - disable the deleting of files from current seccion after being uploaded to the cloud, 1 - enable the deleting files of files from current seccion after being uploaded to the cloud (BE CAREFUL WITH THIS OPTION) self.cleanRaw = 1 # 0 - disable the deleting of raw (.ts) files, 1 - enable the deleteing of raw (.ts) files (if upload enable they will be deleted before) self.hls_segments = 3 # 1-10 for live stream, it's possible to use multiple threads to potentially increase the throughput. 2-3 is enough self.hls_segmentsVOD = 10 # 1-10 for downloading vod, it's possible to use multiple threads to potentially increase the throughput @@ -44,9 +44,6 @@ class TwitchArchive: else: print(f'{Fore.GREEN}'+'\033[1m'+f'Files will NOT be deleted{Style.RESET_ALL}') if self.uploadCloud == 0 and self.deleteFiles == 1: print(f'{Fore.RED}'+'\033[1m'+f'FILES WILL BE DELETED AND NO UPLOADED {Style.RESET_ALL}{Fore.GREEN}\n"CTRL + C"{Style.RESET_ALL}{Fore.RED}'+'\033[1m'+f' TO STOP AND CHANGED CONFIGURATION{Style.RESET_ALL}') - self.oauth_token = self.get_oauth_token() - self.channel_id = self.get_channel_id() - self.raw_path = str(pathlib.Path(os.path.join(self.root_path,self.username,"video", "raw")).absolute()) self.video_path = str(pathlib.Path(os.path.join(self.root_path, self.username, "video")).absolute()) self.chatJSON_path = str(pathlib.Path(os.path.join(self.root_path, self.username, "chat", "json")).absolute()) @@ -74,36 +71,52 @@ class TwitchArchive: print('OS no supported') return - def get_oauth_token(self): - try: - return requests.post(f"https://id.twitch.tv/oauth2/token?client_id={os.getenv('CLIENT-ID')}&client_secret={os.getenv('CLIENT-SECRET')}&grant_type=client_credentials").json()['access_token'] - except: - return None - def get_channel_id(self): - try: - r = requests.get(f'https://api.twitch.tv/helix/users?login={self.username}', headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.getenv('CLIENT-ID')}, timeout = 15) - r.raise_for_status() - info = r.json() - if info["data"] != []: - return info["data"][0]["id"] - else: - return None - except requests.exceptions.RequestException as e: - print(f'\n{e}\n') def check_user(self): - try: - url = 'https://api.twitch.tv/helix/streams?user_id=' + self.channel_id - live = requests.get(url, headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.environ.get('CLIENT-ID')}, timeout = 30) - stream_data = live.json() - if len(stream_data['data']) == 1: - self.live_info = stream_data['data'][0] - return True - else: - return False - except Exception as e: - print("ERROR checking user: ", e) - return False + client_id = "kimne78kx3ncx6brgo4mv6wki5h1ko" + query = ''' + query { + user(login: "''' + self.username + '''") { + stream { + archiveVideo{ + id + } + title + createdAt + } + } + } + ''' + url = 'https://gql.twitch.tv/gql' + response = requests.post(url,json={'query': query},headers={"Client-ID": client_id}) + return json.loads(response.text) + + def get_vod(self): + client_id = "kimne78kx3ncx6brgo4mv6wki5h1ko" + query = ''' + query { + user(login: "''' + self.username + '''") { + videos(first: 1) { + edges { + node { + id + scope + title + description + recordedAt + lengthSeconds + animatedPreviewURL + previewThumbnailURL(height: 1280, width: 720) + thumbnailURLs(height: 1280, width: 720) + } + } + } + } + } + ''' + url = 'https://gql.twitch.tv/gql' + response = requests.post(url, json={'query': query}, headers={"Client-ID": client_id}) + return json.loads(response.text) def sendNotif(self, subject, content): if self.notifications == 1: @@ -124,127 +137,124 @@ class TwitchArchive: def loopcheck(self): while True: - if self.check_user() is True: - live_date = datetime.strptime(self.live_info["started_at"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) - live_raw_filename = datetime.strftime(live_date,'%Y%m%d_%Hh%Mm%Ss') - - live_raw_path = os.path.join(self.raw_path, "LIVE_" + live_raw_filename + ".ts") - live_proc_path = os.path.join(self.video_path, "LIVE_" + live_raw_filename + ".mp4") - - with open(os.path.join(self.root_path, ".log")) as logs: - logs = logs.read() - log_id = self.live_info["started_at"] + " - " + self.live_info["title"] - if log_id in logs: - time.sleep(self.refresh) - - with open(os.path.join(self.root_path, ".log"), "r+") as logs: - log_id = self.live_info["started_at"] + " - " + self.username + " - " + self.live_info["title"] - for line in logs: - if log_id in line: - break - else: - logs.write(self.live_info["started_at"] + " - " + self.username + " - " + self.live_info["title"] + "\n") - - - self.sendNotif('Stream - ' + live_raw_filename, 'Streamer went live: ' + self.live_info["title"]) - subprocess.call(['streamlink', 'twitch.tv/'+ self.username, self.quality, '--twitch-api-header', 'Authorization=OAuth ' + os.getenv('OAUTH-PRIVATE-TOKEN'), '--hls-segment-threads', str(self.hls_segments), '--hls-live-restart', '--retry-streams', str(self.refresh), '--twitch-disable-reruns', '-o', live_raw_path]) - if(os.path.exists(live_raw_path) is True): - if self.os == 'windows': subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', live_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', live_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - elif self.os == 'linux': subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', live_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', live_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - else: - print("Skip fixing. File not found.") - try: - vodurl = f'https://api.twitch.tv/helix/videos?user_id={str(self.channel_id)}&period=day&type=archive' - vods = requests.get(vodurl, headers = {"Authorization" : "Bearer " + self.oauth_token, "Client-ID": os.getenv('CLIENT-ID')}, timeout = 30) - vodsinfo = json.loads(vods.text) - if vodsinfo["data"][0] != []: - vod_date = datetime.strptime(vodsinfo["data"][0]["created_at"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) - vod_raw_filename = datetime.strftime(vod_date,'%Y%m%d_%Hh%Mm%Ss') - if self.live_info["id"] == vodsinfo["data"][0]["stream_id"]: - current_vod = vodsinfo["data"][0] - vod_raw_path = os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts") - vod_proc_path = os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4") - - if self.downloadMETADATA == 1: - self.sendNotif('Metadata - ' + live_raw_filename,'Downloading and saving metadata:\n' + json.dumps(current_vod, indent=4)) - with open(os.path.join(self.metadata_path, "METADA_" + live_raw_filename + ".json"), 'w', encoding='utf-8') as f: - json.dump(current_vod, f, ensure_ascii=False, indent=4) - - if self.downloadVOD == 1: - print('Downloading VOD: ' + current_vod["title"]) - self.sendNotif('VOD - ' + live_raw_filename,'Downloading VOD: ' + current_vod["title"]) - try: - subprocess.call(['streamlink', 'twitch.tv/videos/' + current_vod["id"], self.quality, '--twitch-api-header', 'Authorization=OAuth ' + os.getenv('OAUTH-PRIVATE-TOKEN'), "--hls-segment-threads", str(self.hls_segmentsVOD), "-o", vod_raw_path]) - if(os.path.exists(vod_raw_path) is True): - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) - else: - print("Skip fixing. File not found.") - except Exception as e: - print('Error', 'A ERROR has ocurred and the VOD will not be downloaded.\n') - self.sendNotif('ERROR - ' + live_raw_filename, 'A ERROR has ocurred and the VOD will not be downloaded.\n') + is_live = self.check_user()['data']['user']['stream'] + if is_live is not None: + is_live_ready = self.check_user()['data']['user']['stream']['title'] + if is_live_ready is not None: + live_date = datetime.strptime(is_live["createdAt"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) + live_raw_filename = datetime.strftime(live_date,'%Y%m%d_%Hh%Mm%Ss') - if self.downloadCHAT == 1: - print('Downloading and rendering CHAT: ' + current_vod["title"]) - self.sendNotif('CHAT - ' + live_raw_filename,'Downloading JSON and rendering chat logs from VOD:\n' + current_vod["title"]) - try: - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.bat", current_vod["id"], os.path.join(self.chatJSON_path, "CHAT_" + live_raw_filename + ".json"), os.path.join(self.chatMP4_path, "CHAT_" + live_raw_filename + ".mp4")]) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.sh", current_vod["id"], os.path.join(self.chatJSON_path, "CHAT_" + live_raw_filename + ".json"), os.path.join(self.chatMP4_path, "CHAT_" + live_raw_filename + ".mp4")]) - except Exception as e: - self.sendNotif('ERROR - ' + live_raw_filename, "A ERROR has ocurred and chat will need to be downloaded and rendered manually.\n") - print("A ERROR has ocurred and chat will need to be downloaded and rendered manually\n") + live_raw_path = os.path.join(self.raw_path, "LIVE_" + live_raw_filename + ".ts") + live_proc_path = os.path.join(self.video_path, "LIVE_" + live_raw_filename + ".mp4") + + with open(os.path.join(self.root_path, ".log")) as logs: + logs = logs.read() + log_id = is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] + if log_id in logs: + time.sleep(self.refresh) + + with open(os.path.join(self.root_path, ".log"), "r+") as logs: + log_id = is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] + for line in logs: + if log_id in line: + break else: - print('A ERROR has ocurred, the latest VOD doesnt match with the livestream, the VOD is not published\nThe VOD and chat will not be downloaded and rendered.\nThe current livestream date: ' + live_raw_filename + '\nThe VOD date: ' + vod_raw_filename) - self.sendNotif('ERROR - ' + live_raw_filename, 'A ERROR has ocurred, the latest VOD doesnt match with the livestream, the VOD is not published\nThe VOD and chat will not be downloaded and rendered.\nThe current livestream date: ' + live_raw_filename + '\nThe VOD date: ' + vod_raw_filename) - except Exception as e: - print('An error has occurred. VOD and chat will not be downloaded. Please check them manually.\n') - self.sendNotif('ERROR - ' + live_raw_filename, 'An error has occurred. VOD and chat will not be downloaded. Please check them manually.\n') - - if self.cleanRaw == 1: - print('Deleting raw files') - if(os.path.exists(live_raw_path) is True): os.remove(live_raw_path) - if self.downloadVOD == 1: - if(os.path.exists(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) is True): - os.remove(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) - if self.uploadCloud == 1: - if self.os == 'windows': - tree = subprocess.run(['powershell.exe','tree', f'{self.root_path}/{self.username}', '/f'], capture_output=True, text=True).stdout.split("\n",2)[2] - elif self.os == 'linux': - tree = subprocess.check_output(['tree', str(pathlib.Path(self.root_path).resolve())+'/'+self.username]).decode(sys.stdout.encoding) - print('Uploading the following files:\n' + tree) - self.sendNotif("UPLOADING - " + live_raw_filename, 'Uploading the following files: \n' + tree) - if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.bat', str(pathlib.Path(self.root_path).resolve()),self.username]) - elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.sh', str(pathlib.Path(self.root_path).resolve()),self.username]) - if self.deleteFiles == 1: - self.sendNotif("DELETING - " + live_raw_filename, "Deleting the files from current seccion.") - print(f'{Fore.RED}DELETING FILES{Style.RESET_ALL}') - if self.cleanRaw == 0: - print(f'{Fore.RED}Deleting ' + live_raw_path + f'{Style.RESET_ALL}') - os.remove(live_raw_path) - print(f'{Fore.RED}Deleting ' + live_proc_path + f'{Style.RESET_ALL}') - os.remove(live_proc_path) - if self.downloadVOD == 1: - if(os.path.exists(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) is True): - if self.cleanRaw == 0: - print(f'{Fore.RED}Deleting ' + os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts") + f'{Style.RESET_ALL}') + logs.write(is_live["createdAt"] + " - " + self.username + " - " + is_live["title"] +"\n") + + self.sendNotif('Stream - ' + live_raw_filename, 'Streamer went live: ' + is_live["title"]) + subprocess.call(['streamlink', 'twitch.tv/'+ self.username, self.quality, '--twitch-api-header', 'Authorization=OAuth ' + os.getenv('OAUTH-PRIVATE-TOKEN'), '--hls-segment-threads', str(self.hls_segments), '--hls-live-restart', '--retry-streams', str(self.refresh), '--twitch-disable-reruns', '-o', live_raw_path]) + if(os.path.exists(live_raw_path) is True): + if self.os == 'windows': subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', live_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', live_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + elif self.os == 'linux': subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', live_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', live_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + else: + print("Skip fixing. File not found.") + + current_vod = self.get_vod()['data']['user']['videos']['edges'][0]['node'] + live_date_min = live_date - timedelta(minutes=1) + live_date_max = live_date + timedelta(minutes=1) + + vod_date = datetime.strptime(current_vod["recordedAt"],'%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=timezone('UTC')).astimezone(tz=None).replace(tzinfo=None) + + if live_date_min <= vod_date <= live_date_max: + vod_raw_path = os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts") + vod_proc_path = os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4") + + if self.downloadMETADATA == 1: + self.sendNotif('Metadata - ' + live_raw_filename,'Downloading and saving metadata:\n' + json.dumps(current_vod, indent=4)) + with open(os.path.join(self.metadata_path, "METADA_" + live_raw_filename + ".json"), 'w', encoding='utf-8') as f: + json.dump(current_vod, f, ensure_ascii=False, indent=4) + + if self.downloadVOD == 1: + print('Downloading VOD: ' + current_vod["title"]) + self.sendNotif('VOD - ' + live_raw_filename,'Downloading VOD: ' + current_vod["title"]) + try: + subprocess.call(['streamlink', 'twitch.tv/videos/' + str(current_vod["id"]), self.quality, '--twitch-api-header', 'Authorization=OAuth ' + os.getenv('OAUTH-PRIVATE-TOKEN'), "--hls-segment-threads", str(self.hls_segmentsVOD), "-o", vod_raw_path]) + if(os.path.exists(vod_raw_path) is True): + if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg.exe', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/ffmpeg', '-y', '-i', vod_raw_path, '-analyzeduration', '2147483647', '-probesize', '2147483647', '-c:v', 'copy', '-c:a', 'copy', '-start_at_zero', '-copyts', vod_proc_path], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) + else: + print("Skip fixing. File not found.") + except Exception as e: + print('Error', 'A ERROR has ocurred and the VOD will not be downloaded.\n') + self.sendNotif('ERROR - ' + live_raw_filename, 'A ERROR has ocurred and the VOD will not be downloaded.\n') + + if self.downloadCHAT == 1: + print('Downloading and rendering CHAT: ' + current_vod["title"]) + self.sendNotif('CHAT - ' + live_raw_filename,'Downloading JSON and rendering chat logs from VOD:\n' + current_vod["title"]) + try: + if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.bat", str(current_vod["id"]), os.path.join(self.chatJSON_path, "CHAT_" + live_raw_filename + ".json"), os.path.join(self.chatMP4_path, "CHAT_" + live_raw_filename + ".mp4")]) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+"/bin/chat.sh", str(current_vod["id"]), os.path.join(self.chatJSON_path, "CHAT_" + live_raw_filename + ".json"), os.path.join(self.chatMP4_path, "CHAT_" + live_raw_filename + ".mp4")]) + except Exception as e: + self.sendNotif('ERROR - ' + live_raw_filename, "A ERROR has ocurred and chat will need to be downloaded and rendered manually.\n") + print("A ERROR has ocurred and chat will need to be downloaded and rendered manually\n") + else: + print('not VOD associated with stream found') + if self.cleanRaw == 1: + print('Deleting raw files') + if(os.path.exists(live_raw_path) is True): os.remove(live_raw_path) + if self.downloadVOD == 1: + if(os.path.exists(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) is True): os.remove(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) - if(os.path.exists(os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4")) is True): - print(f'{Fore.RED}Deleting ' + os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4") + f'{Style.RESET_ALL}') - os.remove(os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4")) - if self.downloadCHAT == 1: - if(os.path.exists(os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json")) is True): - print(f'{Fore.RED}Deleting ' + os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json") + f'{Style.RESET_ALL}') - os.remove(os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json")) - if(os.path.exists(os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4")) is True): - print(f'{Fore.RED}Deleting ' + os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4") + f'{Style.RESET_ALL}') - os.remove(os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4")) - if self.downloadMETADATA == 1: - if(os.path.exists(os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json")) is True): - print(f'{Fore.RED}Deleting ' + os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json") + f'{Style.RESET_ALL}') - os.remove(os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json")) - print('CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') - self.sendNotif("SECCION DONE - " + live_raw_filename, 'CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') - time.sleep(self.refresh) + if self.uploadCloud == 1: + with open(str(pathlib.Path(__file__).parent.resolve())+"/bin/temp/upload.txt", "a") as myfile: + myfile.write("LIVE_" + live_raw_filename + ".ts\n"+"VOD_" + live_raw_filename + ".ts\n"+"LIVE_" + live_raw_filename + ".mp4\n"+"VOD_" + live_raw_filename + ".mp4\n"+"METADATA_" + live_raw_filename + ".json\n"+"CHAT_" + live_raw_filename + ".json\n"+"CHAT_" + live_raw_filename + ".mp4\n") + print('Uploading files') + self.sendNotif("UPLOADING - " + live_raw_filename, 'The files are being uploaded') + if self.os == 'windows':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.bat', str(pathlib.Path(self.root_path).resolve()),self.username]) + elif self.os == 'linux':subprocess.call([str(pathlib.Path(__file__).parent.resolve())+'/bin/upload.sh', str(pathlib.Path(self.root_path).resolve()),self.username]) + os.remove(str(pathlib.Path(__file__).parent.resolve())+"/bin/temp/upload.txt") + if self.deleteFiles == 1: + self.sendNotif("DELETING - " + live_raw_filename, "Deleting the files from current seccion.") + print(f'{Fore.RED}DELETING FILES{Style.RESET_ALL}') + if self.cleanRaw == 0: + print(f'{Fore.RED}Deleting ' + live_raw_path + f'{Style.RESET_ALL}') + os.remove(live_raw_path) + print(f'{Fore.RED}Deleting ' + live_proc_path + f'{Style.RESET_ALL}') + os.remove(live_proc_path) + if self.downloadVOD == 1: + if(os.path.exists(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) is True): + if self.cleanRaw == 0: + print(f'{Fore.RED}Deleting ' + os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts") + f'{Style.RESET_ALL}') + os.remove(os.path.join(self.raw_path, "VOD_" + live_raw_filename + ".ts")) + if(os.path.exists(os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4")) is True): + print(f'{Fore.RED}Deleting ' + os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4") + f'{Style.RESET_ALL}') + os.remove(os.path.join(self.video_path, "VOD_" + live_raw_filename + ".mp4")) + if self.downloadCHAT == 1: + if(os.path.exists(os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json")) is True): + print(f'{Fore.RED}Deleting ' + os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json") + f'{Style.RESET_ALL}') + os.remove(os.path.join(self.chatJSON_path, "CHAT_"+live_raw_filename + ".json")) + if(os.path.exists(os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4")) is True): + print(f'{Fore.RED}Deleting ' + os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4") + f'{Style.RESET_ALL}') + os.remove(os.path.join(self.chatMP4_path, "CHAT_"+live_raw_filename + ".mp4")) + if self.downloadMETADATA == 1: + if(os.path.exists(os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json")) is True): + print(f'{Fore.RED}Deleting ' + os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json") + f'{Style.RESET_ALL}') + os.remove(os.path.join(self.metadata_path, "METADA_"+live_raw_filename+".json")) + print('CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') + self.sendNotif("SECCION DONE - " + live_raw_filename, 'CURRENT SECCION HAVE FINISHED GOING BACK TO CHECKING') + time.sleep(self.refresh) + else: time.sleep(self.refresh) + else: time.sleep(self.refresh) def main(argv): twitch_archive = TwitchArchive() help_msg = 'Twitch-Archive\nPython script to record twitch live stream, download the VOD, metadata, chat and render it, and uploads them to any cloud storage.\n -h, --help Display this information\n -u, --username Twitch channel username\n -q, --quality best/source high/720p medium/480p worst/360p\n -v, --vod <1/0> Download vod\n -c, --chat <1/0> Download chat and render it\n -m, --metadata <1/0> Download metadata\n -r, --upload <1/0> Upload to cloud storage\n -d, --delete <1/0> Delete all files after upload (CAREFUL with this arg)\n -n, --notifications <1/0> Receive email notification of the proccess through gmail\n'