podflow 20250608__py3-none-any.whl → 20250629__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.
@@ -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 = None # 初始化 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
- return response
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
- err = f"{err}\n{str(http_get_error)}"
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
- return response
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
- return response
87
+ if mistake:
88
+ return response, err
89
+ else:
90
+ return response
@@ -0,0 +1,10 @@
1
+ # podflow/basic/random_sequence.py
2
+ # coding: utf-8
3
+
4
+ import random
5
+
6
+
7
+ def random_sequence(n):
8
+ arr = list(range(n)) # 生成0到n-1的列表
9
+ random.shuffle(arr) # 原地随机打乱列表顺序
10
+ return arr # 返回打乱后的列表
@@ -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(upload_url):
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()
@@ -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
- try:
320
- # 获取上传数据配置(存储用户名和密码)
321
- upload_data = gVar.upload_data
322
- # 从请求参数中获取用户名,默认为空字符串
323
- username = request.query.get("username", "")
324
- # 从请求参数中获取密码,默认为空字符串
325
- password = request.query.get("password", "")
326
- upload_hash = request.query.get("hash", "")
327
- channelid = request.query.get("channel_id", "")
328
-
329
- # 验证用户是否存在
330
- if username not in upload_data:
331
- self.print_out("login", 401)
332
- return {
333
- "code": -2,
334
- "message": "Username Error", # 用户名错误
335
- }
336
- # 验证密码是否正确
337
- if upload_data[username] != password:
338
- self.print_out("login", 401)
339
- return {
340
- "code": -3,
341
- "message": "Password Error", # 密码错误
342
- }
343
- # 从请求中获取上传的文件对象
344
- upload_file = request.files.get("file")
345
- # 检查是否有文件被上传
346
- if not upload_file:
347
- # 打印错误信息并返回错误码
348
- self.print_out("upload", 404)
349
- return {
350
- "code": -4,
351
- "message": "No File Provided", # 没有上传文件
352
- }
353
-
354
- # 获取实际的文件句柄
355
- uploadfile_obj = upload_file.file
356
-
357
- # 判断文件是否完整
358
- uploadfile_obj.seek(0) # 确保从文件开头计算哈希
359
- uploadfile_hash = build_hash(uploadfile_obj)
360
- if upload_hash != uploadfile_hash:
361
- self.print_out("upload", 401)
362
- return {
363
- "code": -5,
364
- "message": "Incomplete File", # 文件不完整
365
- "hash": uploadfile_hash,
366
- }
367
- if not channelid:
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": -6,
372
- "message": "ChannelId Does Not Exist", # 频道ID不存在
378
+ "code": -9,
379
+ "message": "Check Error", # 检查错误
373
380
  }
374
- # 获取上传文件的原始文件名
375
- filename = upload_file.filename
376
- # 安全地分割文件名和后缀
377
- parts = filename.rsplit(".", 1)
378
- name = parts[0]
379
- suffix = parts[1].lower() if len(parts) > 1 else "" # 转换为小写以便比较
380
-
381
- if suffix not in ["mp4", "m4a"]:
382
- self.print_out("upload", 404)
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": -7,
385
- "message": "File Format Error", # 文件格式错误
451
+ "code": -9,
452
+ "message": f"Server Error: {str(e)}", # 将异常信息返回给客户端
386
453
  }
387
- address = f"channel_audiovisual/{channelid}"
388
- file_list = os.listdir(address) if os.path.exists(address) else []
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 = f"{name}.{suffix}" if num == 0 else f"{name}.{num}.{suffix}"
393
- full_target_path = os.path.join(os.getcwd(), address, current_filename) # 完整的保存路径
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": 0,
420
- "message": "Upload Success", # 上传成功
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
- except Exception as e:
426
- # 捕获所有其他可能的异常
427
- self.print_out("upload", 500)
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": -99,
430
- "message": f"Server Error: {str(e)}", # 将异常信息返回给客户端
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
@@ -14,7 +14,7 @@ def main():
14
14
  parse_arguments()
15
15
  # 开始运行
16
16
  if parse.upload:
17
- time_print("Podflow|{version('Podflow')} 接收开始运行...")
17
+ time_print(f"Podflow|{version('Podflow')} 接收开始运行...")
18
18
  reverse_log("upload")
19
19
  main_upload()
20
20
  else:
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.download.delete_part import delete_part
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
- # 更新Youtube和哔哩哔哩频道xml
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
+ thread_find_and_duild = threading.Thread(target=find_and_duild)
65
+ if upload_url:
66
+ thread_upload = threading.Thread(
67
+ target=all_upload,
68
+ args=(upload_url,)
69
+ )
70
+
71
+ thread_find_and_duild.start()
72
+ if upload_url:
73
+ thread_upload.start()
74
+
75
+ thread_find_and_duild.join()
76
+ if upload_url:
77
+ thread_upload.join()
@@ -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
@@ -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(upload_url, username, password, channelid, filename):
14
- filename = f"channel_audiovisual/{channelid}/{filename}"
15
- with open(filename, "rb") as file:
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 response := http_client(
26
- url=f"{upload_url}/upload",
27
- name="",
28
- data=data,
29
- mode="post",
30
- file=file,
31
- ):
32
- return response.json(), hashs
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
- return None, hashs
35
- return None, hashs
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 response:
82
- code = response.get("code")
83
- data = response.get("data", {})
84
- message = response.get("message", "")
85
- if code in [0, 1]:
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 := data.get("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
- if code == 0:
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
- bottle_text = f"\033[31m上传失败\033[0m: {result.get(code, message)}"
121
+ ahead_bottle_text = f"\033[31m上传校验失败\033[0m: {result.get(ahead_code, ahead_message)}"
98
122
  else:
99
- bottle_text = "\033[31m上传失败\033[0m: 网络连接失败"
100
- bottle_text = f"{now_time}|{channelname}/{name}|{bottle_text}"
101
- bottle_app_instance.bottle_print.append(bottle_text)
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.config["upload"]:
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: 20250608
3
+ Version: 20250629
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.5.22
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=vwyVs6MMLgbWZjGCFnPcj08dGxplgmU7u9CAP_ujJ8g,1037
2
+ podflow/download_and_build.py,sha256=x7S7N26B1G9Yn2yr7YthDJgKUwEKBLtHBLlaqpofLas,746
3
3
  podflow/ffmpeg_judge.py,sha256=wM49pPXOFwFAA_8TKHal5fV6ka9sAA87yGQMDOssvXo,1340
4
- podflow/main.py,sha256=6cUgu8niM6LryBXCppQv0Nj4I2ye2bwoVrTF5vYmVFw,754
5
- podflow/main_podcast.py,sha256=J63BSzj044Q8YaErSoV-zE2kYrqhPqS6-TqZCEG-VOA,12396
6
- podflow/main_upload.py,sha256=H_T5KQMYzToqzQbjGQ6DWDGziy8iMnpmf7A1qOStJuo,2296
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=GYyrwurtb0ln7VkZLwxF3HlLjDlPSpZuRbcLO859LL4,2790
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=lSDfWYF5nZ6LPEXyNjUVudPFTo1fcaPauFjIuq68JR4,2863
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=8KHi_MxHK1HMCiWb8CqnkEWxMGAu3FVS5KRA2sPGbC8,23338
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=OlkPQUU2qgTJ-wcFhyGiTAeoY0qy_eOOQGkA0PtyxHQ,6711
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=_2-V0z75Lwu-PUCfMD9HOSxZTB102yZlZW5hSdlHcsc,1432
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=sy4GOIWpHPPiqoZzrMXQVzRCNT2QwEWwsraUj3CCRwY,3891
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-20250608.dist-info/METADATA,sha256=p_3SBZZLCDjvgy6iy3n8rRdD_glGFTLxzodyVGdIX-A,14195
108
- podflow-20250608.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
109
- podflow-20250608.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
110
- podflow-20250608.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
111
- podflow-20250608.dist-info/RECORD,,
110
+ podflow-20250629.dist-info/METADATA,sha256=HuCtP5vuE3A32KzkqIzEFC3e1-8-o_GNTGmeF-2Hm_o,14195
111
+ podflow-20250629.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
112
+ podflow-20250629.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
113
+ podflow-20250629.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
114
+ podflow-20250629.dist-info/RECORD,,