podflow 20250429__py3-none-any.whl → 20250522__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/file_save.py +12 -8
- podflow/basic/http_client.py +5 -5
- podflow/httpfs/app_bottle.py +18 -3
- podflow/templates/css/config.css +225 -0
- podflow/templates/index.html +18 -6
- podflow/templates/js/config.js +832 -0
- podflow/templates/js/index.js +690 -690
- podflow/upload/linked_client.py +64 -27
- podflow/upload/upload_files.py +58 -0
- {podflow-20250429.dist-info → podflow-20250522.dist-info}/METADATA +2 -2
- {podflow-20250429.dist-info → podflow-20250522.dist-info}/RECORD +14 -11
- {podflow-20250429.dist-info → podflow-20250522.dist-info}/WHEEL +0 -0
- {podflow-20250429.dist-info → podflow-20250522.dist-info}/entry_points.txt +0 -0
- {podflow-20250429.dist-info → podflow-20250522.dist-info}/top_level.txt +0 -0
podflow/upload/linked_client.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# podflow/upload/linked_client.py
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
|
-
import os
|
5
4
|
import time
|
6
5
|
import socket
|
7
|
-
|
6
|
+
import struct
|
7
|
+
import threading
|
8
8
|
from podflow import gVar
|
9
9
|
from podflow.upload.time_key import time_key
|
10
10
|
from podflow.basic.time_print import time_print
|
@@ -16,24 +16,57 @@ TIMEOUT = 1 # 搜索超时时间(秒)
|
|
16
16
|
MAX_BROADCAST_PORT = 37010 # 尝试广播的最大端口
|
17
17
|
|
18
18
|
|
19
|
+
# 获取本机局域网 IP (此函数在有代理时可能失效,但保留作为fallback或无代理时的功能)
|
20
|
+
def get_local_ip():
|
21
|
+
try:
|
22
|
+
# 尝试连接一个外部地址来确定哪个本地接口被用于路由
|
23
|
+
# 注意:在某些代理/VPN配置下,这可能返回代理或VPN分配的IP
|
24
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
25
|
+
s.connect(("8.8.8.8", 80)) # 非真实连接
|
26
|
+
ip = s.getsockname()[0]
|
27
|
+
time_print(f"局域网IP:{ip}")
|
28
|
+
return ip
|
29
|
+
except Exception as e:
|
30
|
+
time_print(f"\033[31m获取本地 IP 失败:\033[0m {e}")
|
31
|
+
return None
|
32
|
+
|
33
|
+
|
34
|
+
# 计算广播地址(默认 255.255.255.0)
|
35
|
+
def calculate_broadcast(ip, netmask="255.255.255.0"):
|
36
|
+
try:
|
37
|
+
# 确保输入是有效的IPv4地址
|
38
|
+
socket.inet_aton(ip)
|
39
|
+
socket.inet_aton(netmask)
|
40
|
+
|
41
|
+
ip_packed = struct.unpack("!I", socket.inet_aton(ip))[0]
|
42
|
+
mask_packed = struct.unpack("!I", socket.inet_aton(netmask))[0]
|
43
|
+
broadcast_packed = ip_packed | ~mask_packed & 0xFFFFFFFF
|
44
|
+
address = socket.inet_ntoa(struct.pack("!I", broadcast_packed))
|
45
|
+
time_print(f"广播地址:{address}")
|
46
|
+
return address
|
47
|
+
except socket.error as e:
|
48
|
+
time_print(f"\033[31m计算广播地址失败(无效IP或掩码):\033[0m {e}")
|
49
|
+
return "255.255.255.255" # 回退地址
|
50
|
+
except Exception as e:
|
51
|
+
time_print(f"\033[31m计算广播地址失败:\033[0m {e}")
|
52
|
+
return "255.255.255.255" # 回退地址
|
53
|
+
|
54
|
+
|
19
55
|
# 发现局域网内的服务器
|
20
|
-
def discover_server(broadcast_port, time_out):
|
56
|
+
def discover_server(broadcast_ip, broadcast_port, time_out):
|
21
57
|
servers = []
|
22
|
-
|
23
58
|
# 创建UDP socket
|
24
59
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
25
60
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
26
61
|
sock.settimeout(time_out)
|
27
62
|
send_text = time_key("PODFLOW_DISCOVER_SERVER_REQUEST")
|
28
63
|
send_text = send_text.encode("utf-8")
|
29
|
-
|
30
64
|
try:
|
31
65
|
# 发送广播请求
|
32
|
-
sock.sendto(send_text, (
|
66
|
+
sock.sendto(send_text, (broadcast_ip, broadcast_port))
|
33
67
|
except Exception:
|
34
68
|
time_print("\033[31m请求发送失败\033[0m", False, True, False)
|
35
69
|
return servers
|
36
|
-
|
37
70
|
# 等待响应
|
38
71
|
start_time = time.time()
|
39
72
|
while time.time() - start_time < time_out:
|
@@ -57,31 +90,35 @@ def discover_server(broadcast_port, time_out):
|
|
57
90
|
def connect_upload_server():
|
58
91
|
# 如果配置中启用了上传功能
|
59
92
|
if gVar.config["upload"]:
|
93
|
+
local_ip = get_local_ip()
|
94
|
+
if not local_ip:
|
95
|
+
# 如果无法获取本地IP,广播发现也无法进行
|
96
|
+
time_print("\033[31m无法获取本地IP,跳过广播发现。\033[0m")
|
97
|
+
return
|
98
|
+
broadcast_ip = calculate_broadcast(local_ip)
|
99
|
+
if broadcast_ip in ["255.255.255.255", local_ip, "0.0.0.0"]:
|
100
|
+
# 避免向无效或自己的地址广播
|
101
|
+
time_print(f"\033[31m计算出的广播地址无效或为本机地址: {broadcast_ip},跳过广播发现。\033[0m")
|
102
|
+
return
|
60
103
|
# 打印正在搜索上传服务器
|
61
104
|
time_print("正在搜索上传服务器...")
|
62
|
-
# 当前端口设置为广播端口
|
63
|
-
current_port = BROADCAST_PORT
|
64
105
|
# 服务器列表为空
|
65
106
|
servers = []
|
66
|
-
# 获取当前时间
|
67
|
-
time_text = f"{datetime.now().strftime('%H:%M:%S')}|"
|
68
|
-
# 获取命令行字节宽度
|
69
|
-
try:
|
70
|
-
terminal_width = os.get_terminal_size().columns
|
71
|
-
except OSError:
|
72
|
-
terminal_width = 47
|
73
107
|
# 在允许的端口范围内尝试发现服务器
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
108
|
+
progress_lock = threading.Lock()
|
109
|
+
def try_port(port, servers):
|
110
|
+
server = discover_server(broadcast_ip, port, TIMEOUT)
|
111
|
+
with progress_lock:
|
112
|
+
if server:
|
113
|
+
servers.extend(server)
|
114
|
+
progress_update(0.0005, added=True)
|
115
|
+
threads = []
|
116
|
+
for port in range(BROADCAST_PORT, MAX_BROADCAST_PORT + 1):
|
117
|
+
t = threading.Thread(target=try_port, args=(port, servers))
|
118
|
+
t.start()
|
119
|
+
threads.append(t)
|
120
|
+
for t in threads:
|
121
|
+
t.join()
|
85
122
|
if not servers:
|
86
123
|
time_print("找不到上传服务器", True)
|
87
124
|
else:
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# podflow/upload/upload_files.py
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
import time
|
5
|
+
from podflow.upload.build_hash import build_hash
|
6
|
+
from podflow.basic.http_client import http_client
|
7
|
+
|
8
|
+
|
9
|
+
def upload_file(username, password, channelid, filename):
|
10
|
+
filename = f"channel_audiovisual/{channelid}/{filename}"
|
11
|
+
with open(filename, "rb") as file:
|
12
|
+
file.seek(0)
|
13
|
+
hashs = build_hash(file)
|
14
|
+
file.seek(0)
|
15
|
+
data = {
|
16
|
+
"username": username,
|
17
|
+
"password": password,
|
18
|
+
"channel_id": channelid,
|
19
|
+
"hash": hashs,
|
20
|
+
}
|
21
|
+
if response := http_client(
|
22
|
+
url="http://10.0.3.231:5000/upload",
|
23
|
+
name="1",
|
24
|
+
data=data,
|
25
|
+
mode="post",
|
26
|
+
file=file,
|
27
|
+
):
|
28
|
+
return response.json()
|
29
|
+
else:
|
30
|
+
return None
|
31
|
+
return None
|
32
|
+
|
33
|
+
|
34
|
+
def find_media_index(upload_original, target_media_id):
|
35
|
+
for index, item in enumerate(upload_original):
|
36
|
+
if item.get("media_id") == target_media_id:
|
37
|
+
return index # 返回找到的索引
|
38
|
+
return -1
|
39
|
+
|
40
|
+
|
41
|
+
def filter_and_sort_media(media_list, day):
|
42
|
+
current_time = int(time.time())
|
43
|
+
one_month_ago = current_time - day * 24 * 60 * 60 # 30天前的时间戳
|
44
|
+
filtered_sorted = sorted(
|
45
|
+
(
|
46
|
+
item
|
47
|
+
for item in media_list
|
48
|
+
if not item["upload"]
|
49
|
+
and not item["remove"]
|
50
|
+
and item["media_time"] < one_month_ago
|
51
|
+
),
|
52
|
+
key=lambda x: x["media_time"],
|
53
|
+
)
|
54
|
+
result = [
|
55
|
+
{"media_id": item["media_id"], "channel_id": item["channel_id"]}
|
56
|
+
for item in filtered_sorted
|
57
|
+
]
|
58
|
+
return result
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: podflow
|
3
|
-
Version:
|
3
|
+
Version: 20250522
|
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.4.30
|
18
18
|
Requires-Dist: chardet>=5.2.0
|
19
19
|
Requires-Dist: cherrypy>=18.10.0
|
20
20
|
Requires-Dist: pyqrcode>=1.2.1
|
@@ -6,12 +6,12 @@ podflow/main_podcast.py,sha256=D1eBxeGNks0q8_zhVG2uUuE1pBcPEXGDAfd1CwAtuOs,12321
|
|
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=
|
9
|
+
podflow/basic/file_save.py,sha256=JPrX0cWJmVSgI8XTb326AlneNJauEYj8oHKakkqYGfk,991
|
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
|
13
13
|
podflow/basic/get_html_dict.py,sha256=V-PgDtD6pm5mZC1LUPttUbZzxhjkS3WDYHxWR3yzIEY,869
|
14
|
-
podflow/basic/http_client.py,sha256=
|
14
|
+
podflow/basic/http_client.py,sha256=lSDfWYF5nZ6LPEXyNjUVudPFTo1fcaPauFjIuq68JR4,2863
|
15
15
|
podflow/basic/list_merge_tidy.py,sha256=7hWfSnsPh23edHNU92vxtI0nfpfN8m54GTEt2rGm2HQ,368
|
16
16
|
podflow/basic/qr_code.py,sha256=lZo11jbYqFQYy9gjBtRRUoLjlaEmoES-phydnrOMcLo,1727
|
17
17
|
podflow/basic/split_dict.py,sha256=Ir6GTortcWMUeFITFgY1v-INMla5y0IN3RN3nTgzWqM,401
|
@@ -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=
|
43
|
+
podflow/httpfs/app_bottle.py,sha256=A-EZuuY1Xlpuu0_kQSeRgswhLbGw9J_3BbxuO8L2nZg,21305
|
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
|
@@ -83,26 +83,29 @@ podflow/remove/remove_dir.py,sha256=xQIhrnqnYjMzXjoSWaTvm7JwPYOFTN1muuTPdaLDXpQ,
|
|
83
83
|
podflow/remove/remove_file.py,sha256=8wAJQehs-XBqvu0vPlEme2_tt0FZxc5ELwGMxXA_558,982
|
84
84
|
podflow/repair/__init__.py,sha256=Gpc1i6xiSLodKjjmzH66c_Y1z0HQ9E9CS3p95FRnVFM,45
|
85
85
|
podflow/repair/reverse_log.py,sha256=Wc_vAH0WB-z1fNdWx7FYaVH4caRPtot7tDwDwFhmpz4,1106
|
86
|
-
podflow/templates/index.html,sha256=
|
86
|
+
podflow/templates/index.html,sha256=kGsp1TAcf_qkV6hYRE8Ueq7CaTflR73rsTWtjnWuwwY,2775
|
87
|
+
podflow/templates/css/config.css,sha256=-xjFlrbP2BAeTYTLs2M2u-4--klwSSC7HE2av58QUF0,5224
|
87
88
|
podflow/templates/css/index.css,sha256=dgrlonF2BYdAtIFYpDChvSBnXAndbdoyY6c2ysOgdL0,9641
|
88
|
-
podflow/templates/js/
|
89
|
+
podflow/templates/js/config.js,sha256=VZmpvtQWszofoccjJZNhbjvNkpl-CjGOdTrPkI83ND4,43634
|
90
|
+
podflow/templates/js/index.js,sha256=GUfFhZM3vjiwfJ7USQZIIv5c7cyZwt64QZt0VInq5TI,34051
|
89
91
|
podflow/templates/js/qrcode.min.js,sha256=xUHvBjJ4hahBW8qN9gceFBibSFUzbe9PNttUvehITzY,19927
|
90
92
|
podflow/upload/__init__.py,sha256=AtOSXDrE5EjUe3z-iBd1NTDaH8n_X9qA5WXdBLkONjA,45
|
91
93
|
podflow/upload/add_upload.py,sha256=_2-V0z75Lwu-PUCfMD9HOSxZTB102yZlZW5hSdlHcsc,1432
|
92
94
|
podflow/upload/build_hash.py,sha256=9opa3xLd7nJbGGX5xa3uuKPS6dxlbkAb87ZdEiUxmxI,473
|
93
95
|
podflow/upload/get_upload_original.py,sha256=TEDnRutumm2FZNIesPJIlExHyKWpfB3ZAHb3sZt7V6A,4312
|
94
|
-
podflow/upload/linked_client.py,sha256=
|
96
|
+
podflow/upload/linked_client.py,sha256=gXcqwvyJtRZ-bAygQu6EyPoOa1y8GuJILTTVvGhu6DY,5130
|
95
97
|
podflow/upload/linked_server.py,sha256=h-qSx13fP8_Ny2IKW3wCNPwqRqW6-Iz1pqxD9ga9-dM,2308
|
96
98
|
podflow/upload/login.py,sha256=85sqr12T-3NH-TD3kAMzy4yb1KOheV3Tr0eGee7NCJo,4007
|
97
99
|
podflow/upload/time_key.py,sha256=6jZ3cxUjzj_umYDwH27R0YNZlLXxfhNp-CqV_K22wlo,967
|
98
100
|
podflow/upload/update_upload.py,sha256=_5tp1zPNsC9DdDnLzm-P8bLcOBuDov4eMRHp_861j80,3183
|
101
|
+
podflow/upload/upload_files.py,sha256=5QZUjnfH3kVTfKCo0673j19bh00JLTyA92TLAN9oVfU,1634
|
99
102
|
podflow/upload/upload_server.py,sha256=BFq3QrWE7U97LbC4EQiDhQXbLapEc4R00eRDBH12E6A,565
|
100
103
|
podflow/youtube/__init__.py,sha256=pgXod8gq0IijZxIkPSwgAOcb9JI5rd1mqMomoR7bcJ4,46
|
101
104
|
podflow/youtube/build.py,sha256=67m74rQOrvqU6ZZybP85ORpg3pOCkpoikttBbtO_PxY,12315
|
102
105
|
podflow/youtube/get.py,sha256=oO32GjTFvUgP5AfFX5AlIuXU2UT6QtOUOXWLFzi8XtI,17157
|
103
106
|
podflow/youtube/login.py,sha256=KYl--ya6Z1u0uIcOp9l8i3DIIj9hsYUDH4dtJjI0MLM,1295
|
104
|
-
podflow-
|
105
|
-
podflow-
|
106
|
-
podflow-
|
107
|
-
podflow-
|
108
|
-
podflow-
|
107
|
+
podflow-20250522.dist-info/METADATA,sha256=xM46jtPG8HRrJ_IY4WYaOTqePoRHvZtct2Z6lIdkrv8,14195
|
108
|
+
podflow-20250522.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
109
|
+
podflow-20250522.dist-info/entry_points.txt,sha256=mn7hD_c_dmpKe3XU0KNekheBvD01LhlJ9htY-Df0j2A,131
|
110
|
+
podflow-20250522.dist-info/top_level.txt,sha256=fUujhhz-RrMI8aGvi-3Ey5y7FQnpOOgoFw9OWM3yLCU,8
|
111
|
+
podflow-20250522.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|