diff --git a/clipper/chat.py b/clipper/chat.py index 965a82f..af6d743 100644 --- a/clipper/chat.py +++ b/clipper/chat.py @@ -1,5 +1,6 @@ import logging from datetime import datetime +import multiprocessing logger = logging.getLogger(__name__) @@ -8,12 +9,18 @@ CHAT_DIVIDER = "<~|~>" class TwitchChatRecorder: is_running = False + chat_process = None def __init__(self, api, debug=False): self.debug = debug self.api = api def run(self, streamer_name, output_file): + self.is_running = True + self.chat_process = multiprocessing.Process(target=self._record_chat, args=(streamer_name, output_file)) + self.chat_process.start() + + def _record_chat(self, streamer_name, output_file): with open(output_file, "w") as stream: def on_message(twitch_msg): user, msg = self.parse_msg(twitch_msg) @@ -25,9 +32,21 @@ class TwitchChatRecorder: if self.debug: logger.info("Chat: %s", msg_line) - self.is_running = True self.api.start_chat(streamer_name, on_message) + def stop(self): + try: + if self.chat_process: + self.chat_process.terminate() + + self.chat_process = None + logger.error("Chat stopped") + except BaseException as e: + logger.error("Unable to stop chat") + logger.error(e) + + self.is_running = False + def parse_msg(self, msg): try: return msg[1:].split('!')[0], msg.split(":", 2)[2] diff --git a/clipper/recorder.py b/clipper/recorder.py index 106d657..312f54a 100644 --- a/clipper/recorder.py +++ b/clipper/recorder.py @@ -2,7 +2,6 @@ import logging import os import time import sys -import threading from datetime import datetime from clipper.api import TwitchApi, TwitchStreamStatus @@ -22,21 +21,29 @@ class RecorderConfig: class Recorder: - audio_thread = None - video_thread = None - def __init__(self, config): self.config = config self.api = TwitchApi(config.tw_client, config.tw_secret) self.streamer_folder = os.path.join(self.config.output_folder, self.config.tw_streamer) self.video_recorder = TwitchVideoRecorder() - self.chat_recorder = TwitchChatRecorder(self.api, debug=True) + self.chat_recorder = TwitchChatRecorder(self.api, debug=False) def run(self): + logger.info("Start watching streamer %s", self.config.tw_streamer) + status = self.api.get_user_status(self.config.tw_streamer) + while True: - logger.info("Start watching streamer %s", self.config.tw_streamer) - status = self.api.get_user_status(self.config.tw_streamer) - if status == TwitchStreamStatus.ONLINE: + if self.video_recorder.is_running or self.chat_recorder.is_running: + if not (self.video_recorder.is_running and self.chat_recorder.is_running): + self.video_recorder.stop() + self.chat_recorder.stop() + time.sleep(1) + continue + + logger.info("Recording in progress. Wait 1m") + time.sleep(60) + + elif status == TwitchStreamStatus.ONLINE: logger.info("Streamer %s is online. Start recording", self.config.tw_streamer) start_time = datetime.now() @@ -44,16 +51,15 @@ class Recorder: record_folder = os.path.join(self.streamer_folder, record_folder_name) os.makedirs(record_folder) - chat_file = os.path.join(record_folder, "chat.txt") + chat_file = os.path.join(record_folder, "chat.txt") video_file = os.path.join(record_folder, "video.mp4") self.chat_recorder.run(self.config.tw_streamer, chat_file) - # self.video_recorder.run(file_template) + self.video_recorder.run(self.config.tw_streamer, video_file, quality="160p") - logger.info("Streamer %s has finished stream", self.config.tw_streamer) - time.sleep(15) + time.sleep(5) - if status == TwitchStreamStatus.OFFLINE: + elif status == TwitchStreamStatus.OFFLINE: logger.info("Streamer %s is offline. Waiting for 300 sec", self.config.tw_streamer) time.sleep(300) @@ -61,6 +67,6 @@ class Recorder: logger.critical("Error occurred. Exit", self.config.tw_streamer) sys.exit(1) - if status == TwitchStreamStatus.NOT_FOUND: + elif status == TwitchStreamStatus.NOT_FOUND: logger.critical(f"Streamer %s not found, invalid streamer_name or typo", self.config.tw_streamer) sys.exit(1) diff --git a/clipper/video.py b/clipper/video.py index 5b3a4fb..bea109a 100644 --- a/clipper/video.py +++ b/clipper/video.py @@ -9,22 +9,35 @@ class TwitchVideoRecorder: refresh_timeout = 15 streamlink_process = None - def run(self, streamer_name, output_file, quality="480p"): + def run(self, streamer_name, output_file, quality="720p"): + self.is_running = True self._record_stream(streamer_name, output_file, quality) def stop(self): - if self.streamlink_process: - self.streamlink_process.kill() + try: + if self.streamlink_process: + self.streamlink_process.terminate() + + self.streamlink_process = None + logger.error("Video stopped") + except BaseException as e: + logger.error("Unable to stop video") + logger.error(e) + + self.is_running = False def _record_stream(self, streamer_name, output_file, quality): - # subprocess.call() - self.streamlink_process = subprocess.Popen([ - "streamlink", - "--twitch-disable-ads", - "twitch.tv/" + streamer_name, - quality, - "-o", - output_file - ]) + try: + self.streamlink_process = subprocess.Popen([ + "streamlink", + "--twitch-disable-ads", + "twitch.tv/" + streamer_name, + quality, + "-o", + output_file + ]) - self.is_running = True + except BaseException as e: + logger.error("Unable to run streamlink") + logger.error(e) + self.is_running = False