podflow 20250308__py3-none-any.whl → 20250315__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/__init__.py +2 -1
- Podflow/basic/write_log.py +5 -14
- Podflow/httpfs/app_bottle.py +116 -71
- Podflow/main.py +6 -13
- Podflow/main_podcast.py +12 -9
- Podflow/main_upload.py +37 -5
- Podflow/repair/__init__.py +2 -0
- Podflow/repair/reverse_log.py +31 -0
- Podflow/upload/linked_client.py +1 -1
- Podflow/upload/linked_server.py +4 -4
- Podflow/upload/login.py +28 -0
- {podflow-20250308.dist-info → podflow-20250315.dist-info}/METADATA +1 -1
- {podflow-20250308.dist-info → podflow-20250315.dist-info}/RECORD +16 -13
- {podflow-20250308.dist-info → podflow-20250315.dist-info}/WHEEL +0 -0
- {podflow-20250308.dist-info → podflow-20250315.dist-info}/entry_points.txt +0 -0
- {podflow-20250308.dist-info → podflow-20250315.dist-info}/top_level.txt +0 -0
Podflow/__init__.py
CHANGED
@@ -114,8 +114,9 @@ class Application_gVar:
|
|
114
114
|
self.overall_rss = "" # 更新后的rss文本
|
115
115
|
self.make_up_file_format = {} # 补全缺失媒体字典
|
116
116
|
self.make_up_file_format_fail = {} # 补全缺失媒体失败字典
|
117
|
-
|
117
|
+
|
118
118
|
self.upload_original = [] # 原始上传信息字典
|
119
|
+
self.upload_data = {} # 上传用户账号密码字典
|
119
120
|
|
120
121
|
self.shortcuts_url = {} # 输出至shortcut的url字典
|
121
122
|
|
Podflow/basic/write_log.py
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
import re
|
5
5
|
from datetime import datetime
|
6
|
-
from Podflow.basic.file_save import file_save
|
7
6
|
|
8
7
|
|
9
8
|
# 日志模块
|
@@ -19,26 +18,18 @@ def write_log(
|
|
19
18
|
current_time = datetime.now()
|
20
19
|
# 格式化输出, 只保留年月日时分秒
|
21
20
|
formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
|
22
|
-
# 打开文件, 并读取原有内容
|
23
|
-
try:
|
24
|
-
with open(file_name, "r", encoding="utf-8") as file:
|
25
|
-
contents = file.read()
|
26
|
-
except FileNotFoundError:
|
27
|
-
contents = ""
|
28
21
|
# 将新的日志内容添加在原有内容之前
|
29
22
|
log_in = re.sub(r"\033\[[0-9;]+m", "", log)
|
30
23
|
log_in = re.sub(r"\n", "", log_in)
|
31
|
-
if only_log
|
32
|
-
only_log = re.sub(r"\033\[[0-9;]+m", "", str(only_log))
|
33
|
-
else:
|
34
|
-
only_log = ""
|
24
|
+
only_log = re.sub(r"\033\[[0-9;]+m", "", str(only_log)) if only_log else ""
|
35
25
|
new_contents = (
|
36
|
-
f"{formatted_time} {log_in}{only_log}\n
|
26
|
+
f"{formatted_time} {log_in}{only_log}\n"
|
37
27
|
if only_log
|
38
|
-
else f"{formatted_time} {log_in}\n
|
28
|
+
else f"{formatted_time} {log_in}\n"
|
39
29
|
)
|
40
30
|
# 将新的日志内容写入文件
|
41
|
-
|
31
|
+
with open(file_name, "a", encoding="utf-8") as file:
|
32
|
+
file.write(new_contents)
|
42
33
|
if display:
|
43
34
|
formatted_time_mini = current_time.strftime("%H:%M:%S")
|
44
35
|
log_print = f"{formatted_time_mini}|{log}" if time_display else f"{log}"
|
Podflow/httpfs/app_bottle.py
CHANGED
@@ -5,9 +5,11 @@ 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
|
8
|
+
from bottle import Bottle, abort, redirect, request, static_file, response
|
9
9
|
from Podflow import gVar
|
10
|
+
from Podflow.upload.login import create
|
10
11
|
from Podflow.basic.write_log import write_log
|
12
|
+
from Podflow.upload.time_key import check_time_key
|
11
13
|
|
12
14
|
|
13
15
|
class bottle_app:
|
@@ -16,16 +18,27 @@ class bottle_app:
|
|
16
18
|
self.app_bottle = Bottle() # 创建 Bottle 应用
|
17
19
|
self.bottle_print = [] # 存储打印日志
|
18
20
|
self.setup_routes() # 设置路由
|
21
|
+
self.logname = "httpfs.log" # 默认日志文件名
|
22
|
+
self.http_fs = False
|
19
23
|
|
20
|
-
def setup_routes(self):
|
24
|
+
def setup_routes(self, upload=False):
|
25
|
+
# 设置/favicon.ico路由,回调函数为favicon
|
26
|
+
self.app_bottle.route("/favicon.ico", callback=self.favicon)
|
21
27
|
# 设置根路由,回调函数为home
|
22
28
|
self.app_bottle.route("/", callback=self.home)
|
23
29
|
# 设置/shutdown路由,回调函数为shutdown
|
24
30
|
self.app_bottle.route("/shutdown", callback=self.shutdown)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
if upload:
|
32
|
+
self.app_bottle.route("/newuser", callback=self.new_user)
|
33
|
+
self.app_bottle.route("/login", callback=self.login)
|
34
|
+
else:
|
35
|
+
# 设置其他路由,回调函数为serve_static
|
36
|
+
self.app_bottle.route("/<filename:path>", callback=self.serve_static)
|
37
|
+
|
38
|
+
# 设置日志文件名及写入判断
|
39
|
+
def set_logname(self, logname="httpfs.log", http_fs=False):
|
40
|
+
self.logname = logname
|
41
|
+
self.http_fs = http_fs
|
29
42
|
|
30
43
|
# 判断token是否正确的验证模块
|
31
44
|
def token_judgment(self, token, VALID_TOKEN="", filename="", foldername=""):
|
@@ -62,14 +75,14 @@ class bottle_app:
|
|
62
75
|
status = f"{color}{status}\033[0m"
|
63
76
|
now_time = datetime.now().strftime("%H:%M:%S")
|
64
77
|
client_ip = f"\033[34m{client_ip}\033[0m"
|
65
|
-
if
|
78
|
+
if self.http_fs:
|
66
79
|
write_log(
|
67
80
|
f"{client_ip} {filename} {status}",
|
68
81
|
None,
|
69
82
|
False,
|
70
83
|
True,
|
71
84
|
None,
|
72
|
-
|
85
|
+
self.logname,
|
73
86
|
)
|
74
87
|
for suffix in suffixs:
|
75
88
|
filename = filename.replace(suffix, "")
|
@@ -82,8 +95,7 @@ class bottle_app:
|
|
82
95
|
gVar.server_process_print_flag[0] = "keep"
|
83
96
|
# 如果gVar.server_process_print_flag[0]为"keep"且self.bottle_print不为空,则打印日志
|
84
97
|
if (
|
85
|
-
gVar.server_process_print_flag[0] == "keep"
|
86
|
-
and self.bottle_print
|
98
|
+
gVar.server_process_print_flag[0] == "keep" and self.bottle_print
|
87
99
|
): # 如果设置为保持输出, 则打印日志
|
88
100
|
# 遍历self.bottle_print中的每个元素,并打印
|
89
101
|
for info_print in self.bottle_print:
|
@@ -91,25 +103,48 @@ class bottle_app:
|
|
91
103
|
# 清空self.bottle_print
|
92
104
|
self.bottle_print.clear()
|
93
105
|
|
106
|
+
# 输出请求日志的函数
|
107
|
+
def print_out(self, filename, status):
|
108
|
+
client_ip = request.remote_addr
|
109
|
+
client_port = request.environ.get("REMOTE_PORT")
|
110
|
+
if client_port:
|
111
|
+
client_ip = f"{client_ip}:{client_port}"
|
112
|
+
if filename not in [
|
113
|
+
"favicon.ico",
|
114
|
+
"/",
|
115
|
+
"shutdown",
|
116
|
+
"newuser",
|
117
|
+
"login",
|
118
|
+
]:
|
119
|
+
bottle_channelid = (
|
120
|
+
gVar.channelid_youtube_ids_original
|
121
|
+
| gVar.channelid_bilibili_ids_original
|
122
|
+
| {"channel_audiovisual/": "", "channel_rss/": ""}
|
123
|
+
) # 合并多个频道 ID
|
124
|
+
for (
|
125
|
+
bottle_channelid_key,
|
126
|
+
bottle_channelid_value,
|
127
|
+
) in bottle_channelid.items():
|
128
|
+
filename = filename.replace(
|
129
|
+
bottle_channelid_key, bottle_channelid_value
|
130
|
+
) # 替换频道路径
|
131
|
+
if status == 200 and request.headers.get(
|
132
|
+
"Range"
|
133
|
+
): # 如果是部分请求, 则返回 206 状态
|
134
|
+
status = 206
|
135
|
+
self.add_bottle_print(client_ip, filename, status) # 输出日志
|
136
|
+
self.cherry_print(False)
|
137
|
+
|
94
138
|
# 主路由处理根路径请求
|
95
139
|
def home(self):
|
96
140
|
VALID_TOKEN = gVar.config["token"] # 从配置中读取主验证 Token
|
97
|
-
|
98
|
-
# 输出请求日志的函数
|
99
|
-
def print_out(status):
|
100
|
-
client_ip = request.remote_addr # 获取客户端 IP 地址
|
101
|
-
client_port = request.environ.get("REMOTE_PORT") # 获取客户端端口
|
102
|
-
if client_port:
|
103
|
-
client_ip = f"{client_ip}:{client_port}" # 如果有端口信息, 则包括端口
|
104
|
-
self.add_bottle_print(client_ip, "/", status) # 添加日志信息
|
105
|
-
self.cherry_print(False)
|
106
|
-
|
107
141
|
token = request.query.get("token") # 获取请求中的 Token
|
142
|
+
|
108
143
|
if self.token_judgment(token, VALID_TOKEN): # 验证 Token
|
109
|
-
print_out(303) # 如果验证成功, 输出 200 状态
|
144
|
+
self.print_out("/", 303) # 如果验证成功, 输出 200 状态
|
110
145
|
return redirect("https://github.com/gruel-zxz/podflow") # 返回正常响应
|
111
146
|
else:
|
112
|
-
print_out(401) # 如果验证失败, 输出 401 状态
|
147
|
+
self.print_out("/", 401) # 如果验证失败, 输出 401 状态
|
113
148
|
abort(401, "Unauthorized: Invalid Token") # 返回未经授权错误
|
114
149
|
|
115
150
|
# 路由处理关闭服务器的请求
|
@@ -120,36 +155,21 @@ class bottle_app:
|
|
120
155
|
Shutdown_VALID_TOKEN = hashlib.sha256(
|
121
156
|
Shutdown_VALID_TOKEN.encode()
|
122
157
|
).hexdigest() # 用于服务器关闭的验证 Token
|
123
|
-
|
124
|
-
# 输出关闭请求日志的函数
|
125
|
-
def print_out(status):
|
126
|
-
client_ip = request.remote_addr
|
127
|
-
client_port = request.environ.get("REMOTE_PORT")
|
128
|
-
if client_port:
|
129
|
-
client_ip = f"{client_ip}:{client_port}"
|
130
|
-
self.add_bottle_print(client_ip, "shutdown", status)
|
131
|
-
self.cherry_print(False)
|
132
|
-
|
133
158
|
token = request.query.get("token") # 获取请求中的 Token
|
159
|
+
|
134
160
|
if self.token_judgment(
|
135
161
|
token, Shutdown_VALID_TOKEN
|
136
162
|
): # 验证 Token 是否为关闭用的 Token
|
137
|
-
print_out(200) # 如果验证成功, 输出 200 状态
|
163
|
+
self.print_out("shutdown", 200) # 如果验证成功, 输出 200 状态
|
138
164
|
cherrypy.engine.exit() # 使用 CherryPy 提供的停止功能来关闭服务器
|
139
165
|
return "Shutting down..." # 返回关机响应
|
140
166
|
else:
|
141
|
-
print_out(401) # 如果验证失败, 输出 401 状态
|
167
|
+
self.print_out("shutdown", 401) # 如果验证失败, 输出 401 状态
|
142
168
|
abort(401, "Unauthorized: Invalid Token") # 返回未经授权错误
|
143
169
|
|
144
170
|
# 路由处理 favicon 请求
|
145
171
|
def favicon(self):
|
146
|
-
#
|
147
|
-
client_ip = request.remote_addr
|
148
|
-
# 如果存在客户端端口,则将 IP 地址和端口拼接
|
149
|
-
if client_port := request.environ.get("REMOTE_PORT"):
|
150
|
-
client_ip = f"{client_ip}:{client_port}"
|
151
|
-
self.add_bottle_print(client_ip, "favicon.ico", 303) # 输出访问 favicon 的日志
|
152
|
-
self.cherry_print(False)
|
172
|
+
self.print_out("favicon.ico", 303) # 输出访问 favicon 的日志
|
153
173
|
return redirect(
|
154
174
|
"https://raw.githubusercontent.com/gruel-zxz/podflow/main/Podflow.png"
|
155
175
|
) # 重定向到图标 URL
|
@@ -163,33 +183,8 @@ class bottle_app:
|
|
163
183
|
bottle_filename.lower(): f"{bottle_filename}.xml", # 文件路径映射, 支持大小写不敏感的文件名
|
164
184
|
f"{bottle_filename.lower()}.xml": f"{bottle_filename}.xml", # 同上, 支持带 .xml 后缀
|
165
185
|
}
|
166
|
-
bottle_channelid = (
|
167
|
-
gVar.channelid_youtube_ids_original
|
168
|
-
| gVar.channelid_bilibili_ids_original
|
169
|
-
| {"channel_audiovisual/": "", "channel_rss/": ""}
|
170
|
-
) # 合并多个频道 ID
|
171
186
|
token = request.query.get("token") # 获取请求中的 Token
|
172
187
|
|
173
|
-
# 输出文件请求日志的函数
|
174
|
-
def print_out(filename, status):
|
175
|
-
client_ip = request.remote_addr
|
176
|
-
client_port = request.environ.get("REMOTE_PORT")
|
177
|
-
if client_port:
|
178
|
-
client_ip = f"{client_ip}:{client_port}"
|
179
|
-
for (
|
180
|
-
bottle_channelid_key,
|
181
|
-
bottle_channelid_value,
|
182
|
-
) in bottle_channelid.items():
|
183
|
-
filename = filename.replace(
|
184
|
-
bottle_channelid_key, bottle_channelid_value
|
185
|
-
) # 替换频道路径
|
186
|
-
if status == 200 and request.headers.get(
|
187
|
-
"Range"
|
188
|
-
): # 如果是部分请求, 则返回 206 状态
|
189
|
-
status = 206
|
190
|
-
self.add_bottle_print(client_ip, filename, status) # 输出日志
|
191
|
-
self.cherry_print(False)
|
192
|
-
|
193
188
|
# 文件是否存在检查的函数
|
194
189
|
def file_exist(token, VALID_TOKEN, filename, foldername=""):
|
195
190
|
# 验证 Token
|
@@ -198,18 +193,18 @@ class bottle_app:
|
|
198
193
|
): # 验证 Token
|
199
194
|
# 如果文件存在, 返回文件
|
200
195
|
if os.path.exists(filename): # 如果文件存在, 返回文件
|
201
|
-
print_out(filename, 200)
|
196
|
+
self.print_out(filename, 200)
|
202
197
|
return static_file(filename, root=".")
|
203
198
|
else: # 如果文件不存在, 返回 404 错误
|
204
|
-
print_out(filename, 404)
|
199
|
+
self.print_out(filename, 404)
|
205
200
|
abort(404, "File not found")
|
206
201
|
else: # 如果 Token 验证失败, 返回 401 错误
|
207
|
-
print_out(filename, 401)
|
202
|
+
self.print_out(filename, 401)
|
208
203
|
abort(401, "Unauthorized: Invalid Token")
|
209
204
|
|
210
205
|
# 处理不同的文件路径
|
211
206
|
if filename in ["channel_audiovisual/", "channel_rss/"]:
|
212
|
-
print_out(filename, 404)
|
207
|
+
self.print_out(filename, 404)
|
213
208
|
abort(404, "File not found")
|
214
209
|
elif filename.startswith("channel_audiovisual/"):
|
215
210
|
return file_exist(token, VALID_TOKEN, filename, "channel_audiovisual/")
|
@@ -220,8 +215,58 @@ class bottle_app:
|
|
220
215
|
elif filename.lower() in shared_files:
|
221
216
|
return file_exist(token, VALID_TOKEN, shared_files[filename.lower()])
|
222
217
|
else:
|
223
|
-
print_out(filename, 404) # 如果文件路径未匹配, 返回 404 错误
|
218
|
+
self.print_out(filename, 404) # 如果文件路径未匹配, 返回 404 错误
|
224
219
|
abort(404, "File not found")
|
225
220
|
|
221
|
+
# 路由获取账号密码请求
|
222
|
+
def new_user(self):
|
223
|
+
seed = "We need to generate an account password for uploading non one-time items that need to be saved."
|
224
|
+
token = request.query.get("token") # 获取请求中的 Token
|
225
|
+
response.content_type = 'application/json'
|
226
|
+
|
227
|
+
if check_time_key(token, seed): # 验证 Token
|
228
|
+
username, password = create() # 生成用户名和密码
|
229
|
+
self.print_out("newuser", 200)
|
230
|
+
return {
|
231
|
+
"code":0,
|
232
|
+
"message":"Get New Username And Password Success",
|
233
|
+
"data": {
|
234
|
+
"username": username,
|
235
|
+
"password": password,
|
236
|
+
},
|
237
|
+
}
|
238
|
+
else:
|
239
|
+
self.print_out("newuser", 401)
|
240
|
+
return {
|
241
|
+
"code":-1,
|
242
|
+
"message":"Unauthorized: Invalid Token",
|
243
|
+
}
|
244
|
+
|
245
|
+
# 路由处理登陆请求
|
246
|
+
def login(self):
|
247
|
+
upload_data = gVar.upload_data
|
248
|
+
username = request.query.get("username")
|
249
|
+
password = request.query.get("password")
|
250
|
+
|
251
|
+
if username in upload_data:
|
252
|
+
if upload_data[username] == password:
|
253
|
+
self.print_out("login", 200)
|
254
|
+
return {
|
255
|
+
"code":0,
|
256
|
+
"message":"Login Success",
|
257
|
+
}
|
258
|
+
else:
|
259
|
+
self.print_out("login", 401)
|
260
|
+
return {
|
261
|
+
"code":-3,
|
262
|
+
"message":"Password Error",
|
263
|
+
}
|
264
|
+
else:
|
265
|
+
self.print_out("login", 401)
|
266
|
+
return {
|
267
|
+
"code":-2,
|
268
|
+
"message":"Username Error",
|
269
|
+
}
|
270
|
+
|
226
271
|
|
227
272
|
bottle_app_instance = bottle_app()
|
Podflow/main.py
CHANGED
@@ -1,33 +1,26 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
import signal
|
4
|
-
import sys
|
5
|
-
from datetime import datetime
|
6
3
|
from importlib.metadata import version
|
7
4
|
from Podflow import parse
|
8
5
|
from Podflow.main_upload import main_upload
|
9
6
|
from Podflow.main_podcast import main_podcast
|
10
7
|
from Podflow.basic.time_print import time_print
|
8
|
+
from Podflow.repair.reverse_log import reverse_log
|
11
9
|
from Podflow.parse_arguments import parse_arguments
|
12
10
|
|
13
11
|
|
14
|
-
def signal_handler(sig, frame):
|
15
|
-
time_print("Podflow被中断, 正在退出...")
|
16
|
-
sys.exit(0)
|
17
|
-
|
18
|
-
|
19
12
|
def main():
|
20
|
-
# 注册SIGINT信号处理器(Ctrl+C)
|
21
|
-
signal.signal(signal.SIGINT, signal_handler)
|
22
|
-
|
23
13
|
# 获取传入的参数
|
24
14
|
parse_arguments()
|
25
15
|
# 开始运行
|
26
16
|
if parse.upload:
|
27
|
-
time_print("Podflow
|
17
|
+
time_print("Podflow|接收服务开始运行...")
|
18
|
+
reverse_log("upload")
|
28
19
|
main_upload()
|
29
20
|
else:
|
30
|
-
time_print(f"Podflow|{version('Podflow')}
|
21
|
+
time_print(f"Podflow|{version('Podflow')} 开始运行...")
|
22
|
+
reverse_log("Podflow")
|
23
|
+
reverse_log("httpfs")
|
31
24
|
main_podcast()
|
32
25
|
|
33
26
|
|
Podflow/main_podcast.py
CHANGED
@@ -6,13 +6,13 @@ import json
|
|
6
6
|
import time
|
7
7
|
import urllib
|
8
8
|
import subprocess
|
9
|
-
from datetime import datetime
|
10
9
|
|
11
10
|
import cherrypy
|
12
11
|
|
13
12
|
# 基本功能模块
|
14
13
|
from Podflow import gVar, parse
|
15
14
|
from Podflow.basic.split_dict import split_dict
|
15
|
+
from Podflow.basic.time_print import time_print
|
16
16
|
|
17
17
|
# 网络和 HTTP 模块
|
18
18
|
from Podflow.httpfs.port_judge import port_judge
|
@@ -68,6 +68,13 @@ def main_podcast():
|
|
68
68
|
port = gVar.config["port"]
|
69
69
|
hostip = "0.0.0.0"
|
70
70
|
if port_judge(hostip, port):
|
71
|
+
# 设置路由
|
72
|
+
bottle_app_instance.setup_routes(upload=False)
|
73
|
+
# 设置logname
|
74
|
+
bottle_app_instance.set_logname(
|
75
|
+
logname="httpfs.log",
|
76
|
+
http_fs=gVar.config["httpfs"],
|
77
|
+
)
|
71
78
|
# 启动 CherryPy 服务器
|
72
79
|
cherrypy.tree.graft(
|
73
80
|
bottle_app_instance.app_bottle
|
@@ -85,16 +92,12 @@ def main_podcast():
|
|
85
92
|
}
|
86
93
|
)
|
87
94
|
cherrypy.engine.start() # 启动 CherryPy 服务器
|
88
|
-
|
89
|
-
f"{datetime.now().strftime('%H:%M:%S')}|HTTP服务器启动, 端口: \033[32m{port}\033[0m"
|
90
|
-
)
|
95
|
+
time_print(f"HTTP服务器启动, 端口: \033[32m{port}\033[0m")
|
91
96
|
if parse.httpfs: # HttpFS参数判断, 是否继续运行
|
92
97
|
cherrypy.engine.block() # 阻止程序退出, 保持HTTP服务运行
|
93
98
|
sys.exit(0)
|
94
99
|
else:
|
95
|
-
|
96
|
-
f"{datetime.now().strftime('%H:%M:%S')}|HTTP服务器端口: \033[32m{port}\033[0m, \033[31m被占用\033[0m"
|
97
|
-
)
|
100
|
+
time_print(f"HTTP服务器端口: \033[32m{port}\033[0m, \033[31m被占用\033[0m")
|
98
101
|
if parse.httpfs:
|
99
102
|
sys.exit(0)
|
100
103
|
# 主流程
|
@@ -191,7 +194,7 @@ def main_podcast():
|
|
191
194
|
# 更新并保存上传列表
|
192
195
|
update_upload()
|
193
196
|
else:
|
194
|
-
|
197
|
+
time_print("频道无更新内容")
|
195
198
|
|
196
199
|
# 将需要更新转为否
|
197
200
|
gVar.update_generate_rss = False
|
@@ -215,4 +218,4 @@ def main_podcast():
|
|
215
218
|
time.sleep(parse.time_delay)
|
216
219
|
# 关闭CherryPy服务器
|
217
220
|
cherrypy.engine.exit()
|
218
|
-
|
221
|
+
time_print("Podflow运行结束")
|
Podflow/main_upload.py
CHANGED
@@ -2,24 +2,56 @@
|
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
4
|
import sys
|
5
|
-
import
|
5
|
+
import cherrypy
|
6
|
+
from Podflow.upload.login import get_login
|
6
7
|
from Podflow.basic.time_print import time_print
|
8
|
+
from Podflow.basic.folder_build import folder_build
|
9
|
+
from Podflow.httpfs.app_bottle import bottle_app_instance
|
7
10
|
from Podflow.upload.linked_server import handle_discovery, usable_port
|
8
11
|
|
9
12
|
|
10
13
|
def main_upload():
|
14
|
+
# 构建文件夹channel_audiovisual
|
15
|
+
folder_build("channel_audiovisual")
|
16
|
+
# 构建文件夹channel_data
|
17
|
+
folder_build("channel_data")
|
18
|
+
# 获取账号密码
|
19
|
+
get_login()
|
11
20
|
# 服务发现相关配置
|
12
21
|
broadcast_port = 37001 # 服务发现用端口
|
13
22
|
service_port = 5000 # 实际服务端口
|
23
|
+
hostip = "0.0.0.0"
|
14
24
|
|
15
25
|
broadcast_port = usable_port(broadcast_port, 37010)
|
16
26
|
service_port = usable_port(service_port, 5010)
|
27
|
+
|
17
28
|
if broadcast_port and service_port:
|
18
|
-
|
19
|
-
|
20
|
-
|
29
|
+
# 设置路由
|
30
|
+
bottle_app_instance.setup_routes(upload=True)
|
31
|
+
# 设置logname
|
32
|
+
bottle_app_instance.set_logname(
|
33
|
+
logname="upload.log",
|
34
|
+
http_fs=True,
|
35
|
+
)
|
36
|
+
# 启动 CherryPy 服务器
|
37
|
+
cherrypy.tree.graft(
|
38
|
+
bottle_app_instance.app_bottle
|
39
|
+
) # 将 Bottle 应用嵌入到 CherryPy 中
|
40
|
+
cherrypy.config.update(
|
41
|
+
{
|
42
|
+
"global": {
|
43
|
+
"tools.sessions.on": True, # 启用会话支持
|
44
|
+
"server.socket_host": hostip, # 监听所有 IP 地址
|
45
|
+
"server.socket_port": service_port, # 设置监听端口
|
46
|
+
"log.screen": False, # 禁用屏幕日志输出
|
47
|
+
"log.access_file": "", # 关闭访问日志
|
48
|
+
"log.error_file": "", # 关闭错误日志
|
49
|
+
}
|
50
|
+
}
|
21
51
|
)
|
22
|
-
|
52
|
+
cherrypy.engine.start() # 启动 CherryPy 服务器
|
53
|
+
time_print(f"上传服务已启动|端口: \033[32m{service_port}\033[0m")
|
54
|
+
# 服务发现
|
23
55
|
handle_discovery(broadcast_port, service_port)
|
24
56
|
else:
|
25
57
|
if not broadcast_port:
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Podflow/repair/reverse_log.py
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
import re
|
5
|
+
from Podflow.basic.time_print import time_print
|
6
|
+
|
7
|
+
|
8
|
+
def reverse_log(filename):
|
9
|
+
try:
|
10
|
+
with open(f"{filename}.log", "r", encoding="utf-8") as file:
|
11
|
+
lines = file.readlines()
|
12
|
+
except Exception:
|
13
|
+
return
|
14
|
+
num = 0
|
15
|
+
end_num = len(lines) - 1
|
16
|
+
|
17
|
+
def date_time(num):
|
18
|
+
pattern = r"^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"
|
19
|
+
date_str = lines[num][:19]
|
20
|
+
return re.match(pattern, date_str)
|
21
|
+
|
22
|
+
while not date_time(num):
|
23
|
+
num += 1
|
24
|
+
while not date_time(end_num):
|
25
|
+
end_num -= 1
|
26
|
+
if end_num > num and lines[num][:19] > lines[end_num][:19]:
|
27
|
+
# 反转行的顺序
|
28
|
+
reversed_lines = lines[::-1]
|
29
|
+
with open(f"{filename}.log", "w", encoding="utf-8") as file:
|
30
|
+
file.writelines(reversed_lines)
|
31
|
+
time_print(f"{filename}.log反转成功")
|
Podflow/upload/linked_client.py
CHANGED
Podflow/upload/linked_server.py
CHANGED
@@ -33,9 +33,9 @@ def handle_discovery(broadcast_port, service_port):
|
|
33
33
|
# 设置套接字选项,允许广播
|
34
34
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
35
35
|
# 绑定套接字到广播端口
|
36
|
-
sock.bind(("", broadcast_port))
|
36
|
+
sock.bind(("0.0.0.0", broadcast_port))
|
37
37
|
# 打印发现服务已启动
|
38
|
-
time_print("
|
38
|
+
time_print(f"发现服务已启动|端口: \033[32m{broadcast_port}\033[0m")
|
39
39
|
# 无限循环,等待接收广播消息
|
40
40
|
while True:
|
41
41
|
# 接收广播消息
|
@@ -45,11 +45,11 @@ def handle_discovery(broadcast_port, service_port):
|
|
45
45
|
# 检查消息是否包含时间关键字
|
46
46
|
if check_time_key(data ,"PODFLOW_DISCOVER_SERVER_REQUEST"):
|
47
47
|
# 打印接收到的发现请求成功
|
48
|
-
time_print(f"来自{addr}的发现请求\033[32m成功\033[0m")
|
48
|
+
time_print(f"来自{addr[0]}的发现请求\033[32m成功\033[0m")
|
49
49
|
# 构造响应消息
|
50
50
|
response = f"PODFLOW_SERVER_INFO|{service_port}".encode()
|
51
51
|
# 发送响应消息
|
52
52
|
sock.sendto(response, addr)
|
53
53
|
else:
|
54
54
|
# 打印接收到的发现请求失败
|
55
|
-
time_print(f"来自{addr}的发现请求\033[31m失败\033[0m")
|
55
|
+
time_print(f"来自{addr[0]}的发现请求\033[31m失败\033[0m")
|
Podflow/upload/login.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Podflow/upload/login.py
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
import os
|
5
|
+
import json
|
6
|
+
import uuid
|
7
|
+
import hashlib
|
8
|
+
from Podflow import gVar
|
9
|
+
from Podflow.basic.file_save import file_save
|
10
|
+
|
11
|
+
|
12
|
+
def get_login():
|
13
|
+
try:
|
14
|
+
with open("channel_data/upload_login.json", "r") as file:
|
15
|
+
upload_data = file.read()
|
16
|
+
gVar.upload_data = json.loads(upload_data)
|
17
|
+
except Exception:
|
18
|
+
file_save(gVar.upload_data, "upload_login.json", "channel_data")
|
19
|
+
|
20
|
+
|
21
|
+
def create():
|
22
|
+
new_username = str(uuid.uuid4())
|
23
|
+
while new_username in gVar.upload_data:
|
24
|
+
new_username = str(uuid.uuid4())
|
25
|
+
new_password = hashlib.sha256(os.urandom(64)).hexdigest()
|
26
|
+
gVar.upload_data[new_username] = new_password
|
27
|
+
file_save(gVar.upload_data, "upload_login.json", "channel_data")
|
28
|
+
return new_username, new_password
|
@@ -1,9 +1,9 @@
|
|
1
|
-
Podflow/__init__.py,sha256
|
1
|
+
Podflow/__init__.py,sha256=-TdRoLAAMAPVNx2S2qSWR2vN-ZRD8wsEjZR4X1-7U1Q,6964
|
2
2
|
Podflow/download_and_build.py,sha256=LeLjLHnF5N9vdrroDsB-mT4UKY2OwPSL3APUAkhTuwc,671
|
3
3
|
Podflow/ffmpeg_judge.py,sha256=krttVs1PDot_0CDq5rmtUIpchiaiqtAkPYFQRLG6OQM,1275
|
4
|
-
Podflow/main.py,sha256=
|
5
|
-
Podflow/main_podcast.py,sha256=
|
6
|
-
Podflow/main_upload.py,sha256=
|
4
|
+
Podflow/main.py,sha256=tevbRqCDPuIrKuViI1Zm2lfdfjushYd7Nai6xZCGF4k,739
|
5
|
+
Podflow/main_podcast.py,sha256=6p-JrDfLVOYic_X_wsVrtjOZKH1SbMRWOEe7KO2vsZQ,8455
|
6
|
+
Podflow/main_upload.py,sha256=9FoIEO7kRwGwyyF-KKKEz5vRO9vE9_ab2VE6xTMroeM,2296
|
7
7
|
Podflow/parse_arguments.py,sha256=H2OXiOIHUuEUKOD0fk3zt_m1VsorGkL0eTcvx4N_C3Y,2441
|
8
8
|
Podflow/basic/__init__.py,sha256=SyFA_F_0-zn1VejCL83IPeZx1k2HCiqNY-0l0bp1N88,44
|
9
9
|
Podflow/basic/file_save.py,sha256=mstWM6njYtCpq2sa28JD_neClvVLcjJOrGlCXBjUnZs,696
|
@@ -19,7 +19,7 @@ Podflow/basic/time_format.py,sha256=Rddq-5wQgo6IrgiMlcMgDA52vQnMvWZvZC8g1Bj3BaQ,
|
|
19
19
|
Podflow/basic/time_print.py,sha256=2M22bcHRNEkaTZ1lvbHEILUYXEQImJJmOzHa9kamDR8,323
|
20
20
|
Podflow/basic/time_stamp.py,sha256=vf0p6FIK2-ZN2p2sotbpf4dewQMy-Vior-aREYfT0Zc,1888
|
21
21
|
Podflow/basic/vary_replace.py,sha256=aecFDuAOvQjTpgtoSW5uDu8Tx_YTs4bCFF9imVFkfVY,211
|
22
|
-
Podflow/basic/write_log.py,sha256=
|
22
|
+
Podflow/basic/write_log.py,sha256=3S7afoJvVHAGRa8SV9y71YL2_P_QvQ4QXn6LQUTTmlM,1169
|
23
23
|
Podflow/bilibili/__init__.py,sha256=ekvpCzR4bg6ar73Gq0YWQcPXND4TEqP46pb9iLyke9g,47
|
24
24
|
Podflow/bilibili/build.py,sha256=Oeh6Cqb61F5zQWe8ohDP0QKwykAa4_I2fa-Yl6ZxkCw,7957
|
25
25
|
Podflow/bilibili/get.py,sha256=PXPh_H8B_zP9dhqe6sA_QCeJcdnriBCpbF7mPq46xMw,20337
|
@@ -40,7 +40,7 @@ Podflow/download/show_progress.py,sha256=7oGzhj_frO2A1o5JeGuHn7bHtma5oPpD_IWcctI
|
|
40
40
|
Podflow/download/wait_animation.py,sha256=E2V3cm-10e5Iif40oU722OfzDe7YiLMbDqsjZ6dshBE,1056
|
41
41
|
Podflow/download/youtube_and_bilibili_download.py,sha256=0uuEO2ybyLlg9uOButjqFvmIkCfq6xiQ7QLV2_u4c_M,1294
|
42
42
|
Podflow/httpfs/__init__.py,sha256=agnAtd2Xe0qfOrElKgoBattAVqUBdj79wU2e2UOpcJM,45
|
43
|
-
Podflow/httpfs/app_bottle.py,sha256=
|
43
|
+
Podflow/httpfs/app_bottle.py,sha256=ZkCRXYrBJFUEatboUEB6Og35JoguWGnnuxImFLflsVA,11424
|
44
44
|
Podflow/httpfs/port_judge.py,sha256=RrBTxD6lXHbkfiDMu69-EUv0kbflfu1HpPfpB5Wz3MU,764
|
45
45
|
Podflow/makeup/__init__.py,sha256=HaBchKbUjRqqXSGCkMfEqLOyx3tlqB2htXvTDs59owI,45
|
46
46
|
Podflow/makeup/del_makeup_format_fail.py,sha256=rUSJD5lXMBM5pCde1amrtF6s93MMHp66-NHCXZy56AI,642
|
@@ -75,19 +75,22 @@ Podflow/netscape/get_cookie_dict.py,sha256=ptT2H8ZwFseK8EmpH0jn-lhzh-KCciOOPwpAJ
|
|
75
75
|
Podflow/remove/__init__.py,sha256=kns-jfTXH8lXh9OQ5E5-llsrAPlET5rl6RYpjoZKav8,45
|
76
76
|
Podflow/remove/remove_dir.py,sha256=tah3LCD0bCcf5dDg3NrHuseaje3-31C5NLNupMg15TU,1099
|
77
77
|
Podflow/remove/remove_file.py,sha256=ACO2iK8RAZKGJ08uABbzGwu5-B0RLklQ-EOOkSuPFiU,982
|
78
|
+
Podflow/repair/__init__.py,sha256=sfrjrUGdBuCri8x51oassbkHJMDqmEp0MMZHodMxYNM,45
|
79
|
+
Podflow/repair/reverse_log.py,sha256=nGVM4DOcnPz-VXJG6aHoKc1E461edYlaYoQYx7i6atQ,957
|
78
80
|
Podflow/upload/__init__.py,sha256=9uOIL8vr_vP_XYrhfZ4IDZmfSGyCf0_MpLOc-KnbpSY,45
|
79
81
|
Podflow/upload/add_upload.py,sha256=8kxHDLFa225WFze3oTPNtOWbcECF--bQXuALfsRJLoo,1432
|
80
82
|
Podflow/upload/get_upload_original.py,sha256=h2aoutZ-po40N8auRDbKvse14261Y5H7vHgfAN23vV0,4358
|
81
|
-
Podflow/upload/linked_client.py,sha256=
|
82
|
-
Podflow/upload/linked_server.py,sha256=
|
83
|
+
Podflow/upload/linked_client.py,sha256=ODaS95VNKcAUpfcnMxZBM4nHlZ6S9jBDFpDEmapzT5I,3242
|
84
|
+
Podflow/upload/linked_server.py,sha256=Tf3ANSryGuqjHsH1EqCrCA_pxo_dDuoYfCBzSgVVTrI,2264
|
85
|
+
Podflow/upload/login.py,sha256=ovQKdtrddsoea_4s-SpnMHTVstH1pWoo0dFx1dpU_sU,798
|
83
86
|
Podflow/upload/time_key.py,sha256=aR6xVe9x7ry8dKSHKoFLSUIfor2CoCuv8N9NRmsnUVo,967
|
84
87
|
Podflow/upload/update_upload.py,sha256=4B5HyWwfmc_4Z5ZS_Wt2VcL6sgQFvq3JEl0Qubh7TwE,3183
|
85
88
|
Podflow/youtube/__init__.py,sha256=-bdMyuw-wxoz2miVkp284amS4Qg0k7VN0JPuGF-cXlM,46
|
86
89
|
Podflow/youtube/build.py,sha256=o6gld4qMph7UKq9pdO2E4dmtOA8brCK4sa_-vKEtYMM,12006
|
87
90
|
Podflow/youtube/get.py,sha256=dFLyiHttygqdJltwC29jD_v8wwoLynE5NUdow_0wERI,16970
|
88
91
|
Podflow/youtube/login.py,sha256=DlS_ZG4g6CKWqS5ojE4UwFJSCSZDsXbeuDVgHtQAa4A,1380
|
89
|
-
podflow-
|
90
|
-
podflow-
|
91
|
-
podflow-
|
92
|
-
podflow-
|
93
|
-
podflow-
|
92
|
+
podflow-20250315.dist-info/METADATA,sha256=sWLPHwYRGI7rcDccvaXhU_KSsgq30adtNg2lgiN_Yjo,14030
|
93
|
+
podflow-20250315.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
94
|
+
podflow-20250315.dist-info/entry_points.txt,sha256=44nj8jJB7bo1JLNrKQZmwMGEA1OalrALJ0tF_G0yXLY,131
|
95
|
+
podflow-20250315.dist-info/top_level.txt,sha256=KcvRCiz_DRWWc9i-PgpARvFB0J4CKmpZOZgPqOdG-Lk,8
|
96
|
+
podflow-20250315.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|