python简单gui

代码:

import hashlib
import os
import queue
import time
import random
from urllib.parse import urlparse

import requests
from tkinter import *
from tkinter import ttk

from loguru import logger
from concurrent.futures.thread import ThreadPoolExecutor

logger.add("download.log", rotation="23:59", encoding="utf-8")
requests.packages.urllib3.disable_warnings()


class ThreadPoolExecutorWithQueueSizeLimit(ThreadPoolExecutor):
    """
    实现多线程有界队列
    队列数为线程数的2倍
    """

    def __init__(self, max_workers=None, *args, **kwargs):
        super().__init__(max_workers, *args, **kwargs)
        self._work_queue = queue.Queue(max_workers * 2)


def get_ts_url_list(m3u8_url):
    """
    根据m3u8获取所有ts片段流地址
    :param m3u8_url:
    :return: ts流地址的列表
    """

    headers = {
        "user-agent": "Mozilla/5.0 (Linux; Android 7.1.2; HD1910 Build/N2G48H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.70 Mobile Safari/537.36",
        "accept": "*/*"
    }
    response = requests.get(m3u8_url, headers=headers)
    if response and response.status_code == 200:
        ts_list = [text for text in response.text.split('\n') if
                   text and text.endswith(".ts")]
        logger.info(f"要抓取的数量为:{len(ts_list)}")
        return ts_list
    else:
        logger.error(f"crawl ts list err,status_code is {response.status_code}")
        raise Exception("crawl ts lis err")


def download_ts(ts_url, dirname):
    """
    下载 .ts 文件
    """
    logger.info(f"download ts_video ,ts_url is :{ts_url}")
    ts_headers = {
        "user-agent": "Mozilla/5.0 (Linux; Android 7.1.2; HD1910 Build/N2G48H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/68.0.3440.70 Mobile Safari/537.36",
        "accept": "*/*",
    }
    # host 一定要根据实际的host变化,否则很容易触发cloudfare
    parser = urlparse(ts_url)
    ts_headers["Host"] = parser.hostname
    # 文件命名直接拿最后的尾缀就行
    suf = ts_url.rsplit("/", 1)[1]
    filename = f'{dirname}/{suf}'
    if os.path.exists(filename):
        os.remove(filename)
    with requests.get(ts_url, stream=True, timeout=(60, 300), verify=False, headers=ts_headers) as res:
        if res.status_code == 200:
            with open(filename, "wb") as ts:
                for chunk in res.iter_content(chunk_size=1024):
                    if chunk:
                        ts.write(chunk)
                logger.info(f"down load ts:{filename} finished")
        else:
            logger.error(f"下载ts失败:{ts_url},status code is {res.status_code}")
            raise Exception("下载ts失败")


def run():
    m3u8_url = m3u8_url_entry.get()

    if not os.path.exists("video"):
        os.mkdir("video")
    _max_workers = 30  # 30个线程

    # 存放ts文件的目录名,合并的文件名也是这个
    # dirname = mk_md5(m3u8_url)
    dirname = file_dir_entry.get()

    ts_url_list = get_ts_url_list(m3u8_url)
    # todo ts的url是不是要处理?
    if ts_url_list:
        with ThreadPoolExecutorWithQueueSizeLimit(_max_workers) as pool:
            for ts_url in ts_url_list:
                pool.submit(download_ts, ts_url, dirname)

    else:
        logger.error("crawl, no ts_url_list")


# 创建窗体
root = Tk()
root.title('m3u8下载器')
root.resizable(width=False, height=False)
root.config(background='#EEE')
root.geometry('500x240')

# 创建界面
ttk.Frame(root, height=20).grid()
rown = 0
# url 输入框
rown += 1
m3u8_url = StringVar()
m3u8_url.set("请输入m3u8url")
m3u8_url_entry = ttk.Entry(root, textvariable=m3u8_url)
m3u8_url_entry.grid(row=rown, column=1, pady=10, padx=10, ipady=5, sticky='WE')

# 文件保存位置
rown += 2
file_dir = StringVar()
file_dir.set("请输入要保存的目录")
file_dir_entry = ttk.Entry(root, textvariable=file_dir)
file_dir_entry.grid(row=rown, column=1, padx=10, pady=10, ipady=5, sticky='WE')

# 运行按钮
rown += 2
bt = ttk.Button(root, text='开始下载', width=30, command=run)
bt.grid(
    row=rown, column=1, ipady=10, ipadx=10, sticky=E)

root.mainloop()

 

posted @ 2023-06-08 11:05  阿布_alone  阅读(12)  评论(0编辑  收藏  举报
TOP