podflow 20250318__tar.gz → 20250323.1__tar.gz

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.
Files changed (105) hide show
  1. {podflow-20250318 → podflow-20250323.1}/PKG-INFO +2 -1
  2. {podflow-20250318 → podflow-20250323.1}/Podflow/__init__.py +1 -0
  3. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/file_save.py +2 -0
  4. {podflow-20250318 → podflow-20250323.1}/Podflow/download/dl_aideo_video.py +4 -1
  5. {podflow-20250318 → podflow-20250323.1}/Podflow/httpfs/app_bottle.py +139 -18
  6. podflow-20250323.1/Podflow/httpfs/browser.py +9 -0
  7. podflow-20250323.1/Podflow/httpfs/get_channelid.py +81 -0
  8. podflow-20250323.1/Podflow/httpfs/html.py +145 -0
  9. {podflow-20250318 → podflow-20250323.1}/Podflow/main_podcast.py +3 -0
  10. {podflow-20250318 → podflow-20250323.1}/Podflow/parse_arguments.py +6 -0
  11. podflow-20250323.1/Podflow/upload/build_hash.py +16 -0
  12. {podflow-20250318 → podflow-20250323.1}/README.md +1 -0
  13. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/PKG-INFO +2 -1
  14. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/SOURCES.txt +4 -0
  15. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/requires.txt +1 -1
  16. {podflow-20250318 → podflow-20250323.1}/setup.py +2 -2
  17. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/__init__.py +0 -0
  18. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/folder_build.py +0 -0
  19. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/get_duration.py +0 -0
  20. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/get_file_list.py +0 -0
  21. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/get_html_dict.py +0 -0
  22. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/http_client.py +0 -0
  23. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/list_merge_tidy.py +0 -0
  24. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/qr_code.py +0 -0
  25. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/split_dict.py +0 -0
  26. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/time_format.py +0 -0
  27. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/time_print.py +0 -0
  28. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/time_stamp.py +0 -0
  29. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/vary_replace.py +0 -0
  30. {podflow-20250318 → podflow-20250323.1}/Podflow/basic/write_log.py +0 -0
  31. {podflow-20250318 → podflow-20250323.1}/Podflow/bilibili/__init__.py +0 -0
  32. {podflow-20250318 → podflow-20250323.1}/Podflow/bilibili/build.py +0 -0
  33. {podflow-20250318 → podflow-20250323.1}/Podflow/bilibili/get.py +0 -0
  34. {podflow-20250318 → podflow-20250323.1}/Podflow/bilibili/login.py +0 -0
  35. {podflow-20250318 → podflow-20250323.1}/Podflow/config/__init__.py +0 -0
  36. {podflow-20250318 → podflow-20250323.1}/Podflow/config/build_original.py +0 -0
  37. {podflow-20250318 → podflow-20250323.1}/Podflow/config/channge_icon.py +0 -0
  38. {podflow-20250318 → podflow-20250323.1}/Podflow/config/correct_channelid.py +0 -0
  39. {podflow-20250318 → podflow-20250323.1}/Podflow/config/correct_config.py +0 -0
  40. {podflow-20250318 → podflow-20250323.1}/Podflow/config/get_channelid.py +0 -0
  41. {podflow-20250318 → podflow-20250323.1}/Podflow/config/get_channelid_id.py +0 -0
  42. {podflow-20250318 → podflow-20250323.1}/Podflow/config/get_config.py +0 -0
  43. {podflow-20250318 → podflow-20250323.1}/Podflow/download/__init__.py +0 -0
  44. {podflow-20250318 → podflow-20250323.1}/Podflow/download/convert_bytes.py +0 -0
  45. {podflow-20250318 → podflow-20250323.1}/Podflow/download/delete_part.py +0 -0
  46. {podflow-20250318 → podflow-20250323.1}/Podflow/download/show_progress.py +0 -0
  47. {podflow-20250318 → podflow-20250323.1}/Podflow/download/wait_animation.py +0 -0
  48. {podflow-20250318 → podflow-20250323.1}/Podflow/download/youtube_and_bilibili_download.py +0 -0
  49. {podflow-20250318 → podflow-20250323.1}/Podflow/download_and_build.py +0 -0
  50. {podflow-20250318 → podflow-20250323.1}/Podflow/ffmpeg_judge.py +0 -0
  51. {podflow-20250318 → podflow-20250323.1}/Podflow/httpfs/__init__.py +0 -0
  52. {podflow-20250318 → podflow-20250323.1}/Podflow/httpfs/port_judge.py +0 -0
  53. {podflow-20250318 → podflow-20250323.1}/Podflow/main.py +0 -0
  54. {podflow-20250318 → podflow-20250323.1}/Podflow/main_upload.py +0 -0
  55. {podflow-20250318 → podflow-20250323.1}/Podflow/makeup/__init__.py +0 -0
  56. {podflow-20250318 → podflow-20250323.1}/Podflow/makeup/del_makeup_format_fail.py +0 -0
  57. {podflow-20250318 → podflow-20250323.1}/Podflow/makeup/make_up_file.py +0 -0
  58. {podflow-20250318 → podflow-20250323.1}/Podflow/makeup/make_up_file_format_mod.py +0 -0
  59. {podflow-20250318 → podflow-20250323.1}/Podflow/makeup/make_up_file_mod.py +0 -0
  60. {podflow-20250318 → podflow-20250323.1}/Podflow/message/__init__.py +0 -0
  61. {podflow-20250318 → podflow-20250323.1}/Podflow/message/backup_zip_save.py +0 -0
  62. {podflow-20250318 → podflow-20250323.1}/Podflow/message/create_main_rss.py +0 -0
  63. {podflow-20250318 → podflow-20250323.1}/Podflow/message/display_qrcode_and_url.py +0 -0
  64. {podflow-20250318 → podflow-20250323.1}/Podflow/message/fail_message_initialize.py +0 -0
  65. {podflow-20250318 → podflow-20250323.1}/Podflow/message/format_time.py +0 -0
  66. {podflow-20250318 → podflow-20250323.1}/Podflow/message/get_media_name.py +0 -0
  67. {podflow-20250318 → podflow-20250323.1}/Podflow/message/get_original_rss.py +0 -0
  68. {podflow-20250318 → podflow-20250323.1}/Podflow/message/get_video_format.py +0 -0
  69. {podflow-20250318 → podflow-20250323.1}/Podflow/message/get_video_format_multithread.py +0 -0
  70. {podflow-20250318 → podflow-20250323.1}/Podflow/message/get_youtube_and_bilibili_video_format.py +0 -0
  71. {podflow-20250318 → podflow-20250323.1}/Podflow/message/media_format.py +0 -0
  72. {podflow-20250318 → podflow-20250323.1}/Podflow/message/original_rss_fail_print.py +0 -0
  73. {podflow-20250318 → podflow-20250323.1}/Podflow/message/rss_create_hash.py +0 -0
  74. {podflow-20250318 → podflow-20250323.1}/Podflow/message/save_rss.py +0 -0
  75. {podflow-20250318 → podflow-20250323.1}/Podflow/message/title_correction.py +0 -0
  76. {podflow-20250318 → podflow-20250323.1}/Podflow/message/update_information_display.py +0 -0
  77. {podflow-20250318 → podflow-20250323.1}/Podflow/message/update_youtube_bilibili_rss.py +0 -0
  78. {podflow-20250318 → podflow-20250323.1}/Podflow/message/want_retry.py +0 -0
  79. {podflow-20250318 → podflow-20250323.1}/Podflow/message/xml_item.py +0 -0
  80. {podflow-20250318 → podflow-20250323.1}/Podflow/message/xml_original_item.py +0 -0
  81. {podflow-20250318 → podflow-20250323.1}/Podflow/message/xml_rss.py +0 -0
  82. {podflow-20250318 → podflow-20250323.1}/Podflow/netscape/__init__.py +0 -0
  83. {podflow-20250318 → podflow-20250323.1}/Podflow/netscape/bulid_netscape.py +0 -0
  84. {podflow-20250318 → podflow-20250323.1}/Podflow/netscape/get_cookie_dict.py +0 -0
  85. {podflow-20250318 → podflow-20250323.1}/Podflow/remove/__init__.py +0 -0
  86. {podflow-20250318 → podflow-20250323.1}/Podflow/remove/remove_dir.py +0 -0
  87. {podflow-20250318 → podflow-20250323.1}/Podflow/remove/remove_file.py +0 -0
  88. {podflow-20250318 → podflow-20250323.1}/Podflow/repair/__init__.py +0 -0
  89. {podflow-20250318 → podflow-20250323.1}/Podflow/repair/reverse_log.py +0 -0
  90. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/__init__.py +0 -0
  91. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/add_upload.py +0 -0
  92. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/get_upload_original.py +0 -0
  93. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/linked_client.py +0 -0
  94. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/linked_server.py +0 -0
  95. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/login.py +0 -0
  96. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/time_key.py +0 -0
  97. {podflow-20250318 → podflow-20250323.1}/Podflow/upload/update_upload.py +0 -0
  98. {podflow-20250318 → podflow-20250323.1}/Podflow/youtube/__init__.py +0 -0
  99. {podflow-20250318 → podflow-20250323.1}/Podflow/youtube/build.py +0 -0
  100. {podflow-20250318 → podflow-20250323.1}/Podflow/youtube/get.py +0 -0
  101. {podflow-20250318 → podflow-20250323.1}/Podflow/youtube/login.py +0 -0
  102. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/dependency_links.txt +0 -0
  103. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/entry_points.txt +0 -0
  104. {podflow-20250318 → podflow-20250323.1}/podflow.egg-info/top_level.txt +0 -0
  105. {podflow-20250318 → podflow-20250323.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: podflow
3
- Version: 20250318
3
+ Version: 20250323.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
@@ -38,6 +38,7 @@ Description: # Podflow
38
38
  | `-d` | `--delay` | `int` | 1500 | 延迟(单位: 秒) |
39
39
  | `-c` | `--config` | `string` | "config.json" | 配置文件的路径 |
40
40
  | `--shortcuts` | | `string` | [] | 仅适用于捷径APP |
41
+ | `--index` | | `boolean` | 无 | 仅适用于捷径APP |
41
42
  | `--httpfs` | | `boolean` | 无 | 仅启用服务器功能, 不更新频道 |
42
43
  | `--upload` | | `boolean` | 无 | 仅上传服务器功能, 仅用于局域网备份(适用iOS) |
43
44
 
@@ -132,6 +132,7 @@ class Application_parse:
132
132
  self.period = 1
133
133
  self.file = ""
134
134
  self.httpfs = False
135
+ self.index = False
135
136
 
136
137
 
137
138
  # 创建 Application 类的实例
@@ -15,7 +15,9 @@ def file_save(content, file_name, folder=None):
15
15
  file_path = os.path.join(os.getcwd(), file_name)
16
16
  # 保存文件
17
17
  with open(file_path, "w", encoding="utf-8") as file:
18
+ # 如果文件名中包含"."且文件类型为json,则将内容以json格式保存
18
19
  if "." in file_name and file_name.split(".")[-1] == "json":
19
20
  json.dump(content, file, ensure_ascii=False, indent=4)
20
21
  else:
22
+ # 否则将内容以文本格式保存
21
23
  file.write(content)
@@ -123,7 +123,10 @@ def dl_full_video(
123
123
  duration_video = get_duration(
124
124
  f"channel_audiovisual/{output_dir}/{video_url}{sesuffix}.{output_format}"
125
125
  ) # 获取已下载视频的实际时长
126
- if abs(id_duration - duration_video) <= 1: # 检查实际时长与预计时长是否一致
126
+ if (
127
+ duration_video is not None
128
+ and abs(id_duration - duration_video) <= 1
129
+ ): # 检查实际时长与预计时长是否一致
127
130
  return None, None
128
131
  if duration_video:
129
132
  fail_info = f"不完整({id_duration}|{duration_video}"
@@ -5,11 +5,15 @@ import os
5
5
  import hashlib
6
6
  from datetime import datetime
7
7
  import cherrypy
8
- from bottle import Bottle, abort, redirect, request, static_file, response
8
+ from bottle import Bottle, abort, redirect, request, static_file, response, template
9
9
  from Podflow import gVar
10
10
  from Podflow.upload.login import create
11
+ from Podflow.httpfs.html import html_index
12
+ from Podflow.basic.file_save import file_save
11
13
  from Podflow.basic.write_log import write_log
14
+ from Podflow.upload.build_hash import build_hash
12
15
  from Podflow.upload.time_key import check_time_key
16
+ from Podflow.httpfs.get_channelid import get_channelid
13
17
 
14
18
 
15
19
  class bottle_app:
@@ -31,8 +35,10 @@ class bottle_app:
31
35
  if upload:
32
36
  self.app_bottle.route("/newuser", callback=self.new_user)
33
37
  self.app_bottle.route("/login", callback=self.login)
38
+ self.app_bottle.route("/upload", method="POST", callback=self.upload)
34
39
  else:
35
40
  # 设置其他路由,回调函数为serve_static
41
+ self.app_bottle.route("/index", method=["GET", "POST"], callback=self.index)
36
42
  self.app_bottle.route("/<filename:path>", callback=self.serve_static)
37
43
 
38
44
  # 设置日志文件名及写入判断
@@ -106,8 +112,7 @@ class bottle_app:
106
112
  # 输出请求日志的函数
107
113
  def print_out(self, filename, status):
108
114
  client_ip = request.remote_addr
109
- client_port = request.environ.get("REMOTE_PORT")
110
- if client_port:
115
+ if client_port := request.environ.get("REMOTE_PORT"):
111
116
  client_ip = f"{client_ip}:{client_port}"
112
117
  if filename not in [
113
118
  "favicon.ico",
@@ -120,7 +125,7 @@ class bottle_app:
120
125
  gVar.channelid_youtube_ids_original
121
126
  | gVar.channelid_bilibili_ids_original
122
127
  | {"channel_audiovisual/": "", "channel_rss/": ""}
123
- ) # 合并多个频道 ID
128
+ ) # 合并多个频道 ID
124
129
  for (
125
130
  bottle_channelid_key,
126
131
  bottle_channelid_value,
@@ -139,7 +144,7 @@ class bottle_app:
139
144
  def home(self):
140
145
  VALID_TOKEN = gVar.config["token"] # 从配置中读取主验证 Token
141
146
  token = request.query.get("token") # 获取请求中的 Token
142
-
147
+
143
148
  if self.token_judgment(token, VALID_TOKEN): # 验证 Token
144
149
  self.print_out("/", 303) # 如果验证成功, 输出 200 状态
145
150
  return redirect("https://github.com/gruel-zxz/podflow") # 返回正常响应
@@ -156,7 +161,7 @@ class bottle_app:
156
161
  Shutdown_VALID_TOKEN.encode()
157
162
  ).hexdigest() # 用于服务器关闭的验证 Token
158
163
  token = request.query.get("token") # 获取请求中的 Token
159
-
164
+
160
165
  if self.token_judgment(
161
166
  token, Shutdown_VALID_TOKEN
162
167
  ): # 验证 Token 是否为关闭用的 Token
@@ -220,16 +225,17 @@ class bottle_app:
220
225
 
221
226
  # 路由获取账号密码请求
222
227
  def new_user(self):
228
+ # 生成一个用于上传非一次性项目的账户密码,该密码需要保存
223
229
  seed = "We need to generate an account password for uploading non one-time items that need to be saved."
224
230
  token = request.query.get("token") # 获取请求中的 Token
225
- response.content_type = 'application/json'
226
-
231
+ response.content_type = "application/json"
232
+
227
233
  if check_time_key(token, seed): # 验证 Token
228
234
  username, password = create() # 生成用户名和密码
229
235
  self.print_out("newuser", 200)
230
236
  return {
231
- "code":0,
232
- "message":"Get New Username And Password Success",
237
+ "code": 0,
238
+ "message": "Get New Username And Password Success",
233
239
  "data": {
234
240
  "username": username,
235
241
  "password": password,
@@ -238,34 +244,149 @@ class bottle_app:
238
244
  else:
239
245
  self.print_out("newuser", 401)
240
246
  return {
241
- "code":-1,
242
- "message":"Unauthorized: Invalid Token",
247
+ "code": -1,
248
+ "message": "Unauthorized: Invalid Token",
243
249
  }
244
250
 
251
+ # 获取Channel-ID请求
252
+ def index(self):
253
+ if request.method == "POST":
254
+ user_input = request.forms.get("inputOutput") # 获取用户输入
255
+ processed_input = get_channelid(user_input)
256
+ self.print_out("channelid", 200)
257
+ return template(html_index, processed_input=processed_input) # 直接回显到输入框
258
+ else:
259
+ self.print_out("index", 200)
260
+ return template(html_index, processed_input="") # 默认输入框为空
261
+
245
262
  # 路由处理登陆请求
246
263
  def login(self):
264
+ # 获取上传的数据
247
265
  upload_data = gVar.upload_data
266
+ # 获取用户名
248
267
  username = request.query.get("username")
268
+ # 获取密码
249
269
  password = request.query.get("password")
270
+ # 判断用户名是否在上传的数据中
250
271
  if username in upload_data:
272
+ # 判断密码是否正确
251
273
  if upload_data[username] == password:
274
+ # 打印登录成功
252
275
  self.print_out("login", 200)
276
+ # 返回登录成功的信息
253
277
  return {
254
- "code":0,
255
- "message":"Login Success",
278
+ "code": 0,
279
+ "message": "Login Success",
256
280
  }
257
281
  else:
282
+ # 打印密码错误
258
283
  self.print_out("login", 401)
284
+ # 返回密码错误的信息
259
285
  return {
260
- "code":-3,
261
- "message":"Password Error",
286
+ "code": -3,
287
+ "message": "Password Error",
262
288
  }
263
289
  else:
290
+ # 打印用户名错误
291
+ self.print_out("login", 401)
292
+ # 返回用户名错误的信息
293
+ return {
294
+ "code": -2,
295
+ "message": "Username Error",
296
+ }
297
+
298
+ # 文件上传处理请求
299
+ def upload(self):
300
+ # 获取上传数据配置(存储用户名和密码)
301
+ upload_data = gVar.upload_data
302
+ # 从请求参数中获取用户名,默认为空字符串
303
+ username = request.query.get("username", "")
304
+ # 从请求参数中获取密码,默认为空字符串
305
+ password = request.query.get("password", "")
306
+ upload_hash = request.query.get("hash", "")
307
+ channelid = request.query.get("channel_id", "")
308
+
309
+ # 验证用户是否存在
310
+ if username not in upload_data:
311
+ self.print_out("login", 401)
312
+ return {
313
+ "code": -2,
314
+ "message": "Username Error",
315
+ }
316
+ # 验证密码是否正确
317
+ if upload_data[username] != password:
264
318
  self.print_out("login", 401)
265
319
  return {
266
- "code":-2,
267
- "message":"Username Error",
320
+ "code": -3,
321
+ "message": "Password Error",
322
+ }
323
+ # 从请求中获取上传的文件对象
324
+ upload_file = request.files.get("file")
325
+ # 检查是否有文件被上传
326
+ if not upload_file:
327
+ # 打印错误信息并返回错误码
328
+ self.print_out("upload", 404)
329
+ return {
330
+ "code": -4,
331
+ "message": "No File Provided",
332
+ }
333
+ # 判断文件是否完整
334
+ if upload_hash != build_hash(upload_file):
335
+ self.print_out("upload", 401)
336
+ return {
337
+ "code": -5,
338
+ "message": "Incomplete File",
339
+ }
340
+ if not channelid:
341
+ # 打印错误信息并返回错误码
342
+ self.print_out("upload", 404)
343
+ return {
344
+ "code": -6,
345
+ "message": "ChannelId Does Not Exist",
268
346
  }
347
+ # 获取上传文件的原始文件名
348
+ filename = upload_file.filename
349
+ name = filename.split(".")[0]
350
+ suffix = filename.split(".")[1]
351
+ if suffix in ["mp4", "m4a"]:
352
+ self.print_out("upload", 404)
353
+ return {
354
+ "code": -6,
355
+ "message": "File Format Error",
356
+ }
357
+ address = f"/channel_audiovisual/{channelid}"
358
+ if os.path.exists(address):
359
+ file_list = os.listdir(address)
360
+ else:
361
+ file_list = []
362
+ num = 0
363
+ while True:
364
+ if num != 0:
365
+ filename = f"{name}.{num}.{suffix}"
366
+ if filename in file_list:
367
+ with open(f"{address}/{filename}", "rb") as original_file:
368
+ if upload_hash == build_hash(original_file):
369
+ self.print_out("upload", 200)
370
+ return {
371
+ "code": 1,
372
+ "message": "The Same File Exists",
373
+ "data": {
374
+ "filename": filename,
375
+ },
376
+ }
377
+ else:
378
+ num += 1
379
+ else:
380
+ file_save(upload_file, filename, address)
381
+ # 打印成功信息并返回成功码
382
+ self.print_out("upload", 200)
383
+ return {
384
+ "code": 0,
385
+ "message": "Upload Success",
386
+ "data": {
387
+ "filename": filename,
388
+ },
389
+ }
269
390
 
270
391
 
271
392
  bottle_app_instance = bottle_app()
@@ -0,0 +1,9 @@
1
+ # Podflow/httpfs/browser.py
2
+ # coding: utf-8
3
+
4
+ import os
5
+
6
+
7
+ def open_url(url):
8
+ browser = os.getenv("BROWSER", "internalbrowser")
9
+ os.system(f"{browser} {url}") # 在后台运行,避免阻塞
@@ -0,0 +1,81 @@
1
+ # Podflow/httpfs/get_channelid.py
2
+ # coding: utf-8
3
+
4
+ import re
5
+ from Podflow.basic.http_client import http_client
6
+
7
+
8
+ def get_response(
9
+ text,
10
+ name,
11
+ re_ucid,
12
+ mod_ucid,
13
+ re_title,
14
+ ):
15
+ if response := http_client(
16
+ url=text,
17
+ name=name,
18
+ headers_possess=True
19
+ ):
20
+ if mod_ucid == "text":
21
+ ucid = re.search(re_ucid, response.text)
22
+ elif mod_ucid == "url":
23
+ ucid = re.search(re_ucid, response.url)
24
+ else:
25
+ ucid = ""
26
+ title = re.search(re_title, response.text)
27
+ if ucid and title :
28
+ ucid = ucid.group(0)
29
+ title = title.group(0)
30
+ return f'''"{title}": "{ucid}"
31
+
32
+ "{title}": {{
33
+ "id": "{ucid}",
34
+ "quality": "1080",
35
+ "media": "mp4",
36
+ "InmainRSS": false,
37
+ "update_size": 2
38
+ }}'''
39
+ else:
40
+ return "Network Error"
41
+ else:
42
+ return "Network Error"
43
+
44
+
45
+ def get_channelid(text):
46
+ if text in [None, ""]:
47
+ return ""
48
+ url_pattern = re.compile(r'https?://[^\s<>"]+|www\.[^\s<>"]+')
49
+ text_match = url_pattern.search(text) # 使用 search() 而不是 match()
50
+ if text_match:
51
+ text = text_match.group(0)
52
+ if "youtube" in text:
53
+ return get_response(
54
+ text,
55
+ "youtube",
56
+ r"(?<=https://www.youtube.com/channel/)UC.{22}",
57
+ "text",
58
+ r'(?<=<link itemprop="name" content=").+?(?=")',
59
+ )
60
+ elif "bilibili" in text or "b23.tv" in text:
61
+ return get_response(
62
+ text,
63
+ "bilibili",
64
+ r'(?<=https://space\.bilibili\.com/)([0-9]+)',
65
+ "url",
66
+ r'(?<=<title>).+(?=的个人空间-)',
67
+ )
68
+ else:
69
+ text_match = re.search(r'(?<=UID:)([0-9]+)', text, re.IGNORECASE)
70
+ if text_match:
71
+ text = f"https://space.bilibili.com/{text_match.group(0)}"
72
+ return get_response(
73
+ text,
74
+ "bilibili",
75
+ r'(?<=https://space\.bilibili\.com/)([0-9]+)',
76
+ "url",
77
+ r'(?<=<title>).+(?=的个人空间-)',
78
+ )
79
+ else:
80
+ return "Network Error"
81
+ return "Network Error"
@@ -0,0 +1,145 @@
1
+ # Podflow/httpfs/html.py
2
+ # coding: utf-8
3
+
4
+
5
+ html_index = '''<!DOCTYPE html>
6
+ <html lang="zh">
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
10
+ <title>输入输出示例</title>
11
+ <style>
12
+ /* 基本样式 */
13
+ body {
14
+ font-family: Arial, sans-serif;
15
+ text-align: center;
16
+ padding: 20px;
17
+ background-color: #f8f9fa;
18
+ }
19
+
20
+ h2 {
21
+ color: #333;
22
+ }
23
+
24
+ /* 响应式输入框 */
25
+ textarea {
26
+ width: 90%;
27
+ max-width: 600px;
28
+ height: 250px; /* 增加默认高度 */
29
+ font-size: 16px;
30
+ padding: 10px;
31
+ border: 1px solid #ccc;
32
+ border-radius: 8px;
33
+ resize: vertical; /* 允许手动调整高度 */
34
+ overflow-y: auto; /* 始终显示垂直滚动条(如需自动出现滚动条,可用 `overflow-y: auto;`) */
35
+ }
36
+
37
+ /* 按钮样式 */
38
+ .button-container {
39
+ margin-top: 10px;
40
+ }
41
+
42
+ button {
43
+ background-color: #007bff;
44
+ color: white;
45
+ border: none;
46
+ padding: 12px 18px;
47
+ font-size: 16px;
48
+ border-radius: 6px;
49
+ cursor: pointer;
50
+ transition: 0.3s;
51
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.2);
52
+ margin: 5px;
53
+ }
54
+
55
+ button:hover {
56
+ background-color: #0056b3;
57
+ }
58
+
59
+ /* 手机端优化 */
60
+ @media (max-width: 600px) {
61
+ textarea {
62
+ font-size: 18px;
63
+ height: 180px;
64
+ }
65
+
66
+ button {
67
+ width: 90%;
68
+ font-size: 18px;
69
+ padding: 14px;
70
+ }
71
+ }
72
+
73
+ /* 提示信息 */
74
+ .hint {
75
+ font-size: 14px;
76
+ color: #666;
77
+ margin-top: 10px;
78
+ }
79
+ </style>
80
+ </head>
81
+ <body>
82
+ <h2>获取Channel-ID</h2>
83
+ <form id="inputForm" method="post">
84
+ <label for="inputOutput">请输入:</label><br>
85
+ <textarea name="inputOutput" id="inputOutput">{{ processed_input }}</textarea><br>
86
+ <div class="button-container">
87
+ <button type="button" onclick="pasteFromClipboard()">📋 粘贴</button>
88
+ <button type="submit">✅ 提交</button>
89
+ //<button type="button" onclick="copyText()">📄 拷贝</button>
90
+ <button type="button" onclick="clearInput()">🗑️ 清空</button>
91
+ </div>
92
+ <p class="hint">📌 如果粘贴按钮无效,请长按输入框手动粘贴。</p>
93
+ </form>
94
+ <script>
95
+ function pasteFromClipboard() {
96
+ let inputOutput = document.getElementById('inputOutput');
97
+
98
+ if (navigator.clipboard && navigator.clipboard.readText) {
99
+ navigator.clipboard.readText().then(text => {
100
+ inputOutput.value = text;
101
+ inputOutput.focus(); // 聚焦输入框
102
+ //alert("✅ 已成功粘贴!");
103
+ }).catch(err => {
104
+ console.warn("❌ 剪贴板读取失败:", err);
105
+ alert("❌ 无法读取剪贴板,请手动粘贴!");
106
+ });
107
+ } else {
108
+ // 兼容旧版浏览器
109
+ try {
110
+ inputOutput.focus();
111
+ document.execCommand('paste'); // 仅部分浏览器支持
112
+ //alert("✅ 尝试使用旧版粘贴方法!");
113
+ } catch (err) {
114
+ console.warn("❌ execCommand 粘贴失败:", err);
115
+ alert("❌ 您的浏览器不支持自动粘贴,请手动操作!");
116
+ }
117
+ }
118
+ }
119
+ function copyText() {
120
+ let inputOutput = document.getElementById('inputOutput');
121
+ if (navigator.clipboard && navigator.clipboard.writeText) {
122
+ navigator.clipboard.writeText(inputOutput.value).then(() => {
123
+ //alert("✅ 已拷贝到剪贴板!");
124
+ }).catch(err => {
125
+ console.warn("拷贝失败:", err);
126
+ alert("❌ 无法拷贝,请手动选择文本后按 Ctrl+C 复制!");
127
+ });
128
+ } else {
129
+ // 兼容旧版浏览器
130
+ try {
131
+ inputOutput.select();
132
+ document.execCommand('copy');
133
+ //alert("✅ 已拷贝到剪贴板!");
134
+ } catch (err) {
135
+ console.warn("execCommand 复制失败:", err);
136
+ alert("❌ 您的浏览器不支持拷贝,请手动操作!");
137
+ }
138
+ }
139
+ }
140
+ function clearInput() {
141
+ document.getElementById('inputOutput').value = '';
142
+ }
143
+ </script>
144
+ </body>
145
+ </html>'''
@@ -15,6 +15,7 @@ from Podflow.basic.split_dict import split_dict
15
15
  from Podflow.basic.time_print import time_print
16
16
 
17
17
  # 网络和 HTTP 模块
18
+ from Podflow.httpfs.browser import open_url
18
19
  from Podflow.httpfs.port_judge import port_judge
19
20
  from Podflow.httpfs.app_bottle import bottle_app_instance
20
21
 
@@ -94,6 +95,8 @@ def main_podcast():
94
95
  )
95
96
  cherrypy.engine.start() # 启动 CherryPy 服务器
96
97
  time_print(f"HTTP服务器启动, 端口: \033[32m{port}\033[0m")
98
+ if parse.index:
99
+ open_url(f"{gVar.config['address']}/index")
97
100
  if parse.httpfs: # HttpFS参数判断, 是否继续运行
98
101
  cherrypy.engine.block() # 阻止程序退出, 保持HTTP服务运行
99
102
  sys.exit(0)
@@ -58,6 +58,11 @@ def parse_arguments():
58
58
  metavar="URL",
59
59
  help="Only shortcuts can be work",
60
60
  )
61
+ parser.add_argument(
62
+ "--index",
63
+ action="store_true",
64
+ help="Only shortcuts can be work",
65
+ )
61
66
  parser.add_argument(
62
67
  "--httpfs",
63
68
  action="store_true",
@@ -77,6 +82,7 @@ def parse_arguments():
77
82
  parse.file = args.file
78
83
  parse.httpfs = args.httpfs
79
84
  parse.upload = args.upload
85
+ parse.index = args.index
80
86
  # 检查并处理参数的状态
81
87
  if args.times is not None:
82
88
  parse.update_num = int(args.times[0])
@@ -0,0 +1,16 @@
1
+ # Podflow/upload/build_hash.py
2
+ # coding: utf-8
3
+
4
+ import hashlib
5
+
6
+
7
+ # 定义一个函数,用于计算文件的哈希值
8
+ def build_hash(file):
9
+ # 获取hashlib模块中的sha256函数
10
+ hash_func = getattr(hashlib, "sha256")()
11
+ # 循环读取文件内容,每次读取4096字节
12
+ for chunk in iter(lambda: file.read(4096), b''):
13
+ # 更新哈希值
14
+ hash_func.update(chunk)
15
+ # 返回哈希值的十六进制表示
16
+ return hash_func.hexdigest()
@@ -30,6 +30,7 @@ pip install Podflow
30
30
  | `-d` | `--delay` | `int` | 1500 | 延迟(单位: 秒) |
31
31
  | `-c` | `--config` | `string` | "config.json" | 配置文件的路径 |
32
32
  | `--shortcuts` | | `string` | [] | 仅适用于捷径APP |
33
+ | `--index` | | `boolean` | 无 | 仅适用于捷径APP |
33
34
  | `--httpfs` | | `boolean` | 无 | 仅启用服务器功能, 不更新频道 |
34
35
  | `--upload` | | `boolean` | 无 | 仅上传服务器功能, 仅用于局域网备份(适用iOS) |
35
36
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: podflow
3
- Version: 20250318
3
+ Version: 20250323.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
@@ -38,6 +38,7 @@ Description: # Podflow
38
38
  | `-d` | `--delay` | `int` | 1500 | 延迟(单位: 秒) |
39
39
  | `-c` | `--config` | `string` | "config.json" | 配置文件的路径 |
40
40
  | `--shortcuts` | | `string` | [] | 仅适用于捷径APP |
41
+ | `--index` | | `boolean` | 无 | 仅适用于捷径APP |
41
42
  | `--httpfs` | | `boolean` | 无 | 仅启用服务器功能, 不更新频道 |
42
43
  | `--upload` | | `boolean` | 无 | 仅上传服务器功能, 仅用于局域网备份(适用iOS) |
43
44
 
@@ -43,6 +43,9 @@ Podflow/download/wait_animation.py
43
43
  Podflow/download/youtube_and_bilibili_download.py
44
44
  Podflow/httpfs/__init__.py
45
45
  Podflow/httpfs/app_bottle.py
46
+ Podflow/httpfs/browser.py
47
+ Podflow/httpfs/get_channelid.py
48
+ Podflow/httpfs/html.py
46
49
  Podflow/httpfs/port_judge.py
47
50
  Podflow/makeup/__init__.py
48
51
  Podflow/makeup/del_makeup_format_fail.py
@@ -81,6 +84,7 @@ Podflow/repair/__init__.py
81
84
  Podflow/repair/reverse_log.py
82
85
  Podflow/upload/__init__.py
83
86
  Podflow/upload/add_upload.py
87
+ Podflow/upload/build_hash.py
84
88
  Podflow/upload/get_upload_original.py
85
89
  Podflow/upload/linked_client.py
86
90
  Podflow/upload/linked_server.py
@@ -1,6 +1,6 @@
1
1
  astral>=3.2
2
2
  bottle>=0.13.2
3
- yt-dlp>=2025.2.19
3
+ yt-dlp>=2025.3.21
4
4
  chardet>=5.2.0
5
5
  cherrypy>=18.10.0
6
6
  pyqrcode>=1.2.1
@@ -5,7 +5,7 @@ from setuptools import setup, find_packages
5
5
 
6
6
  setup(
7
7
  name="podflow",
8
- version="20250318",
8
+ version="20250323.1",
9
9
  author="gruel_zxz",
10
10
  author_email="zhuxizhouzxz@gmail.com",
11
11
  description="A podcast server that includes YouTube and BiliBili",
@@ -30,7 +30,7 @@ setup(
30
30
  install_requires=[
31
31
  "astral>=3.2",
32
32
  "bottle>=0.13.2",
33
- "yt-dlp>=2025.2.19",
33
+ "yt-dlp>=2025.3.21",
34
34
  "chardet>=5.2.0",
35
35
  "cherrypy>=18.10.0",
36
36
  "pyqrcode>=1.2.1",
File without changes
File without changes