diff --git a/douyinliverecorder/initializer.py b/douyinliverecorder/initializer.py index bb0088e..2b339a1 100644 --- a/douyinliverecorder/initializer.py +++ b/douyinliverecorder/initializer.py @@ -23,13 +23,16 @@ execute_dir = os.path.split(os.path.realpath(sys.argv[0]))[0] current_env_path = os.environ.get('PATH') -def unzip_file(zip_path: str | Path, extract_to: str | Path) -> None: +def unzip_file(zip_path: str | Path, extract_to: str | Path, delete: bool = True) -> None: if not os.path.exists(extract_to): os.makedirs(extract_to) with zipfile.ZipFile(zip_path, 'r') as zip_ref: zip_ref.extractall(extract_to) + if delete and os.path.exists(zip_path): + os.remove(zip_path) + def install_nodejs_windows(): try: @@ -148,14 +151,22 @@ def install_nodejs_mac(): logger.error(f"An unexpected error occurred: {e}") +def get_package_manager(): + dist_id = distro.id() + if dist_id in ["centos", "fedora", "rhel", "amzn", "oracle", "scientific", "opencloudos", "alinux"]: + return "RHS" + else: + return "DBS" + + def install_nodejs() -> bool: if current_platform == "Windows": return install_nodejs_windows() elif current_platform == "Linux": - dist = distro.id() - if dist.lower() == "centos": + os_type = get_package_manager() + if os_type == "RHS": return install_nodejs_centos() - elif dist.lower() == "ubuntu": + else: return install_nodejs_ubuntu() elif current_platform == "Darwin": return install_nodejs_mac() @@ -206,4 +217,4 @@ def check_nodejs_installed() -> bool: def check_node() -> bool: if not check_nodejs_installed(): - return install_nodejs() \ No newline at end of file + return install_nodejs() diff --git a/ffmpeg.exe b/ffmpeg.exe deleted file mode 100644 index 7902bad..0000000 Binary files a/ffmpeg.exe and /dev/null differ diff --git a/ffmpeg_install.py b/ffmpeg_install.py new file mode 100644 index 0000000..fc86037 --- /dev/null +++ b/ffmpeg_install.py @@ -0,0 +1,221 @@ +# -*- coding: utf-8 -*- + +""" +Author: Hmily +GitHub: https://github.com/ihmily +Copyright (c) 2024 by Hmily, All Rights Reserved. +""" + +import os +import re +import subprocess +import sys +import platform +import zipfile +from pathlib import Path +import requests +from tqdm import tqdm +from douyinliverecorder.logger import logger + +current_platform = platform.system() +execute_dir = os.path.split(os.path.realpath(sys.argv[0]))[0] +current_env_path = os.environ.get('PATH') + + +def unzip_file(zip_path: str | Path, extract_to: str | Path, delete: bool = True) -> None: + if not os.path.exists(extract_to): + os.makedirs(extract_to) + + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + zip_ref.extractall(extract_to) + + if delete and os.path.exists(zip_path): + os.remove(zip_path) + + +def get_lanzou_download_link(url: str, password: str | None = None) -> str | None: + try: + headers = { + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', + 'Origin': 'https://wweb.lanzouv.com', + 'Referer': 'https://wweb.lanzouv.com/iXncv0dly6mh', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0', + } + response = requests.get(url, headers=headers) + sign = re.search("var skdklds = '(.*?)';", response.text).group(1) + data = { + 'action': 'downprocess', + 'sign': sign, + 'p': password, + 'kd': '1', + } + response = requests.post('https://wweb.lanzouv.com/ajaxm.php', headers=headers, data=data) + json_data = response.json() + download_url = json_data['dom'] + "/file/" + json_data['url'] + response = requests.get(download_url, headers=headers) + return response.url + except Exception as e: + logger.error(f"Failed to obtain ffmpeg download address. {e}") + + +def install_ffmpeg_windows(): + try: + logger.warning("ffmpeg is not installed.") + logger.debug("Installing the stable version of ffmpeg for Windows...") + ffmpeg_url = get_lanzou_download_link('https://wweb.lanzouv.com/in54b2gmj24b', 'e3ut') + if ffmpeg_url: + full_file_name = 'ffmpeg-7.1.zip' + version = '7.1' + zip_file_path = Path(execute_dir) / full_file_name + if Path(zip_file_path).exists(): + logger.debug("ffmpeg installation file already exists, start install...") + else: + response = requests.get(ffmpeg_url, stream=True) + total_size = int(response.headers.get('Content-Length', 0)) + block_size = 1024 + + with tqdm(total=total_size, unit="B", unit_scale=True, + ncols=100, desc=f'Downloading ffmpeg ({version})') as t: + with open(zip_file_path, 'wb') as f: + for data in response.iter_content(block_size): + t.update(len(data)) + f.write(data) + + unzip_file(zip_file_path, execute_dir) + extract_dir_path = str(zip_file_path).rsplit('.', maxsplit=1)[0] + os.environ['PATH'] = execute_dir + '/' + extract_dir_path + os.pathsep + current_env_path + result = subprocess.run(["ffmpeg", "-version"], capture_output=True) + if result.returncode == 0: + logger.debug('ffmpeg installation was successful') + else: + logger.error('ffmpeg installation failed. Please manually install ffmpeg by yourself') + return True + else: + logger.error("Please manually install ffmpeg by yourself") + except Exception as e: + logger.error(f"type: {type(e).__name__}, ffmpeg installation failed {e}") + + +def install_ffmpeg_mac(): + logger.warning("ffmpeg is not installed.") + logger.debug("Installing the stable version of ffmpeg for macOS...") + try: + result = subprocess.run(["brew", "install", "ffmpeg"], capture_output=True) + if result.returncode == 0: + logger.debug('ffmpeg installation was successful. Restart for changes to take effect.') + return True + else: + logger.error("ffmpeg installation failed") + except subprocess.CalledProcessError as e: + logger.error(f"Failed to install ffmpeg using Homebrew. {e}") + logger.error("Please install ffmpeg manually or check your Homebrew installation.") + except Exception as e: + logger.error(f"An unexpected error occurred: {e}") + + +def install_ffmpeg_linux(): + is_RHS = True + + try: + logger.warning("ffmpeg is not installed.") + logger.debug("Trying to install the stable version of ffmpeg") + result = subprocess.run(['yum', '-y', 'update'], capture_output=True) + if result.returncode != 0: + logger.error(f"Failed to update package lists using yum.") + return False + + result = subprocess.run(['yum', 'install', '-y', 'ffmpeg'], capture_output=True) + if result.returncode == 0: + logger.debug("ffmpeg installation was successful using yum. Restart for changes to take effect.") + return True + logger.error(result.stderr.decode('utf-8').strip()) + except FileNotFoundError: + logger.debug("yum command not found, trying to install using apt...") + is_RHS = False + except Exception as e: + logger.error(f"An error occurred while trying to install ffmpeg using yum: {e}") + + if not is_RHS: + try: + logger.debug("Trying to install the stable version of ffmpeg for Linux using apt...") + result = subprocess.run(['apt', 'update'], capture_output=True) + if result.returncode != 0: + logger.error("Failed to update package lists using apt") + return False + + result = subprocess.run(['apt', 'install', '-y', 'ffmpeg'], capture_output=True) + if result.returncode == 0: + logger.debug("ffmpeg installation was successful using apt. Restart for changes to take effect.") + return True + else: + logger.error(result.stderr.decode('utf-8').strip()) + except FileNotFoundError: + logger.error("apt command not found, unable to install ffmpeg. Please manually install ffmpeg by yourself") + except Exception as e: + logger.error(f"An error occurred while trying to install ffmpeg using apt: {e}") + logger.error("Manual installation of ffmpeg is required. Please manually install ffmpeg by yourself.") + return False + + +def install_ffmpeg() -> bool: + if current_platform == "Windows": + return install_ffmpeg_windows() + elif current_platform == "Linux": + return install_ffmpeg_linux() + elif current_platform == "Darwin": + return install_ffmpeg_mac() + else: + logger.debug(f"ffmpeg auto installation is not supported on this platform: {current_platform}. " + f"Please install ffmpeg manually.") + return False + + +def ensure_ffmpeg_installed(func): + def wrapper(*args, **kwargs): + try: + result = subprocess.run(['ffmpeg', '-version'], capture_output=True) + version = result.stdout.strip() + if result.returncode == 0 and version: + return func(*args, **kwargs) + except FileNotFoundError: + pass + return False + + def wrapped_func(*args, **kwargs): + if sys.version_info >= (3, 7): + res = wrapper(*args, **kwargs) + else: + res = wrapper(*args, **kwargs) + if not res: + install_ffmpeg() + res = wrapper(*args, **kwargs) + + if not res: + raise RuntimeError("ffmpeg is not installed.") + + return func(*args, **kwargs) + + return wrapped_func + + +def check_ffmpeg_installed() -> bool: + try: + result = subprocess.run(['ffmpeg', '-version'], capture_output=True) + version = result.stdout.strip() + if result.returncode == 0 and version: + return True + except FileNotFoundError: + pass + except OSError as e: + print(f"OSError occurred: {e}. ffmpeg may not be installed correctly or is not available in the system PATH.") + print("Please delete the ffmpeg and try to download and install again.") + except Exception as e: + print(f"An unexpected error occurred: {e}") + return False + + +def check_ffmpeg() -> bool: + if not check_ffmpeg_installed(): + return install_ffmpeg() + return True diff --git a/main.py b/main.py index 1f7afa8..a22b669 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,7 @@ Author: Hmily GitHub: https://github.com/ihmily Date: 2023-07-17 23:52:05 -Update: 2024-11-16 04:28:00 +Update: 2024-11-29 19:53:00 Copyright (c) 2023-2024 by Hmily, All Rights Reserved. Function: Record live stream video. """ @@ -27,6 +27,7 @@ import urllib.request from urllib.error import URLError, HTTPError from typing import Any import configparser +from ffmpeg_install import check_ffmpeg from douyinliverecorder import spider, stream from douyinliverecorder.proxy import ProxyDetector from douyinliverecorder.utils import logger @@ -1063,7 +1064,8 @@ def start_record(url_data: tuple, count_variable: int = -1) -> None: _filepath, _ = urllib.request.urlretrieve(flv_url, save_file_path) record_finished = True recording.discard(record_name) - print(f"\n{anchor_name} {time.strftime('%Y-%m-%d %H:%M:%S')} 直播录制完成\n") + print( + f"\n{anchor_name} {time.strftime('%Y-%m-%d %H:%M:%S')} 直播录制完成\n") else: logger.debug("未找到FLV直播流,跳过录制") except Exception as e: @@ -1435,33 +1437,29 @@ def backup_file_start() -> None: logger.error(f"备份配置文件失败, 错误信息: {e}") -# --------------------------检查是否存在ffmpeg------------------------------------- def check_ffmpeg_existence() -> bool: dev_null = open(os.devnull, 'wb') try: subprocess.run(['ffmpeg', '--help'], stdout=dev_null, stderr=dev_null, check=True) except subprocess.CalledProcessError as e: logger.error(e) - return False except FileNotFoundError: ffmpeg_file_check = subprocess.getoutput(ffmpeg_path) if ffmpeg_file_check.find("run") > -1 and os.path.isfile(ffmpeg_path): os.environ['PATH'] += os.pathsep + os.path.dirname(os.path.abspath(ffmpeg_path)) - # print(f"已将ffmpeg路径添加到环境变量:{ffmpeg_path}") return True - else: - logger.error("未检测到ffmpeg,请确保ffmpeg位于系统路径中,或将其路径添加到环境变量。") - sys.exit(0) finally: dev_null.close() - return True + if check_ffmpeg(): + time.sleep(1) + return True + return False +# --------------------------初始化程序------------------------------------- if not check_ffmpeg_existence(): logger.error("缺少ffmpeg无法进行录制,程序退出") sys.exit(1) - -# --------------------------初始化程序------------------------------------- print("-----------------------------------------------------") print("| DouyinLiveRecorder |") print("-----------------------------------------------------") @@ -1524,7 +1522,8 @@ try: except HTTPError as err: print(f"HTTP error occurred: {err.code} - {err.reason}") except URLError as err: - color_obj.print_colored(f"INFO:未检测到全局/规则网络代理,请检查代理配置(若无需录制海外直播请忽略此条提示)", color_obj.YELLOW) + color_obj.print_colored(f"INFO:未检测到全局/规则网络代理,请检查代理配置(若无需录制海外直播请忽略此条提示)", + color_obj.YELLOW) except Exception as err: print("An unexpected error occurred:", err) @@ -1873,5 +1872,3 @@ while True: first_run = False time.sleep(3) - -