podflow 20250608__py3-none-any.whl → 20250629.1__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/basic/http_client.py +16 -5
- podflow/basic/random_sequence.py +10 -0
- podflow/download_and_build.py +1 -11
- podflow/httpfs/app_bottle.py +200 -96
- podflow/main.py +1 -1
- podflow/main_podcast.py +7 -55
- podflow/main_upload.py +6 -0
- podflow/message/fail_message_initialize.py +25 -0
- podflow/remove/remove_flush.py +50 -0
- podflow/run_and_upload.py +77 -0
- podflow/upload/add_upload.py +3 -0
- podflow/upload/upload_files.py +87 -33
- {podflow-20250608.dist-info → podflow-20250629.1.dist-info}/METADATA +2 -2
- {podflow-20250608.dist-info → podflow-20250629.1.dist-info}/RECORD +17 -14
- {podflow-20250608.dist-info → podflow-20250629.1.dist-info}/WHEEL +0 -0
- {podflow-20250608.dist-info → podflow-20250629.1.dist-info}/entry_points.txt +0 -0
- {podflow-20250608.dist-info → podflow-20250629.1.dist-info}/top_level.txt +0 -0
podflow/basic/http_client.py
CHANGED
@@ -17,6 +17,7 @@ def http_client(
|
|
17
17
|
data=None,
|
18
18
|
mode="get",
|
19
19
|
file=None,
|
20
|
+
mistake=False,
|
20
21
|
):
|
21
22
|
user_agent = {
|
22
23
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
|
@@ -41,7 +42,7 @@ def http_client(
|
|
41
42
|
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",
|
42
43
|
}
|
43
44
|
user_agent |= headers_douyin
|
44
|
-
err =
|
45
|
+
err = "" # 初始化 err 变量
|
45
46
|
response = None # 初始化 response 变量
|
46
47
|
# 创建一个Session对象
|
47
48
|
session = requests.Session()
|
@@ -64,16 +65,26 @@ def http_client(
|
|
64
65
|
response.raise_for_status()
|
65
66
|
except Exception as http_get_error:
|
66
67
|
if response is not None and response.status_code in {404}:
|
67
|
-
|
68
|
+
if mistake:
|
69
|
+
return response, err
|
70
|
+
else:
|
71
|
+
return response
|
68
72
|
if name:
|
69
73
|
time_print(f"{name}|\033[31m连接异常重试中...\033[97m{num + 1}\033[0m")
|
70
74
|
if err:
|
71
|
-
|
75
|
+
if err.split('\n')[-1] != str(http_get_error):
|
76
|
+
err = f"{err}\n{str(http_get_error)}"
|
72
77
|
else:
|
73
78
|
err = f":\n{str(http_get_error)}"
|
74
79
|
else:
|
75
|
-
|
80
|
+
if mistake:
|
81
|
+
return response, err
|
82
|
+
else:
|
83
|
+
return response
|
76
84
|
time.sleep(retry_delay)
|
77
85
|
if name:
|
78
86
|
time_print(f"{name}|\033[31m达到最大重试次数\033[97m{max_retries}\033[0m{err}")
|
79
|
-
|
87
|
+
if mistake:
|
88
|
+
return response, err
|
89
|
+
else:
|
90
|
+
return response
|
podflow/download_and_build.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
import threading
|
5
5
|
from podflow import gVar
|
6
|
-
from podflow.upload.upload_files import all_upload
|
7
6
|
from podflow.youtube.build import get_youtube_introduction
|
8
7
|
from podflow.message.create_main_rss import create_main_rss
|
9
8
|
from podflow.download.youtube_and_bilibili_download import youtube_and_bilibili_download
|
@@ -16,21 +15,12 @@ def get_and_duild():
|
|
16
15
|
|
17
16
|
|
18
17
|
# 下载并构建YouTube和哔哩哔哩视频模块
|
19
|
-
def download_and_build(
|
18
|
+
def download_and_build():
|
20
19
|
thread_download = threading.Thread(target=youtube_and_bilibili_download)
|
21
20
|
thread_build = threading.Thread(target=get_and_duild)
|
22
|
-
if upload_url:
|
23
|
-
thread_upload = threading.Thread(
|
24
|
-
target=all_upload,
|
25
|
-
args=(upload_url,)
|
26
|
-
)
|
27
21
|
|
28
22
|
thread_download.start()
|
29
23
|
thread_build.start()
|
30
|
-
if upload_url:
|
31
|
-
thread_upload.start()
|
32
24
|
|
33
25
|
thread_download.join()
|
34
26
|
thread_build.join()
|
35
|
-
if upload_url:
|
36
|
-
thread_upload.join()
|
podflow/httpfs/app_bottle.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
4
|
import os
|
5
|
+
import re
|
5
6
|
import json
|
6
7
|
import time
|
7
8
|
import hashlib
|
@@ -19,6 +20,7 @@ from podflow.upload.build_hash import build_hash
|
|
19
20
|
from podflow.upload.time_key import check_time_key
|
20
21
|
from podflow.basic.folder_build import folder_build
|
21
22
|
from podflow.httpfs.get_channelid import get_channelid
|
23
|
+
from podflow.basic.random_sequence import random_sequence
|
22
24
|
|
23
25
|
|
24
26
|
class bottle_app:
|
@@ -30,6 +32,7 @@ class bottle_app:
|
|
30
32
|
self.logname = "httpfs.log" # 默认日志文件名
|
31
33
|
self.http_fs = False
|
32
34
|
self._last_message_state = {} # 用于 SSE,跟踪消息状态
|
35
|
+
self.random_list = random_sequence(64)
|
33
36
|
|
34
37
|
def setup_routes(self, upload=False):
|
35
38
|
# 设置/favicon.ico路由,回调函数为favicon
|
@@ -42,6 +45,7 @@ class bottle_app:
|
|
42
45
|
self.app_bottle.route("/newuser", callback=self.new_user)
|
43
46
|
self.app_bottle.route("/login", callback=self.login)
|
44
47
|
self.app_bottle.route("/upload", method="POST", callback=self.upload)
|
48
|
+
self.app_bottle.route("/flush", method="POST", callback=self.clear_cache)
|
45
49
|
else:
|
46
50
|
self.app_bottle.route("/index", callback=self.index)
|
47
51
|
self.app_bottle.route("/getid", method="POST", callback=self.getid)
|
@@ -88,7 +92,7 @@ class bottle_app:
|
|
88
92
|
206: "\033[36m", # 青色 (部分内容)
|
89
93
|
}
|
90
94
|
# 默认颜色
|
91
|
-
if status:
|
95
|
+
if status in status_colors:
|
92
96
|
color = status_colors.get(status, "\033[0m")
|
93
97
|
status = f"{color}{status}\033[0m"
|
94
98
|
now_time = datetime.now().strftime("%H:%M:%S")
|
@@ -316,90 +320,161 @@ class bottle_app:
|
|
316
320
|
def upload(self):
|
317
321
|
# 初始化 upload_file 为 None,以便在 finally 块中安全检查
|
318
322
|
upload_file = None
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
323
|
+
# 获取上传数据配置(存储用户名和密码)
|
324
|
+
upload_data = gVar.upload_data
|
325
|
+
# 从请求参数中获取用户名,默认为空字符串
|
326
|
+
username = request.query.get("username", "")
|
327
|
+
# 从请求参数中获取密码,默认为空字符串
|
328
|
+
password = request.query.get("password", "")
|
329
|
+
upload_hash = request.query.get("hash", "")
|
330
|
+
channelid = request.query.get("channel_id", "")
|
331
|
+
check = request.query.get("check", "")
|
332
|
+
filename = request.query.get("filename", "")
|
333
|
+
if username not in upload_data:
|
334
|
+
self.print_out("login", 401)
|
335
|
+
return {
|
336
|
+
"code": -2,
|
337
|
+
"message": "Username Error", # 用户名错误
|
338
|
+
}
|
339
|
+
# 验证密码是否正确
|
340
|
+
if upload_data[username] != password:
|
341
|
+
self.print_out("login", 401)
|
342
|
+
return {
|
343
|
+
"code": -3,
|
344
|
+
"message": "Password Error", # 密码错误
|
345
|
+
}
|
346
|
+
if not re.match(r"^[0-9a-fA-F]{64}$", upload_hash):
|
347
|
+
self.print_out("upload", 404)
|
348
|
+
return {
|
349
|
+
"code": -8,
|
350
|
+
"message": "Invalid Hash Format", # 哈希值格式不正确
|
351
|
+
}
|
352
|
+
if not channelid:
|
353
|
+
# 打印错误信息并返回错误码
|
354
|
+
self.print_out("upload", 404)
|
355
|
+
return {
|
356
|
+
"code": -6,
|
357
|
+
"message": "ChannelId Does Not Exist", # 频道ID不存在
|
358
|
+
}
|
359
|
+
address = f"channel_audiovisual/{channelid}"
|
360
|
+
file_list = os.listdir(address) if os.path.exists(address) else []
|
361
|
+
# 安全地分割文件名和后缀
|
362
|
+
parts = filename.rsplit(".", 1)
|
363
|
+
name = parts[0]
|
364
|
+
suffix = parts[1].lower() if len(parts) > 1 else "" # 转换为小写以便比较
|
365
|
+
if suffix not in ["mp4", "m4a"]:
|
366
|
+
self.print_out("upload", 404)
|
367
|
+
return {
|
368
|
+
"code": -7,
|
369
|
+
"message": "File Name Error", # 文件格式错误
|
370
|
+
}
|
371
|
+
create_check = ""
|
372
|
+
for ref in self.random_list:
|
373
|
+
create_check += upload_hash[ref]
|
374
|
+
if check:
|
375
|
+
if check != create_check:
|
369
376
|
self.print_out("upload", 404)
|
370
377
|
return {
|
371
|
-
"code": -
|
372
|
-
"message": "
|
378
|
+
"code": -9,
|
379
|
+
"message": "Check Error", # 检查错误
|
373
380
|
}
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
381
|
+
try:
|
382
|
+
# 从请求中获取上传的文件对象
|
383
|
+
upload_file = request.files.get("file")
|
384
|
+
# 检查是否有文件被上传
|
385
|
+
if not upload_file:
|
386
|
+
# 打印错误信息并返回错误码
|
387
|
+
self.print_out("upload", 404)
|
388
|
+
return {
|
389
|
+
"code": -4,
|
390
|
+
"message": "No File Provided", # 没有上传文件
|
391
|
+
}
|
392
|
+
# 获取实际的文件句柄
|
393
|
+
uploadfile_obj = upload_file.file
|
394
|
+
# 判断文件是否完整
|
395
|
+
uploadfile_obj.seek(0) # 确保从文件开头计算哈希
|
396
|
+
uploadfile_hash = build_hash(uploadfile_obj)
|
397
|
+
if upload_hash != uploadfile_hash:
|
398
|
+
self.print_out("upload", 401)
|
399
|
+
return {
|
400
|
+
"code": -5,
|
401
|
+
"message": "Incomplete File", # 文件不完整
|
402
|
+
"hash": uploadfile_hash,
|
403
|
+
}
|
404
|
+
num = 0
|
405
|
+
while True:
|
406
|
+
# 构建当前尝试的文件名
|
407
|
+
current_filename = (
|
408
|
+
f"{name}.{suffix}" if num == 0 else f"{name}.{num}.{suffix}"
|
409
|
+
)
|
410
|
+
full_target_path = os.path.join(
|
411
|
+
os.getcwd(), address, current_filename
|
412
|
+
) # 完整的保存路径
|
413
|
+
if current_filename in file_list:
|
414
|
+
# 如果文件名已存在,检查是否是相同文件
|
415
|
+
# 再次检查文件是否存在于磁盘,以防在列表检查后文件被删除
|
416
|
+
if os.path.exists(full_target_path):
|
417
|
+
with open(full_target_path, "rb") as original_file:
|
418
|
+
original_file.seek(0)
|
419
|
+
if upload_hash == build_hash(original_file):
|
420
|
+
self.print_out("upload same", 200)
|
421
|
+
return {
|
422
|
+
"code": 1,
|
423
|
+
"message": "The Same File Exists", # 相同文件已存在
|
424
|
+
"data": {
|
425
|
+
"filename": current_filename,
|
426
|
+
},
|
427
|
+
}
|
428
|
+
num += 1 # 如果哈希不同,尝试下一个文件名
|
429
|
+
else:
|
430
|
+
# 文件名不存在,可以保存
|
431
|
+
folder_build(
|
432
|
+
channelid, "channel_audiovisual"
|
433
|
+
) # 确保目标文件夹存在
|
434
|
+
uploadfile_obj.seek(0) # 再次重置文件指针到开头,准备写入
|
435
|
+
file_save(
|
436
|
+
uploadfile_obj, current_filename, address, True
|
437
|
+
) # 传递文件对象
|
438
|
+
# 打印成功信息并返回成功码
|
439
|
+
self.print_out("upload", 200)
|
440
|
+
return {
|
441
|
+
"code": 0,
|
442
|
+
"message": "Upload Success", # 上传成功
|
443
|
+
"data": {
|
444
|
+
"filename": current_filename,
|
445
|
+
},
|
446
|
+
}
|
447
|
+
except Exception as e:
|
448
|
+
# 捕获所有其他可能的异常
|
449
|
+
self.print_out("upload", 500)
|
383
450
|
return {
|
384
|
-
"code": -
|
385
|
-
"message": "
|
451
|
+
"code": -9,
|
452
|
+
"message": f"Server Error: {str(e)}", # 将异常信息返回给客户端
|
386
453
|
}
|
387
|
-
|
388
|
-
|
454
|
+
finally:
|
455
|
+
# 无论函数如何退出(正常返回或抛出异常),都会执行此块
|
456
|
+
if (
|
457
|
+
upload_file
|
458
|
+
and hasattr(upload_file, "file")
|
459
|
+
and not upload_file.file.closed
|
460
|
+
):
|
461
|
+
upload_file.file.close()
|
462
|
+
else:
|
389
463
|
num = 0
|
390
464
|
while True:
|
391
465
|
# 构建当前尝试的文件名
|
392
|
-
current_filename =
|
393
|
-
|
394
|
-
|
466
|
+
current_filename = (
|
467
|
+
f"{name}.{suffix}" if num == 0 else f"{name}.{num}.{suffix}"
|
468
|
+
)
|
469
|
+
full_target_path = os.path.join(
|
470
|
+
os.getcwd(), address, current_filename
|
471
|
+
) # 完整的保存路径
|
395
472
|
if current_filename in file_list:
|
396
|
-
# 如果文件名已存在,检查是否是相同文件
|
397
|
-
# 再次检查文件是否存在于磁盘,以防在列表检查后文件被删除
|
398
473
|
if os.path.exists(full_target_path):
|
399
474
|
with open(full_target_path, "rb") as original_file:
|
400
475
|
original_file.seek(0)
|
401
476
|
if upload_hash == build_hash(original_file):
|
402
|
-
self.print_out("upload", 200)
|
477
|
+
self.print_out("upload same", 200)
|
403
478
|
return {
|
404
479
|
"code": 1,
|
405
480
|
"message": "The Same File Exists", # 相同文件已存在
|
@@ -407,34 +482,65 @@ class bottle_app:
|
|
407
482
|
"filename": current_filename,
|
408
483
|
},
|
409
484
|
}
|
410
|
-
num += 1
|
485
|
+
num += 1 # 如果哈希不同,尝试下一个文件名
|
411
486
|
else:
|
412
|
-
|
413
|
-
folder_build(channelid, "channel_audiovisual") # 确保目标文件夹存在
|
414
|
-
uploadfile_obj.seek(0) # 再次重置文件指针到开头,准备写入
|
415
|
-
file_save(uploadfile_obj, current_filename, address, True) # 传递文件对象
|
416
|
-
# 打印成功信息并返回成功码
|
417
|
-
self.print_out("upload", 200)
|
487
|
+
self.print_out("advance upload", 200)
|
418
488
|
return {
|
419
|
-
"code":
|
420
|
-
"message": "
|
489
|
+
"code": 2,
|
490
|
+
"message": "Can Be Uploaded", # 可以上传
|
421
491
|
"data": {
|
422
492
|
"filename": current_filename,
|
493
|
+
"check": create_check, # 返回创建的检查值
|
423
494
|
},
|
424
495
|
}
|
425
|
-
|
426
|
-
|
427
|
-
|
496
|
+
|
497
|
+
# 路由处理清除缓存请求
|
498
|
+
def clear_cache(self):
|
499
|
+
# 获取上传数据配置(存储用户名和密码)
|
500
|
+
upload_data = gVar.upload_data
|
501
|
+
# 从请求参数中获取用户名,默认为空字符串
|
502
|
+
username = request.query.get("username", "")
|
503
|
+
# 从请求参数中获取密码,默认为空字符串
|
504
|
+
password = request.query.get("password", "")
|
505
|
+
if username not in upload_data:
|
506
|
+
self.print_out("login", 401)
|
428
507
|
return {
|
429
|
-
"code": -
|
430
|
-
"message":
|
508
|
+
"code": -2,
|
509
|
+
"message": "Username Error", # 用户名错误
|
510
|
+
}
|
511
|
+
# 验证密码是否正确
|
512
|
+
if upload_data[username] != password:
|
513
|
+
self.print_out("login", 401)
|
514
|
+
return {
|
515
|
+
"code": -3,
|
516
|
+
"message": "Password Error", # 密码错误
|
517
|
+
}
|
518
|
+
if os.path.exists("tmp"):
|
519
|
+
# 清除 tmp 目录下的所有文件
|
520
|
+
for filename in os.listdir("tmp"):
|
521
|
+
file_path = os.path.join("tmp", filename)
|
522
|
+
try:
|
523
|
+
os.remove(file_path) # 删除文件
|
524
|
+
except Exception as e:
|
525
|
+
self.print_out("flush", 500)
|
526
|
+
return {
|
527
|
+
"code": -11,
|
528
|
+
"message": "Error removing flush", # 删除文件错误
|
529
|
+
"error": str(e),
|
530
|
+
}
|
531
|
+
self.print_out("flush", 200)
|
532
|
+
return {
|
533
|
+
"code": 3,
|
534
|
+
"message": "Cache Cleared Successfully", # 缓存清除成功
|
535
|
+
}
|
536
|
+
else:
|
537
|
+
self.print_out("flush", 404)
|
538
|
+
return {
|
539
|
+
"code": -10,
|
540
|
+
"message": "Cache Does Not Exist", # 频道ID不存在
|
431
541
|
}
|
432
|
-
finally:
|
433
|
-
# 无论函数如何退出(正常返回或抛出异常),都会执行此块
|
434
|
-
if upload_file and hasattr(upload_file, 'file') and not upload_file.file.closed:
|
435
|
-
upload_file.file.close()
|
436
|
-
|
437
542
|
|
543
|
+
# 路由处理模板文件请求
|
438
544
|
def serve_template_file(self, filepath):
|
439
545
|
template_dir = pkg_resources.resource_filename("podflow", "templates")
|
440
546
|
return static_file(filepath, root=template_dir)
|
@@ -451,16 +557,14 @@ class bottle_app:
|
|
451
557
|
|
452
558
|
# 获取 JSON 数据,Bottle 会自动解析请求体中的 JSON 数据
|
453
559
|
def getid(self):
|
454
|
-
if getid_data := request.json
|
455
|
-
content = getid_data.get("content", "")
|
456
|
-
else:
|
457
|
-
content = ""
|
560
|
+
content = getid_data.get("content", "") if (getid_data := request.json) else ""
|
458
561
|
response_message = get_channelid(content)
|
459
562
|
self.print_out("channelid", 200)
|
460
563
|
# 设置响应头为 application/json
|
461
564
|
response.content_type = "application/json"
|
462
565
|
return {"response": response_message}
|
463
|
-
|
566
|
+
|
567
|
+
# 获取配置数据
|
464
568
|
def getconfig(self):
|
465
569
|
self.print_out("getconfig", 200)
|
466
570
|
# 设置响应头为 application/json
|
podflow/main.py
CHANGED
podflow/main_podcast.py
CHANGED
@@ -22,24 +22,18 @@ from podflow.httpfs.app_bottle import bottle_app_instance
|
|
22
22
|
|
23
23
|
# 下载和视频处理模块
|
24
24
|
from podflow.ffmpeg_judge import ffmpeg_judge
|
25
|
-
from podflow.
|
26
|
-
from podflow.download_and_build import download_and_build
|
25
|
+
from podflow.run_and_upload import run_and_upload
|
27
26
|
|
28
27
|
# RSS 和消息处理模块
|
29
28
|
from podflow.message.save_rss import save_rss
|
30
29
|
from podflow.message.get_original_rss import get_original_rss
|
31
|
-
from podflow.message.get_video_format import get_video_format
|
32
|
-
from podflow.message.optimize_download import optimize_download
|
33
30
|
from podflow.message.original_rss_fail_print import original_rss_fail_print
|
34
|
-
from podflow.message.update_information_display import update_information_display
|
35
|
-
from podflow.message.update_youtube_bilibili_rss import update_youtube_bilibili_rss
|
36
31
|
|
37
32
|
# 登录模块
|
38
33
|
from podflow.bilibili.login import get_bilibili_data
|
39
34
|
from podflow.youtube.login import get_youtube_cookie
|
40
35
|
|
41
36
|
# 配置和图标模块
|
42
|
-
from podflow.config.channge_icon import channge_icon
|
43
37
|
from podflow.config.build_original import build_original
|
44
38
|
|
45
39
|
# 制作和修改文件模块
|
@@ -51,6 +45,7 @@ from podflow.makeup.make_up_file_format_mod import make_up_file_format_mod
|
|
51
45
|
# 移除模块
|
52
46
|
from podflow.remove.remove_dir import remove_dir
|
53
47
|
from podflow.remove.remove_file import remove_file
|
48
|
+
from podflow.remove.remove_flush import remove_flush
|
54
49
|
|
55
50
|
# 处理 YouTube 信息模块
|
56
51
|
from podflow.youtube.build import print_fail_youtube
|
@@ -139,59 +134,13 @@ def main_podcast():
|
|
139
134
|
bottle_app_instance.cherry_print()
|
140
135
|
# 登陆上传服务器
|
141
136
|
if upload_url:
|
142
|
-
upload_json = login_upload(upload_url)
|
143
|
-
if upload_json:
|
144
|
-
gVar.upload_json = upload_json
|
145
|
-
else:
|
146
|
-
gVar.config["upload"] = False
|
147
|
-
else:
|
148
|
-
gVar.config["upload"] = False
|
137
|
+
gVar.upload_json = login_upload(upload_url)
|
149
138
|
progress_update(0.035, num=0.0024)
|
150
139
|
# 初始化原始上传信息
|
151
140
|
get_upload_original()
|
152
141
|
progress_update(0.04)
|
153
|
-
|
154
|
-
update_youtube_bilibili_rss()
|
155
|
-
progress_update(0.1)
|
156
|
-
# 判断是否有更新内容
|
157
|
-
if gVar.channelid_youtube_ids_update or gVar.channelid_bilibili_ids_update:
|
158
|
-
gVar.update_generate_rss = True
|
142
|
+
run_and_upload(upload_url)
|
159
143
|
if gVar.update_generate_rss:
|
160
|
-
# 根据日出日落修改封面(只适用原封面)
|
161
|
-
channge_icon()
|
162
|
-
progress_update(0.11, num=0.0049)
|
163
|
-
# 输出需要更新的信息
|
164
|
-
update_information_display(
|
165
|
-
gVar.channelid_youtube_ids_update,
|
166
|
-
gVar.youtube_content_ytid_update,
|
167
|
-
gVar.youtube_content_ytid_backward_update,
|
168
|
-
"YouTube",
|
169
|
-
)
|
170
|
-
update_information_display(
|
171
|
-
gVar.channelid_bilibili_ids_update,
|
172
|
-
gVar.bilibili_content_bvid_update,
|
173
|
-
gVar.bilibili_content_bvid_backward_update,
|
174
|
-
"BiliBili",
|
175
|
-
)
|
176
|
-
progress_update(0.12)
|
177
|
-
# 暂停进程打印
|
178
|
-
gVar.server_process_print_flag[0] = "pause"
|
179
|
-
# 获取视频格式信息
|
180
|
-
get_video_format()
|
181
|
-
progress_update(0.199)
|
182
|
-
# 恢复进程打印
|
183
|
-
bottle_app_instance.cherry_print()
|
184
|
-
# 优化下载顺序
|
185
|
-
optimize_download()
|
186
|
-
# 删除中断下载的媒体文件
|
187
|
-
if gVar.config["delete_incompletement"]:
|
188
|
-
delete_part(gVar.channelid_youtube_ids | gVar.channelid_bilibili_ids)
|
189
|
-
progress_update(0.20, refresh=2)
|
190
|
-
# 暂停进程打印
|
191
|
-
gVar.server_process_print_flag[0] = "pause"
|
192
|
-
# 下载并构建YouTube和哔哩哔哩视频
|
193
|
-
download_and_build(upload_url)
|
194
|
-
progress_update(0.8)
|
195
144
|
# 添加新媒体至上传列表
|
196
145
|
add_upload()
|
197
146
|
progress_update(0.81, num=0.0049)
|
@@ -243,6 +192,8 @@ def main_podcast():
|
|
243
192
|
# 更新并保存上传列表
|
244
193
|
update_upload()
|
245
194
|
progress_update(1, refresh=3)
|
195
|
+
# 清理缓存文件
|
196
|
+
remove_flush(upload_url)
|
246
197
|
else:
|
247
198
|
time_print("频道无更新内容")
|
248
199
|
# 清空变量内数据
|
@@ -267,6 +218,7 @@ def main_podcast():
|
|
267
218
|
gVar.overall_rss = "" # 更新后的rss文本
|
268
219
|
gVar.make_up_file_format.clear() # 补全缺失媒体字典
|
269
220
|
gVar.make_up_file_format_fail.clear() # 补全缺失媒体失败字典
|
221
|
+
gVar.upload_original.clear() # 原始上传信息字典
|
270
222
|
# 将需要更新转为否
|
271
223
|
gVar.update_generate_rss = False
|
272
224
|
if parse.update_num != -1:
|
podflow/main_upload.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# podflow/main_upload.py
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
+
import os
|
4
5
|
import sys
|
5
6
|
import cherrypy
|
6
7
|
from podflow.upload.login import get_login
|
@@ -15,6 +16,11 @@ def main_upload():
|
|
15
16
|
folder_build("channel_audiovisual")
|
16
17
|
# 构建文件夹channel_data
|
17
18
|
folder_build("channel_data")
|
19
|
+
# 在程序启动时设置 TMPDIR 环境变量
|
20
|
+
new_tmp_dir = os.path.join(os.getcwd(), "tmp")
|
21
|
+
os.makedirs(new_tmp_dir, exist_ok=True) # 确保目录存在
|
22
|
+
os.environ['TMPDIR'] = new_tmp_dir
|
23
|
+
time_print(f"临时文件目录已设置为: {os.environ['TMPDIR']}")
|
18
24
|
# 获取账号密码
|
19
25
|
get_login()
|
20
26
|
# 服务发现相关配置
|
@@ -139,6 +139,11 @@ error_reason = [
|
|
139
139
|
"\033[31m响应超时\033[0m",
|
140
140
|
"regexp",
|
141
141
|
],
|
142
|
+
[
|
143
|
+
r"Got error: HTTPSConnectionPool\(host='rr[0-9]---sn-.{8}\.googlevideo.com', port=443\): Read timed out\.",
|
144
|
+
"\033[31m响应超时\033[0m",
|
145
|
+
"regexp",
|
146
|
+
],
|
142
147
|
[
|
143
148
|
r"Requested format is not available. Use --list-formats for a list of available formats",
|
144
149
|
"\033[31m格式不可用\033[0m",
|
@@ -154,6 +159,26 @@ error_reason = [
|
|
154
159
|
"\033[31m无法解析\033[0m",
|
155
160
|
"regexp",
|
156
161
|
],
|
162
|
+
[
|
163
|
+
r"An extractor error has occurred. (caused by KeyError('bvid')); please report this issue on https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using yt-dlp -U",
|
164
|
+
"\033[31m提取错误\033[0m",
|
165
|
+
"text",
|
166
|
+
],
|
167
|
+
[
|
168
|
+
r"Unable to download JSON metadata: HTTP Error 504: Gateway Time-out (caused by <HTTPError 504: Gateway Time-out>)",
|
169
|
+
"\033[31m网关超时\033[0m",
|
170
|
+
"text",
|
171
|
+
],
|
172
|
+
[
|
173
|
+
r"Got error: HTTPSConnectionPool\(host='.+\.mcdn\.bilivideo\.cn', port=8082\): Read timed out\. \(read timeout=20\.0\)",
|
174
|
+
"\033[31m响应超时\033[0m",
|
175
|
+
"regexp",
|
176
|
+
],
|
177
|
+
[
|
178
|
+
r"Got error: \<urllib3\.connection\.HTTPSConnection object at .{18}\>: Failed to establish a new connection: \[WinError 10061\] 由于目标计算机积极拒绝,无法连接。"
|
179
|
+
"\033[31m链接拒绝\033[0m",
|
180
|
+
"regexp",
|
181
|
+
],
|
157
182
|
]
|
158
183
|
|
159
184
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# podflow/remove/remove_flush.py
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
from podflow import gVar
|
5
|
+
from podflow.basic.http_client import http_client
|
6
|
+
from podflow.httpfs.app_bottle import bottle_app_instance
|
7
|
+
|
8
|
+
# 缓存文件清理模块
|
9
|
+
def remove_flush(upload_url):
|
10
|
+
if gVar.upload_json:
|
11
|
+
result = {
|
12
|
+
3: "缓存文件清理成功",
|
13
|
+
-2: "用户名错误",
|
14
|
+
-3: "密码错误",
|
15
|
+
-10: "缓存文件不存在",
|
16
|
+
-11: "缓存文件删除失败"
|
17
|
+
}
|
18
|
+
username = gVar.upload_json["username"]
|
19
|
+
password = gVar.upload_json["password"]
|
20
|
+
data = {
|
21
|
+
"username": username,
|
22
|
+
"password": password,
|
23
|
+
}
|
24
|
+
response, err = http_client(
|
25
|
+
url=f"{upload_url}/flush",
|
26
|
+
name="",
|
27
|
+
max_retries=3,
|
28
|
+
data=data,
|
29
|
+
mode="post",
|
30
|
+
mistake=True,
|
31
|
+
)
|
32
|
+
if response:
|
33
|
+
response = response.json()
|
34
|
+
code = response.get("code")
|
35
|
+
data = response.get("data", {})
|
36
|
+
message = response.get("message", "")
|
37
|
+
if code == 3:
|
38
|
+
bottle_text = "\033[32m缓存文件清理成功\033[0m"
|
39
|
+
elif code == -11:
|
40
|
+
error_message = response.get("error", "")
|
41
|
+
if error_message:
|
42
|
+
bottle_text = f"\033[31m缓存文件清理失败\033[0m: {error_message}"
|
43
|
+
else:
|
44
|
+
bottle_text = "\033[31m缓存文件清理失败\033[0m"
|
45
|
+
else:
|
46
|
+
bottle_text = f"\033[31m缓存文件清理失败\033[0m: {result.get(code, message)}"
|
47
|
+
else:
|
48
|
+
bottle_text = f"\033[31m缓存文件清理失败\033[0m: 网络连接失败{err}"
|
49
|
+
bottle_app_instance.add_bottle_print(upload_url, "flush", bottle_text)
|
50
|
+
bottle_app_instance.cherry_print(False)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# podflow/run_and_upload.py
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
import threading
|
5
|
+
from podflow import gVar
|
6
|
+
from podflow.upload.upload_files import all_upload
|
7
|
+
from podflow.config.channge_icon import channge_icon
|
8
|
+
from podflow.download.delete_part import delete_part
|
9
|
+
from podflow.httpfs.progress_bar import progress_update
|
10
|
+
from podflow.download_and_build import download_and_build
|
11
|
+
from podflow.httpfs.app_bottle import bottle_app_instance
|
12
|
+
from podflow.message.get_video_format import get_video_format
|
13
|
+
from podflow.message.optimize_download import optimize_download
|
14
|
+
from podflow.message.update_information_display import update_information_display
|
15
|
+
from podflow.message.update_youtube_bilibili_rss import update_youtube_bilibili_rss
|
16
|
+
|
17
|
+
|
18
|
+
def find_and_duild():
|
19
|
+
# 更新Youtube和哔哩哔哩频道xml
|
20
|
+
update_youtube_bilibili_rss()
|
21
|
+
progress_update(0.1)
|
22
|
+
# 判断是否有更新内容
|
23
|
+
if gVar.channelid_youtube_ids_update or gVar.channelid_bilibili_ids_update:
|
24
|
+
gVar.update_generate_rss = True
|
25
|
+
if gVar.update_generate_rss:
|
26
|
+
# 根据日出日落修改封面(只适用原封面)
|
27
|
+
channge_icon()
|
28
|
+
progress_update(0.11, num=0.0049)
|
29
|
+
# 输出需要更新的信息
|
30
|
+
update_information_display(
|
31
|
+
gVar.channelid_youtube_ids_update,
|
32
|
+
gVar.youtube_content_ytid_update,
|
33
|
+
gVar.youtube_content_ytid_backward_update,
|
34
|
+
"YouTube",
|
35
|
+
)
|
36
|
+
update_information_display(
|
37
|
+
gVar.channelid_bilibili_ids_update,
|
38
|
+
gVar.bilibili_content_bvid_update,
|
39
|
+
gVar.bilibili_content_bvid_backward_update,
|
40
|
+
"BiliBili",
|
41
|
+
)
|
42
|
+
progress_update(0.12)
|
43
|
+
# 暂停进程打印
|
44
|
+
gVar.server_process_print_flag[0] = "pause"
|
45
|
+
# 获取视频格式信息
|
46
|
+
get_video_format()
|
47
|
+
progress_update(0.199)
|
48
|
+
# 恢复进程打印
|
49
|
+
bottle_app_instance.cherry_print()
|
50
|
+
# 优化下载顺序
|
51
|
+
optimize_download()
|
52
|
+
# 删除中断下载的媒体文件
|
53
|
+
if gVar.config["delete_incompletement"]:
|
54
|
+
delete_part(gVar.channelid_youtube_ids | gVar.channelid_bilibili_ids)
|
55
|
+
progress_update(0.20, refresh=2)
|
56
|
+
# 暂停进程打印
|
57
|
+
gVar.server_process_print_flag[0] = "pause"
|
58
|
+
# 下载并构建YouTube和哔哩哔哩视频
|
59
|
+
download_and_build()
|
60
|
+
progress_update(0.8)
|
61
|
+
|
62
|
+
# 运行并上传模块
|
63
|
+
def run_and_upload(upload_url):
|
64
|
+
if upload_url:
|
65
|
+
thread_find_and_duild = threading.Thread(target=find_and_duild)
|
66
|
+
thread_upload = threading.Thread(
|
67
|
+
target=all_upload,
|
68
|
+
args=(upload_url,)
|
69
|
+
)
|
70
|
+
|
71
|
+
thread_find_and_duild.start()
|
72
|
+
thread_upload.start()
|
73
|
+
|
74
|
+
thread_find_and_duild.join()
|
75
|
+
thread_upload.join()
|
76
|
+
else:
|
77
|
+
find_and_duild()
|
podflow/upload/add_upload.py
CHANGED
@@ -7,6 +7,9 @@ from podflow import gVar
|
|
7
7
|
|
8
8
|
# 添加新媒体至上传列表模块
|
9
9
|
def add_upload():
|
10
|
+
# 如果没有开启上传功能,则直接返回
|
11
|
+
if not gVar.config["upload"]:
|
12
|
+
return
|
10
13
|
# 获取video_id_update_format和video_id_failed的值
|
11
14
|
video_id_update_format = gVar.video_id_update_format
|
12
15
|
video_id_failed = gVar.video_id_failed
|
podflow/upload/upload_files.py
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
# podflow/upload/upload_files.py
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
from datetime import datetime
|
5
4
|
from podflow import gVar
|
6
|
-
from podflow.httpfs.to_html import ansi_to_html
|
7
5
|
from podflow.upload.build_hash import build_hash
|
8
6
|
from podflow.basic.http_client import http_client
|
9
7
|
from podflow.httpfs.app_bottle import bottle_app_instance
|
10
8
|
|
11
9
|
|
12
10
|
# 上传文件模块
|
13
|
-
def upload_file(
|
14
|
-
|
15
|
-
|
11
|
+
def upload_file(
|
12
|
+
upload_url,
|
13
|
+
username,
|
14
|
+
password,
|
15
|
+
channelid,
|
16
|
+
filename,
|
17
|
+
upload_filename=False,
|
18
|
+
check=""
|
19
|
+
):
|
20
|
+
address = f"channel_audiovisual/{channelid}/{filename}"
|
21
|
+
with open(address, "rb") as file:
|
16
22
|
file.seek(0)
|
17
23
|
hashs = build_hash(file)
|
18
24
|
file.seek(0)
|
@@ -21,18 +27,30 @@ def upload_file(upload_url, username, password, channelid, filename):
|
|
21
27
|
"password": password,
|
22
28
|
"channel_id": channelid,
|
23
29
|
"hash": hashs,
|
30
|
+
"filename": filename,
|
24
31
|
}
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
if upload_filename:
|
33
|
+
data["check"] = check
|
34
|
+
response, err = http_client(
|
35
|
+
url=f"{upload_url}/upload",
|
36
|
+
name="",
|
37
|
+
max_retries=3,
|
38
|
+
data=data,
|
39
|
+
mode="post",
|
40
|
+
file=file,
|
41
|
+
mistake=True,
|
42
|
+
)
|
33
43
|
else:
|
34
|
-
|
35
|
-
|
44
|
+
response, err = http_client(
|
45
|
+
url=f"{upload_url}/upload",
|
46
|
+
name="",
|
47
|
+
max_retries=3,
|
48
|
+
data=data,
|
49
|
+
mode="post",
|
50
|
+
mistake=True,
|
51
|
+
)
|
52
|
+
return (response.json(), hashs, "") if response else (None, hashs, err)
|
53
|
+
return None, hashs, ""
|
36
54
|
|
37
55
|
|
38
56
|
# 查找位置模块
|
@@ -62,13 +80,12 @@ def filter_and_sort_media(media_list):
|
|
62
80
|
|
63
81
|
# 媒体文件上传模块
|
64
82
|
def record_upload(upload_url, username, password, channelid, filename):
|
65
|
-
response, hashs = upload_file(upload_url, username, password, channelid, filename)
|
66
83
|
channelname = (
|
67
84
|
gVar.channelid_youtube_ids_original | gVar.channelid_bilibili_ids_original
|
68
85
|
).get(channelid, "")
|
69
|
-
now_time = datetime.now().strftime("%H:%M:%S")
|
70
86
|
result = {
|
71
87
|
0: "",
|
88
|
+
2: "可以上传",
|
72
89
|
1: "存在相同文件",
|
73
90
|
-2: "用户名错误",
|
74
91
|
-3: "密码错误",
|
@@ -76,36 +93,73 @@ def record_upload(upload_url, username, password, channelid, filename):
|
|
76
93
|
-5: "文件不完整",
|
77
94
|
-6: "频道ID不存在",
|
78
95
|
-7: "文件格式有误",
|
96
|
+
-8: "哈希值格式错",
|
79
97
|
}
|
98
|
+
ahead_response, hashs, ahead_err = upload_file(
|
99
|
+
upload_url,
|
100
|
+
username,
|
101
|
+
password,
|
102
|
+
channelid,
|
103
|
+
filename,
|
104
|
+
)
|
80
105
|
name = filename.split(".")[0]
|
81
|
-
if
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
if
|
106
|
+
if ahead_response:
|
107
|
+
ahead_code = ahead_response.get("code")
|
108
|
+
ahead_data = ahead_response.get("data", {})
|
109
|
+
ahead_message = ahead_response.get("message", "")
|
110
|
+
if ahead_code == 2:
|
111
|
+
ahead_bottle_text = "\033[33m上传校验成功\033[0m"
|
112
|
+
elif ahead_code == 1:
|
86
113
|
index = find_media_index(gVar.upload_original, filename)
|
87
114
|
if index != -1:
|
88
|
-
if filename :=
|
115
|
+
if filename := ahead_data.get("filename"):
|
89
116
|
gVar.upload_original[index]["upload"] = True
|
90
117
|
gVar.upload_original[index]["hash"] = hashs
|
91
118
|
gVar.upload_original[index]["filename"] = filename
|
92
|
-
|
93
|
-
bottle_text = "\033[32m上传成功\033[0m"
|
94
|
-
elif code == 1:
|
95
|
-
bottle_text = f"\033[33m上传成功\033[0m: {result.get(code, message)}"
|
119
|
+
ahead_bottle_text = f"\033[33m上传校成功\033[0m: {result.get(ahead_code, ahead_message)}"
|
96
120
|
else:
|
97
|
-
|
121
|
+
ahead_bottle_text = f"\033[31m上传校验失败\033[0m: {result.get(ahead_code, ahead_message)}"
|
98
122
|
else:
|
99
|
-
|
100
|
-
|
101
|
-
bottle_app_instance.
|
102
|
-
gVar.index_message["http"].append(ansi_to_html(bottle_text))
|
123
|
+
ahead_data = {}
|
124
|
+
ahead_bottle_text = f"\033[31m上传校验失败\033[0m: 网络连接失败{ahead_err}"
|
125
|
+
bottle_app_instance.add_bottle_print(channelname, name, ahead_bottle_text)
|
103
126
|
bottle_app_instance.cherry_print(False)
|
127
|
+
if ahead_code == 2:
|
128
|
+
response, hashs, err = upload_file(
|
129
|
+
upload_url,
|
130
|
+
username,
|
131
|
+
password,
|
132
|
+
channelid,
|
133
|
+
filename,
|
134
|
+
True,
|
135
|
+
ahead_data.get("check","")
|
136
|
+
)
|
137
|
+
if response:
|
138
|
+
code = response.get("code")
|
139
|
+
data = response.get("data", {})
|
140
|
+
message = response.get("message", "")
|
141
|
+
if code in [0, 1]:
|
142
|
+
index = find_media_index(gVar.upload_original, filename)
|
143
|
+
if index != -1:
|
144
|
+
if filename := data.get("filename"):
|
145
|
+
gVar.upload_original[index]["upload"] = True
|
146
|
+
gVar.upload_original[index]["hash"] = hashs
|
147
|
+
gVar.upload_original[index]["filename"] = filename
|
148
|
+
if code == 0:
|
149
|
+
bottle_text = "\033[32m上传成功\033[0m"
|
150
|
+
elif code == 1:
|
151
|
+
bottle_text = f"\033[33m上传成功\033[0m: {result.get(code, message)}"
|
152
|
+
else:
|
153
|
+
bottle_text = f"\033[31m上传失败\033[0m: {result.get(code, message)}"
|
154
|
+
else:
|
155
|
+
bottle_text = f"\033[31m上传失败\033[0m: 网络连接失败{err}"
|
156
|
+
bottle_app_instance.add_bottle_print(channelname, name, bottle_text)
|
157
|
+
bottle_app_instance.cherry_print(False)
|
104
158
|
|
105
159
|
|
106
160
|
# 总体上传模块
|
107
161
|
def all_upload(upload_url):
|
108
|
-
if gVar.
|
162
|
+
if gVar.upload_json:
|
109
163
|
result = filter_and_sort_media(gVar.upload_original)
|
110
164
|
username = gVar.upload_json["username"]
|
111
165
|
password = gVar.upload_json["password"]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: podflow
|
3
|
-
Version:
|
3
|
+
Version: 20250629.1
|
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.
|
17
|
+
Requires-Dist: yt-dlp>=2025.6.25
|
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,19 +1,21 @@
|
|
1
1
|
podflow/__init__.py,sha256=mquu8BdWK9V4dDObCCfnPodeXOPkz-kj8_RNB7kK3Ys,7628
|
2
|
-
podflow/download_and_build.py,sha256=
|
2
|
+
podflow/download_and_build.py,sha256=x7S7N26B1G9Yn2yr7YthDJgKUwEKBLtHBLlaqpofLas,746
|
3
3
|
podflow/ffmpeg_judge.py,sha256=wM49pPXOFwFAA_8TKHal5fV6ka9sAA87yGQMDOssvXo,1340
|
4
|
-
podflow/main.py,sha256=
|
5
|
-
podflow/main_podcast.py,sha256=
|
6
|
-
podflow/main_upload.py,sha256=
|
4
|
+
podflow/main.py,sha256=7zWdpw80jqPaYu1Un1nPqaZoiAb7Dqg8zaF-cUioU4c,755
|
5
|
+
podflow/main_podcast.py,sha256=vV4knnqzHehFjCBFRtAzq8K0xlnkWNGV320tSYDQ09o,10248
|
6
|
+
podflow/main_upload.py,sha256=xuN15GAXokl2xzZrraLeusevl0j-TnHVziL0wobsBZc,2586
|
7
7
|
podflow/parse_arguments.py,sha256=h3a7EaRZS04kNMFYbxTW9Ch29KgZ7dyS-yqEEt_etQI,2592
|
8
|
+
podflow/run_and_upload.py,sha256=EtkQtmiqZh8pqXQfQnn6hfjk0T-1wmc0YUFhTOqPRPw,2799
|
8
9
|
podflow/basic/__init__.py,sha256=CAfI6mVQtz7KKbAiTIZ9_IbvaTXeAqxR1U7ov9GDoDo,44
|
9
10
|
podflow/basic/file_save.py,sha256=6vu4EkbsN4df5-ci6sJOgIOUEhh-WaRBOyMJ8rpouXo,1233
|
10
11
|
podflow/basic/folder_build.py,sha256=5oHyfiDcSp2YITXQWIPwriBF9XuU3qs7wZQOWJHYJ1s,546
|
11
12
|
podflow/basic/get_duration.py,sha256=eqdE85b7sgLyp6brhnGcOIQEWX6JqtNCGAsGyJOuXFI,532
|
12
13
|
podflow/basic/get_file_list.py,sha256=XmnC4faObislyTsL9WUeyztyTQrvdi76lMzPudKEfXw,2389
|
13
14
|
podflow/basic/get_html_dict.py,sha256=V-PgDtD6pm5mZC1LUPttUbZzxhjkS3WDYHxWR3yzIEY,869
|
14
|
-
podflow/basic/http_client.py,sha256=
|
15
|
+
podflow/basic/http_client.py,sha256=1kh0FBbPSoUtWooYdNZMLZd_V1aBo19L79nEkfTwb6E,3184
|
15
16
|
podflow/basic/list_merge_tidy.py,sha256=7hWfSnsPh23edHNU92vxtI0nfpfN8m54GTEt2rGm2HQ,368
|
16
17
|
podflow/basic/qr_code.py,sha256=lZo11jbYqFQYy9gjBtRRUoLjlaEmoES-phydnrOMcLo,1727
|
18
|
+
podflow/basic/random_sequence.py,sha256=5VuXg7EfC8g8RpDouPfxDdgec3oaSruy8tXZMG68P3s,255
|
17
19
|
podflow/basic/split_dict.py,sha256=Ir6GTortcWMUeFITFgY1v-INMla5y0IN3RN3nTgzWqM,401
|
18
20
|
podflow/basic/time_format.py,sha256=T3tw2vbOwxMYYXDaV4Sj76WOZtsspj2lWA_DzWqUEJA,487
|
19
21
|
podflow/basic/time_print.py,sha256=foPezlEnYU0tOb8h79nDXZNElgNjRsHScYHYk9hGeTM,1481
|
@@ -40,7 +42,7 @@ podflow/download/show_progress.py,sha256=y46chchUC9eZCg4ZdNMFnx_bXJQV_IUq15jVzZt
|
|
40
42
|
podflow/download/wait_animation.py,sha256=AUTvszXF89QA7XYjocFIauPKV7Qj8cFqry44teClaLQ,1314
|
41
43
|
podflow/download/youtube_and_bilibili_download.py,sha256=VCEhz6pGXFWXusdbGWqkCzi4f4VsKQVn6sZz1pfGsns,1335
|
42
44
|
podflow/httpfs/__init__.py,sha256=BxEXkufjcx-a0F7sDVXo65hmyANqCCbZUd6EH9i8T2c,45
|
43
|
-
podflow/httpfs/app_bottle.py,sha256=
|
45
|
+
podflow/httpfs/app_bottle.py,sha256=f0bPGGVGSMabIaURmWeXwRT9k_rG3-akq6V6Ql9zrWU,27978
|
44
46
|
podflow/httpfs/browser.py,sha256=BJ4Xkfiki_tDr0Sc9RqAcEfIVpkAZ3RFOwo0aMHlY3U,197
|
45
47
|
podflow/httpfs/download_bar.py,sha256=0n3HATEO3pdsIpx-E_IZG9OlXa6u-9SeBCoZVgUutyc,965
|
46
48
|
podflow/httpfs/get_channelid.py,sha256=gcwy4IVHBWNQz7qPCpjwiAklGFLRGzvM33-UZz7oFvo,2296
|
@@ -56,7 +58,7 @@ podflow/message/__init__.py,sha256=pZkcrrtkdtxgMriEHBZ0_rptKaQrQeMPJvPSaoI1Awo,4
|
|
56
58
|
podflow/message/backup_zip_save.py,sha256=c81jnx8IxHjTcO7G0OUAppawpBIPxa9wgkj9AQhqeJc,1864
|
57
59
|
podflow/message/create_main_rss.py,sha256=kW2QvJhxl2ZcqGV-M-OztlOaQ27ODuQxADeP8poymBQ,3118
|
58
60
|
podflow/message/display_qrcode_and_url.py,sha256=VqmRkDYYG03VihfW4SAU49HJVmfqWbLTgMxqCaREeCo,1037
|
59
|
-
podflow/message/fail_message_initialize.py,sha256=
|
61
|
+
podflow/message/fail_message_initialize.py,sha256=0Itu-7bJfdPI3D508TN4Tr5MgDA_Z4ZxmPyubXrkNEQ,7864
|
60
62
|
podflow/message/format_time.py,sha256=gveNh4FGeS3ytwDyYB-h12d1_Km6XoX7WSPcFmDfCBk,909
|
61
63
|
podflow/message/get_media_name.py,sha256=5ULPQOQCZ2-lxdkILwlBP-ItzdFEgvEAKxeLtplACbQ,861
|
62
64
|
podflow/message/get_original_rss.py,sha256=Bzy-Fs1vZEjwvQq6D6xp-2IUidliSyaL1P4WtkLJaRg,2450
|
@@ -81,6 +83,7 @@ podflow/netscape/get_cookie_dict.py,sha256=laqw-eriABiLyciRLzDmistVHHWqmUM-9eEbY
|
|
81
83
|
podflow/remove/__init__.py,sha256=x1pMfpIyE6xUrmIOkdl43mbvKLwndGo5pIoOBXhJsP4,45
|
82
84
|
podflow/remove/remove_dir.py,sha256=zqgf47UgxiGiLipb1FeoWKzrSHSxcHaEuu0261bqR1s,1105
|
83
85
|
podflow/remove/remove_file.py,sha256=ZusvZsBQX_yRdLuboD7bZKiOX4z4Rxg66zZK9KDWHwE,1006
|
86
|
+
podflow/remove/remove_flush.py,sha256=HWCe5SjNJ3VXaXbgFtqGdTXeJ1R2vv5qllNilB-G0_g,1851
|
84
87
|
podflow/repair/__init__.py,sha256=Gpc1i6xiSLodKjjmzH66c_Y1z0HQ9E9CS3p95FRnVFM,45
|
85
88
|
podflow/repair/reverse_log.py,sha256=Wc_vAH0WB-z1fNdWx7FYaVH4caRPtot7tDwDwFhmpz4,1106
|
86
89
|
podflow/templates/index.html,sha256=kGsp1TAcf_qkV6hYRE8Ueq7CaTflR73rsTWtjnWuwwY,2775
|
@@ -90,7 +93,7 @@ podflow/templates/js/config.js,sha256=VZmpvtQWszofoccjJZNhbjvNkpl-CjGOdTrPkI83ND
|
|
90
93
|
podflow/templates/js/index.js,sha256=GUfFhZM3vjiwfJ7USQZIIv5c7cyZwt64QZt0VInq5TI,34051
|
91
94
|
podflow/templates/js/qrcode.min.js,sha256=xUHvBjJ4hahBW8qN9gceFBibSFUzbe9PNttUvehITzY,19927
|
92
95
|
podflow/upload/__init__.py,sha256=AtOSXDrE5EjUe3z-iBd1NTDaH8n_X9qA5WXdBLkONjA,45
|
93
|
-
podflow/upload/add_upload.py,sha256=
|
96
|
+
podflow/upload/add_upload.py,sha256=LloIucGJSXARhxiWerAbJVW-FpTkTUxvYCAKPbl93Ew,1536
|
94
97
|
podflow/upload/build_hash.py,sha256=9opa3xLd7nJbGGX5xa3uuKPS6dxlbkAb87ZdEiUxmxI,473
|
95
98
|
podflow/upload/get_upload_original.py,sha256=TEDnRutumm2FZNIesPJIlExHyKWpfB3ZAHb3sZt7V6A,4312
|
96
99
|
podflow/upload/linked_client.py,sha256=NdSi5uh0TbZUhOHbA_mkHo4aIz1XNKoSXHhT4rMRUpc,5288
|
@@ -98,14 +101,14 @@ podflow/upload/linked_server.py,sha256=h-qSx13fP8_Ny2IKW3wCNPwqRqW6-Iz1pqxD9ga9-
|
|
98
101
|
podflow/upload/login.py,sha256=85sqr12T-3NH-TD3kAMzy4yb1KOheV3Tr0eGee7NCJo,4007
|
99
102
|
podflow/upload/time_key.py,sha256=6jZ3cxUjzj_umYDwH27R0YNZlLXxfhNp-CqV_K22wlo,967
|
100
103
|
podflow/upload/update_upload.py,sha256=_5tp1zPNsC9DdDnLzm-P8bLcOBuDov4eMRHp_861j80,3183
|
101
|
-
podflow/upload/upload_files.py,sha256=
|
104
|
+
podflow/upload/upload_files.py,sha256=zKMv27cqj7u-c8dHKNZx67UNx0gkMkQAnu2oxnk6a5M,5749
|
102
105
|
podflow/upload/upload_server.py,sha256=BFq3QrWE7U97LbC4EQiDhQXbLapEc4R00eRDBH12E6A,565
|
103
106
|
podflow/youtube/__init__.py,sha256=pgXod8gq0IijZxIkPSwgAOcb9JI5rd1mqMomoR7bcJ4,46
|
104
107
|
podflow/youtube/build.py,sha256=j6SVq3HFFGlNNqRrHfnBIThdzsH88PFmwLnejosif1U,12311
|
105
108
|
podflow/youtube/get.py,sha256=oO32GjTFvUgP5AfFX5AlIuXU2UT6QtOUOXWLFzi8XtI,17157
|
106
109
|
podflow/youtube/login.py,sha256=KYl--ya6Z1u0uIcOp9l8i3DIIj9hsYUDH4dtJjI0MLM,1295
|
107
|
-
podflow-
|
108
|
-
podflow-
|
109
|
-
podflow-
|
110
|
-
podflow-
|
111
|
-
podflow-
|
110
|
+
podflow-20250629.1.dist-info/METADATA,sha256=d_skuEp5UWtZo7psoKOfx5716KfNPrnHneH8zO2HdKo,14197
|
111
|
+
podflow-20250629.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
112
|
+
podflow-20250629.1.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
|
113
|
+
podflow-20250629.1.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
|
114
|
+
podflow-20250629.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|