bizydraft 0.2.78.dev20251030100819__py3-none-any.whl → 0.2.82.dev20251209023307__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.
- bizydraft/hijack_routes.py +28 -1
- bizydraft/oss_utils.py +14 -3
- bizydraft/patch_handlers.py +105 -5
- bizydraft/static/js/aspectRatio.js +751 -0
- bizydraft/static/js/clipspaceToOss.js +57 -26
- bizydraft/static/js/handleStyle.js +54 -12
- bizydraft/static/js/hookLoad/media.js +415 -0
- bizydraft/static/js/hookLoadMedia.js +92 -285
- bizydraft/static/js/hookLoadModel.js +49 -3
- bizydraft/static/js/imageUpload.js +146 -0
- bizydraft/static/js/limitTimeRange.js +129 -0
- bizydraft/static/js/main.js +4 -1
- {bizydraft-0.2.78.dev20251030100819.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/METADATA +1 -1
- {bizydraft-0.2.78.dev20251030100819.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/RECORD +16 -13
- {bizydraft-0.2.78.dev20251030100819.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/WHEEL +0 -0
- {bizydraft-0.2.78.dev20251030100819.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/top_level.txt +0 -0
bizydraft/hijack_routes.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
1
3
|
from aiohttp import web
|
|
2
4
|
from loguru import logger
|
|
3
5
|
|
|
@@ -51,6 +53,31 @@ def hijack_routes_pre_add_routes():
|
|
|
51
53
|
|
|
52
54
|
return middleware_handler
|
|
53
55
|
|
|
56
|
+
# 覆盖 /settings 响应,修改设置 NodeIdBadgeMode 为 ShowAll显示id,将 LinkRenderMode 为(Spline=2),显示连线
|
|
57
|
+
async def settings_response_middleware(app, handler):
|
|
58
|
+
async def middleware_handler(request):
|
|
59
|
+
if request.method == "GET":
|
|
60
|
+
p = request.path
|
|
61
|
+
if p == "/settings" or p == "/api/settings":
|
|
62
|
+
resp = await handler(request)
|
|
63
|
+
if getattr(resp, "content_type", None) == "application/json":
|
|
64
|
+
body_bytes = getattr(resp, "body", b"")
|
|
65
|
+
charset = getattr(resp, "charset", None) or "utf-8"
|
|
66
|
+
payload = json.loads(body_bytes.decode(charset))
|
|
67
|
+
if payload.get("Comfy.NodeBadge.NodeIdBadgeMode") != "ShowAll":
|
|
68
|
+
payload["Comfy.NodeBadge.NodeIdBadgeMode"] = "ShowAll"
|
|
69
|
+
if payload.get("Comfy.LinkRenderMode") != 2:
|
|
70
|
+
payload["Comfy.LinkRenderMode"] = 2
|
|
71
|
+
if payload.get("Comfy.VueNodes.Enabled") != False:
|
|
72
|
+
payload["Comfy.VueNodes.Enabled"] = False
|
|
73
|
+
return web.json_response(
|
|
74
|
+
payload, status=getattr(resp, "status", 200)
|
|
75
|
+
)
|
|
76
|
+
return resp
|
|
77
|
+
return await handler(request)
|
|
78
|
+
|
|
79
|
+
return middleware_handler
|
|
80
|
+
|
|
54
81
|
async def access_control_middleware(app, handler):
|
|
55
82
|
base_white_list = [
|
|
56
83
|
"/prompt",
|
|
@@ -98,7 +125,7 @@ def hijack_routes_pre_add_routes():
|
|
|
98
125
|
|
|
99
126
|
return middleware_handler
|
|
100
127
|
|
|
101
|
-
app.middlewares.extend([custom_business_middleware])
|
|
128
|
+
app.middlewares.extend([custom_business_middleware, settings_response_middleware])
|
|
102
129
|
|
|
103
130
|
logger.info("Optimized middleware setup complete.")
|
|
104
131
|
|
bizydraft/oss_utils.py
CHANGED
|
@@ -64,6 +64,9 @@ def decrypt(encrypted_message):
|
|
|
64
64
|
if not encrypted_message or not isinstance(encrypted_message, str):
|
|
65
65
|
raise ValueError("无效的加密消息")
|
|
66
66
|
|
|
67
|
+
if "v4.public" in encrypted_message:
|
|
68
|
+
return encrypted_message
|
|
69
|
+
|
|
67
70
|
private_key = serialization.load_pem_private_key(
|
|
68
71
|
private_key_pem.encode(), password=None, backend=default_backend()
|
|
69
72
|
)
|
|
@@ -309,9 +312,17 @@ async def upload_mask(request):
|
|
|
309
312
|
if "http" in original_subfolder:
|
|
310
313
|
# subfolder 中包含 URL 基础路径
|
|
311
314
|
original_subfolder = original_subfolder[original_subfolder.find("http") :]
|
|
312
|
-
original_subfolder = unquote(original_subfolder)
|
|
313
|
-
|
|
314
|
-
|
|
315
|
+
original_subfolder = unquote(original_subfolder)
|
|
316
|
+
if "https:/" in original_subfolder and not original_subfolder.startswith(
|
|
317
|
+
"https://"
|
|
318
|
+
):
|
|
319
|
+
original_subfolder = original_subfolder.replace(
|
|
320
|
+
"https:/", "https://", 1
|
|
321
|
+
)
|
|
322
|
+
if "http:/" in original_subfolder and not original_subfolder.startswith(
|
|
323
|
+
"http://"
|
|
324
|
+
):
|
|
325
|
+
original_subfolder = original_subfolder.replace("http:/", "http://", 1)
|
|
315
326
|
original_url = f"{original_subfolder}/{original_filename}"
|
|
316
327
|
elif original_filename.startswith(http_prefix_options):
|
|
317
328
|
# filename 本身就是完整 URL
|
bizydraft/patch_handlers.py
CHANGED
|
@@ -3,10 +3,12 @@ import math
|
|
|
3
3
|
import mimetypes
|
|
4
4
|
import os
|
|
5
5
|
import uuid
|
|
6
|
+
from io import BytesIO
|
|
6
7
|
from urllib.parse import unquote
|
|
7
8
|
|
|
8
9
|
from aiohttp import ClientSession, ClientTimeout, web
|
|
9
10
|
from loguru import logger
|
|
11
|
+
from PIL import Image
|
|
10
12
|
|
|
11
13
|
try:
|
|
12
14
|
import execution
|
|
@@ -37,6 +39,8 @@ async def view_image(request):
|
|
|
37
39
|
|
|
38
40
|
filename = request.rel_url.query["filename"]
|
|
39
41
|
subfolder = request.rel_url.query.get("subfolder", "")
|
|
42
|
+
channel = request.rel_url.query.get("channel", "rgba")
|
|
43
|
+
preview = request.rel_url.query.get("preview", None)
|
|
40
44
|
|
|
41
45
|
http_prefix_options = ("http:", "https:")
|
|
42
46
|
|
|
@@ -56,17 +60,22 @@ async def view_image(request):
|
|
|
56
60
|
subfolder = subfolder.replace("https:/", "https://", 1)
|
|
57
61
|
if "http:/" in subfolder and not subfolder.startswith("http://"):
|
|
58
62
|
subfolder = subfolder.replace("http:/", "http://", 1)
|
|
59
|
-
|
|
63
|
+
|
|
64
|
+
# 构建完整URL
|
|
65
|
+
full_url = (
|
|
60
66
|
f"{subfolder}/{filename}"
|
|
61
67
|
if not filename.startswith(http_prefix_options)
|
|
62
68
|
else filename
|
|
63
|
-
)
|
|
69
|
+
)
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
# 获取原始文件名用于响应头
|
|
72
|
+
original_filename = filename.split("/")[-1] if "/" in filename else filename
|
|
73
|
+
|
|
74
|
+
content_type, _ = mimetypes.guess_type(full_url)
|
|
66
75
|
|
|
67
76
|
timeout = ClientTimeout(total=BIZYDRAFT_REQUEST_TIMEOUT)
|
|
68
77
|
async with ClientSession(timeout=timeout) as session:
|
|
69
|
-
async with session.get(
|
|
78
|
+
async with session.get(full_url) as resp:
|
|
70
79
|
resp.raise_for_status()
|
|
71
80
|
|
|
72
81
|
# 优先使用服务器返回的Content-Type,如果无法获取则使用猜测的类型
|
|
@@ -86,8 +95,98 @@ async def view_image(request):
|
|
|
86
95
|
text=f"File size exceeds limit ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
|
|
87
96
|
)
|
|
88
97
|
|
|
98
|
+
# 检查是否需要图像处理(preview或channel参数)
|
|
99
|
+
is_image = final_content_type and final_content_type.startswith(
|
|
100
|
+
"image/"
|
|
101
|
+
)
|
|
102
|
+
needs_processing = is_image and (
|
|
103
|
+
preview is not None or channel != "rgba"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if needs_processing:
|
|
107
|
+
logger.debug(f"Image processing requested: {channel=}, {preview=}")
|
|
108
|
+
# 下载完整图像到内存
|
|
109
|
+
image_data = await resp.read()
|
|
110
|
+
|
|
111
|
+
# 检查实际大小
|
|
112
|
+
if len(image_data) > BIZYDRAFT_MAX_FILE_SIZE:
|
|
113
|
+
return web.Response(
|
|
114
|
+
status=413,
|
|
115
|
+
text=f"File size exceeds limit ({human_readable_size(BIZYDRAFT_MAX_FILE_SIZE)})",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# 使用PIL处理图像
|
|
119
|
+
with Image.open(BytesIO(image_data)) as img:
|
|
120
|
+
# 处理preview参数
|
|
121
|
+
if preview is not None:
|
|
122
|
+
preview_info = preview.split(";")
|
|
123
|
+
image_format = preview_info[0]
|
|
124
|
+
if image_format not in ["webp", "jpeg"] or "a" in channel:
|
|
125
|
+
image_format = "webp"
|
|
126
|
+
quality = 90
|
|
127
|
+
if preview_info[-1].isdigit():
|
|
128
|
+
quality = int(preview_info[-1])
|
|
129
|
+
|
|
130
|
+
buffer = BytesIO()
|
|
131
|
+
if image_format in ["jpeg"] or channel == "rgb":
|
|
132
|
+
img = img.convert("RGB")
|
|
133
|
+
img.save(buffer, format=image_format, quality=quality)
|
|
134
|
+
buffer.seek(0)
|
|
135
|
+
|
|
136
|
+
return web.Response(
|
|
137
|
+
body=buffer.read(),
|
|
138
|
+
content_type=f"image/{image_format}",
|
|
139
|
+
headers={
|
|
140
|
+
"Content-Disposition": f'filename="{original_filename}"'
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# 处理channel参数
|
|
145
|
+
if channel == "rgb":
|
|
146
|
+
logger.debug("Converting image to RGB (removing alpha)")
|
|
147
|
+
if img.mode == "RGBA":
|
|
148
|
+
r, g, b, a = img.split()
|
|
149
|
+
new_img = Image.merge("RGB", (r, g, b))
|
|
150
|
+
else:
|
|
151
|
+
new_img = img.convert("RGB")
|
|
152
|
+
|
|
153
|
+
buffer = BytesIO()
|
|
154
|
+
new_img.save(buffer, format="PNG")
|
|
155
|
+
buffer.seek(0)
|
|
156
|
+
|
|
157
|
+
return web.Response(
|
|
158
|
+
body=buffer.read(),
|
|
159
|
+
content_type="image/png",
|
|
160
|
+
headers={
|
|
161
|
+
"Content-Disposition": f'filename="{original_filename}"'
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
elif channel == "a":
|
|
166
|
+
logger.debug("Extracting alpha channel only")
|
|
167
|
+
if img.mode == "RGBA":
|
|
168
|
+
_, _, _, a = img.split()
|
|
169
|
+
else:
|
|
170
|
+
a = Image.new("L", img.size, 255)
|
|
171
|
+
|
|
172
|
+
# 创建alpha通道图像
|
|
173
|
+
alpha_img = Image.new("RGBA", img.size)
|
|
174
|
+
alpha_img.putalpha(a)
|
|
175
|
+
alpha_buffer = BytesIO()
|
|
176
|
+
alpha_img.save(alpha_buffer, format="PNG")
|
|
177
|
+
alpha_buffer.seek(0)
|
|
178
|
+
|
|
179
|
+
return web.Response(
|
|
180
|
+
body=alpha_buffer.read(),
|
|
181
|
+
content_type="image/png",
|
|
182
|
+
headers={
|
|
183
|
+
"Content-Disposition": f'filename="{original_filename}"'
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# 默认流式传输(无需处理或非图像文件)
|
|
89
188
|
headers = {
|
|
90
|
-
"Content-Disposition": f'attachment; filename="{
|
|
189
|
+
"Content-Disposition": f'attachment; filename="{original_filename}"',
|
|
91
190
|
"Content-Type": final_content_type,
|
|
92
191
|
}
|
|
93
192
|
|
|
@@ -113,6 +212,7 @@ async def view_image(request):
|
|
|
113
212
|
text=f"Request timed out (max {BIZYDRAFT_REQUEST_TIMEOUT//60} minutes)",
|
|
114
213
|
)
|
|
115
214
|
except Exception as e:
|
|
215
|
+
logger.error(f"Error in view_image: {str(e)}", exc_info=True)
|
|
116
216
|
return web.Response(
|
|
117
217
|
status=502, text=f"Failed to fetch remote resource: {str(e)}"
|
|
118
218
|
)
|