podflow 20250327__py3-none-any.whl → 20250330__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- podflow/__init__.py +6 -0
- podflow/basic/time_print.py +14 -2
- podflow/basic/write_log.py +3 -0
- podflow/httpfs/ansi_to_html.py +52 -0
- podflow/httpfs/app_bottle.py +17 -6
- podflow/makeup/make_up_file_format_mod.py +2 -2
- podflow/message/get_youtube_and_bilibili_video_format.py +3 -3
- podflow/templates/index.html +428 -120
- {podflow-20250327.dist-info → podflow-20250330.dist-info}/METADATA +2 -2
- {podflow-20250327.dist-info → podflow-20250330.dist-info}/RECORD +13 -12
- {podflow-20250327.dist-info → podflow-20250330.dist-info}/WHEEL +0 -0
- {podflow-20250327.dist-info → podflow-20250330.dist-info}/entry_points.txt +0 -0
- {podflow-20250327.dist-info → podflow-20250330.dist-info}/top_level.txt +0 -0
    
        podflow/__init__.py
    CHANGED
    
    | @@ -119,6 +119,12 @@ class Application_gVar: | |
| 119 119 | 
             
                    self.upload_data = {}  # 上传用户账号密码字典
         | 
| 120 120 |  | 
| 121 121 | 
             
                    self.shortcuts_url = {}  # 输出至shortcut的url字典
         | 
| 122 | 
            +
                    
         | 
| 123 | 
            +
                    self.index_message = {  # 图形界面显示信息字典
         | 
| 124 | 
            +
                        "podflow": [],  # 主窗口信息列表
         | 
| 125 | 
            +
                        "http": [],  # httpfs窗口信息列表
         | 
| 126 | 
            +
                        "enter": True,  # 是否换行
         | 
| 127 | 
            +
                    }
         | 
| 122 128 |  | 
| 123 129 |  | 
| 124 130 | 
             
            # 参数变量
         | 
    
        podflow/basic/time_print.py
    CHANGED
    
    | @@ -2,14 +2,26 @@ | |
| 2 2 | 
             
            # coding: utf-8
         | 
| 3 3 |  | 
| 4 4 | 
             
            from datetime import datetime
         | 
| 5 | 
            +
            from podflow import gVar
         | 
| 6 | 
            +
            from podflow.httpfs.ansi_to_html import ansi_to_html
         | 
| 5 7 |  | 
| 6 8 |  | 
| 7 | 
            -
            def time_print(text, Top=False,  | 
| 9 | 
            +
            def time_print(text, Top=False, NoEnter=False, Time=True):
         | 
| 8 10 | 
             
                if Time:
         | 
| 9 11 | 
             
                    text = f"{datetime.now().strftime('%H:%M:%S')}|{text}"
         | 
| 10 12 | 
             
                if Top:
         | 
| 11 13 | 
             
                    text = f"\r{text}"
         | 
| 12 | 
            -
                if  | 
| 14 | 
            +
                if NoEnter:
         | 
| 13 15 | 
             
                    print(text, end="")
         | 
| 14 16 | 
             
                else:
         | 
| 15 17 | 
             
                    print(text)
         | 
| 18 | 
            +
                text = ansi_to_html(text)
         | 
| 19 | 
            +
                if not gVar.index_message["enter"] and gVar.index_message["podflow"]:
         | 
| 20 | 
            +
                    if Top:
         | 
| 21 | 
            +
                        gVar.index_message["podflow"][0] = text
         | 
| 22 | 
            +
                    else:
         | 
| 23 | 
            +
                        gVar.index_message["podflow"][0] += (text)
         | 
| 24 | 
            +
                else:
         | 
| 25 | 
            +
                    gVar.index_message["podflow"].append(text)
         | 
| 26 | 
            +
                if NoEnter:
         | 
| 27 | 
            +
                    gVar.index_message["enter"] = False
         | 
    
        podflow/basic/write_log.py
    CHANGED
    
    | @@ -3,6 +3,8 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            import re
         | 
| 5 5 | 
             
            from datetime import datetime
         | 
| 6 | 
            +
            from podflow import gVar
         | 
| 7 | 
            +
            from podflow.httpfs.ansi_to_html import ansi_to_html
         | 
| 6 8 |  | 
| 7 9 |  | 
| 8 10 | 
             
            # 日志模块
         | 
| @@ -34,4 +36,5 @@ def write_log( | |
| 34 36 | 
             
                    formatted_time_mini = current_time.strftime("%H:%M:%S")
         | 
| 35 37 | 
             
                    log_print = f"{formatted_time_mini}|{log}" if time_display else f"{log}"
         | 
| 36 38 | 
             
                    log_print = f"{log_print}|{suffix}" if suffix else f"{log_print}"
         | 
| 39 | 
            +
                    gVar.index_message["podflow"].append(ansi_to_html(log_print))
         | 
| 37 40 | 
             
                    print(log_print)
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            # podflow/httpfs/ansi_to_htmlpy
         | 
| 2 | 
            +
            # coding: utf-8
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            import re
         | 
| 5 | 
            +
            import html
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            def ansi_to_html(ansi_text):
         | 
| 9 | 
            +
                html_output = ""
         | 
| 10 | 
            +
                ansi_codes = {
         | 
| 11 | 
            +
                    "\033[30m": "color: black;",  # 黑色
         | 
| 12 | 
            +
                    "\033[31m": "color: red;",  # 红色
         | 
| 13 | 
            +
                    "\033[32m": "color: green;",  # 绿色
         | 
| 14 | 
            +
                    "\033[33m": "color: yellow;",  # 黄色
         | 
| 15 | 
            +
                    "\033[34m": "color: blue;",  # 蓝色
         | 
| 16 | 
            +
                    "\033[35m": "color: magenta;",  # 品红
         | 
| 17 | 
            +
                    "\033[36m": "color: cyan;",  # 青色
         | 
| 18 | 
            +
                    "\033[37m": "color: white;",  # 白色
         | 
| 19 | 
            +
                    "\033[90m": "color: gray;",  # 亮黑色 (通常显示为灰色)
         | 
| 20 | 
            +
                    "\033[91m": "color: #ff69b4;",  # 亮红色 (例如:热粉色)
         | 
| 21 | 
            +
                    "\033[92m": "color: #90ee90;",  # 亮绿色 (例如:浅绿色)
         | 
| 22 | 
            +
                    "\033[93m": "color: #ffff00;",  # 亮黄色 (通常与黄色相同)
         | 
| 23 | 
            +
                    "\033[94m": "color: #add8e6;",  # 亮蓝色 (例如:浅蓝色)
         | 
| 24 | 
            +
                    "\033[95m": "color: #ff00ff;",  # 亮品红 (通常与品红相同)
         | 
| 25 | 
            +
                    "\033[96m": "color: #00ffff;",  # 亮青色 (通常与青色相同)
         | 
| 26 | 
            +
                    "\033[97m": "color: #f0f8ff;",  # 亮白色 (例如:爱丽丝蓝)
         | 
| 27 | 
            +
                    "\033[0m": "",  # 重置
         | 
| 28 | 
            +
                }
         | 
| 29 | 
            +
                inside_span = False
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                parts = re.split(r"(\033\[\d+m)", ansi_text)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                for part in parts:
         | 
| 34 | 
            +
                    if part in ansi_codes:
         | 
| 35 | 
            +
                        style = ansi_codes[part]
         | 
| 36 | 
            +
                        if style:
         | 
| 37 | 
            +
                            if inside_span:
         | 
| 38 | 
            +
                                html_output += "</span>"
         | 
| 39 | 
            +
                            html_output += f'<span style="{style}">'
         | 
| 40 | 
            +
                            inside_span = True
         | 
| 41 | 
            +
                        elif inside_span:  # Reset code
         | 
| 42 | 
            +
                            html_output += "</span>"
         | 
| 43 | 
            +
                            inside_span = False
         | 
| 44 | 
            +
                    else:
         | 
| 45 | 
            +
                        escaped_part = html.escape(part)
         | 
| 46 | 
            +
                        html_output += escaped_part
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                if inside_span:
         | 
| 49 | 
            +
                    html_output += "</span>"
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                #html_output = html_output.replace("\n", "</p><p>")
         | 
| 52 | 
            +
                return html_output
         | 
    
        podflow/httpfs/app_bottle.py
    CHANGED
    
    | @@ -13,6 +13,7 @@ from podflow.basic.file_save import file_save | |
| 13 13 | 
             
            from podflow.basic.write_log import write_log
         | 
| 14 14 | 
             
            from podflow.upload.build_hash import build_hash
         | 
| 15 15 | 
             
            from podflow.upload.time_key import check_time_key
         | 
| 16 | 
            +
            from podflow.httpfs.ansi_to_html import ansi_to_html
         | 
| 16 17 | 
             
            from podflow.httpfs.get_channelid import get_channelid
         | 
| 17 18 |  | 
| 18 19 |  | 
| @@ -40,6 +41,7 @@ class bottle_app: | |
| 40 41 | 
             
                        self.app_bottle.route("/index", callback=self.index)
         | 
| 41 42 | 
             
                        self.app_bottle.route("/getid", method="POST", callback=self.getid)
         | 
| 42 43 | 
             
                        self.app_bottle.route("/<filename:path>", callback=self.serve_static)
         | 
| 44 | 
            +
                        self.app_bottle.route("/message", callback=self.message)
         | 
| 43 45 |  | 
| 44 46 | 
             
                # 设置日志文件名及写入判断
         | 
| 45 47 | 
             
                def set_logname(self, logname="httpfs.log", http_fs=False):
         | 
| @@ -92,7 +94,9 @@ class bottle_app: | |
| 92 94 | 
             
                        )
         | 
| 93 95 | 
             
                    for suffix in suffixs:
         | 
| 94 96 | 
             
                        filename = filename.replace(suffix, "")
         | 
| 95 | 
            -
                     | 
| 97 | 
            +
                    bottle_text = f"{now_time}|{client_ip} {filename} {status}"
         | 
| 98 | 
            +
                    self.bottle_print.append(bottle_text)
         | 
| 99 | 
            +
                    gVar.index_message["http"].append(ansi_to_html(bottle_text))
         | 
| 96 100 |  | 
| 97 101 | 
             
                # CherryPy 服务器打印模块
         | 
| 98 102 | 
             
                def cherry_print(self, flag_judgment=True):
         | 
| @@ -376,23 +380,30 @@ class bottle_app: | |
| 376 380 | 
             
                                },
         | 
| 377 381 | 
             
                            }
         | 
| 378 382 |  | 
| 383 | 
            +
                # 使用pkg_resources获取模板文件路径
         | 
| 379 384 | 
             
                def index(self):
         | 
| 380 | 
            -
                    # 使用pkg_resources获取模板文件路径
         | 
| 381 385 | 
             
                    template_path = pkg_resources.resource_filename('podflow', 'templates/index.html')
         | 
| 382 386 | 
             
                    with open(template_path, 'r', encoding="UTF-8") as f:
         | 
| 383 387 | 
             
                        html_content = f.read()
         | 
| 388 | 
            +
                    self.print_out("index", 200)
         | 
| 384 389 | 
             
                    return html_content
         | 
| 385 390 |  | 
| 391 | 
            +
                # 获取 JSON 数据,Bottle 会自动解析请求体中的 JSON 数据
         | 
| 386 392 | 
             
                def getid(self):
         | 
| 387 | 
            -
                     | 
| 388 | 
            -
             | 
| 389 | 
            -
                     | 
| 390 | 
            -
             | 
| 393 | 
            +
                    if getid_data := request.json:
         | 
| 394 | 
            +
                        content = getid_data.get("content", "")
         | 
| 395 | 
            +
                    else:
         | 
| 396 | 
            +
                        content = ""
         | 
| 391 397 | 
             
                    response_message = get_channelid(content)
         | 
| 392 398 | 
             
                    self.print_out("channelid", 200)
         | 
| 393 399 | 
             
                    # 设置响应头为 application/json
         | 
| 394 400 | 
             
                    response.content_type = 'application/json'
         | 
| 395 401 | 
             
                    return {"response": response_message}
         | 
| 396 402 |  | 
| 403 | 
            +
                # 处理消息的接收和发送。
         | 
| 404 | 
            +
                def message(self):
         | 
| 405 | 
            +
                    response.content_type = 'application/json'
         | 
| 406 | 
            +
                    return gVar.index_message # 获取消息列表
         | 
| 407 | 
            +
             | 
| 397 408 |  | 
| 398 409 | 
             
            bottle_app_instance = bottle_app()
         | 
| @@ -31,9 +31,9 @@ def makeup_format(video_id, makeup_format_lock): | |
| 31 31 | 
             
                                "channel_data/yt_dlp_youtube.txt",
         | 
| 32 32 | 
             
                            )
         | 
| 33 33 | 
             
                            if fail_info in makeup_id_format:
         | 
| 34 | 
            -
                                makeup_id_format = f"\ | 
| 34 | 
            +
                                makeup_id_format = f"\033[31m{fail_info}\033[0m(Cookies错误)"
         | 
| 35 35 | 
             
                        else:
         | 
| 36 | 
            -
                            makeup_id_format = f"\ | 
| 36 | 
            +
                            makeup_id_format = f"\033[31m{fail_info}\033[0m(需要Cookies)"
         | 
| 37 37 | 
             
                        break
         | 
| 38 38 | 
             
                if isinstance(makeup_id_format, list):
         | 
| 39 39 | 
             
                    if len(makeup_id_format) == 1:
         | 
| @@ -53,15 +53,15 @@ def get_youtube_and_bilibili_video_format( | |
| 53 53 | 
             
                                    gVar.video_id_update_format[id_num]["cookie"],
         | 
| 54 54 | 
             
                                )
         | 
| 55 55 | 
             
                                if fail_info in id_update_format:
         | 
| 56 | 
            -
                                    id_update_format = f"\ | 
| 56 | 
            +
                                    id_update_format = f"\033[31m{fail_info}\033[0m(Cookies错误)"
         | 
| 57 57 | 
             
                            else:
         | 
| 58 | 
            -
                                id_update_format = f"\ | 
| 58 | 
            +
                                id_update_format = f"\033[31m{fail_info}\033[0m(需要Cookies)"
         | 
| 59 59 | 
             
                            break
         | 
| 60 60 | 
             
                else:
         | 
| 61 61 | 
             
                    if gVar.video_id_update_format[id_num]["power"] is True and (
         | 
| 62 62 | 
             
                        "试看" in id_update_format or id_update_format == "无法获取音频ID"
         | 
| 63 63 | 
             
                    ):
         | 
| 64 | 
            -
                        id_update_format = "\ | 
| 64 | 
            +
                        id_update_format = "\033[31m充电专属\033[0m"
         | 
| 65 65 | 
             
                if isinstance(id_update_format, list):
         | 
| 66 66 | 
             
                    if len(id_update_format) == 1:
         | 
| 67 67 | 
             
                        one_format(id_update_format, id_num)
         | 
    
        podflow/templates/index.html
    CHANGED
    
    | @@ -3,168 +3,476 @@ | |
| 3 3 | 
             
            <head>
         | 
| 4 4 | 
             
              <meta charset="UTF-8">
         | 
| 5 5 | 
             
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
         | 
| 6 | 
            -
              <title | 
| 6 | 
            +
              <title>Podflow</title>
         | 
| 7 7 | 
             
              <style>
         | 
| 8 | 
            +
                /* 定义颜色变量 - 浅色模式 */
         | 
| 9 | 
            +
                :root {
         | 
| 10 | 
            +
                  --bg-color: #f8f9fa;
         | 
| 11 | 
            +
                  --text-color: #333333;
         | 
| 12 | 
            +
                  --secondary-text: #666666;
         | 
| 13 | 
            +
                  --input-bg: #ffffff;
         | 
| 14 | 
            +
                  --input-border: #cccccc;
         | 
| 15 | 
            +
                  --button-bg: #007bff;
         | 
| 16 | 
            +
                  --button-hover: #0056b3;
         | 
| 17 | 
            +
                  --button-text: #ffffff;
         | 
| 18 | 
            +
                  --button-shadow: hsla(0, 0%, 0%, 0.20);
         | 
| 19 | 
            +
                  --menu-bg: #f0f0f0;
         | 
| 20 | 
            +
                  --menu-text: #333333;
         | 
| 21 | 
            +
                  --menu-width: 170px;
         | 
| 22 | 
            +
                  --menu-selected-bg: #cccccc;
         | 
| 23 | 
            +
                  .ansi-black { color: black; }
         | 
| 24 | 
            +
                  .ansi-red { color: red; }
         | 
| 25 | 
            +
                  .ansi-green { color: green; }
         | 
| 26 | 
            +
                  .ansi-yellow { color: yellow; }
         | 
| 27 | 
            +
                  .ansi-blue { color: blue; }
         | 
| 28 | 
            +
                  .ansi-magenta { color: magenta; }
         | 
| 29 | 
            +
                  .ansi-cyan { color: cyan; }
         | 
| 30 | 
            +
                  .ansi-white { color: white; }
         | 
| 31 | 
            +
                  .ansi-bright-black { color: gray; }
         | 
| 32 | 
            +
                  .ansi-bright-red { color: #ff69b4; }
         | 
| 33 | 
            +
                  .ansi-bright-green { color: #90ee90; }
         | 
| 34 | 
            +
                  .ansi-bright-yellow { color: #ffff00; }
         | 
| 35 | 
            +
                  .ansi-bright-blue { color: #add8e6; }
         | 
| 36 | 
            +
                  .ansi-bright-magenta { color: #ff00ff; }
         | 
| 37 | 
            +
                  .ansi-bright-cyan { color: #00ffff; }
         | 
| 38 | 
            +
                  .ansi-bright-white { color: #f0f8ff; }
         | 
| 39 | 
            +
                }
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                /* 深色模式变量 */
         | 
| 42 | 
            +
                @media (prefers-color-scheme: dark) {
         | 
| 43 | 
            +
                  :root {
         | 
| 44 | 
            +
                    --bg-color: #222222;
         | 
| 45 | 
            +
                    --text-color: #e0e0e0;
         | 
| 46 | 
            +
                    --secondary-text: #aaaaaa;
         | 
| 47 | 
            +
                    --input-bg: #333333;
         | 
| 48 | 
            +
                    --input-border: #555555;
         | 
| 49 | 
            +
                    --button-bg: #0062cc;
         | 
| 50 | 
            +
                    --button-hover: #0069d9;
         | 
| 51 | 
            +
                    --button-text: #f0f0f0;
         | 
| 52 | 
            +
                    --button-shadow: hsla(0, 0%, 0%, 0.40);
         | 
| 53 | 
            +
                    --menu-bg: #333333;
         | 
| 54 | 
            +
                    --menu-text: #e0e0e0;
         | 
| 55 | 
            +
                    --menu-selected-bg: #555555;
         | 
| 56 | 
            +
                    .ansi-black { color: #d3d3d3; /* LightGray */ }
         | 
| 57 | 
            +
                    .ansi-red { color: #ff4d4d; /* Lighter Red */ }
         | 
| 58 | 
            +
                    .ansi-green { color: #98fb98; /* PaleGreen */ }
         | 
| 59 | 
            +
                    .ansi-yellow { color: #ffff66; /* Lighter Yellow */ }
         | 
| 60 | 
            +
                    .ansi-blue { color: #87cefa; /* LightSkyBlue */ }
         | 
| 61 | 
            +
                    .ansi-magenta { color: #ff80ff; /* Lighter Magenta */ }
         | 
| 62 | 
            +
                    .ansi-cyan { color: #00ced1; /* DarkTurquoise */ }
         | 
| 63 | 
            +
                    .ansi-white { color: #333; /* Dark Gray */ }
         | 
| 64 | 
            +
                    .ansi-bright-black { color: #a9a9a9; /* DarkGray */ }
         | 
| 65 | 
            +
                    .ansi-bright-red { color: #ff8080; /* Brighter Red */ }
         | 
| 66 | 
            +
                    .ansi-bright-green { color: #b0f0b0; /* Brighter Green */ }
         | 
| 67 | 
            +
                    .ansi-bright-yellow { color: #ffff80; /* Brighter Yellow */ }
         | 
| 68 | 
            +
                    .ansi-bright-blue { color: #a0cfff; /* Brighter Blue */ }
         | 
| 69 | 
            +
                    .ansi-bright-magenta { color: #ff80ff; /* Brighter Magenta */ }
         | 
| 70 | 
            +
                    .ansi-bright-cyan { color: #80ffff; /* Brighter Cyan */ }
         | 
| 71 | 
            +
                    .ansi-bright-white { color: #fff; /* White */ }
         | 
| 72 | 
            +
                  }
         | 
| 73 | 
            +
                }
         | 
| 74 | 
            +
                
         | 
| 8 75 | 
             
                /* 基本样式 */
         | 
| 9 76 | 
             
                body {
         | 
| 10 77 | 
             
                  font-family: Arial, sans-serif;
         | 
| 78 | 
            +
                  background-color: var(--bg-color);
         | 
| 79 | 
            +
                  color: var(--text-color);
         | 
| 80 | 
            +
                  transition: background-color 0.3s, color 0.3s;
         | 
| 81 | 
            +
                  margin: 0;
         | 
| 82 | 
            +
                  display: flex;
         | 
| 83 | 
            +
                }
         | 
| 84 | 
            +
                nav {
         | 
| 85 | 
            +
                  width: var(--menu-width);
         | 
| 86 | 
            +
                  background-color: var(--menu-bg);
         | 
| 87 | 
            +
                  color: var(--menu-text);
         | 
| 88 | 
            +
                  height: 100vh;
         | 
| 89 | 
            +
                  position: sticky;
         | 
| 90 | 
            +
                  top: 0;
         | 
| 91 | 
            +
                  z-index: 1000;
         | 
| 92 | 
            +
                  transition: width 0.3s, padding 0.3s, color 0.3s;
         | 
| 93 | 
            +
                }
         | 
| 94 | 
            +
                nav.hidden {
         | 
| 95 | 
            +
                  width: 0;
         | 
| 96 | 
            +
                  padding: 0;
         | 
| 97 | 
            +
                  overflow: hidden;
         | 
| 98 | 
            +
                }
         | 
| 99 | 
            +
                nav ul {
         | 
| 100 | 
            +
                  list-style: none;
         | 
| 101 | 
            +
                  padding: 0;
         | 
| 102 | 
            +
                }
         | 
| 103 | 
            +
                nav h3 {
         | 
| 11 104 | 
             
                  text-align: center;
         | 
| 12 | 
            -
                   | 
| 13 | 
            -
                   | 
| 105 | 
            +
                  margin: 20px 0 0;
         | 
| 106 | 
            +
                  font-size: 20px;
         | 
| 14 107 | 
             
                }
         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                   | 
| 108 | 
            +
                nav li {
         | 
| 109 | 
            +
                  margin: 5px 0;
         | 
| 110 | 
            +
                  cursor: pointer;
         | 
| 111 | 
            +
                  transition: background-color 0.3s, color 0.3s;
         | 
| 112 | 
            +
                  padding: 0 20px;
         | 
| 113 | 
            +
                  height: 40px;
         | 
| 114 | 
            +
                  line-height: 40px;
         | 
| 18 115 | 
             
                }
         | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
                   | 
| 25 | 
            -
                   | 
| 26 | 
            -
                   | 
| 27 | 
            -
                   | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 116 | 
            +
                nav li:hover {
         | 
| 117 | 
            +
                  background-color: var(--menu-selected-bg);
         | 
| 118 | 
            +
                  color: var(--button-hover);
         | 
| 119 | 
            +
                }
         | 
| 120 | 
            +
                main {
         | 
| 121 | 
            +
                  flex: 1;
         | 
| 122 | 
            +
                  padding: 40px;
         | 
| 123 | 
            +
                  max-width: 520px;
         | 
| 124 | 
            +
                  transition: margin-left 0.3s;
         | 
| 125 | 
            +
                }
         | 
| 126 | 
            +
                main.full {
         | 
| 127 | 
            +
                  margin-left: 0;
         | 
| 128 | 
            +
                }
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                /* 表单与消息区域共用样式 */
         | 
| 131 | 
            +
                .common-area {
         | 
| 132 | 
            +
                  width: 100%;
         | 
| 133 | 
            +
                  max-width: 520px;
         | 
| 134 | 
            +
                  font-size: 16px;
         | 
| 135 | 
            +
                  padding: 2px;
         | 
| 136 | 
            +
                  border: 1px solid var(--input-border);
         | 
| 137 | 
            +
                  border-radius: 4px;
         | 
| 138 | 
            +
                  background-color: var(--input-bg);
         | 
| 139 | 
            +
                  color: var(--text-color);
         | 
| 140 | 
            +
                  transition: background-color 0.3s, color 0.3s, border-color 0.3s;
         | 
| 141 | 
            +
                  box-sizing: border-box;
         | 
| 142 | 
            +
                  line-height: 1.1;
         | 
| 143 | 
            +
                  overflow-x: auto; /* 当内容超出宽度时显示水平滚动条(可选) */
         | 
| 30 144 | 
             
                  overflow-y: auto;
         | 
| 31 145 | 
             
                }
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 146 | 
            +
                textarea {
         | 
| 147 | 
            +
                  height: 250px;
         | 
| 148 | 
            +
                }
         | 
| 149 | 
            +
                #messageArea {
         | 
| 150 | 
            +
                  height: 250px;
         | 
| 151 | 
            +
                }
         | 
| 152 | 
            +
                #messageHttp {
         | 
| 153 | 
            +
                  height: 150px;
         | 
| 154 | 
            +
                }
         | 
| 34 155 | 
             
                .button-container {
         | 
| 35 156 | 
             
                  margin-top: 10px;
         | 
| 36 157 | 
             
                }
         | 
| 37 | 
            -
             | 
| 38 158 | 
             
                button {
         | 
| 39 | 
            -
                  background-color:  | 
| 40 | 
            -
                  color:  | 
| 159 | 
            +
                  background-color: var(--button-bg);
         | 
| 160 | 
            +
                  color: var(--button-text);
         | 
| 41 161 | 
             
                  border: none;
         | 
| 42 162 | 
             
                  padding: 12px 18px;
         | 
| 43 163 | 
             
                  font-size: 16px;
         | 
| 44 164 | 
             
                  border-radius: 6px;
         | 
| 45 165 | 
             
                  cursor: pointer;
         | 
| 46 | 
            -
                  transition: 0.3s;
         | 
| 47 | 
            -
                  box-shadow: 2px 2px 8px  | 
| 166 | 
            +
                  transition: background-color 0.3s, box-shadow 0.3s;
         | 
| 167 | 
            +
                  box-shadow: 2px 2px 8px var(--button-shadow);
         | 
| 48 168 | 
             
                  margin: 5px;
         | 
| 49 169 | 
             
                }
         | 
| 50 | 
            -
             | 
| 51 170 | 
             
                button:hover {
         | 
| 52 | 
            -
                  background-color:  | 
| 171 | 
            +
                  background-color: var(--button-hover);
         | 
| 53 172 | 
             
                }
         | 
| 54 | 
            -
             | 
| 173 | 
            +
                .hint {
         | 
| 174 | 
            +
                  font-size: 14px;
         | 
| 175 | 
            +
                  color: var(--secondary-text);
         | 
| 176 | 
            +
                  margin-top: 10px;
         | 
| 177 | 
            +
                }
         | 
| 178 | 
            +
                
         | 
| 179 | 
            +
                /* 菜单切换按钮 */
         | 
| 180 | 
            +
                #toggleMenu {
         | 
| 181 | 
            +
                  width: 35px;
         | 
| 182 | 
            +
                  height: 40px;
         | 
| 183 | 
            +
                  position: fixed;
         | 
| 184 | 
            +
                  left: var(--menu-width);
         | 
| 185 | 
            +
                  top: 5px;
         | 
| 186 | 
            +
                  background: var(--menu-bg);
         | 
| 187 | 
            +
                  border: none;
         | 
| 188 | 
            +
                  font-size: 20px;
         | 
| 189 | 
            +
                  color: var(--text-color);
         | 
| 190 | 
            +
                  cursor: pointer;
         | 
| 191 | 
            +
                  transition: left 0.3s, color 0.3s;
         | 
| 192 | 
            +
                  border-radius: 0 10px 10px 0;
         | 
| 193 | 
            +
                  display: flex;
         | 
| 194 | 
            +
                  justify-content: center;
         | 
| 195 | 
            +
                  align-items: center;
         | 
| 196 | 
            +
                  box-shadow: 0px 0px 8px var(--button-shadow);
         | 
| 197 | 
            +
                  margin: 0;
         | 
| 198 | 
            +
                }
         | 
| 199 | 
            +
                #toggleMenu:hover {
         | 
| 200 | 
            +
                  color: var(--button-hover);
         | 
| 201 | 
            +
                }
         | 
| 202 | 
            +
                
         | 
| 55 203 | 
             
                /* 手机端优化 */
         | 
| 56 204 | 
             
                @media (max-width: 600px) {
         | 
| 205 | 
            +
                  #messageArea, textarea {
         | 
| 206 | 
            +
                    max-width: none;
         | 
| 207 | 
            +
                  }
         | 
| 57 208 | 
             
                  textarea {
         | 
| 58 209 | 
             
                    font-size: 18px;
         | 
| 59 | 
            -
                    height: 180px;
         | 
| 60 210 | 
             
                  }
         | 
| 61 | 
            -
             | 
| 62 211 | 
             
                  button {
         | 
| 63 212 | 
             
                    width: 90%;
         | 
| 64 213 | 
             
                    font-size: 18px;
         | 
| 65 | 
            -
                    padding: 14px;
         | 
| 66 214 | 
             
                  }
         | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
                .hint {
         | 
| 71 | 
            -
                  font-size: 14px;
         | 
| 72 | 
            -
                  color: #666;
         | 
| 73 | 
            -
                  margin-top: 10px;
         | 
| 215 | 
            +
                  nav {
         | 
| 216 | 
            +
                    position: fixed;
         | 
| 217 | 
            +
                  }
         | 
| 74 218 | 
             
                }
         | 
| 75 219 | 
             
              </style>
         | 
| 76 220 | 
             
            </head>
         | 
| 77 221 | 
             
            <body>
         | 
| 78 | 
            -
               | 
| 79 | 
            -
               | 
| 80 | 
            -
             | 
| 81 | 
            -
                < | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 222 | 
            +
              <!-- 菜单栏 -->
         | 
| 223 | 
            +
              <nav id="menu">
         | 
| 224 | 
            +
                <h3>菜单栏</h3>
         | 
| 225 | 
            +
                <ul>
         | 
| 226 | 
            +
                  <li data-page="pageMessage">Podflow 运行情况</li>
         | 
| 227 | 
            +
                  <li data-page="pageChannel">获取媒体频道 ID</li>
         | 
| 228 | 
            +
                </ul>
         | 
| 229 | 
            +
              </nav>
         | 
| 230 | 
            +
              <!-- 菜单切换按钮 -->
         | 
| 231 | 
            +
              <button id="toggleMenu">❮</button>
         | 
| 232 | 
            +
              <!-- 主体区域 -->
         | 
| 233 | 
            +
              <main id="main">
         | 
| 234 | 
            +
                <!-- 获取 Channel-ID 页面 -->
         | 
| 235 | 
            +
                <section id="pageChannel" style="display: none;">
         | 
| 236 | 
            +
                  <h2>获取媒体频道 ID</h2>
         | 
| 237 | 
            +
                  <form id="inputForm" method="post" action="getid">
         | 
| 238 | 
            +
                    <label for="inputOutput">请输入:</label><br>
         | 
| 239 | 
            +
                    <textarea class="common-area" name="inputOutput" id="inputOutput"></textarea><br>
         | 
| 240 | 
            +
                    <div class="button-container">
         | 
| 241 | 
            +
                      <button type="button" id="pasteBtn">📋 粘贴</button>
         | 
| 242 | 
            +
                      <button type="submit">✅ 提交</button>
         | 
| 243 | 
            +
                      <button type="button" id="copyBtn">📄 拷贝</button>
         | 
| 244 | 
            +
                      <button type="button" id="clearBtn">🗑️ 清空</button>
         | 
| 245 | 
            +
                    </div>
         | 
| 246 | 
            +
                    <p class="hint">📌 如果粘贴按钮无效,请长按输入框手动粘贴。</p>
         | 
| 247 | 
            +
                  </form>
         | 
| 248 | 
            +
                </section>
         | 
| 249 | 
            +
                <!-- 消息滚动显示页面 -->
         | 
| 250 | 
            +
                <section id="pageMessage">
         | 
| 251 | 
            +
                  <h2>Podflow 运行情况</h2>
         | 
| 252 | 
            +
                  <form>
         | 
| 253 | 
            +
                    <label>构建服务:</label><br>
         | 
| 254 | 
            +
                    <div class="common-area" id="messageArea"></div>
         | 
| 255 | 
            +
                    <label>服务器:</label><br>
         | 
| 256 | 
            +
                    <div class="common-area" id="messageHttp"></div>
         | 
| 257 | 
            +
                  </form>
         | 
| 258 | 
            +
                </section>
         | 
| 259 | 
            +
              </main>
         | 
| 91 260 | 
             
              <script>
         | 
| 92 | 
            -
                 | 
| 93 | 
            -
             | 
| 94 | 
            -
                   | 
| 95 | 
            -
                   | 
| 96 | 
            -
                  const  | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
                     | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
                   | 
| 105 | 
            -
                  . | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 261 | 
            +
                (function() {
         | 
| 262 | 
            +
                  // 缓存常用节点
         | 
| 263 | 
            +
                  const menu = document.getElementById('menu');
         | 
| 264 | 
            +
                  const toggleMenuBtn = document.getElementById('toggleMenu');
         | 
| 265 | 
            +
                  const mainArea = document.getElementById('main');
         | 
| 266 | 
            +
                  const pages = {
         | 
| 267 | 
            +
                    pageChannel: document.getElementById('pageChannel'),
         | 
| 268 | 
            +
                    pageMessage: document.getElementById('pageMessage')
         | 
| 269 | 
            +
                  };
         | 
| 270 | 
            +
                  const inputForm = document.getElementById('inputForm');
         | 
| 271 | 
            +
                  const inputOutput = document.getElementById('inputOutput');
         | 
| 272 | 
            +
                  const messageArea = document.getElementById('messageArea');
         | 
| 273 | 
            +
                  const messageHttp = document.getElementById('messageHttp');
         | 
| 274 | 
            +
                  const pasteBtn = document.getElementById('pasteBtn');
         | 
| 275 | 
            +
                  const copyBtn = document.getElementById('copyBtn');
         | 
| 276 | 
            +
                  const clearBtn = document.getElementById('clearBtn');
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                  let pollingTimer = null;
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                  // 菜单切换函数
         | 
| 281 | 
            +
                  function toggleMenu() {
         | 
| 282 | 
            +
                    menu.classList.toggle('hidden');
         | 
| 283 | 
            +
                    if (menu.classList.contains('hidden')) {
         | 
| 284 | 
            +
                      toggleMenuBtn.style.left = '0px';
         | 
| 285 | 
            +
                      toggleMenuBtn.textContent = '❯';
         | 
| 286 | 
            +
                    } else {
         | 
| 287 | 
            +
                      toggleMenuBtn.style.left = 'var(--menu-width)';
         | 
| 288 | 
            +
                      toggleMenuBtn.textContent = '❮';
         | 
| 108 289 | 
             
                    }
         | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
                   | 
| 112 | 
            -
             | 
| 113 | 
            -
                     | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
                // 从剪贴板粘贴内容
         | 
| 122 | 
            -
                function pasteFromClipboard() {
         | 
| 123 | 
            -
                  let inputOutput = document.getElementById('inputOutput');
         | 
| 124 | 
            -
                  if (navigator.clipboard && navigator.clipboard.readText) {
         | 
| 125 | 
            -
                    navigator.clipboard.readText().then(text => {
         | 
| 126 | 
            -
                      inputOutput.value = text;
         | 
| 127 | 
            -
                      inputOutput.focus();
         | 
| 128 | 
            -
                    }).catch(err => {
         | 
| 129 | 
            -
                      console.warn("剪贴板读取失败:", err);
         | 
| 130 | 
            -
                      alert("无法读取剪贴板,请手动粘贴!");
         | 
| 131 | 
            -
                    });
         | 
| 132 | 
            -
                  } else {
         | 
| 133 | 
            -
                    try {
         | 
| 134 | 
            -
                      inputOutput.focus();
         | 
| 135 | 
            -
                      document.execCommand('paste');
         | 
| 136 | 
            -
                    } catch (err) {
         | 
| 137 | 
            -
                      console.warn("execCommand 粘贴失败:", err);
         | 
| 138 | 
            -
                      alert("您的浏览器不支持自动粘贴,请手动操作!");
         | 
| 290 | 
            +
                  }
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                  // 根据页面标识显示对应面板
         | 
| 293 | 
            +
                  function showPage(pageId) {
         | 
| 294 | 
            +
                    Object.values(pages).forEach(page => page.style.display = 'none');
         | 
| 295 | 
            +
                    if (pages[pageId]) {
         | 
| 296 | 
            +
                      pages[pageId].style.display = 'block';
         | 
| 297 | 
            +
                      // 手机模式下自动隐藏菜单
         | 
| 298 | 
            +
                      if (window.innerWidth <= 600 && !menu.classList.contains('hidden')) {
         | 
| 299 | 
            +
                        toggleMenu();
         | 
| 300 | 
            +
                      }
         | 
| 301 | 
            +
                      pageId === 'pageMessage' ? startMessagePolling() : stopMessagePolling();
         | 
| 139 302 | 
             
                    }
         | 
| 140 303 | 
             
                  }
         | 
| 141 | 
            -
                }
         | 
| 142 304 |  | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
                   | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
                     | 
| 153 | 
            -
             | 
| 154 | 
            -
                     | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 305 | 
            +
                  // 初始化默认页面
         | 
| 306 | 
            +
                  showPage('pageMessage');
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                  let lastMessage = { podflow: [], http: [] };
         | 
| 309 | 
            +
                  let userScrolled = false;
         | 
| 310 | 
            +
                
         | 
| 311 | 
            +
                  // 监听滚动事件,检测用户是否手动滚动
         | 
| 312 | 
            +
                  function onUserScroll(event) {
         | 
| 313 | 
            +
                    const element = event.target;
         | 
| 314 | 
            +
                    // 判断是否接近底部
         | 
| 315 | 
            +
                    const nearBottom = element.scrollHeight - element.scrollTop <= element.clientHeight + 10;
         | 
| 316 | 
            +
                    userScrolled = !nearBottom;
         | 
| 317 | 
            +
                  }
         | 
| 318 | 
            +
                
         | 
| 319 | 
            +
                  messageArea.addEventListener('scroll', onUserScroll);
         | 
| 320 | 
            +
                  messageHttp.addEventListener('scroll', onUserScroll);
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                  // 轮询消息更新,更新 messageArea 与 messageHttp
         | 
| 323 | 
            +
                  function getMessages() {
         | 
| 324 | 
            +
                    fetch('message')
         | 
| 325 | 
            +
                      .then(response => response.json()) // 解析 JSON 数据
         | 
| 326 | 
            +
                      .then(data => {
         | 
| 327 | 
            +
                        if (JSON.stringify(data) !== JSON.stringify(lastMessage)) {
         | 
| 328 | 
            +
                          // 追加新消息
         | 
| 329 | 
            +
                          appendMessages(messageArea, data.podflow, lastMessage.podflow);
         | 
| 330 | 
            +
                          appendMessages(messageHttp, data.http, lastMessage.http);
         | 
| 331 | 
            +
                          lastMessage = data;
         | 
| 332 | 
            +
                        }
         | 
| 333 | 
            +
                      })
         | 
| 334 | 
            +
                      .catch(error => console.error('获取消息失败:', error));
         | 
| 335 | 
            +
                  }
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                  function appendMessages(container, newMessages, oldMessages) {
         | 
| 338 | 
            +
                    // 判断当前是否在底部
         | 
| 339 | 
            +
                    const isAtBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 10;
         | 
| 340 | 
            +
                
         | 
| 341 | 
            +
                    // 只追加新数据,避免重复渲染
         | 
| 342 | 
            +
                    if (newMessages.length === oldMessages.length && newMessages.length > 0) {
         | 
| 343 | 
            +
                      const lastNewMessage = newMessages[newMessages.length - 1];
         | 
| 344 | 
            +
                      const lastOldMessage = oldMessages[oldMessages.length - 1];
         | 
| 345 | 
            +
                      if (lastNewMessage !== lastOldMessage) {
         | 
| 346 | 
            +
                        const br = document.createElement('br'); // 创建 <br> 标签
         | 
| 347 | 
            +
                        const textNode = document.createTextNode(lastNewMessage); // 创建文本节点
         | 
| 348 | 
            +
             | 
| 349 | 
            +
                        // 获取容器的最后一个子元素
         | 
| 350 | 
            +
                        const lastChild = container.lastElementChild;
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                        // 如果容器有子元素,则替换最后一个(这里逻辑可能需要调整,因为你不再替换 <p>)
         | 
| 353 | 
            +
                        if (lastChild) {
         | 
| 354 | 
            +
                          container.removeChild(lastChild); // 移除最后一个元素
         | 
| 355 | 
            +
                          container.appendChild(textNode);   // 添加新的文本节点
         | 
| 356 | 
            +
                          container.appendChild(br);       // 添加换行符
         | 
| 357 | 
            +
                        } else {
         | 
| 358 | 
            +
                          container.appendChild(textNode);
         | 
| 359 | 
            +
                          container.appendChild(br);
         | 
| 360 | 
            +
                        }
         | 
| 361 | 
            +
                      }
         | 
| 362 | 
            +
                    } else {
         | 
| 363 | 
            +
                      // 如果 newMessages 和 oldMessages 元素数量不一致,则执行原来的添加逻辑
         | 
| 364 | 
            +
                      newMessages.slice(oldMessages.length).forEach(msg => {
         | 
| 365 | 
            +
                        const br = document.createElement('br');
         | 
| 366 | 
            +
                        const textNode = document.createTextNode(msg);
         | 
| 367 | 
            +
                        container.appendChild(textNode);
         | 
| 368 | 
            +
                        container.appendChild(br);
         | 
| 369 | 
            +
                      });
         | 
| 370 | 
            +
                    }
         | 
| 371 | 
            +
                
         | 
| 372 | 
            +
                    // 如果用户没有主动滚动,才自动滚动到底部
         | 
| 373 | 
            +
                    if (!userScrolled) {
         | 
| 374 | 
            +
                      container.scrollTop = container.scrollHeight;
         | 
| 160 375 | 
             
                    }
         | 
| 161 376 | 
             
                  }
         | 
| 162 | 
            -
                }
         | 
| 163 377 |  | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 378 | 
            +
                  function startMessagePolling() {
         | 
| 379 | 
            +
                    getMessages();
         | 
| 380 | 
            +
                    pollingTimer = setInterval(getMessages, 1000);
         | 
| 381 | 
            +
                  }
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                  function stopMessagePolling() {
         | 
| 384 | 
            +
                    if (pollingTimer !== null) {
         | 
| 385 | 
            +
                      clearInterval(pollingTimer);
         | 
| 386 | 
            +
                      pollingTimer = null;
         | 
| 387 | 
            +
                    }
         | 
| 388 | 
            +
                  }
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                  startMessagePolling();
         | 
| 391 | 
            +
             | 
| 392 | 
            +
                  // 表单异步提交(获取 Channel-ID)
         | 
| 393 | 
            +
                  inputForm.addEventListener('submit', function(event) {
         | 
| 394 | 
            +
                    event.preventDefault();
         | 
| 395 | 
            +
                    const content = inputOutput.value;
         | 
| 396 | 
            +
                    fetch('getid', {
         | 
| 397 | 
            +
                      method: 'POST',
         | 
| 398 | 
            +
                      headers: { 'Content-Type': 'application/json' },
         | 
| 399 | 
            +
                      body: JSON.stringify({ content })
         | 
| 400 | 
            +
                    })
         | 
| 401 | 
            +
                    .then(response => {
         | 
| 402 | 
            +
                      if (!response.ok) {
         | 
| 403 | 
            +
                        throw new Error('网络响应异常');
         | 
| 404 | 
            +
                      }
         | 
| 405 | 
            +
                      return response.json();
         | 
| 406 | 
            +
                    })
         | 
| 407 | 
            +
                    .then(data => inputOutput.value = data.response)
         | 
| 408 | 
            +
                    .catch(error => {
         | 
| 409 | 
            +
                      console.error('请求失败:', error);
         | 
| 410 | 
            +
                      alert('请求失败,请稍后重试!');
         | 
| 411 | 
            +
                    });
         | 
| 412 | 
            +
                  });
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                  // 粘贴功能
         | 
| 415 | 
            +
                  pasteBtn.addEventListener('click', function() {
         | 
| 416 | 
            +
                    if (navigator.clipboard && navigator.clipboard.readText) {
         | 
| 417 | 
            +
                      navigator.clipboard.readText().then(text => {
         | 
| 418 | 
            +
                        inputOutput.value = text;
         | 
| 419 | 
            +
                        inputOutput.focus();
         | 
| 420 | 
            +
                      }).catch(err => {
         | 
| 421 | 
            +
                        console.warn("剪贴板读取失败:", err);
         | 
| 422 | 
            +
                        alert("无法读取剪贴板,请手动粘贴!");
         | 
| 423 | 
            +
                      });
         | 
| 424 | 
            +
                    } else {
         | 
| 425 | 
            +
                      try {
         | 
| 426 | 
            +
                        inputOutput.focus();
         | 
| 427 | 
            +
                        document.execCommand('paste');
         | 
| 428 | 
            +
                      } catch (err) {
         | 
| 429 | 
            +
                        console.warn("execCommand 粘贴失败:", err);
         | 
| 430 | 
            +
                        alert("您的浏览器不支持自动粘贴,请手动操作!");
         | 
| 431 | 
            +
                      }
         | 
| 432 | 
            +
                    }
         | 
| 433 | 
            +
                  });
         | 
| 434 | 
            +
             | 
| 435 | 
            +
                  // 复制功能
         | 
| 436 | 
            +
                  copyBtn.addEventListener('click', function() {
         | 
| 437 | 
            +
                    if (navigator.clipboard && navigator.clipboard.writeText) {
         | 
| 438 | 
            +
                      navigator.clipboard.writeText(inputOutput.value).catch(err => {
         | 
| 439 | 
            +
                        console.warn("复制失败:", err);
         | 
| 440 | 
            +
                        alert("无法复制,请手动选择文本后按 Ctrl+C 复制!");
         | 
| 441 | 
            +
                      });
         | 
| 442 | 
            +
                    } else {
         | 
| 443 | 
            +
                      try {
         | 
| 444 | 
            +
                        inputOutput.select();
         | 
| 445 | 
            +
                        document.execCommand('copy');
         | 
| 446 | 
            +
                      } catch (err) {
         | 
| 447 | 
            +
                        console.warn("execCommand 复制失败:", err);
         | 
| 448 | 
            +
                        alert("您的浏览器不支持复制,请手动操作!");
         | 
| 449 | 
            +
                      }
         | 
| 450 | 
            +
                    }
         | 
| 451 | 
            +
                  });
         | 
| 452 | 
            +
             | 
| 453 | 
            +
                  // 清空输入框
         | 
| 454 | 
            +
                  clearBtn.addEventListener('click', function() {
         | 
| 455 | 
            +
                    inputOutput.value = '';
         | 
| 456 | 
            +
                  });
         | 
| 457 | 
            +
             | 
| 458 | 
            +
                  // 菜单项点击事件委托
         | 
| 459 | 
            +
                  menu.addEventListener('click', function(event) {
         | 
| 460 | 
            +
                    const target = event.target;
         | 
| 461 | 
            +
                    if (target.tagName.toLowerCase() === 'li' && target.dataset.page) {
         | 
| 462 | 
            +
                      showPage(target.dataset.page);
         | 
| 463 | 
            +
                    }
         | 
| 464 | 
            +
                  });
         | 
| 465 | 
            +
             | 
| 466 | 
            +
                  // 菜单切换按钮事件绑定
         | 
| 467 | 
            +
                  toggleMenuBtn.addEventListener('click', toggleMenu);
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                  // 针对手机端,初始化时隐藏菜单
         | 
| 470 | 
            +
                  if (window.innerWidth <= 600) {
         | 
| 471 | 
            +
                    menu.classList.add('hidden');
         | 
| 472 | 
            +
                    toggleMenuBtn.style.left = '0px';
         | 
| 473 | 
            +
                    toggleMenuBtn.textContent = '❯';
         | 
| 474 | 
            +
                  }
         | 
| 475 | 
            +
                })();
         | 
| 168 476 | 
             
              </script>
         | 
| 169 477 | 
             
            </body>
         | 
| 170 | 
            -
            </html>
         | 
| 478 | 
            +
            </html>
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.1
         | 
| 2 2 | 
             
            Name: podflow
         | 
| 3 | 
            -
            Version:  | 
| 3 | 
            +
            Version: 20250330
         | 
| 4 4 | 
             
            Summary: A podcast server that includes YouTube and BiliBili
         | 
| 5 5 | 
             
            Home-page: https://github.com/gruel-zxz/podflow
         | 
| 6 6 | 
             
            Author: gruel_zxz
         | 
| @@ -14,7 +14,7 @@ Requires-Python: >=3.8 | |
| 14 14 | 
             
            Description-Content-Type: text/markdown
         | 
| 15 15 | 
             
            Requires-Dist: astral>=3.2
         | 
| 16 16 | 
             
            Requires-Dist: bottle>=0.13.2
         | 
| 17 | 
            -
            Requires-Dist: yt-dlp>=2025.3. | 
| 17 | 
            +
            Requires-Dist: yt-dlp>=2025.3.27
         | 
| 18 18 | 
             
            Requires-Dist: chardet>=5.2.0
         | 
| 19 19 | 
             
            Requires-Dist: cherrypy>=18.10.0
         | 
| 20 20 | 
             
            Requires-Dist: pyqrcode>=1.2.1
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            podflow/__init__.py,sha256= | 
| 1 | 
            +
            podflow/__init__.py,sha256=N8hpfDHmVdVyDQs50yt_EMscS2v6CTD5a8oBWUkUOf0,7222
         | 
| 2 2 | 
             
            podflow/download_and_build.py,sha256=GKQ1uX8Nuwdhr4wgnGr3jP1Mu0llRUPFcboQ3S05WkU,671
         | 
| 3 3 | 
             
            podflow/ffmpeg_judge.py,sha256=3EtNlHhinsFPtRp74JwCK2TFM6VOjsvpn7rW0OhEMi8,1275
         | 
| 4 4 | 
             
            podflow/main.py,sha256=Cz2E33-Kcc_1_oxNs4Z1OoqJYhonmClsrtoCW1oQmZA,739
         | 
| @@ -16,10 +16,10 @@ podflow/basic/list_merge_tidy.py,sha256=7hWfSnsPh23edHNU92vxtI0nfpfN8m54GTEt2rGm | |
| 16 16 | 
             
            podflow/basic/qr_code.py,sha256=PvtCIq1THH72-xfxmhlI4Lz3ncE04po4XfH2XSjbhm0,1520
         | 
| 17 17 | 
             
            podflow/basic/split_dict.py,sha256=Ir6GTortcWMUeFITFgY1v-INMla5y0IN3RN3nTgzWqM,401
         | 
| 18 18 | 
             
            podflow/basic/time_format.py,sha256=T3tw2vbOwxMYYXDaV4Sj76WOZtsspj2lWA_DzWqUEJA,487
         | 
| 19 | 
            -
            podflow/basic/time_print.py,sha256 | 
| 19 | 
            +
            podflow/basic/time_print.py,sha256=-OcqzMsvPqAp7HOCrpK6435DEWBQ5zP-s7EtbLctPTw,767
         | 
| 20 20 | 
             
            podflow/basic/time_stamp.py,sha256=Kbz9PzgPtss1fRqPXdfz1q6MTGVMRi3LPClN7wrXSIk,1888
         | 
| 21 21 | 
             
            podflow/basic/vary_replace.py,sha256=-TyvZxfak6U7Ak8F87ctYUBpHB2Il6iYZof37lwKjto,211
         | 
| 22 | 
            -
            podflow/basic/write_log.py,sha256= | 
| 22 | 
            +
            podflow/basic/write_log.py,sha256=3m7S1G2rqe1gKz4ErI1ay17rymxmPOuHMC1IYh2BTzo,1317
         | 
| 23 23 | 
             
            podflow/bilibili/__init__.py,sha256=6ZTpvhZTyn4f0LryXzH8lzyK1_rRHBeM-hkBoklKHRA,47
         | 
| 24 24 | 
             
            podflow/bilibili/build.py,sha256=PKxkjUa8EedpoQTFZIgdcsVbiAWRISA-qKCpCaSTLTU,7957
         | 
| 25 25 | 
             
            podflow/bilibili/get.py,sha256=Ld8lhb_3eiSagVXWyj1KIrRLjfH6p0sUolEG5VtN8mk,20337
         | 
| @@ -40,14 +40,15 @@ podflow/download/show_progress.py,sha256=cWlyIh6WqoH3s4WpFSyL6xtiXhQFbrVJVcckxO- | |
| 40 40 | 
             
            podflow/download/wait_animation.py,sha256=RnByMq0Ql_yr9OqQ3dl3W-41GgP0T8PvlbwwVeMb7_k,1056
         | 
| 41 41 | 
             
            podflow/download/youtube_and_bilibili_download.py,sha256=dlUh9cPHrYgZAhtXlBUOdFIpZOhv9xOtgdcTaqUvLuY,1294
         | 
| 42 42 | 
             
            podflow/httpfs/__init__.py,sha256=BxEXkufjcx-a0F7sDVXo65hmyANqCCbZUd6EH9i8T2c,45
         | 
| 43 | 
            -
            podflow/httpfs/ | 
| 43 | 
            +
            podflow/httpfs/ansi_to_html.py,sha256=tdTDGBIvvlRXyN4fe6s5s8Fo74s57RXNApWitFs99TU,1863
         | 
| 44 | 
            +
            podflow/httpfs/app_bottle.py,sha256=XozAAbcV1kikS2NISKcN0UI7d6at1hpi8pBpjUoUvls,16792
         | 
| 44 45 | 
             
            podflow/httpfs/browser.py,sha256=BJ4Xkfiki_tDr0Sc9RqAcEfIVpkAZ3RFOwo0aMHlY3U,197
         | 
| 45 46 | 
             
            podflow/httpfs/get_channelid.py,sha256=gcwy4IVHBWNQz7qPCpjwiAklGFLRGzvM33-UZz7oFvo,2296
         | 
| 46 47 | 
             
            podflow/httpfs/port_judge.py,sha256=l_nLpsSiIhAzfJGCOWyYC-KkCCWPUW2ybe_5hdMOEzE,764
         | 
| 47 48 | 
             
            podflow/makeup/__init__.py,sha256=ligUtfj0stTcOHFXDF6eAN7Up2PxlB0GnGbLq7iDY3c,45
         | 
| 48 49 | 
             
            podflow/makeup/del_makeup_format_fail.py,sha256=XizQh74QYXxRg0e1uerXjd4Tiq5qChks0fTAY7n3Z1I,642
         | 
| 49 50 | 
             
            podflow/makeup/make_up_file.py,sha256=WJnKtdr6-CMEpxJAADCEhcyIwdUdisxbqXGmzo3R5KQ,2222
         | 
| 50 | 
            -
            podflow/makeup/make_up_file_format_mod.py,sha256= | 
| 51 | 
            +
            podflow/makeup/make_up_file_format_mod.py,sha256=VlR4yG7N6C2laYIBKb7J6Alqq2_X5Y7kgXMQSN6lJ6E,3613
         | 
| 51 52 | 
             
            podflow/makeup/make_up_file_mod.py,sha256=padTanSPw5Dysf_CcUUVy65nCC6zbz1gPJRX98tmUdY,1075
         | 
| 52 53 | 
             
            podflow/message/__init__.py,sha256=pZkcrrtkdtxgMriEHBZ0_rptKaQrQeMPJvPSaoI1Awo,46
         | 
| 53 54 | 
             
            podflow/message/backup_zip_save.py,sha256=0SIxVvAtgSWAr_TvdXLVDIpxvXOHeFUN8n8QzfnIB84,1740
         | 
| @@ -59,7 +60,7 @@ podflow/message/get_media_name.py,sha256=5ULPQOQCZ2-lxdkILwlBP-ItzdFEgvEAKxeLtpl | |
| 59 60 | 
             
            podflow/message/get_original_rss.py,sha256=PYA7UGhHXbUN66vWmxWOp5Ns423CopHxw4vR19zXaPs,2383
         | 
| 60 61 | 
             
            podflow/message/get_video_format.py,sha256=-LsgmawTKcDvR1wMgr3ue09fCHnmDvJNJxh7ztk-SZA,4770
         | 
| 61 62 | 
             
            podflow/message/get_video_format_multithread.py,sha256=2t2UlBWG1RF0IRBBbGzeeWshWXfMgyny6keaWbmgTaI,1406
         | 
| 62 | 
            -
            podflow/message/get_youtube_and_bilibili_video_format.py,sha256= | 
| 63 | 
            +
            podflow/message/get_youtube_and_bilibili_video_format.py,sha256=BFlplFy-j3J_2UVvmtNsfCK-Uvfjj3JZu8pscn1U0Ts,4439
         | 
| 63 64 | 
             
            podflow/message/media_format.py,sha256=Q4WoML4UqL0Ry-QN8DHFJqOQ2tXcFN6u5hmhdSLdP1g,7346
         | 
| 64 65 | 
             
            podflow/message/original_rss_fail_print.py,sha256=7HM5Gwi3GqBIg2dtTTDlN_FRgZZjYv6ejizS3tDiePE,502
         | 
| 65 66 | 
             
            podflow/message/rss_create_hash.py,sha256=M5OS9KcQ4mIxLes9ij4oNji-4VKgi56bg0Shv5nCIQ4,638
         | 
| @@ -79,7 +80,7 @@ podflow/remove/remove_dir.py,sha256=xQIhrnqnYjMzXjoSWaTvm7JwPYOFTN1muuTPdaLDXpQ, | |
| 79 80 | 
             
            podflow/remove/remove_file.py,sha256=8wAJQehs-XBqvu0vPlEme2_tt0FZxc5ELwGMxXA_558,982
         | 
| 80 81 | 
             
            podflow/repair/__init__.py,sha256=Gpc1i6xiSLodKjjmzH66c_Y1z0HQ9E9CS3p95FRnVFM,45
         | 
| 81 82 | 
             
            podflow/repair/reverse_log.py,sha256=Wc_vAH0WB-z1fNdWx7FYaVH4caRPtot7tDwDwFhmpz4,1106
         | 
| 82 | 
            -
            podflow/templates/index.html,sha256= | 
| 83 | 
            +
            podflow/templates/index.html,sha256=HxFnXOwR390eoPGTJzxRAnF5N1NjVBPH0x_gjkFKWmk,15589
         | 
| 83 84 | 
             
            podflow/upload/__init__.py,sha256=AtOSXDrE5EjUe3z-iBd1NTDaH8n_X9qA5WXdBLkONjA,45
         | 
| 84 85 | 
             
            podflow/upload/add_upload.py,sha256=_2-V0z75Lwu-PUCfMD9HOSxZTB102yZlZW5hSdlHcsc,1432
         | 
| 85 86 | 
             
            podflow/upload/build_hash.py,sha256=9opa3xLd7nJbGGX5xa3uuKPS6dxlbkAb87ZdEiUxmxI,473
         | 
| @@ -94,8 +95,8 @@ podflow/youtube/__init__.py,sha256=pgXod8gq0IijZxIkPSwgAOcb9JI5rd1mqMomoR7bcJ4,4 | |
| 94 95 | 
             
            podflow/youtube/build.py,sha256=3LYk_ICVXj9XkE9jZ8jEVI8596xxS_QZkcoIwcBE3Ys,12006
         | 
| 95 96 | 
             
            podflow/youtube/get.py,sha256=Of7PRgUknhpyW70nvyVAUYVb5KyFViKiBTfH3Y6Mke8,16970
         | 
| 96 97 | 
             
            podflow/youtube/login.py,sha256=3nLj0KLdsc-kQmXxG5FyZfR-kiDzbQy2J0KhPXMxJGc,1380
         | 
| 97 | 
            -
            podflow- | 
| 98 | 
            -
            podflow- | 
| 99 | 
            -
            podflow- | 
| 100 | 
            -
            podflow- | 
| 101 | 
            -
            podflow- | 
| 98 | 
            +
            podflow-20250330.dist-info/METADATA,sha256=eGyPZg6u4JCFAg3-oboWU6_xlw5SaWTjHsuhTcqGU74,14163
         | 
| 99 | 
            +
            podflow-20250330.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
         | 
| 100 | 
            +
            podflow-20250330.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
         | 
| 101 | 
            +
            podflow-20250330.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
         | 
| 102 | 
            +
            podflow-20250330.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         |