podflow 20250405__py3-none-any.whl → 20250413__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 +1 -0
- podflow/basic/qr_code.py +13 -5
- podflow/basic/time_print.py +25 -13
- podflow/bilibili/login.py +50 -36
- podflow/download/dl_aideo_video.py +6 -4
- podflow/httpfs/to_html.py +4 -4
- podflow/main_podcast.py +27 -0
- podflow/makeup/make_up_file.py +19 -3
- podflow/message/create_main_rss.py +7 -0
- podflow/message/fail_message_initialize.py +5 -0
- podflow/message/get_video_format.py +17 -1
- podflow/message/get_video_format_multithread.py +13 -2
- podflow/message/get_youtube_and_bilibili_video_format.py +11 -1
- podflow/message/update_youtube_bilibili_rss.py +15 -0
- podflow/netscape/get_cookie_dict.py +3 -3
- podflow/templates/index.html +161 -101
- {podflow-20250405.dist-info → podflow-20250413.dist-info}/METADATA +1 -1
- {podflow-20250405.dist-info → podflow-20250413.dist-info}/RECORD +21 -21
- {podflow-20250405.dist-info → podflow-20250413.dist-info}/WHEEL +0 -0
- {podflow-20250405.dist-info → podflow-20250413.dist-info}/entry_points.txt +0 -0
- {podflow-20250405.dist-info → podflow-20250413.dist-info}/top_level.txt +0 -0
podflow/__init__.py
CHANGED
podflow/basic/qr_code.py
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
|
4
4
|
import math
|
5
5
|
import pyqrcode
|
6
|
-
from podflow.
|
6
|
+
from podflow.basic.time_print import time_print
|
7
7
|
|
8
8
|
|
9
9
|
# 网址二维码模块
|
10
|
-
def qr_code(
|
11
|
-
|
12
|
-
|
10
|
+
def qr_code(
|
11
|
+
data,
|
12
|
+
to_html=False,
|
13
|
+
num=None
|
14
|
+
):
|
13
15
|
qr = pyqrcode.create(
|
14
16
|
data,
|
15
17
|
error='L', # 对应于ERROR_CORRECT_L,可选值: 'L','M','Q','H'
|
@@ -47,5 +49,11 @@ def qr_code(data, to_html=False):
|
|
47
49
|
else:
|
48
50
|
ascii_art += fonts[3]
|
49
51
|
ascii_art += "\n"
|
50
|
-
|
52
|
+
Qrcode = data if to_html else ""
|
53
|
+
time_print(
|
54
|
+
ascii_art,
|
55
|
+
Time=False,
|
56
|
+
Qrcode=Qrcode,
|
57
|
+
Number=num,
|
58
|
+
)
|
51
59
|
return height_double
|
podflow/basic/time_print.py
CHANGED
@@ -3,36 +3,48 @@
|
|
3
3
|
|
4
4
|
from datetime import datetime
|
5
5
|
from podflow import gVar
|
6
|
-
from podflow.httpfs.to_html import ansi_to_html
|
6
|
+
from podflow.httpfs.to_html import ansi_to_html, qrcode_to_html
|
7
7
|
|
8
8
|
|
9
|
-
def time_print(
|
9
|
+
def time_print(
|
10
|
+
text,
|
11
|
+
Top=False,
|
12
|
+
NoEnter=False,
|
13
|
+
Time=True,
|
14
|
+
Url="",
|
15
|
+
Qrcode=False,
|
16
|
+
Number=None,
|
17
|
+
Head="",
|
18
|
+
):
|
10
19
|
if Time:
|
11
20
|
text = f"{datetime.now().strftime('%H:%M:%S')}|{text}"
|
12
|
-
if Top
|
13
|
-
text_print = f"\r{text}"
|
14
|
-
else:
|
15
|
-
text_print = f"{text}"
|
21
|
+
text_print = f"\r{text}" if Top else f"{text}"
|
16
22
|
if Url:
|
17
23
|
text_print = f"{text_print}\n\033[34m{Url}\033[0m"
|
24
|
+
if Head:
|
25
|
+
text_print = f"{Head}{text_print}"
|
18
26
|
if NoEnter:
|
19
27
|
print(text_print, end="")
|
20
28
|
else:
|
21
29
|
print(text_print)
|
22
30
|
|
31
|
+
if Number is not None and (
|
32
|
+
not isinstance(Number, int)
|
33
|
+
or not -min(len(gVar.index_message["podflow"]), 4) <= Number < 0
|
34
|
+
):
|
35
|
+
Number = None
|
23
36
|
if text:
|
24
|
-
text = ansi_to_html(text)
|
25
|
-
if
|
26
|
-
|
37
|
+
text = qrcode_to_html(Qrcode) if Qrcode else ansi_to_html(text)
|
38
|
+
if Number:
|
39
|
+
gVar.index_message["podflow"][Number] = text
|
40
|
+
elif not gVar.index_message["enter"] and gVar.index_message["podflow"]:
|
41
|
+
if Top:
|
27
42
|
gVar.index_message["podflow"][-1] = text
|
28
43
|
else:
|
29
44
|
gVar.index_message["podflow"][-1] += text
|
30
45
|
else:
|
31
46
|
gVar.index_message["podflow"].append(text)
|
32
|
-
|
33
|
-
gVar.index_message["enter"] = False
|
34
|
-
else:
|
35
|
-
gVar.index_message["enter"] = True
|
47
|
+
gVar.index_message["enter"] = not NoEnter
|
36
48
|
if Url:
|
37
49
|
gVar.index_message["podflow"].append(
|
38
50
|
f'<a href="{Url}" target="_blank"><span class="ansi-url">{Url}</span></a>'
|
podflow/bilibili/login.py
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
# podflow/bilibili/login.py
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
import binascii
|
5
|
-
import json
|
6
4
|
import os
|
7
5
|
import re
|
8
6
|
import time
|
9
|
-
|
7
|
+
import json
|
8
|
+
import binascii
|
10
9
|
import requests
|
11
|
-
from
|
12
|
-
from podflow.basic.http_client import http_client
|
10
|
+
from datetime import datetime
|
13
11
|
from podflow.basic.qr_code import qr_code
|
14
|
-
from podflow.basic.time_stamp import time_stamp
|
15
12
|
from podflow.basic.write_log import write_log
|
13
|
+
from podflow.basic.file_save import file_save
|
14
|
+
from podflow.basic.time_print import time_print
|
15
|
+
from podflow.basic.time_stamp import time_stamp
|
16
|
+
from podflow.basic.http_client import http_client
|
16
17
|
from podflow.netscape.bulid_netscape import bulid_netscape
|
17
18
|
|
18
19
|
try:
|
@@ -75,13 +76,17 @@ def bilibili_scan_login(token):
|
|
75
76
|
|
76
77
|
|
77
78
|
# 登陆哔哩哔哩模块
|
78
|
-
def bilibili_login():
|
79
|
+
def bilibili_login(retry=False):
|
79
80
|
buvid3_and_bnut = http_client(
|
80
81
|
"https://www.bilibili.com", "哔哩哔哩主页", 10, 4, True
|
81
82
|
).cookies.get_dict()
|
82
83
|
token, url = bilibili_request_qr_code()
|
83
|
-
|
84
|
-
|
84
|
+
if retry:
|
85
|
+
time_print("请用BiliBili App扫描登录:", Number=-3)
|
86
|
+
upward = qr_code(url, to_html=True, num=-2)
|
87
|
+
else:
|
88
|
+
time_print("请用BiliBili App扫描登录:")
|
89
|
+
upward = qr_code(url, to_html=True)
|
85
90
|
login_status_change = ""
|
86
91
|
time_text = f"{datetime.now().strftime('%H:%M:%S')}|BiliBili "
|
87
92
|
while True:
|
@@ -97,16 +102,34 @@ def bilibili_login():
|
|
97
102
|
else:
|
98
103
|
login_status = "\033[31m错误\033[0m"
|
99
104
|
if login_status_change != login_status:
|
105
|
+
num = -1 if retry else None
|
100
106
|
if login_status == "":
|
101
|
-
|
107
|
+
time_print(
|
108
|
+
f"{time_text}{login_status}".ljust(42),
|
109
|
+
NoEnter=True,
|
110
|
+
Time=False,
|
111
|
+
Number=num,
|
112
|
+
)
|
102
113
|
else:
|
103
|
-
|
114
|
+
time_print(
|
115
|
+
f"{time_text}{login_status}".ljust(42),
|
116
|
+
Top=True,
|
117
|
+
NoEnter=True,
|
118
|
+
Time=False,
|
119
|
+
Number=num,
|
120
|
+
)
|
104
121
|
login_status_change = login_status
|
105
122
|
if status == 86038:
|
106
|
-
|
123
|
+
time_print(
|
124
|
+
"",
|
125
|
+
Time=False,
|
126
|
+
)
|
107
127
|
return status, refresh_token, upward
|
108
128
|
elif status == 0:
|
109
|
-
|
129
|
+
time_print(
|
130
|
+
"",
|
131
|
+
Time=False,
|
132
|
+
)
|
110
133
|
cookie["buvid3"] = buvid3_and_bnut.get("buvid3", "")
|
111
134
|
cookie["b_nut"] = buvid3_and_bnut.get("b_nut", "")
|
112
135
|
return cookie, refresh_token, upward
|
@@ -114,8 +137,8 @@ def bilibili_login():
|
|
114
137
|
|
115
138
|
|
116
139
|
# 保存哔哩哔哩登陆成功后的cookies模块
|
117
|
-
def save_bilibili_cookies():
|
118
|
-
bilibili_cookie, refresh_token, upward = bilibili_login()
|
140
|
+
def save_bilibili_cookies(retry=False):
|
141
|
+
bilibili_cookie, refresh_token, upward = bilibili_login(retry)
|
119
142
|
if bilibili_cookie == 86038:
|
120
143
|
return {"cookie": None}, upward
|
121
144
|
bilibili_cookie = requests.utils.dict_from_cookiejar(bilibili_cookie)
|
@@ -238,9 +261,7 @@ JNrRuoEUXpabUzGB8QIDAQAB
|
|
238
261
|
|
239
262
|
|
240
263
|
def get_bilibili_data_success(bilibili_data, channelid_bilibili_ids):
|
241
|
-
|
242
|
-
f"{datetime.now().strftime('%H:%M:%S')}|BiliBili \033[32m获取cookie成功\033[0m"
|
243
|
-
)
|
264
|
+
time_print("BiliBili \033[32m获取cookie成功\033[0m")
|
244
265
|
img_key, sub_key = getWbiKeys()
|
245
266
|
bilibili_data["img_key"] = img_key
|
246
267
|
bilibili_data["sub_key"] = sub_key
|
@@ -262,28 +283,23 @@ def get_bilibili_data_state(bilibili_data, channelid_bilibili_ids):
|
|
262
283
|
):
|
263
284
|
if bilibili_login_code != 0:
|
264
285
|
if try_num == 0:
|
265
|
-
|
266
|
-
|
267
|
-
)
|
286
|
+
time_print("BiliBili \033[31m未登陆\033[0m")
|
287
|
+
bilibili_data, upward = save_bilibili_cookies()
|
268
288
|
else:
|
269
|
-
|
270
|
-
f"
|
289
|
+
time_print(
|
290
|
+
f"BiliBili \033[31m未登陆, 重试第\033[0m{try_num}\033[31m次\033[0m",
|
291
|
+
Head=f"\033[{upward + 3}F\033[{upward + 3}K",
|
292
|
+
Number=-4
|
271
293
|
)
|
272
|
-
|
294
|
+
bilibili_data, upward = save_bilibili_cookies(True)
|
273
295
|
try_num += 1
|
274
296
|
else:
|
275
|
-
|
276
|
-
f"{datetime.now().strftime('%H:%M:%S')}|BiliBili \033[33m需刷新\033[0m"
|
277
|
-
)
|
297
|
+
time_print("BiliBili \033[33m需刷新\033[0m")
|
278
298
|
bilibili_data = bilibili_cookie_update(bilibili_data)
|
279
299
|
if bilibili_data["cookie"]:
|
280
|
-
|
281
|
-
f"{datetime.now().strftime('%H:%M:%S')}|BiliBili \033[32m刷新成功\033[0m"
|
282
|
-
)
|
300
|
+
time_print("BiliBili \033[32m刷新成功\033[0m")
|
283
301
|
else:
|
284
|
-
|
285
|
-
f"{datetime.now().strftime('%H:%M:%S')}|BiliBili \033[31m刷新失败, 重新登陆\033[0m"
|
286
|
-
)
|
302
|
+
time_print("BiliBili \033[31m刷新失败, 重新登陆\033[0m")
|
287
303
|
bilibili_login_code, bilibili_login_refresh_token = judgment_bilibili_update(
|
288
304
|
bilibili_data["cookie"]
|
289
305
|
)
|
@@ -305,9 +321,7 @@ def get_bilibili_data(channelid_bilibili_ids):
|
|
305
321
|
bilibili_data = {"cookie": None, "timestamp": 0.0}
|
306
322
|
if time.time() - bilibili_data["timestamp"] - 60 * 60 > 0:
|
307
323
|
return get_bilibili_data_state(bilibili_data, channelid_bilibili_ids)
|
308
|
-
|
309
|
-
f"{datetime.now().strftime('%H:%M:%S')}|BiliBili \033[33m获取cookie成功\033[0m"
|
310
|
-
)
|
324
|
+
time_print("BiliBili \033[33m获取cookie成功\033[0m")
|
311
325
|
if not os.path.isfile("channel_data/yt_dlp_bilibili.txt"):
|
312
326
|
bulid_netscape("yt_dlp_bilibili", bilibili_data["cookie"])
|
313
327
|
return channelid_bilibili_ids, bilibili_data
|
@@ -37,7 +37,7 @@ def download_video(
|
|
37
37
|
|
38
38
|
def error(self, msg):
|
39
39
|
msg = fail_message_initialize(msg, video_url).ljust(48)
|
40
|
-
time_print(msg, Time=False)
|
40
|
+
time_print(msg, Top=True, Time=False)
|
41
41
|
|
42
42
|
outtmpl = f"channel_audiovisual/{output_dir}/{video_url}{sesuffix}.{output_format}"
|
43
43
|
ydl_opts = {
|
@@ -78,13 +78,15 @@ def download_video(
|
|
78
78
|
or re.search(r"请求拒绝|数据不完整|传输中断|请求超时|响应超时", fail_info)
|
79
79
|
) and "www.youtube.com" in video_website:
|
80
80
|
if fail_info != "":
|
81
|
-
|
81
|
+
remove_info_part = "|"
|
82
|
+
else:
|
83
|
+
remove_info_part = ""
|
82
84
|
if os.path.isfile(outtmpl):
|
83
85
|
os.remove(outtmpl)
|
84
|
-
remove_info
|
86
|
+
remove_info = remove_info_part + "已删除失败文件"
|
85
87
|
elif os.path.isfile(outtmpl + ".part"):
|
86
88
|
os.remove(outtmpl + ".part")
|
87
|
-
remove_info
|
89
|
+
remove_info = remove_info_part + "已删除部分失败文件"
|
88
90
|
write_log(
|
89
91
|
f"{video_write_log} \033[31m下载失败\033[0m",
|
90
92
|
None,
|
podflow/httpfs/to_html.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
import re
|
5
5
|
import html
|
6
|
-
from podflow import gVar
|
7
6
|
|
8
7
|
|
9
8
|
def ansi_to_html(ansi_text):
|
@@ -47,10 +46,11 @@ def ansi_to_html(ansi_text):
|
|
47
46
|
|
48
47
|
if inside_span:
|
49
48
|
html_output += "</span>"
|
50
|
-
|
49
|
+
html_output = re.sub(r'^\n', '', html_output)
|
50
|
+
html_output = re.sub(r'\n+$', '', html_output)
|
51
|
+
html_output = re.sub(r' +$', '', html_output)
|
51
52
|
return html_output
|
52
53
|
|
53
54
|
|
54
55
|
def qrcode_to_html(url):
|
55
|
-
|
56
|
-
gVar.index_message["podflow"].append(text)
|
56
|
+
return f'<span class="qrcode-container" data-url="{url}"></span>'
|
podflow/main_podcast.py
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
import sys
|
5
5
|
import json
|
6
6
|
import time
|
7
|
+
import random
|
7
8
|
import urllib
|
8
9
|
import subprocess
|
9
10
|
|
@@ -106,24 +107,30 @@ def main_podcast():
|
|
106
107
|
sys.exit(0)
|
107
108
|
# 主流程
|
108
109
|
while parse.update_num > 0 or parse.update_num == -1: # 循环主更新
|
110
|
+
# 主进度条
|
111
|
+
gVar.index_message["schedule"] = ["准备中", 0]
|
109
112
|
# 暂停进程打印
|
110
113
|
gVar.server_process_print_flag[0] = "pause"
|
111
114
|
# 获取YouTube cookie
|
112
115
|
gVar.youtube_cookie = get_youtube_cookie(gVar.channelid_youtube_ids_original)
|
116
|
+
gVar.index_message["schedule"][1] = 0.01 + random.uniform(0, 0.0049)
|
113
117
|
# 更新哔哩哔哩data
|
114
118
|
gVar.channelid_bilibili_ids, gVar.bilibili_data = get_bilibili_data(
|
115
119
|
gVar.channelid_bilibili_ids_original
|
116
120
|
)
|
121
|
+
gVar.index_message["schedule"][1] = 0.02 + random.uniform(0, 0.0049)
|
117
122
|
# 恢复进程打印
|
118
123
|
bottle_app_instance.cherry_print()
|
119
124
|
# 获取原始xml字典和rss文本
|
120
125
|
gVar.xmls_original, gVar.hash_rss_original, gVar.xmls_original_fail = (
|
121
126
|
get_original_rss()
|
122
127
|
)
|
128
|
+
gVar.index_message["schedule"][1] = 0.03 + random.uniform(0, 0.0049)
|
123
129
|
# 暂停进程打印
|
124
130
|
gVar.server_process_print_flag[0] = "pause"
|
125
131
|
# 连接上传服务器
|
126
132
|
upload_url = connect_upload_server()
|
133
|
+
gVar.index_message["schedule"][1] = 0.04 + random.uniform(0, 0.0049)
|
127
134
|
# 恢复进程打印
|
128
135
|
bottle_app_instance.cherry_print()
|
129
136
|
# 登陆上传服务器
|
@@ -133,16 +140,20 @@ def main_podcast():
|
|
133
140
|
gVar.config["upload"] = False
|
134
141
|
else:
|
135
142
|
gVar.config["upload"] = False
|
143
|
+
gVar.index_message["schedule"][1] = 0.045 + random.uniform(0, 0.0024)
|
136
144
|
# 初始化原始上传信息
|
137
145
|
get_upload_original()
|
146
|
+
gVar.index_message["schedule"][1] = 0.05
|
138
147
|
# 更新Youtube和哔哩哔哩频道xml
|
139
148
|
update_youtube_bilibili_rss()
|
149
|
+
gVar.index_message["schedule"][1] = 0.1
|
140
150
|
# 判断是否有更新内容
|
141
151
|
if gVar.channelid_youtube_ids_update or gVar.channelid_bilibili_ids_update:
|
142
152
|
gVar.update_generate_rss = True
|
143
153
|
if gVar.update_generate_rss:
|
144
154
|
# 根据日出日落修改封面(只适用原封面)
|
145
155
|
channge_icon()
|
156
|
+
gVar.index_message["schedule"][1] = 0.11 + random.uniform(0, 0.0049)
|
146
157
|
# 输出需要更新的信息
|
147
158
|
update_information_display(
|
148
159
|
gVar.channelid_youtube_ids_update,
|
@@ -156,58 +167,74 @@ def main_podcast():
|
|
156
167
|
gVar.bilibili_content_bvid_backward_update,
|
157
168
|
"BiliBili",
|
158
169
|
)
|
170
|
+
gVar.index_message["schedule"][1] = 0.12
|
159
171
|
# 暂停进程打印
|
160
172
|
gVar.server_process_print_flag[0] = "pause"
|
161
173
|
# 获取视频格式信息
|
162
174
|
get_video_format()
|
175
|
+
gVar.index_message["schedule"][1] = 0.199
|
163
176
|
# 恢复进程打印
|
164
177
|
bottle_app_instance.cherry_print()
|
165
178
|
# 删除中断下载的媒体文件
|
166
179
|
if gVar.config["delete_incompletement"]:
|
167
180
|
delete_part(gVar.channelid_youtube_ids | gVar.channelid_bilibili_ids)
|
181
|
+
gVar.index_message["schedule"] = ["构建中", 0.20]
|
168
182
|
# 暂停进程打印
|
169
183
|
gVar.server_process_print_flag[0] = "pause"
|
170
184
|
# 下载并构建YouTube和哔哩哔哩视频
|
171
185
|
download_and_build()
|
186
|
+
gVar.index_message["schedule"][1] = 0.8
|
172
187
|
# 添加新媒体至上传列表
|
173
188
|
add_upload()
|
189
|
+
gVar.index_message["schedule"][1] = 0.81 + random.uniform(0, 0.0049)
|
174
190
|
# 恢复进程打印
|
175
191
|
bottle_app_instance.cherry_print()
|
176
192
|
# 打印无法保留原节目信息
|
177
193
|
original_rss_fail_print(gVar.xmls_original_fail)
|
194
|
+
gVar.index_message["schedule"][1] = 0.82 + random.uniform(0, 0.0049)
|
178
195
|
# 打印无法获取youtube信息
|
179
196
|
print_fail_youtube()
|
197
|
+
gVar.index_message["schedule"][1] = 0.83 + random.uniform(0, 0.0049)
|
180
198
|
if gVar.config["remove_media"]:
|
181
199
|
# 删除不在rss中的媒体文件
|
182
200
|
remove_file()
|
183
201
|
# 删除已抛弃的媒体文件夹
|
184
202
|
remove_dir()
|
203
|
+
gVar.index_message["schedule"][1] = 0.84
|
185
204
|
# 补全缺失媒体文件到字典
|
186
205
|
make_up_file()
|
206
|
+
gVar.index_message["schedule"][1] = 0.85
|
187
207
|
# 按参数获取需要补全的最大个数
|
188
208
|
gVar.make_up_file_format = split_dict(
|
189
209
|
gVar.make_up_file_format,
|
190
210
|
gVar.config["completion_count"],
|
191
211
|
True,
|
192
212
|
)[0]
|
213
|
+
gVar.index_message["schedule"][1] = 0.86 + random.uniform(0, 0.0049)
|
193
214
|
# 暂停进程打印
|
194
215
|
gVar.server_process_print_flag[0] = "pause"
|
195
216
|
# 补全在rss中缺失的媒体格式信息
|
196
217
|
make_up_file_format_mod()
|
218
|
+
gVar.index_message["schedule"][1] = 0.90 + random.uniform(0, 0.0049)
|
197
219
|
# 恢复进程打印
|
198
220
|
bottle_app_instance.cherry_print()
|
221
|
+
gVar.index_message["schedule"][1] = 0.91 + random.uniform(0, 0.0049)
|
199
222
|
# 删除无法补全的媒体
|
200
223
|
del_makeup_format_fail()
|
224
|
+
gVar.index_message["schedule"][1] = 0.92 + random.uniform(0, 0.0049)
|
201
225
|
# 暂停进程打印
|
202
226
|
gVar.server_process_print_flag[0] = "pause"
|
203
227
|
# 保存rss文件模块
|
204
228
|
save_rss()
|
229
|
+
gVar.index_message["schedule"][1] = 0.93 + random.uniform(0, 0.0049)
|
205
230
|
# 下载补全Youtube和哔哩哔哩视频模块
|
206
231
|
make_up_file_mod()
|
232
|
+
gVar.index_message["schedule"][1] = 0.99 + random.uniform(0, 0.0099)
|
207
233
|
# 恢复进程打印
|
208
234
|
bottle_app_instance.cherry_print()
|
209
235
|
# 更新并保存上传列表
|
210
236
|
update_upload()
|
237
|
+
gVar.index_message["schedule"] = ["已完成", 1]
|
211
238
|
else:
|
212
239
|
time_print("频道无更新内容")
|
213
240
|
# 清空变量内数据
|
podflow/makeup/make_up_file.py
CHANGED
@@ -8,9 +8,17 @@ from podflow import gVar
|
|
8
8
|
# 补全缺失媒体文件到字典模块
|
9
9
|
def make_up_file():
|
10
10
|
channelid_youtube_ids = gVar.channelid_youtube_ids
|
11
|
+
channelid_bilibili_ids = gVar.channelid_bilibili_ids
|
12
|
+
num = 0
|
13
|
+
for output_dir in channelid_youtube_ids:
|
14
|
+
num += len(gVar.all_youtube_content_ytid[output_dir])
|
15
|
+
for output_dir in channelid_bilibili_ids:
|
16
|
+
num += len(gVar.all_bilibili_content_bvid[output_dir])
|
17
|
+
ratio_part = 0.01 / num if num else 0
|
11
18
|
for output_dir, name in channelid_youtube_ids.items():
|
19
|
+
youtube_os_list = os.listdir(f"channel_audiovisual/{output_dir}")
|
12
20
|
for file_name in gVar.all_youtube_content_ytid[output_dir]:
|
13
|
-
if file_name not in
|
21
|
+
if file_name not in youtube_os_list:
|
14
22
|
main = file_name.split(".")[0]
|
15
23
|
media = file_name.split(".")[1]
|
16
24
|
video_id_format = {
|
@@ -27,11 +35,14 @@ def make_up_file():
|
|
27
35
|
video_quality = 1080
|
28
36
|
video_id_format["quality"] = video_quality
|
29
37
|
gVar.make_up_file_format[main] = video_id_format
|
38
|
+
# 更新进度条
|
39
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
40
|
+
gVar.index_message["schedule"][1] = ratio
|
30
41
|
|
31
|
-
channelid_bilibili_ids = gVar.channelid_bilibili_ids
|
32
42
|
for output_dir, name in channelid_bilibili_ids.items():
|
43
|
+
bilibili_os_list = os.listdir(f"channel_audiovisual/{output_dir}")
|
33
44
|
for file_name in gVar.all_bilibili_content_bvid[output_dir]:
|
34
|
-
if file_name not in
|
45
|
+
if file_name not in bilibili_os_list:
|
35
46
|
main = file_name.split(".")[0][:12]
|
36
47
|
if main not in gVar.make_up_file_format:
|
37
48
|
media = file_name.split(".")[1]
|
@@ -49,3 +60,8 @@ def make_up_file():
|
|
49
60
|
video_quality = 1080
|
50
61
|
video_id_format["quality"] = video_quality
|
51
62
|
gVar.make_up_file_format[main] = video_id_format
|
63
|
+
# 更新进度条
|
64
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
65
|
+
if ratio > 0.85:
|
66
|
+
ratio = 0.85
|
67
|
+
gVar.index_message["schedule"][1] = ratio
|
@@ -29,6 +29,8 @@ def create_main_rss():
|
|
29
29
|
}
|
30
30
|
all_channelid = list(gVar.all_items.keys())
|
31
31
|
|
32
|
+
ratio_part = 0.6 / len(all_channelid) if all_channelid else 0
|
33
|
+
|
32
34
|
while all_channelid:
|
33
35
|
for index, output_dir in enumerate(all_channelid):
|
34
36
|
if output_dir in update_output_dir():
|
@@ -66,5 +68,10 @@ def create_main_rss():
|
|
66
68
|
"bilibili", items["items"]
|
67
69
|
)
|
68
70
|
gVar.all_items[output_dir] = items
|
71
|
+
# 主进度条更新
|
72
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
73
|
+
if ratio > 0.8:
|
74
|
+
ratio = 0.8
|
75
|
+
gVar.index_message["schedule"][1] = ratio
|
69
76
|
del all_channelid[index]
|
70
77
|
break
|
@@ -92,6 +92,20 @@ def get_video_format():
|
|
92
92
|
get_bilibili_format_front(gVar.bilibili_content_bvid_update, False)
|
93
93
|
get_youtube_format_front(gVar.youtube_content_ytid_backward_update, True)
|
94
94
|
get_bilibili_format_front(gVar.bilibili_content_bvid_backward_update, True)
|
95
|
+
if (
|
96
|
+
gVar.youtube_content_ytid_update
|
97
|
+
or gVar.bilibili_content_bvid_update
|
98
|
+
or gVar.youtube_content_ytid_backward_update
|
99
|
+
or gVar.bilibili_content_bvid_backward_update
|
100
|
+
):
|
101
|
+
ratio_part = 0.079 / (
|
102
|
+
len(gVar.youtube_content_ytid_update)
|
103
|
+
+ len(gVar.bilibili_content_bvid_update)
|
104
|
+
+ len(gVar.youtube_content_ytid_backward_update)
|
105
|
+
+ len(gVar.bilibili_content_bvid_backward_update)
|
106
|
+
)
|
107
|
+
else:
|
108
|
+
ratio_part = 0
|
95
109
|
# 按参数拆分获取量
|
96
110
|
if len(gVar.video_id_update_format) != 0:
|
97
111
|
video_id_update_format_list = split_dict(
|
@@ -107,5 +121,7 @@ def get_video_format():
|
|
107
121
|
)
|
108
122
|
# 获取视频信息多线程模块
|
109
123
|
get_video_format_multithread(
|
110
|
-
video_id_update_format_item,
|
124
|
+
video_id_update_format_item,
|
125
|
+
wait_animation_display_info,
|
126
|
+
ratio_part,
|
111
127
|
)
|
@@ -10,7 +10,9 @@ from podflow.message.get_youtube_and_bilibili_video_format import (
|
|
10
10
|
|
11
11
|
# YouTube&哔哩哔哩获取视频信息多线程模块
|
12
12
|
def get_video_format_multithread(
|
13
|
-
video_id_update_format_item,
|
13
|
+
video_id_update_format_item,
|
14
|
+
wait_animation_display_info,
|
15
|
+
ratio_part,
|
14
16
|
):
|
15
17
|
# 创建共享的标志变量
|
16
18
|
stop_flag = ["keep"] # 使用列表来存储标志变量
|
@@ -26,12 +28,21 @@ def get_video_format_multithread(
|
|
26
28
|
prepare_animation.start()
|
27
29
|
# 创建线程锁
|
28
30
|
video_format_lock = threading.Lock()
|
31
|
+
ratio_part_lock = threading.Lock()
|
29
32
|
# 创建线程列表
|
30
33
|
video_id_update_threads = []
|
34
|
+
|
31
35
|
for video_id in video_id_update_format_item.keys():
|
32
36
|
thread = threading.Thread(
|
33
37
|
target=get_youtube_and_bilibili_video_format,
|
34
|
-
args=(
|
38
|
+
args=(
|
39
|
+
video_id,
|
40
|
+
stop_flag,
|
41
|
+
video_format_lock,
|
42
|
+
prepare_animation,
|
43
|
+
ratio_part,
|
44
|
+
ratio_part_lock,
|
45
|
+
),
|
35
46
|
)
|
36
47
|
video_id_update_threads.append(thread)
|
37
48
|
thread.start()
|
@@ -26,7 +26,11 @@ def one_format(id_update_format, id_num):
|
|
26
26
|
|
27
27
|
# YouTube&哔哩哔哩视频信息模块
|
28
28
|
def get_youtube_and_bilibili_video_format(
|
29
|
-
id_num, stop_flag,
|
29
|
+
id_num, stop_flag,
|
30
|
+
video_format_lock,
|
31
|
+
prepare_animation,
|
32
|
+
ratio_part,
|
33
|
+
ratio_part_lock,
|
30
34
|
):
|
31
35
|
url = gVar.video_id_update_format[id_num]["url"]
|
32
36
|
media = gVar.video_id_update_format[id_num]["media"]
|
@@ -101,3 +105,9 @@ def get_youtube_and_bilibili_video_format(
|
|
101
105
|
False,
|
102
106
|
)
|
103
107
|
del gVar.video_id_update_format[id_num]
|
108
|
+
with ratio_part_lock:
|
109
|
+
# 主进度条更新
|
110
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
111
|
+
if ratio > 0.199:
|
112
|
+
ratio = 0.199
|
113
|
+
gVar.index_message["schedule"][1] = ratio
|
@@ -61,6 +61,12 @@ def update_youtube_bilibili_rss():
|
|
61
61
|
) in pattern_youtube_error.items():
|
62
62
|
if pattern_youtube_error_key in youtube_content:
|
63
63
|
return pattern_youtube_error_value
|
64
|
+
if gVar.channelid_youtube_ids or gVar.channelid_bilibili_ids:
|
65
|
+
ratio_part = 0.05 / (
|
66
|
+
len(gVar.channelid_youtube_ids) + len(gVar.channelid_bilibili_ids)
|
67
|
+
)
|
68
|
+
else:
|
69
|
+
ratio_part = 0
|
64
70
|
|
65
71
|
# 更新Youtube频道
|
66
72
|
for youtube_key, youtube_value in gVar.channelid_youtube_ids.copy().items():
|
@@ -97,6 +103,10 @@ def update_youtube_bilibili_rss():
|
|
97
103
|
if youtube_response_type == "text":
|
98
104
|
del gVar.channelid_youtube_ids[youtube_key]
|
99
105
|
write_log(f"YouTube频道 {youtube_value} 无法更新")
|
106
|
+
# 更新进度条
|
107
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
108
|
+
gVar.index_message["schedule"][1] = ratio
|
109
|
+
|
100
110
|
# 更新哔哩哔哩频道
|
101
111
|
for bilibili_key, bilibili_value in gVar.channelid_bilibili_ids.copy().items():
|
102
112
|
bilibili_space = gVar.channelid_bilibili_rss[bilibili_key]["content"]
|
@@ -114,3 +124,8 @@ def update_youtube_bilibili_rss():
|
|
114
124
|
file_save(bilibili_space, f"{bilibili_key}.json", "channel_id")
|
115
125
|
# 构建频道文件夹
|
116
126
|
folder_build(bilibili_key, "channel_audiovisual")
|
127
|
+
# 更新进度条
|
128
|
+
ratio = gVar.index_message["schedule"][1] + ratio_part
|
129
|
+
if ratio > 0.1:
|
130
|
+
ratio = 0.1
|
131
|
+
gVar.index_message["schedule"][1] = ratio
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# podflow/Netscape/get_cookie_dict.py
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
from datetime import datetime
|
5
4
|
from http.cookiejar import LoadError, MozillaCookieJar
|
5
|
+
from podflow.basic.time_print import time_print
|
6
6
|
|
7
7
|
|
8
8
|
# 将Netscape转Dict模块
|
@@ -14,8 +14,8 @@ def get_cookie_dict(file):
|
|
14
14
|
cookie_jar.load(ignore_discard=True)
|
15
15
|
return {cookie.name: cookie.value for cookie in cookie_jar}
|
16
16
|
except FileNotFoundError:
|
17
|
-
|
17
|
+
time_print(f"{parts[-1]}文件不存在")
|
18
18
|
return None
|
19
19
|
except LoadError:
|
20
|
-
|
20
|
+
time_print(f"{parts[-1]}文件错误")
|
21
21
|
return None
|
podflow/templates/index.html
CHANGED
@@ -20,6 +20,8 @@
|
|
20
20
|
--menu-text: #333333;
|
21
21
|
--menu-width: 170px;
|
22
22
|
--menu-selected-bg: #cccccc;
|
23
|
+
/* 新增进度条颜色变量 */
|
24
|
+
--progress-bar-color: #28a745; /* 更柔和的绿色 */
|
23
25
|
}
|
24
26
|
|
25
27
|
/* 深色模式变量 */
|
@@ -37,6 +39,8 @@
|
|
37
39
|
--menu-bg: #333333;
|
38
40
|
--menu-text: #e0e0e0;
|
39
41
|
--menu-selected-bg: #555555;
|
42
|
+
/* 深色模式下的进度条颜色 */
|
43
|
+
--progress-bar-color: #40c057; /* 略亮的绿色 */
|
40
44
|
}
|
41
45
|
}
|
42
46
|
|
@@ -241,6 +245,46 @@
|
|
241
245
|
display: inline-block; /* 让容器并排显示 */
|
242
246
|
margin: 0px;
|
243
247
|
}
|
248
|
+
|
249
|
+
/* 主进度条样式 */
|
250
|
+
.progress-bar {
|
251
|
+
width: 100%;
|
252
|
+
height: 22px; /* 略微增加高度 */
|
253
|
+
background-color: #e0e0e0;
|
254
|
+
border-radius: 12px; /* 更圆润的边角 */
|
255
|
+
overflow: hidden;
|
256
|
+
position: relative;
|
257
|
+
border: 1px solid #ccc; /* 增加一个浅灰色边框 */
|
258
|
+
}
|
259
|
+
.progress-bar .progress {
|
260
|
+
height: 100%;
|
261
|
+
background-color: var(--progress-bar-color); /* 使用颜色变量 */
|
262
|
+
/* 添加一个微妙的渐变效果 */
|
263
|
+
background-image: linear-gradient(to right, rgba(255, 255, 255, 0.15) 0%, rgba(0, 0, 0, 0.15) 100%);
|
264
|
+
width: 0%;
|
265
|
+
transition: width 0.3s ease-in-out; /* 更平滑的过渡 */
|
266
|
+
border-radius: 12px; /* 与容器保持一致 */
|
267
|
+
}
|
268
|
+
.progress-bar .status-text {
|
269
|
+
position: absolute;
|
270
|
+
top: 50%;
|
271
|
+
left: 15px; /* 稍微调整左边距 */
|
272
|
+
transform: translateY(-50%);
|
273
|
+
color: var(--text-color); /* 使用文本颜色变量 */
|
274
|
+
font-weight: bold;
|
275
|
+
font-size: 14px;
|
276
|
+
z-index: 2; /* 确保状态文本覆盖在进度条上 */
|
277
|
+
}
|
278
|
+
.progress-bar .percentage-text {
|
279
|
+
position: absolute;
|
280
|
+
top: 50%;
|
281
|
+
right: 15px; /* 稍微调整右边距 */
|
282
|
+
transform: translateY(-50%);
|
283
|
+
color: var(--text-color); /* 使用文本颜色变量 */
|
284
|
+
font-weight: bold;
|
285
|
+
font-size: 14px;
|
286
|
+
z-index: 2; /* 确保百分比文本覆盖在进度条上 */
|
287
|
+
}
|
244
288
|
</style>
|
245
289
|
<script src="https://cdn.jsdelivr.net/gh/davidshimjs/qrcodejs/qrcode.min.js"></script>
|
246
290
|
</head>
|
@@ -275,7 +319,14 @@
|
|
275
319
|
<!-- 消息滚动显示页面 -->
|
276
320
|
<section id="pageMessage">
|
277
321
|
<h2>Podflow 运行情况</h2>
|
322
|
+
</div>
|
278
323
|
<form>
|
324
|
+
<label>主进度:</label>
|
325
|
+
<div class="progress-bar">
|
326
|
+
<div class="progress" id="mainProgress"></div>
|
327
|
+
<div class="status-text" id="progressStatus">准备中</div>
|
328
|
+
<div class="percentage-text" id="progressPercentage">0.00%</div>
|
329
|
+
</div>
|
279
330
|
<label>构建服务:</label><br>
|
280
331
|
<div class="common-area" id="messageArea"></div>
|
281
332
|
<label>服务器:</label><br>
|
@@ -284,7 +335,7 @@
|
|
284
335
|
</section>
|
285
336
|
</main>
|
286
337
|
<script>
|
287
|
-
(function() {
|
338
|
+
(function() {
|
288
339
|
// 生成单个二维码的函数
|
289
340
|
function generateQRCodeForNode(container) {
|
290
341
|
const rootStyles = getComputedStyle(document.documentElement);
|
@@ -305,62 +356,29 @@
|
|
305
356
|
container.textContent = 'URL 未提供';
|
306
357
|
}
|
307
358
|
}
|
308
|
-
|
309
|
-
// 为所有存在的二维码容器生成二维码
|
310
|
-
function generateQRCodes() {
|
311
|
-
const containers = document.querySelectorAll('.qrcode-container');
|
312
|
-
containers.forEach(generateQRCodeForNode);
|
313
|
-
}
|
314
|
-
|
315
|
-
// 利用 MutationObserver 动态监听 container 内新增的二维码容器
|
316
|
-
function observeQRCodes(container) {
|
317
|
-
const observer = new MutationObserver((mutationsList) => {
|
318
|
-
mutationsList.forEach(mutation => {
|
319
|
-
mutation.addedNodes.forEach(node => {
|
320
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
321
|
-
if (node.classList.contains('qrcode-container')) {
|
322
|
-
generateQRCodeForNode(node);
|
323
|
-
// 在生成二维码后,检查是否需要滚动
|
324
|
-
if (!userScrolled && container.scrollHeight - container.scrollTop <= container.clientHeight + 10) {
|
325
|
-
container.scrollTop = container.scrollHeight;
|
326
|
-
}
|
327
|
-
} else {
|
328
|
-
const childContainers = node.querySelectorAll('.qrcode-container');
|
329
|
-
childContainers.forEach(generateQRCodeForNode);
|
330
|
-
// 在生成二维码后,检查是否需要滚动
|
331
|
-
if (!userScrolled && container.scrollHeight - container.scrollTop <= container.clientHeight + 10) {
|
332
|
-
container.scrollTop = container.scrollHeight;
|
333
|
-
}
|
334
|
-
}
|
335
|
-
}
|
336
|
-
});
|
337
|
-
});
|
338
|
-
});
|
339
|
-
observer.observe(container, { childList: true, subtree: true });
|
340
|
-
}
|
341
|
-
|
359
|
+
|
342
360
|
// 缓存常用节点
|
343
361
|
const menu = document.getElementById('menu');
|
344
362
|
const toggleMenuBtn = document.getElementById('toggleMenu');
|
345
|
-
const mainArea = document.getElementById('main');
|
346
363
|
const pages = {
|
347
364
|
pageChannel: document.getElementById('pageChannel'),
|
348
365
|
pageMessage: document.getElementById('pageMessage')
|
349
366
|
};
|
350
367
|
const inputForm = document.getElementById('inputForm');
|
351
368
|
const inputOutput = document.getElementById('inputOutput');
|
352
|
-
const messageArea = document.getElementById('messageArea');
|
353
|
-
const messageHttp = document.getElementById('messageHttp');
|
354
369
|
const pasteBtn = document.getElementById('pasteBtn');
|
355
370
|
const copyBtn = document.getElementById('copyBtn');
|
356
371
|
const clearBtn = document.getElementById('clearBtn');
|
357
|
-
|
372
|
+
// 缓存进度条和文本元素
|
373
|
+
const mainProgress = document.getElementById('mainProgress');
|
374
|
+
const progressStatus = document.getElementById('progressStatus');
|
375
|
+
const progressPercentage = document.getElementById('progressPercentage');
|
376
|
+
const messageArea = document.getElementById('messageArea');
|
377
|
+
const messageHttp = document.getElementById('messageHttp');
|
378
|
+
|
379
|
+
let lastMessage = { podflow: [], http: [], schedule: [] };
|
358
380
|
let pollingTimer = null;
|
359
|
-
|
360
|
-
// 监听 messageArea 内动态新增的二维码容器
|
361
|
-
observeQRCodes(messageArea);
|
362
|
-
observeQRCodes(messageHttp); // Also observe for messageHttp
|
363
|
-
|
381
|
+
|
364
382
|
// 菜单切换函数
|
365
383
|
function toggleMenu() {
|
366
384
|
menu.classList.toggle('hidden');
|
@@ -372,7 +390,7 @@
|
|
372
390
|
toggleMenuBtn.textContent = '❮';
|
373
391
|
}
|
374
392
|
}
|
375
|
-
|
393
|
+
|
376
394
|
// 根据页面标识显示对应面板
|
377
395
|
function showPage(pageId) {
|
378
396
|
Object.values(pages).forEach(page => page.style.display = 'none');
|
@@ -383,35 +401,33 @@
|
|
383
401
|
toggleMenu();
|
384
402
|
}
|
385
403
|
pageId === 'pageMessage' ? startMessagePolling() : stopMessagePolling();
|
386
|
-
if (pageId === 'pageMessage') {
|
387
|
-
generateQRCodes(); // 页面切换时生成已有二维码
|
388
|
-
}
|
389
404
|
}
|
390
405
|
}
|
391
|
-
|
406
|
+
|
392
407
|
// 初始化默认页面
|
393
408
|
showPage('pageMessage');
|
394
|
-
|
395
|
-
let lastMessage = { podflow: [], http: [] };
|
409
|
+
|
396
410
|
let userScrolled = false;
|
397
|
-
|
411
|
+
|
398
412
|
// 监听滚动事件,检测用户是否手动滚动
|
399
413
|
function onUserScroll(event) {
|
400
414
|
const element = event.target;
|
401
415
|
// 判断是否接近底部,增加一定的容差值
|
402
|
-
const nearBottom = element.scrollHeight - element.scrollTop <= element.clientHeight +
|
416
|
+
const nearBottom = element.scrollHeight - element.scrollTop <= element.clientHeight + 10;
|
403
417
|
userScrolled = !nearBottom;
|
404
418
|
}
|
405
|
-
|
419
|
+
|
406
420
|
messageArea.addEventListener('scroll', onUserScroll);
|
407
421
|
messageHttp.addEventListener('scroll', onUserScroll);
|
408
|
-
|
422
|
+
|
409
423
|
// 轮询消息更新,更新 messageArea 与 messageHttp
|
410
424
|
function getMessages() {
|
411
425
|
fetch('message')
|
412
426
|
.then(response => response.json()) // 解析 JSON 数据
|
413
427
|
.then(data => {
|
414
428
|
if (JSON.stringify(data) !== JSON.stringify(lastMessage)) {
|
429
|
+
// 更新进度条
|
430
|
+
updateProgress(data.schedule);
|
415
431
|
// 追加新消息
|
416
432
|
appendMessages(messageArea, data.podflow, lastMessage.podflow);
|
417
433
|
appendMessages(messageHttp, data.http, lastMessage.http);
|
@@ -420,6 +436,23 @@
|
|
420
436
|
})
|
421
437
|
.catch(error => console.error('获取消息失败:', error));
|
422
438
|
}
|
439
|
+
|
440
|
+
// 更新进度条并显示状态和百分比
|
441
|
+
function updateProgress(scheduleData) {
|
442
|
+
// 检查 schedule 数据是否存在且长度为 2
|
443
|
+
if (scheduleData && scheduleData.length === 2) {
|
444
|
+
const [status, progress] = scheduleData; // 直接解构数组
|
445
|
+
if (status === "准备中" || status === "构建中") {
|
446
|
+
mainProgress.style.width = `${progress * 100}%`;
|
447
|
+
progressStatus.textContent = status; // 显示状态
|
448
|
+
progressPercentage.textContent = `${(progress * 100).toFixed(2)}%`; // 显示百分比,保留两位小数
|
449
|
+
} else if (status === "已完成") {
|
450
|
+
mainProgress.style.width = '100%';
|
451
|
+
progressStatus.textContent = '已完成'; // 显示完成状态
|
452
|
+
progressPercentage.textContent = '100.0%'; // 显示百分比
|
453
|
+
}
|
454
|
+
}
|
455
|
+
}
|
423
456
|
|
424
457
|
function createMessageElement(message) {
|
425
458
|
const p = document.createElement('p');
|
@@ -428,29 +461,58 @@
|
|
428
461
|
return p;
|
429
462
|
}
|
430
463
|
|
464
|
+
function processQRCodeContainers(p) {
|
465
|
+
const qrContainers = p.querySelectorAll('.qrcode-container');
|
466
|
+
qrContainers.forEach(container => {
|
467
|
+
// 判断当前容器是否有 data-url 属性,并且值不为空
|
468
|
+
if (container.dataset.url) {
|
469
|
+
generateQRCodeForNode(container);
|
470
|
+
} else {
|
471
|
+
// 如果没有 data-url 或值为空,可以执行其他操作,例如输出提示信息
|
472
|
+
console.log('容器中未提供 URL,跳过二维码生成:', container);
|
473
|
+
container.textContent = '未提供二维码 URL'; // 可选:在容器中显示提示
|
474
|
+
}
|
475
|
+
});
|
476
|
+
}
|
477
|
+
|
478
|
+
// 修改后的 appendMessages 函数:先生成消息节点内的二维码,再将节点追加或替换到消息容器中
|
431
479
|
function appendMessages(container, newMessages, oldMessages) {
|
432
480
|
// 判断当前是否在底部
|
433
481
|
const wasAtBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 10;
|
434
|
-
|
435
|
-
// 当两数组长度相等且有内容时,只比较最后一项
|
482
|
+
// 较为简单的情况:两数组长度相同且有内容,只比较最后四项
|
436
483
|
if (newMessages.length === oldMessages.length && newMessages.length > 0) {
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
484
|
+
let replaceCount;
|
485
|
+
if (newMessages[newMessages.length - 1].includes("未扫描") ||
|
486
|
+
newMessages[newMessages.length - 1].includes("二维码超时, 请重试")) {
|
487
|
+
replaceCount = Math.min(4, newMessages.length);
|
488
|
+
} else {
|
489
|
+
replaceCount = 1;
|
490
|
+
}
|
491
|
+
for (let i = 0; i < replaceCount; i++) {
|
492
|
+
// 计算从后向前的索引位置
|
493
|
+
const index = newMessages.length - 1 - i;
|
494
|
+
const newMessage = newMessages[index];
|
495
|
+
const oldMessage = oldMessages[index];
|
496
|
+
if (newMessage !== oldMessage) {
|
497
|
+
// 先创建消息节点
|
498
|
+
const p = createMessageElement(newMessage);
|
499
|
+
// 在插入前先处理二维码生成
|
500
|
+
processQRCodeContainers(p);
|
501
|
+
// 替换到容器中 - 注意这里要找到对应位置的子元素
|
502
|
+
const childToReplace = container.children[index];
|
503
|
+
if (childToReplace) {
|
504
|
+
container.replaceChild(p, childToReplace);
|
505
|
+
}
|
446
506
|
}
|
447
507
|
}
|
448
508
|
} else {
|
449
|
-
//
|
450
|
-
//
|
509
|
+
// 当 newMessages 与 oldMessages 数量不一致时
|
510
|
+
// 如果 oldMessages 存在数据,先替换容器中最后一项对应的消息
|
451
511
|
if (oldMessages.length > 0) {
|
452
512
|
const replaceIndex = oldMessages.length - 1;
|
453
513
|
const p = createMessageElement(newMessages[replaceIndex]);
|
514
|
+
// 先生成二维码
|
515
|
+
processQRCodeContainers(p);
|
454
516
|
const lastChild = container.lastElementChild;
|
455
517
|
if (lastChild) {
|
456
518
|
container.replaceChild(p, lastChild);
|
@@ -460,30 +522,35 @@
|
|
460
522
|
}
|
461
523
|
// 再追加从 oldMessages.length 开始的后续消息
|
462
524
|
newMessages.slice(oldMessages.length).forEach(msg => {
|
463
|
-
|
525
|
+
const p = createMessageElement(msg);
|
526
|
+
// 先生成二维码
|
527
|
+
processQRCodeContainers(p);
|
528
|
+
// 插入容器中
|
529
|
+
container.appendChild(p);
|
464
530
|
});
|
465
531
|
}
|
466
|
-
|
467
532
|
// 如果之前在底部且用户没有主动滚动,则自动滚动到底部
|
468
533
|
if (wasAtBottom && !userScrolled) {
|
469
534
|
container.scrollTop = container.scrollHeight;
|
470
535
|
}
|
471
536
|
}
|
472
|
-
|
537
|
+
|
538
|
+
// 启动消息轮询
|
473
539
|
function startMessagePolling() {
|
474
540
|
getMessages();
|
475
|
-
pollingTimer = setInterval(getMessages,
|
541
|
+
pollingTimer = setInterval(getMessages, 500);
|
476
542
|
}
|
477
|
-
|
543
|
+
|
544
|
+
// 停止消息轮询
|
478
545
|
function stopMessagePolling() {
|
479
546
|
if (pollingTimer !== null) {
|
480
547
|
clearInterval(pollingTimer);
|
481
548
|
pollingTimer = null;
|
482
549
|
}
|
483
550
|
}
|
484
|
-
|
485
|
-
|
486
|
-
|
551
|
+
|
552
|
+
// startMessagePolling();
|
553
|
+
|
487
554
|
// 表单异步提交(获取 Channel-ID)
|
488
555
|
inputForm && inputForm.addEventListener('submit', function(event) {
|
489
556
|
event.preventDefault();
|
@@ -493,19 +560,19 @@
|
|
493
560
|
headers: { 'Content-Type': 'application/json' },
|
494
561
|
body: JSON.stringify({ content })
|
495
562
|
})
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
563
|
+
.then(response => {
|
564
|
+
if (!response.ok) {
|
565
|
+
throw new Error('网络响应异常');
|
566
|
+
}
|
567
|
+
return response.json();
|
568
|
+
})
|
569
|
+
.then(data => inputOutput.value = data.response)
|
570
|
+
.catch(error => {
|
571
|
+
console.error('请求失败:', error);
|
572
|
+
alert('请求失败,请稍后重试!');
|
573
|
+
});
|
507
574
|
});
|
508
|
-
|
575
|
+
|
509
576
|
// 粘贴功能
|
510
577
|
pasteBtn.addEventListener('click', function() {
|
511
578
|
if (navigator.clipboard && navigator.clipboard.readText) {
|
@@ -526,7 +593,7 @@
|
|
526
593
|
}
|
527
594
|
}
|
528
595
|
});
|
529
|
-
|
596
|
+
|
530
597
|
// 复制功能
|
531
598
|
copyBtn.addEventListener('click', function() {
|
532
599
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
@@ -544,12 +611,12 @@
|
|
544
611
|
}
|
545
612
|
}
|
546
613
|
});
|
547
|
-
|
614
|
+
|
548
615
|
// 清空输入框
|
549
616
|
clearBtn.addEventListener('click', function() {
|
550
617
|
inputOutput.value = '';
|
551
618
|
});
|
552
|
-
|
619
|
+
|
553
620
|
// 菜单项点击事件委托
|
554
621
|
menu.addEventListener('click', function(event) {
|
555
622
|
const target = event.target;
|
@@ -557,24 +624,17 @@
|
|
557
624
|
showPage(target.dataset.page);
|
558
625
|
}
|
559
626
|
});
|
560
|
-
|
627
|
+
|
561
628
|
// 菜单切换按钮事件绑定
|
562
629
|
toggleMenuBtn.addEventListener('click', toggleMenu);
|
563
|
-
|
630
|
+
|
564
631
|
// 针对手机端,初始化时隐藏菜单
|
565
632
|
if (window.innerWidth <= 600) {
|
566
633
|
menu.classList.add('hidden');
|
567
634
|
toggleMenuBtn.style.left = '0px';
|
568
635
|
toggleMenuBtn.textContent = '❯';
|
569
636
|
}
|
570
|
-
|
571
|
-
// 在页面加载完成后首次生成二维码(如果当前显示的是 Channel 页面)
|
572
|
-
window.addEventListener('load', () => {
|
573
|
-
if (pages.pageChannel.style.display === 'block') {
|
574
|
-
generateQRCodes();
|
575
|
-
}
|
576
|
-
});
|
577
637
|
})();
|
578
|
-
|
638
|
+
</script>
|
579
639
|
</body>
|
580
640
|
</html>
|
@@ -1,8 +1,8 @@
|
|
1
|
-
podflow/__init__.py,sha256=
|
1
|
+
podflow/__init__.py,sha256=CgmkC0DhJ05yHdFmZRwImFN1jxf6Z8ggokIlPApDl_I,7275
|
2
2
|
podflow/download_and_build.py,sha256=GKQ1uX8Nuwdhr4wgnGr3jP1Mu0llRUPFcboQ3S05WkU,671
|
3
3
|
podflow/ffmpeg_judge.py,sha256=wM49pPXOFwFAA_8TKHal5fV6ka9sAA87yGQMDOssvXo,1340
|
4
4
|
podflow/main.py,sha256=Cz2E33-Kcc_1_oxNs4Z1OoqJYhonmClsrtoCW1oQmZA,739
|
5
|
-
podflow/main_podcast.py,sha256=
|
5
|
+
podflow/main_podcast.py,sha256=zUDTqabL07Aq-jTfxnCvD2b6NmHK0kUGOb942VfNKgI,12460
|
6
6
|
podflow/main_upload.py,sha256=H_T5KQMYzToqzQbjGQ6DWDGziy8iMnpmf7A1qOStJuo,2296
|
7
7
|
podflow/parse_arguments.py,sha256=h3a7EaRZS04kNMFYbxTW9Ch29KgZ7dyS-yqEEt_etQI,2592
|
8
8
|
podflow/basic/__init__.py,sha256=CAfI6mVQtz7KKbAiTIZ9_IbvaTXeAqxR1U7ov9GDoDo,44
|
@@ -13,17 +13,17 @@ podflow/basic/get_file_list.py,sha256=XmnC4faObislyTsL9WUeyztyTQrvdi76lMzPudKEfX
|
|
13
13
|
podflow/basic/get_html_dict.py,sha256=V-PgDtD6pm5mZC1LUPttUbZzxhjkS3WDYHxWR3yzIEY,869
|
14
14
|
podflow/basic/http_client.py,sha256=h4IwxC7ZSi4rJ-mHvj26FQqz5krERzUg4hKEgj-yj-M,2895
|
15
15
|
podflow/basic/list_merge_tidy.py,sha256=7hWfSnsPh23edHNU92vxtI0nfpfN8m54GTEt2rGm2HQ,368
|
16
|
-
podflow/basic/qr_code.py,sha256=
|
16
|
+
podflow/basic/qr_code.py,sha256=lZo11jbYqFQYy9gjBtRRUoLjlaEmoES-phydnrOMcLo,1727
|
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=foPezlEnYU0tOb8h79nDXZNElgNjRsHScYHYk9hGeTM,1481
|
20
20
|
podflow/basic/time_stamp.py,sha256=Kbz9PzgPtss1fRqPXdfz1q6MTGVMRi3LPClN7wrXSIk,1888
|
21
21
|
podflow/basic/vary_replace.py,sha256=-TyvZxfak6U7Ak8F87ctYUBpHB2Il6iYZof37lwKjto,211
|
22
22
|
podflow/basic/write_log.py,sha256=wfiNfFuRLCWNLXDRNPVaVsKxwB44xxTiCFJ66g71XmU,1255
|
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
|
26
|
-
podflow/bilibili/login.py,sha256=
|
26
|
+
podflow/bilibili/login.py,sha256=oHnuOMvlKZUnJ1OBHuZpTEnG04pboWsueOx871lQWjc,11482
|
27
27
|
podflow/config/__init__.py,sha256=MzgAlkSdV-5MFC11r0QSf-GPxmsLbrMc5ROIrJafjag,45
|
28
28
|
podflow/config/build_original.py,sha256=pG9gCkBBIWwU8QxZA06Br6JRfI4XUSIEiN8eqo1-v7k,1809
|
29
29
|
podflow/config/channge_icon.py,sha256=W-EU_5_wg94_yioNofk8OTyRD2X7SY8HEjvjFmSEyh0,5653
|
@@ -35,7 +35,7 @@ podflow/config/get_config.py,sha256=TpLbh5GoPO7csWUJ-di65XXnkN3LSnMXkFw85h5ndHs,
|
|
35
35
|
podflow/download/__init__.py,sha256=1lATXiOAEx5oDUDR99mQRiTrQlQ9CQkJNAKpsLrnPCo,47
|
36
36
|
podflow/download/convert_bytes.py,sha256=6Q3TcPGzCO2FlhOKWbp9RB_GPmfuyKY5suIyE9EJf6k,543
|
37
37
|
podflow/download/delete_part.py,sha256=wjY6WulpUMjLx38on0kTLXj0gA04rIuKAdwFidZtWGU,679
|
38
|
-
podflow/download/dl_aideo_video.py,sha256=
|
38
|
+
podflow/download/dl_aideo_video.py,sha256=lh-r_SKcR54oxsgS5f0wpgTUS50uOL4cNZQQwaWfxJw,10380
|
39
39
|
podflow/download/show_progress.py,sha256=w_nzq6LbewXpFwXENQwbA5-L-j3XDqzfQSMU7E_CWxs,1716
|
40
40
|
podflow/download/wait_animation.py,sha256=AUTvszXF89QA7XYjocFIauPKV7Qj8cFqry44teClaLQ,1314
|
41
41
|
podflow/download/youtube_and_bilibili_download.py,sha256=dlUh9cPHrYgZAhtXlBUOdFIpZOhv9xOtgdcTaqUvLuY,1294
|
@@ -44,43 +44,43 @@ podflow/httpfs/app_bottle.py,sha256=l2myMkoRoC5O7OWCyYjCmk7wOEIlgTWfFfImlhXMYwY,
|
|
44
44
|
podflow/httpfs/browser.py,sha256=BJ4Xkfiki_tDr0Sc9RqAcEfIVpkAZ3RFOwo0aMHlY3U,197
|
45
45
|
podflow/httpfs/get_channelid.py,sha256=gcwy4IVHBWNQz7qPCpjwiAklGFLRGzvM33-UZz7oFvo,2296
|
46
46
|
podflow/httpfs/port_judge.py,sha256=l_nLpsSiIhAzfJGCOWyYC-KkCCWPUW2ybe_5hdMOEzE,764
|
47
|
-
podflow/httpfs/to_html.py,sha256=
|
47
|
+
podflow/httpfs/to_html.py,sha256=pqNgHz3G4suTuFszULPkhKADKWc8ISlPJp7BxL2ntM4,1941
|
48
48
|
podflow/makeup/__init__.py,sha256=ligUtfj0stTcOHFXDF6eAN7Up2PxlB0GnGbLq7iDY3c,45
|
49
49
|
podflow/makeup/del_makeup_format_fail.py,sha256=XizQh74QYXxRg0e1uerXjd4Tiq5qChks0fTAY7n3Z1I,642
|
50
|
-
podflow/makeup/make_up_file.py,sha256=
|
50
|
+
podflow/makeup/make_up_file.py,sha256=_kpvlOpW1TX379aj83rw7U9fFRsHYkYBja1yUKw6oys,2938
|
51
51
|
podflow/makeup/make_up_file_format_mod.py,sha256=VlR4yG7N6C2laYIBKb7J6Alqq2_X5Y7kgXMQSN6lJ6E,3613
|
52
52
|
podflow/makeup/make_up_file_mod.py,sha256=padTanSPw5Dysf_CcUUVy65nCC6zbz1gPJRX98tmUdY,1075
|
53
53
|
podflow/message/__init__.py,sha256=pZkcrrtkdtxgMriEHBZ0_rptKaQrQeMPJvPSaoI1Awo,46
|
54
54
|
podflow/message/backup_zip_save.py,sha256=0SIxVvAtgSWAr_TvdXLVDIpxvXOHeFUN8n8QzfnIB84,1740
|
55
|
-
podflow/message/create_main_rss.py,sha256=
|
55
|
+
podflow/message/create_main_rss.py,sha256=yo12YYUxYTjGSHD5CrnRIbUZumtr0NOZqQWXpC3t55k,3296
|
56
56
|
podflow/message/display_qrcode_and_url.py,sha256=VqmRkDYYG03VihfW4SAU49HJVmfqWbLTgMxqCaREeCo,1037
|
57
|
-
podflow/message/fail_message_initialize.py,sha256=
|
57
|
+
podflow/message/fail_message_initialize.py,sha256=UPHYNErD2hnzm2WFlNqghBRDCw_sf_3EagAF5LiO9wk,6462
|
58
58
|
podflow/message/format_time.py,sha256=gveNh4FGeS3ytwDyYB-h12d1_Km6XoX7WSPcFmDfCBk,909
|
59
59
|
podflow/message/get_media_name.py,sha256=5ULPQOQCZ2-lxdkILwlBP-ItzdFEgvEAKxeLtplACbQ,861
|
60
60
|
podflow/message/get_original_rss.py,sha256=PYA7UGhHXbUN66vWmxWOp5Ns423CopHxw4vR19zXaPs,2383
|
61
|
-
podflow/message/get_video_format.py,sha256
|
62
|
-
podflow/message/get_video_format_multithread.py,sha256=
|
63
|
-
podflow/message/get_youtube_and_bilibili_video_format.py,sha256=
|
61
|
+
podflow/message/get_video_format.py,sha256=bPetnFwQlhIO9do_nq3B4AwHQRxFn6SDYvFItjwEx0o,5324
|
62
|
+
podflow/message/get_video_format_multithread.py,sha256=tbgQDMpcntulrbmXBbKL4iVr4t_9evGsuMOIZLoLebI,1615
|
63
|
+
podflow/message/get_youtube_and_bilibili_video_format.py,sha256=QvGkm2avYlUlvxfouw545Si72DtT4SAJwWw0zu6eq_U,4705
|
64
64
|
podflow/message/media_format.py,sha256=Q4WoML4UqL0Ry-QN8DHFJqOQ2tXcFN6u5hmhdSLdP1g,7346
|
65
65
|
podflow/message/original_rss_fail_print.py,sha256=7HM5Gwi3GqBIg2dtTTDlN_FRgZZjYv6ejizS3tDiePE,502
|
66
66
|
podflow/message/rss_create_hash.py,sha256=M5OS9KcQ4mIxLes9ij4oNji-4VKgi56bg0Shv5nCIQ4,638
|
67
67
|
podflow/message/save_rss.py,sha256=x-yRwT7bAUt2k-R9DWa5uToqpcOdaXkPW_4VH5Gbeo4,3193
|
68
68
|
podflow/message/title_correction.py,sha256=Zieulj2wQY_o4r3u5ZRsDQP5y8KuZHrL_l8tnM96k6g,915
|
69
69
|
podflow/message/update_information_display.py,sha256=Zn-Xhps4PKf7NbgQrT-qTwhP096RV-48OEncK_vuUe0,3061
|
70
|
-
podflow/message/update_youtube_bilibili_rss.py,sha256=
|
70
|
+
podflow/message/update_youtube_bilibili_rss.py,sha256=ZgR0ARCRNVRxSFP5LKaYWrNIQlYXCvQlDZBOMXYqzKo,5783
|
71
71
|
podflow/message/want_retry.py,sha256=3MtlAG4BZ2oznn0X5zYzAl2S0XzZkXhnN_LHVPcWZjA,699
|
72
72
|
podflow/message/xml_item.py,sha256=jCB93aOoIDK6EaAFrZg5gd6mBMv7fP9uX-Z5eiTSyxg,3127
|
73
73
|
podflow/message/xml_original_item.py,sha256=mlORI0p6aSLP6PWIAuvI4uVN0JbxUDZX5-U52ltn9E4,4048
|
74
74
|
podflow/message/xml_rss.py,sha256=ogCteSUXyJJXLhOE7-ZBcRdWYzrRr2Qykjt3oppRpC4,1679
|
75
75
|
podflow/netscape/__init__.py,sha256=SUw_BtbV3moA324UdxRECkPLv1xHkjio8r_5JTkVfxI,47
|
76
76
|
podflow/netscape/bulid_netscape.py,sha256=wmUPlDGF8G456GGyajU_6Ak5WJzsqsq4bZgPjCSTGhI,2279
|
77
|
-
podflow/netscape/get_cookie_dict.py,sha256=
|
77
|
+
podflow/netscape/get_cookie_dict.py,sha256=laqw-eriABiLyciRLzDmistVHHWqmUM-9eEbYZzsqBQ,643
|
78
78
|
podflow/remove/__init__.py,sha256=x1pMfpIyE6xUrmIOkdl43mbvKLwndGo5pIoOBXhJsP4,45
|
79
79
|
podflow/remove/remove_dir.py,sha256=xQIhrnqnYjMzXjoSWaTvm7JwPYOFTN1muuTPdaLDXpQ,1099
|
80
80
|
podflow/remove/remove_file.py,sha256=8wAJQehs-XBqvu0vPlEme2_tt0FZxc5ELwGMxXA_558,982
|
81
81
|
podflow/repair/__init__.py,sha256=Gpc1i6xiSLodKjjmzH66c_Y1z0HQ9E9CS3p95FRnVFM,45
|
82
82
|
podflow/repair/reverse_log.py,sha256=Wc_vAH0WB-z1fNdWx7FYaVH4caRPtot7tDwDwFhmpz4,1106
|
83
|
-
podflow/templates/index.html,sha256=
|
83
|
+
podflow/templates/index.html,sha256=i8T2wsvPQG6vP0qVN6LiGwC_0QF65IIWlz7MllVWO1Q,21558
|
84
84
|
podflow/upload/__init__.py,sha256=AtOSXDrE5EjUe3z-iBd1NTDaH8n_X9qA5WXdBLkONjA,45
|
85
85
|
podflow/upload/add_upload.py,sha256=_2-V0z75Lwu-PUCfMD9HOSxZTB102yZlZW5hSdlHcsc,1432
|
86
86
|
podflow/upload/build_hash.py,sha256=9opa3xLd7nJbGGX5xa3uuKPS6dxlbkAb87ZdEiUxmxI,473
|
@@ -95,8 +95,8 @@ podflow/youtube/__init__.py,sha256=pgXod8gq0IijZxIkPSwgAOcb9JI5rd1mqMomoR7bcJ4,4
|
|
95
95
|
podflow/youtube/build.py,sha256=3LYk_ICVXj9XkE9jZ8jEVI8596xxS_QZkcoIwcBE3Ys,12006
|
96
96
|
podflow/youtube/get.py,sha256=Of7PRgUknhpyW70nvyVAUYVb5KyFViKiBTfH3Y6Mke8,16970
|
97
97
|
podflow/youtube/login.py,sha256=KYl--ya6Z1u0uIcOp9l8i3DIIj9hsYUDH4dtJjI0MLM,1295
|
98
|
-
podflow-
|
99
|
-
podflow-
|
100
|
-
podflow-
|
101
|
-
podflow-
|
102
|
-
podflow-
|
98
|
+
podflow-20250413.dist-info/METADATA,sha256=Kqj23ZIOpy39Dpz4T9rT-8pymmXHOmVscSBj4wCbKy4,14163
|
99
|
+
podflow-20250413.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
100
|
+
podflow-20250413.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
|
101
|
+
podflow-20250413.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
|
102
|
+
podflow-20250413.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|