diff --git a/app/core/stream_manager.py b/app/core/stream_manager.py index 6aeca65..c914a50 100644 --- a/app/core/stream_manager.py +++ b/app/core/stream_manager.py @@ -140,9 +140,23 @@ class LiveStreamRecorder: cleaned_title = title[:30].replace(",", ",").replace(" ", "") return cleaned_title - def _get_record_url(self, url: str): - http_record_list = ["shopee", "migu"] + @property + def is_flv_preferred_platform(self): + return self.platform_key in {"douyin", "tiktok"} + def _select_source_url(self, stream_info: StreamData): + if ( + self.user_config.get("default_live_source") != "HLS" + and self.is_flv_preferred_platform + and self.quality not in {"OD", 0} + ): + return stream_info.flv_url + return stream_info.record_url + + def _get_record_url(self, stream_info: StreamData): + url = self._select_source_url(stream_info) + + http_record_list = ["shopee", "migu"] if self.user_config.get("force_https_recording") and url.startswith("http://"): url = url.replace("http://", "https://") @@ -190,7 +204,7 @@ class LiveStreamRecorder: logger.info(f"Save Path: {save_path}") self.recording.recording_dir = os.path.dirname(save_path) os.makedirs(self.recording.recording_dir, exist_ok=True) - record_url = self._get_record_url(stream_info.record_url) + record_url = self._get_record_url(stream_info) if use_direct_download: logger.info(f"Use Direct Downloader to Download FLV Stream: {record_url}") @@ -199,14 +213,14 @@ class LiveStreamRecorder: if header_params: key, value = header_params.split(":", 1) headers[key] = value - + self.direct_downloader = DirectStreamDownloader( record_url=record_url, save_path=save_path, headers=headers, proxy=self.proxy ) - + self.app.page.run_task( self.start_direct_download, stream_info.anchor_name, @@ -231,20 +245,20 @@ class LiveStreamRecorder: self.start_ffmpeg, stream_info.anchor_name, self.live_url, - stream_info.record_url, + record_url, ffmpeg_command, self.save_format, self.user_config.get("custom_script_command") ) async def start_ffmpeg( - self, - record_name: str, - live_url: str, - record_url: str, - ffmpeg_command: list, - save_type: str, - script_command: str | None = None + self, + record_name: str, + live_url: str, + record_url: str, + ffmpeg_command: list, + save_type: str, + script_command: str | None = None ) -> bool: """ The child process executes ffmpeg for recording @@ -494,13 +508,13 @@ class LiveStreamRecorder: logger.error(f"An unknown error occurred: {e}") async def custom_script_execute( - self, - script_command: str, - record_name: str, - save_file_path: str, - save_type: str, - split_video_by_time: bool, - converts_to_mp4: bool + self, + script_command: str, + record_name: str, + save_file_path: str, + save_type: str, + split_video_by_time: bool, + converts_to_mp4: bool ): from ..process_manager import BackgroundService @@ -585,36 +599,36 @@ class LiveStreamRecorder: return record_headers.get(platform_key) async def start_direct_download( - self, - record_name: str, - live_url: str, - record_url: str, - save_file_path: str, - save_type: str, - script_command: str | None = None + self, + record_name: str, + live_url: str, + record_url: str, + save_file_path: str, + save_type: str, + script_command: str | None = None ) -> bool: """ Use the direct downloader to download the live stream """ try: await self.direct_downloader.start_download() - + self.recording.status_info = RecordingStatus.RECORDING self.recording.record_url = record_url logger.info(f"Direct Downloading: {live_url}") logger.log("STREAM", f"Direct Download Stream URL: {record_url}") - + while True: if not self.recording.is_recording or not self.app.recording_enabled: logger.info(f"Prepare to end direct download: {live_url}") await self.direct_downloader.stop_download() break - + await asyncio.sleep(1) - + if self.direct_downloader.download_task and self.direct_downloader.download_task.done(): break - + if self.recording.monitor_status: self.recording.status_info = RecordingStatus.MONITORING display_title = self.recording.title @@ -649,7 +663,7 @@ class LiveStreamRecorder: self.recording.notified_live_end = True self.recording.is_recording = False - + try: self.recording.update({"display_title": display_title}) await self.app.record_card_manager.update_card(self.recording) @@ -686,7 +700,7 @@ class LiveStreamRecorder: ) return True - + except Exception as e: logger.error(f"Error occurred during direct download: {e}") self.recording.status_info = RecordingStatus.RECORDING_ERROR @@ -702,4 +716,4 @@ class LiveStreamRecorder: logger.debug(f"Failed to update UI: {e}") return False finally: - self.recording.record_url = None + self.recording.record_url = None \ No newline at end of file diff --git a/app/ui/views/settings_view.py b/app/ui/views/settings_view.py index 9910b8a..0d7b6fa 100644 --- a/app/ui/views/settings_view.py +++ b/app/ui/views/settings_view.py @@ -364,6 +364,17 @@ class SettingsPage(PageBase): on_change=self.on_change, ), ), + self.create_setting_row( + self._["default_live_source"], + ft.Dropdown( + options=[ft.dropdown.Option(i) for i in ['HLS', 'FLV']], + value=self.get_config_value("default_live_source", 'FLV'), + width=200, + data="default_live_source", + on_change=self.on_change, + tooltip=self._["default_live_source_tip"], + ), + ), self.create_setting_row( self._["space_threshold"], ft.TextField( diff --git a/config/default_settings.json b/config/default_settings.json index ca3c5c7..8f463a5 100644 --- a/config/default_settings.json +++ b/config/default_settings.json @@ -14,6 +14,7 @@ "loop_time_seconds": "180", "segmented_recording_enabled": true, "force_https_recording": true, + "default_live_source": "FLV", "recording_space_threshold": "2.0", "video_segment_time": "1800", "convert_to_mp4": true, diff --git a/locales/en.json b/locales/en.json index f3fde8e..131e6eb 100644 --- a/locales/en.json +++ b/locales/en.json @@ -217,6 +217,8 @@ "loop_time": "Loop Time (Seconds)", "is_segmented_recording_enabled": "Enable Segmented Recording", "force_https": "Force HTTPS Recording", + "default_live_source": "Default Live Source", + "default_live_source_tip": "This setting only works for Douyin and TikTok platforms", "space_threshold": "Remaining Space Threshold (GB) for Recording", "segment_time": "Video Segment Time (Seconds)", "convert_mp4": "Convert to MP4 After Recording", diff --git a/locales/zh_CN.json b/locales/zh_CN.json index 81b26e2..62e4d9c 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -219,6 +219,8 @@ "loop_time": "循环时间(秒)", "is_segmented_recording_enabled": "分段录制是否开启", "force_https": "强制启用https录制", + "default_live_source": "默认直播源", + "default_live_source_tip": "该设置只对抖音和TikTok平台有效", "space_threshold": "录制空间剩余阈值(gb)", "segment_time": "视频分段时间(秒)", "convert_mp4": "录制完成后转为mp4格式",