#可以下载pornhub 文件格式为 url-*-name
#20250509 直接使用url下载  
import os,time,subprocess,sys,tempfile

#小于多少大小的内存
MEM_size = 50

processes = []


fork_pid = os.fork()  # 第一次 fork

if fork_pid > 0:
    sys.exit(0)  # 父进程退出，子进程继续运行

os.setsid()  # 创建新的会话，子进程 A 脱离控制终端

fork_pid = os.fork()  # 第二次 fork
if fork_pid > 0:
    sys.exit(0)  # 子进程 A 退出，确保没有父进程


print_file = open("down_output.log", "w", buffering=1)
sys.stdout = print_file
sys.stderr = print_file


with open('example.txt', 'r') as file:
    lines = file.readlines()
    for line in lines:
        url = line = line.split('\n')[0]

        url,name = line.split('-*-')
        print(name)
        try:
            with open(f'{name}.mp4'):
                print('文件存在')
                continue
        except IOError as e:pass

        try:
            with open(f'{name}.mp4.part'):
                print('文件正在下载')
                continue
        except IOError as e:pass



        #nice只能缓解CPU占用高，当进程一多，内存占用变高导致kswapd0进行内存交换导致CPU占用再次变高
        #os.system(f'nohup nice -n 19 yt-dlp "{url}" -o "{name}".mp4 > /dev/null 2>&1 &')
        #os.system(f'nohup nice -n 19 yt-dlp "{url}" > /dev/null 2>&1 &')
        #os.system('ps -aux | grep yt-dlp | grep -v grep')

        print(url)

        temp_files_obj = tempfile.NamedTemporaryFile(mode='w+', delete=True) 

        process = subprocess.Popen(
                                    ['nice', '-n', '19', "yt-dlp", '--concurrent-fragments', '32', '-o', f'{name}.mp4', url],         #下载 
                                    stdout=temp_files_obj,
                                    stderr=temp_files_obj,
                                    text=True
                                    )
        
        print(f'{temp_files_obj.name}')
        
        processes.append({'p':process,
                        'url':url,
                        'file':temp_files_obj})

        time.sleep(25)           #等待yt-dp启动后下载到内存占用到最大

        while True:
            result = subprocess.run(['free', '-m'], stdout=subprocess.PIPE, text=True)
            # 解析命令输出
            for line in result.stdout.splitlines():
                if line.startswith('Mem'):
                    available = int(line.split()[6])  # 获取 available 字段，位于第 7 列
                    break
            #print(f'可分配内容容量 {available}M')
            if available > MEM_size:break
            print(f'可分配内存小于{MEM_size}M {available}M')
            time.sleep(20)
        
        for process in processes[:]:
            return_code = process['p'].poll()
            if return_code is not None:
                if return_code != 0:
                    print(f'进程异常退出 {process["url"]} 返回值{return_code}\n')

                process['file'].close()
                processes.remove(process)

#当所有url已经创建下载 等待下载完成
while len(processes) > 0:
    for process in processes[:]:
        return_code = process['p'].poll()
        if return_code is not None:
            if return_code != 0:
                print(f'进程异常退出 {process["url"]} 返回值{return_code}\n')

            process['file'].close()
            processes.remove(process)
    time.sleep(0.5)

print('全部完成...')
print_file.close()