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.
@@ -6,7 +6,7 @@ import json
6
6
 
7
7
 
8
8
  # 文件保存模块
9
- def file_save(content, file_name, folder=None):
9
+ def file_save(content, file_name, folder=None, binary=False):
10
10
  # 如果指定了文件夹则将文件保存到指定的文件夹中
11
11
  if folder:
12
12
  file_path = os.path.join(os.getcwd(), folder, file_name)
@@ -14,10 +14,14 @@ def file_save(content, file_name, folder=None):
14
14
  # 如果没有指定文件夹则将文件保存在当前工作目录中
15
15
  file_path = os.path.join(os.getcwd(), file_name)
16
16
  # 保存文件
17
- with open(file_path, "w", encoding="utf-8") as file:
18
- # 如果文件名中包含"."且文件类型为json,则将内容以json格式保存
19
- if "." in file_name and file_name.split(".")[-1] == "json":
20
- json.dump(content, file, ensure_ascii=False, indent=4)
21
- else:
22
- # 否则将内容以文本格式保存
23
- file.write(content)
17
+ if binary:
18
+ with open(file_path, "wb") as file:
19
+ file.write(content.read())
20
+ else:
21
+ with open(file_path, "w", encoding="utf-8") as file:
22
+ # 如果文件名中包含"."且文件类型为json,则将内容以json格式保存
23
+ if "." in file_name and file_name.split(".")[-1] == "json":
24
+ json.dump(content, file, ensure_ascii=False, indent=4)
25
+ else:
26
+ # 否则将内容以文本格式保存
27
+ file.write(content)
@@ -16,7 +16,7 @@ def http_client(
16
16
  cookies=None,
17
17
  data=None,
18
18
  mode="get",
19
- filename=None,
19
+ file=None,
20
20
  ):
21
21
  user_agent = {
22
22
  "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"
@@ -55,10 +55,10 @@ def http_client(
55
55
  try:
56
56
  if mode.lower() != "post":
57
57
  response = session.get(url, timeout=8)
58
- elif filename:
59
- with open(filename, "rb") as f:
60
- files = {"file": f} # 这里 "file" 对应服务器端接收文件的字段名称
61
- response = session.post(url, files=files, timeout=8)
58
+ elif file:
59
+ file.seek(0)
60
+ files = {"file": file} # 这里 "file" 对应服务器端接收文件的字段名称
61
+ response = session.post(url, files=files, timeout=8)
62
62
  else:
63
63
  response = session.post(url, timeout=8)
64
64
  response.raise_for_status()
@@ -17,6 +17,7 @@ from podflow.basic.write_log import write_log
17
17
  from podflow.httpfs.to_html import ansi_to_html
18
18
  from podflow.upload.build_hash import build_hash
19
19
  from podflow.upload.time_key import check_time_key
20
+ from podflow.basic.folder_build import folder_build
20
21
  from podflow.httpfs.get_channelid import get_channelid
21
22
 
22
23
 
@@ -44,6 +45,7 @@ class bottle_app:
44
45
  else:
45
46
  self.app_bottle.route("/index", callback=self.index)
46
47
  self.app_bottle.route("/getid", method="POST", callback=self.getid)
48
+ self.app_bottle.route("/getconfig", callback=self.getconfig)
47
49
  self.app_bottle.route(
48
50
  "/templates/<filepath:path>", callback=self.serve_template_file
49
51
  )
@@ -346,11 +348,15 @@ class bottle_app:
346
348
  "message": "No File Provided",
347
349
  }
348
350
  # 判断文件是否完整
349
- if upload_hash != build_hash(upload_file):
351
+ uploadfile = upload_file.file
352
+ uploadfile.seek(0)
353
+ uploadfile_hash = build_hash(uploadfile)
354
+ if upload_hash != uploadfile_hash:
350
355
  self.print_out("upload", 401)
351
356
  return {
352
357
  "code": -5,
353
358
  "message": "Incomplete File",
359
+ "hash": uploadfile_hash,
354
360
  }
355
361
  if not channelid:
356
362
  # 打印错误信息并返回错误码
@@ -369,7 +375,7 @@ class bottle_app:
369
375
  "code": -6,
370
376
  "message": "File Format Error",
371
377
  }
372
- address = f"/channel_audiovisual/{channelid}"
378
+ address = f"channel_audiovisual/{channelid}"
373
379
  if os.path.exists(address):
374
380
  file_list = os.listdir(address)
375
381
  else:
@@ -380,6 +386,7 @@ class bottle_app:
380
386
  filename = f"{name}.{num}.{suffix}"
381
387
  if filename in file_list:
382
388
  with open(f"{address}/{filename}", "rb") as original_file:
389
+ original_file.seek(0)
383
390
  if upload_hash == build_hash(original_file):
384
391
  self.print_out("upload", 200)
385
392
  return {
@@ -391,7 +398,9 @@ class bottle_app:
391
398
  }
392
399
  num += 1
393
400
  else:
394
- file_save(upload_file, filename, address)
401
+ folder_build(channelid, "channel_audiovisual")
402
+ uploadfile.seek(0)
403
+ file_save(uploadfile, filename, address, True)
395
404
  # 打印成功信息并返回成功码
396
405
  self.print_out("upload", 200)
397
406
  return {
@@ -427,6 +436,12 @@ class bottle_app:
427
436
  # 设置响应头为 application/json
428
437
  response.content_type = "application/json"
429
438
  return {"response": response_message}
439
+
440
+ def getconfig(self):
441
+ self.print_out("getconfig", 200)
442
+ # 设置响应头为 application/json
443
+ response.content_type = "application/json"
444
+ return {"response": gVar.config}
430
445
 
431
446
  # --- 新增 SSE 流处理路由 ---
432
447
  def stream(self):
@@ -0,0 +1,225 @@
1
+ /* /templates/css/config.css */
2
+
3
+ #pageConfig label {
4
+ display: block; /* 让标签独占一行 */
5
+ margin-top: 12px;
6
+ font-weight: bold;
7
+ color: #333;
8
+ }
9
+
10
+ #pageConfig input[type="text"],
11
+ #pageConfig input[type="number"],
12
+ #pageConfig input[type="url"],
13
+ #pageConfig select,
14
+ #pageConfig textarea {
15
+ width: 95%; /* 调整宽度 */
16
+ padding: 8px;
17
+ margin-top: 5px;
18
+ border: 1px solid #ccc;
19
+ border-radius: 4px;
20
+ box-sizing: border-box;
21
+ font-size: 1em;
22
+ }
23
+
24
+ #pageConfig input[type="checkbox"] {
25
+ margin-left: 10px;
26
+ vertical-align: middle; /* 垂直居中对齐 */
27
+ }
28
+
29
+ .config-item {
30
+ margin-bottom: 15px;
31
+ padding-bottom: 10px;
32
+ border-bottom: 1px dotted #eee; /* 分隔线 */
33
+ }
34
+ .config-item:last-child {
35
+ border-bottom: none;
36
+ }
37
+
38
+
39
+ /* 可折叠部分的样式 */
40
+ .collapsible-section {
41
+ border: 1px solid #e0e0e0;
42
+ margin-top: 15px;
43
+ border-radius: 5px;
44
+ background-color: #f9f9f9;
45
+ overflow: hidden; /* 防止子元素溢出圆角 */
46
+ }
47
+
48
+ .collapsible-header {
49
+ cursor: pointer;
50
+ font-weight: bold;
51
+ padding: 10px 15px;
52
+ background-color: #f0f0f0;
53
+ border-bottom: 1px solid #e0e0e0;
54
+ display: flex;
55
+ justify-content: space-between;
56
+ align-items: center;
57
+ transition: background-color 0.2s ease;
58
+ }
59
+ .collapsible-header:hover {
60
+ background-color: #e5e5e5;
61
+ }
62
+
63
+
64
+ .collapsible-header .channel-key {
65
+ color: #0056b3; /* 突出频道 Key */
66
+ }
67
+
68
+ .collapsible-header .channel-id {
69
+ font-size: 0.9em;
70
+ color: #555;
71
+ margin-left: 10px;
72
+ }
73
+
74
+
75
+ .collapsible-header .toggle-icon {
76
+ font-size: 1.2em;
77
+ transition: transform 0.3s ease; /* 添加旋转动画 */
78
+ }
79
+
80
+ .collapsible-content {
81
+ padding: 15px;
82
+ padding-top: 5px; /* 减少顶部内边距 */
83
+ border-top: 1px solid #eee; /* 在内容和头部之间加条细线 */
84
+ background-color: #ffffff;
85
+ /* display: none; 由 JS 控制 */
86
+ }
87
+
88
+ .collapsible-content.hidden {
89
+ display: none;
90
+ }
91
+
92
+ /* 旋转展开/收起图标 */
93
+ .collapsible-header.expanded .toggle-icon {
94
+ transform: rotate(90deg);
95
+ }
96
+
97
+
98
+ /* title_change 数组项样式 */
99
+ .title-change-list {
100
+ margin-top: 10px;
101
+ padding-left: 15px;
102
+ border-left: 2px solid #f0f0f0;
103
+ }
104
+ .title-change-item {
105
+ border: 1px dashed #ccc;
106
+ padding: 10px;
107
+ margin-top: 10px;
108
+ margin-bottom: 10px;
109
+ background-color: #fff;
110
+ border-radius: 4px;
111
+ }
112
+ .title-change-item > label { /* 嵌套标签样式调整 */
113
+ font-weight: normal;
114
+ font-size: 0.95em;
115
+ color: #444;
116
+ }
117
+ .title-change-item > input,
118
+ .title-change-item > select {
119
+ width: 90%; /* 稍微缩进 */
120
+ }
121
+
122
+ /* styles.css */
123
+
124
+ /* Button Styles */
125
+ .config-button {
126
+ margin-left: 10px;
127
+ padding: 3px 8px;
128
+ font-size: 0.9em;
129
+ cursor: pointer;
130
+ border: 1px solid #ccc;
131
+ border-radius: 4px;
132
+ background-color: #f0f0f0;
133
+ transition: background-color 0.2s ease;
134
+ vertical-align: middle; /* Align buttons vertically with text/elements */
135
+ }
136
+
137
+ .config-button:hover {
138
+ background-color: #e0e0e0;
139
+ }
140
+
141
+ .add-button {
142
+ background-color: #d4edda; /* Light green */
143
+ border-color: #c3e6cb;
144
+ color: #155724; /* Dark green */
145
+ }
146
+
147
+ .add-button:hover {
148
+ background-color: #c8e5bc;
149
+ }
150
+
151
+ .delete-button {
152
+ background-color: #f8d7da; /* Light red */
153
+ border-color: #f5c6cb;
154
+ color: #721c24; /* Dark red */
155
+ }
156
+
157
+ .delete-button:hover {
158
+ background-color: #f1b0b7;
159
+ }
160
+
161
+ /* Adjust layout for buttons in header */
162
+ .collapsible-header .config-button {
163
+ /* Specific adjustments for buttons inside headers */
164
+ margin-left: 10px; /* Space between title and buttons */
165
+ }
166
+
167
+ .title-change-list label .config-button {
168
+ margin-left: 10px;
169
+ }
170
+
171
+ .title-change-item strong .config-button {
172
+ margin-left: 10px;
173
+ }
174
+
175
+ /* Style for text inputs and selects */
176
+ .config-item input.config-input-text,
177
+ .config-item input[type="number"], /* Keep number type selector */
178
+ .config-item input[type="url"], /* Keep url type selector */
179
+ .config-item select.config-input-select {
180
+ width: calc(100% - 20px); /* Adjust width considering padding/margin */
181
+ padding: 5px;
182
+ margin-top: 5px;
183
+ border: 1px solid #ccc;
184
+ border-radius: 4px;
185
+ box-sizing: border-box; /* Include padding and border in element's total width and height */
186
+ display: block; /* Make inputs/selects take their own line */
187
+ }
188
+
189
+ .config-item input[type="checkbox"] {
190
+ width: auto; /* Checkbox should not take full width */
191
+ margin-top: 0;
192
+ display: inline-block; /* Checkbox stays inline with label */
193
+ }
194
+
195
+ /* Adjust display for channel key/ID display */
196
+ .channel-item .collapsible-header .channel-dom-key {
197
+ font-weight: bold;
198
+ }
199
+
200
+ .channel-item .collapsible-header .channel-id {
201
+ font-size: 0.9em;
202
+ color: #555;
203
+ margin-left: 5px;
204
+ }
205
+
206
+ .channel-item .collapsible-header .id-display {
207
+ font-weight: normal; /* Don't bold the displayed ID */
208
+ }
209
+
210
+ /* Basic styling for channel items */
211
+ .channel-item {
212
+ border: 1px solid #eee;
213
+ margin-bottom: 10px;
214
+ padding: 5px;
215
+ border-radius: 4px;
216
+ background-color: #f9f9f9;
217
+ }
218
+
219
+ .title-change-item {
220
+ border: 1px solid #eee;
221
+ margin-bottom: 10px;
222
+ padding: 5px;
223
+ border-radius: 4px;
224
+ background-color: #f9f9f9;
225
+ }
@@ -5,22 +5,20 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Podflow</title>
7
7
  <link rel="stylesheet" href="/templates/css/index.css" />
8
+ <link rel="stylesheet" href="/templates/css/config.css" />
8
9
  <link rel="icon" href="favicon.ico" type="image/x-icon">
9
10
  </head>
10
11
  <body>
11
- <!-- 菜单栏 -->
12
12
  <nav id="menu">
13
13
  <h3>菜单栏</h3>
14
14
  <ul>
15
15
  <li data-page="pageMessage">Podflow 运行情况</li>
16
16
  <li data-page="pageChannel">获取媒体频道 ID</li>
17
+ <li data-page="pageConfig">修改配置</li>
17
18
  </ul>
18
19
  </nav>
19
- <!-- 菜单切换按钮 -->
20
20
  <button id="toggleMenu">❮</button>
21
- <!-- 主体区域 -->
22
21
  <main id="main">
23
- <!-- 获取 Channel-ID 页面 -->
24
22
  <section id="pageChannel" style="display: none;">
25
23
  <h2>获取媒体频道 ID</h2>
26
24
  <form id="inputForm" method="post" action="getid">
@@ -35,7 +33,7 @@
35
33
  <p class="hint">📌 如果粘贴按钮无效,请长按输入框手动粘贴。</p>
36
34
  </form>
37
35
  </section>
38
- <!-- 消息滚动显示页面 -->
36
+
39
37
  <section id="pageMessage">
40
38
  <h2>Podflow 运行情况</h2>
41
39
  <form>
@@ -53,8 +51,22 @@
53
51
  <div class="common-area" id="messageHttp"></div>
54
52
  </form>
55
53
  </section>
54
+
55
+ <section id="pageConfig" style="display: none;">
56
+ <h2>修改配置</h2>
57
+ <div id="configContainer">
58
+ <p>正在加载配置...</p>
59
+ </div>
60
+ <div class="button-container">
61
+ <button type="button" id="refreshConfigBtn">🔄 刷新配置</button>
62
+ <button type="button" id="saveConfigBtn">💾 保存配置</button>
63
+ </div>
64
+ <div id="configStatus" style="margin-top: 10px; color: green;"></div>
65
+ </section>
66
+
56
67
  </main>
57
68
  <script src="/templates/js/index.js"></script>
58
69
  <script src="/templates/js/qrcode.min.js"></script>
70
+ <script src="/templates/js/config.js"></script>
59
71
  </body>
60
- </html>
72
+ </html>