podflow 20250606__py3-none-any.whl → 20250608__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.
@@ -15,8 +15,13 @@ def file_save(content, file_name, folder=None, binary=False):
15
15
  file_path = os.path.join(os.getcwd(), file_name)
16
16
  # 保存文件
17
17
  if binary:
18
- with open(file_path, "wb") as file:
19
- file.write(content.read())
18
+ # 使用分块读取和写入的方式处理二进制文件
19
+ with open(file_path, "wb") as dest_file:
20
+ while True:
21
+ chunk = content.read(8192) # 每次读取 8KB 的数据
22
+ if not chunk:
23
+ break # 读取完毕
24
+ dest_file.write(chunk)
20
25
  else:
21
26
  with open(file_path, "w", encoding="utf-8") as file:
22
27
  # 如果文件名中包含"."且文件类型为json,则将内容以json格式保存
@@ -16,15 +16,21 @@ def get_and_duild():
16
16
 
17
17
 
18
18
  # 下载并构建YouTube和哔哩哔哩视频模块
19
- def download_and_build():
19
+ def download_and_build(upload_url):
20
20
  thread_download = threading.Thread(target=youtube_and_bilibili_download)
21
21
  thread_build = threading.Thread(target=get_and_duild)
22
- thread_upload = threading.Thread(target=all_upload)
22
+ if upload_url:
23
+ thread_upload = threading.Thread(
24
+ target=all_upload,
25
+ args=(upload_url,)
26
+ )
23
27
 
24
28
  thread_download.start()
25
29
  thread_build.start()
26
- thread_upload.start()
30
+ if upload_url:
31
+ thread_upload.start()
27
32
 
28
33
  thread_download.join()
29
34
  thread_build.join()
30
- thread_upload.join()
35
+ if upload_url:
36
+ thread_upload.join()
@@ -314,102 +314,126 @@ class bottle_app:
314
314
 
315
315
  # 文件上传处理请求
316
316
  def upload(self):
317
- # 获取上传数据配置(存储用户名和密码)
318
- upload_data = gVar.upload_data
319
- # 从请求参数中获取用户名,默认为空字符串
320
- username = request.query.get("username", "")
321
- # 从请求参数中获取密码,默认为空字符串
322
- password = request.query.get("password", "")
323
- upload_hash = request.query.get("hash", "")
324
- channelid = request.query.get("channel_id", "")
325
-
326
- # 验证用户是否存在
327
- if username not in upload_data:
328
- self.print_out("login", 401)
329
- return {
330
- "code": -2,
331
- "message": "Username Error", # 用户名错误
332
- }
333
- # 验证密码是否正确
334
- if upload_data[username] != password:
335
- self.print_out("login", 401)
336
- return {
337
- "code": -3,
338
- "message": "Password Error", # 密码错误
339
- }
340
- # 从请求中获取上传的文件对象
341
- upload_file = request.files.get("file")
342
- # 检查是否有文件被上传
343
- if not upload_file:
344
- # 打印错误信息并返回错误码
345
- self.print_out("upload", 404)
346
- return {
347
- "code": -4,
348
- "message": "No File Provided", # 没有上传文件
349
- }
350
- # 判断文件是否完整
351
- uploadfile = upload_file.file
352
- uploadfile.seek(0)
353
- uploadfile_hash = build_hash(uploadfile)
354
- if upload_hash != uploadfile_hash:
355
- self.print_out("upload", 401)
356
- return {
357
- "code": -5,
358
- "message": "Incomplete File", # 文件不完整
359
- "hash": uploadfile_hash,
360
- }
361
- if not channelid:
362
- # 打印错误信息并返回错误码
363
- self.print_out("upload", 404)
364
- return {
365
- "code": -6,
366
- "message": "ChannelId Does Not Exist", # 频道ID不存在
367
- }
368
- # 获取上传文件的原始文件名
369
- filename = upload_file.filename
370
- name = filename.split(".")[0]
371
- suffix = filename.split(".")[1]
372
- if suffix not in ["mp4", "m4a"]:
373
- self.print_out("upload", 404)
374
- return {
375
- "code": -7,
376
- "message": "File Format Error", # 文件格式错误
377
- }
378
- address = f"channel_audiovisual/{channelid}"
379
- if os.path.exists(address):
380
- file_list = os.listdir(address)
381
- else:
382
- file_list = []
383
- num = 0
384
- while True:
385
- if num != 0:
386
- filename = f"{name}.{num}.{suffix}"
387
- if filename in file_list:
388
- with open(f"{address}/{filename}", "rb") as original_file:
389
- original_file.seek(0)
390
- if upload_hash == build_hash(original_file):
391
- self.print_out("upload", 200)
392
- return {
393
- "code": 1,
394
- "message": "The Same File Exists", # 相同文件已存在
395
- "data": {
396
- "filename": filename,
397
- },
398
- }
399
- num += 1
400
- else:
401
- folder_build(channelid, "channel_audiovisual")
402
- uploadfile.seek(0)
403
- file_save(uploadfile, filename, address, True)
404
- # 打印成功信息并返回成功码
405
- self.print_out("upload", 200)
317
+ # 初始化 upload_file 为 None,以便在 finally 块中安全检查
318
+ 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)
406
332
  return {
407
- "code": 0,
408
- "message": "Upload Success", # 上传成功
409
- "data": {
410
- "filename": filename,
411
- },
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,
412
366
  }
367
+ if not channelid:
368
+ # 打印错误信息并返回错误码
369
+ self.print_out("upload", 404)
370
+ return {
371
+ "code": -6,
372
+ "message": "ChannelId Does Not Exist", # 频道ID不存在
373
+ }
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)
383
+ return {
384
+ "code": -7,
385
+ "message": "File Format Error", # 文件格式错误
386
+ }
387
+ address = f"channel_audiovisual/{channelid}"
388
+ file_list = os.listdir(address) if os.path.exists(address) else []
389
+ num = 0
390
+ while True:
391
+ # 构建当前尝试的文件名
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
+
395
+ if current_filename in file_list:
396
+ # 如果文件名已存在,检查是否是相同文件
397
+ # 再次检查文件是否存在于磁盘,以防在列表检查后文件被删除
398
+ if os.path.exists(full_target_path):
399
+ with open(full_target_path, "rb") as original_file:
400
+ original_file.seek(0)
401
+ if upload_hash == build_hash(original_file):
402
+ self.print_out("upload", 200)
403
+ return {
404
+ "code": 1,
405
+ "message": "The Same File Exists", # 相同文件已存在
406
+ "data": {
407
+ "filename": current_filename,
408
+ },
409
+ }
410
+ num += 1 # 如果哈希不同,尝试下一个文件名
411
+ 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)
418
+ return {
419
+ "code": 0,
420
+ "message": "Upload Success", # 上传成功
421
+ "data": {
422
+ "filename": current_filename,
423
+ },
424
+ }
425
+ except Exception as e:
426
+ # 捕获所有其他可能的异常
427
+ self.print_out("upload", 500)
428
+ return {
429
+ "code": -99,
430
+ "message": f"Server Error: {str(e)}", # 将异常信息返回给客户端
431
+ }
432
+ finally:
433
+ # 无论函数如何退出(正常返回或抛出异常),都会执行此块
434
+ if upload_file and hasattr(upload_file, 'file') and not upload_file.file.closed:
435
+ upload_file.file.close()
436
+
413
437
 
414
438
  def serve_template_file(self, filepath):
415
439
  template_dir = pkg_resources.resource_filename("podflow", "templates")
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|接收服务开始运行...")
17
+ time_print("Podflow|{version('Podflow')} 接收开始运行...")
18
18
  reverse_log("upload")
19
19
  main_upload()
20
20
  else:
podflow/main_podcast.py CHANGED
@@ -190,7 +190,7 @@ def main_podcast():
190
190
  # 暂停进程打印
191
191
  gVar.server_process_print_flag[0] = "pause"
192
192
  # 下载并构建YouTube和哔哩哔哩视频
193
- download_and_build()
193
+ download_and_build(upload_url)
194
194
  progress_update(0.8)
195
195
  # 添加新媒体至上传列表
196
196
  add_upload()
@@ -16,7 +16,7 @@ def remove_dir():
16
16
  if os.path.exists(directory_path):
17
17
  # 删除该目录及其内容
18
18
  shutil.rmtree(directory_path)
19
- write_log(f"{name}文件夹已删除")
19
+ write_log(f"{name}抛弃文件夹已删除")
20
20
 
21
21
  folder_names = [
22
22
  folder
@@ -14,11 +14,11 @@ def remove_file():
14
14
  for file_name in os.listdir(f"channel_audiovisual/{output_dir}"):
15
15
  if file_name not in gVar.all_youtube_content_ytid[output_dir]:
16
16
  os.remove(f"channel_audiovisual/{output_dir}/{file_name}")
17
- write_log(f"{name}|{file_name}已删除")
17
+ write_log(f"{name}|{file_name}抛弃文件已删除")
18
18
 
19
19
  channelid_bilibili_ids = gVar.channelid_bilibili_ids
20
20
  for output_dir, name in channelid_bilibili_ids.items():
21
21
  for file_name in os.listdir(f"channel_audiovisual/{output_dir}"):
22
22
  if file_name not in gVar.all_bilibili_content_bvid[output_dir]:
23
23
  os.remove(f"channel_audiovisual/{output_dir}/{file_name}")
24
- write_log(f"{name}|{file_name}已删除")
24
+ write_log(f"{name}|{file_name}抛弃文件已删除")
@@ -10,7 +10,7 @@ from podflow.httpfs.app_bottle import bottle_app_instance
10
10
 
11
11
 
12
12
  # 上传文件模块
13
- def upload_file(username, password, channelid, filename):
13
+ def upload_file(upload_url, username, password, channelid, filename):
14
14
  filename = f"channel_audiovisual/{channelid}/{filename}"
15
15
  with open(filename, "rb") as file:
16
16
  file.seek(0)
@@ -23,7 +23,7 @@ def upload_file(username, password, channelid, filename):
23
23
  "hash": hashs,
24
24
  }
25
25
  if response := http_client(
26
- url="http://10.0.3.231:5000/upload",
26
+ url=f"{upload_url}/upload",
27
27
  name="",
28
28
  data=data,
29
29
  mode="post",
@@ -54,16 +54,15 @@ def filter_and_sort_media(media_list):
54
54
  ),
55
55
  key=lambda x: x["media_time"],
56
56
  )
57
- result = [
57
+ return [
58
58
  {"media_id": item["media_id"], "channel_id": item["channel_id"]}
59
59
  for item in filtered_sorted
60
60
  ]
61
- return result
62
61
 
63
62
 
64
63
  # 媒体文件上传模块
65
- def record_upload(username, password, channelid, filename):
66
- response, hashs = upload_file(username, password, channelid, filename)
64
+ def record_upload(upload_url, username, password, channelid, filename):
65
+ response, hashs = upload_file(upload_url, username, password, channelid, filename)
67
66
  channelname = (
68
67
  gVar.channelid_youtube_ids_original | gVar.channelid_bilibili_ids_original
69
68
  ).get(channelid, "")
@@ -86,29 +85,31 @@ def record_upload(username, password, channelid, filename):
86
85
  if code in [0, 1]:
87
86
  index = find_media_index(gVar.upload_original, filename)
88
87
  if index != -1:
89
- filename = data.get("filename")
90
- if filename:
88
+ if filename := data.get("filename"):
91
89
  gVar.upload_original[index]["upload"] = True
92
90
  gVar.upload_original[index]["hash"] = hashs
93
91
  gVar.upload_original[index]["filename"] = filename
94
92
  if code == 0:
95
- bottle_text = f"{now_time}|{channelname}/{name}|\033[32m上传成功\033[0m"
93
+ bottle_text = "\033[32m上传成功\033[0m"
94
+ elif code == 1:
95
+ bottle_text = f"\033[33m上传成功\033[0m: {result.get(code, message)}"
96
96
  else:
97
- bottle_text = f"{now_time}|{channelname}/{name}|\033[33m上传成功\033[0m: {result.get(code, message)}"
97
+ bottle_text = f"\033[31m上传失败\033[0m: {result.get(code, message)}"
98
98
  else:
99
- bottle_text = f"{now_time}|{channelname}/{name}|\033[31m上传失败\033[0m: {result.get(code, message)}"
99
+ bottle_text = "\033[31m上传失败\033[0m: 网络连接失败"
100
+ bottle_text = f"{now_time}|{channelname}/{name}|{bottle_text}"
100
101
  bottle_app_instance.bottle_print.append(bottle_text)
101
102
  gVar.index_message["http"].append(ansi_to_html(bottle_text))
102
103
  bottle_app_instance.cherry_print(False)
103
104
 
104
105
 
105
106
  # 总体上传模块
106
- def all_upload():
107
+ def all_upload(upload_url):
107
108
  if gVar.config["upload"]:
108
109
  result = filter_and_sort_media(gVar.upload_original)
109
110
  username = gVar.upload_json["username"]
110
111
  password = gVar.upload_json["password"]
111
112
  for item in result:
112
- record_upload(username, password, item["channel_id"], item["media_id"])
113
+ record_upload(upload_url, username, password, item["channel_id"], item["media_id"])
113
114
  if gVar.upload_stop:
114
115
  break
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: podflow
3
- Version: 20250606
3
+ Version: 20250608
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
@@ -1,12 +1,12 @@
1
1
  podflow/__init__.py,sha256=mquu8BdWK9V4dDObCCfnPodeXOPkz-kj8_RNB7kK3Ys,7628
2
- podflow/download_and_build.py,sha256=UPFTc8XjBEkg3GnCt3zkNjCzSbHugS3O8AreaWIgHJ0,904
2
+ podflow/download_and_build.py,sha256=vwyVs6MMLgbWZjGCFnPcj08dGxplgmU7u9CAP_ujJ8g,1037
3
3
  podflow/ffmpeg_judge.py,sha256=wM49pPXOFwFAA_8TKHal5fV6ka9sAA87yGQMDOssvXo,1340
4
- podflow/main.py,sha256=Cz2E33-Kcc_1_oxNs4Z1OoqJYhonmClsrtoCW1oQmZA,739
5
- podflow/main_podcast.py,sha256=SSFIg73JLu3wS5E3WAo8OAgXG4r_CHsPT-XSga0Vzrg,12386
4
+ podflow/main.py,sha256=6cUgu8niM6LryBXCppQv0Nj4I2ye2bwoVrTF5vYmVFw,754
5
+ podflow/main_podcast.py,sha256=J63BSzj044Q8YaErSoV-zE2kYrqhPqS6-TqZCEG-VOA,12396
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
9
- podflow/basic/file_save.py,sha256=JPrX0cWJmVSgI8XTb326AlneNJauEYj8oHKakkqYGfk,991
9
+ podflow/basic/file_save.py,sha256=6vu4EkbsN4df5-ci6sJOgIOUEhh-WaRBOyMJ8rpouXo,1233
10
10
  podflow/basic/folder_build.py,sha256=5oHyfiDcSp2YITXQWIPwriBF9XuU3qs7wZQOWJHYJ1s,546
11
11
  podflow/basic/get_duration.py,sha256=eqdE85b7sgLyp6brhnGcOIQEWX6JqtNCGAsGyJOuXFI,532
12
12
  podflow/basic/get_file_list.py,sha256=XmnC4faObislyTsL9WUeyztyTQrvdi76lMzPudKEfXw,2389
@@ -40,7 +40,7 @@ podflow/download/show_progress.py,sha256=y46chchUC9eZCg4ZdNMFnx_bXJQV_IUq15jVzZt
40
40
  podflow/download/wait_animation.py,sha256=AUTvszXF89QA7XYjocFIauPKV7Qj8cFqry44teClaLQ,1314
41
41
  podflow/download/youtube_and_bilibili_download.py,sha256=VCEhz6pGXFWXusdbGWqkCzi4f4VsKQVn6sZz1pfGsns,1335
42
42
  podflow/httpfs/__init__.py,sha256=BxEXkufjcx-a0F7sDVXo65hmyANqCCbZUd6EH9i8T2c,45
43
- podflow/httpfs/app_bottle.py,sha256=cRPJe9JvS6FZVumDgQYOzPdpKrLd3gitKetCNVa3TPw,21465
43
+ podflow/httpfs/app_bottle.py,sha256=8KHi_MxHK1HMCiWb8CqnkEWxMGAu3FVS5KRA2sPGbC8,23338
44
44
  podflow/httpfs/browser.py,sha256=BJ4Xkfiki_tDr0Sc9RqAcEfIVpkAZ3RFOwo0aMHlY3U,197
45
45
  podflow/httpfs/download_bar.py,sha256=0n3HATEO3pdsIpx-E_IZG9OlXa6u-9SeBCoZVgUutyc,965
46
46
  podflow/httpfs/get_channelid.py,sha256=gcwy4IVHBWNQz7qPCpjwiAklGFLRGzvM33-UZz7oFvo,2296
@@ -79,8 +79,8 @@ podflow/netscape/__init__.py,sha256=SUw_BtbV3moA324UdxRECkPLv1xHkjio8r_5JTkVfxI,
79
79
  podflow/netscape/bulid_netscape.py,sha256=wmUPlDGF8G456GGyajU_6Ak5WJzsqsq4bZgPjCSTGhI,2279
80
80
  podflow/netscape/get_cookie_dict.py,sha256=laqw-eriABiLyciRLzDmistVHHWqmUM-9eEbYZzsqBQ,643
81
81
  podflow/remove/__init__.py,sha256=x1pMfpIyE6xUrmIOkdl43mbvKLwndGo5pIoOBXhJsP4,45
82
- podflow/remove/remove_dir.py,sha256=xQIhrnqnYjMzXjoSWaTvm7JwPYOFTN1muuTPdaLDXpQ,1099
83
- podflow/remove/remove_file.py,sha256=8wAJQehs-XBqvu0vPlEme2_tt0FZxc5ELwGMxXA_558,982
82
+ podflow/remove/remove_dir.py,sha256=zqgf47UgxiGiLipb1FeoWKzrSHSxcHaEuu0261bqR1s,1105
83
+ podflow/remove/remove_file.py,sha256=ZusvZsBQX_yRdLuboD7bZKiOX4z4Rxg66zZK9KDWHwE,1006
84
84
  podflow/repair/__init__.py,sha256=Gpc1i6xiSLodKjjmzH66c_Y1z0HQ9E9CS3p95FRnVFM,45
85
85
  podflow/repair/reverse_log.py,sha256=Wc_vAH0WB-z1fNdWx7FYaVH4caRPtot7tDwDwFhmpz4,1106
86
86
  podflow/templates/index.html,sha256=kGsp1TAcf_qkV6hYRE8Ueq7CaTflR73rsTWtjnWuwwY,2775
@@ -98,14 +98,14 @@ podflow/upload/linked_server.py,sha256=h-qSx13fP8_Ny2IKW3wCNPwqRqW6-Iz1pqxD9ga9-
98
98
  podflow/upload/login.py,sha256=85sqr12T-3NH-TD3kAMzy4yb1KOheV3Tr0eGee7NCJo,4007
99
99
  podflow/upload/time_key.py,sha256=6jZ3cxUjzj_umYDwH27R0YNZlLXxfhNp-CqV_K22wlo,967
100
100
  podflow/upload/update_upload.py,sha256=_5tp1zPNsC9DdDnLzm-P8bLcOBuDov4eMRHp_861j80,3183
101
- podflow/upload/upload_files.py,sha256=HgnqWA6W1Llonb2wPXxCeIWuZfTte7As1C8qzLSSe5c,3816
101
+ podflow/upload/upload_files.py,sha256=sy4GOIWpHPPiqoZzrMXQVzRCNT2QwEWwsraUj3CCRwY,3891
102
102
  podflow/upload/upload_server.py,sha256=BFq3QrWE7U97LbC4EQiDhQXbLapEc4R00eRDBH12E6A,565
103
103
  podflow/youtube/__init__.py,sha256=pgXod8gq0IijZxIkPSwgAOcb9JI5rd1mqMomoR7bcJ4,46
104
104
  podflow/youtube/build.py,sha256=j6SVq3HFFGlNNqRrHfnBIThdzsH88PFmwLnejosif1U,12311
105
105
  podflow/youtube/get.py,sha256=oO32GjTFvUgP5AfFX5AlIuXU2UT6QtOUOXWLFzi8XtI,17157
106
106
  podflow/youtube/login.py,sha256=KYl--ya6Z1u0uIcOp9l8i3DIIj9hsYUDH4dtJjI0MLM,1295
107
- podflow-20250606.dist-info/METADATA,sha256=zKC-lSx5y_drdcigYN7YXdHvD3QJSNvVCkyIIOiZDfM,14195
108
- podflow-20250606.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
109
- podflow-20250606.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
110
- podflow-20250606.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
111
- podflow-20250606.dist-info/RECORD,,
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,,