bizydraft 0.2.78.dev20251117024007__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 +11 -3
- bizydraft/static/js/aspectRatio.js +751 -0
- bizydraft/static/js/clipspaceToOss.js +57 -26
- bizydraft/static/js/handleStyle.js +44 -5
- bizydraft/static/js/hookLoadModel.js +24 -24
- 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.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/METADATA +1 -1
- {bizydraft-0.2.78.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/RECORD +13 -10
- {bizydraft-0.2.78.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/WHEEL +0 -0
- {bizydraft-0.2.78.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/top_level.txt +0 -0
|
@@ -62,7 +62,7 @@ function replaceClipspaceUrl(urlString) {
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
const originalSetAttribute = HTMLImageElement.prototype.setAttribute;
|
|
65
|
-
HTMLImageElement.prototype.setAttribute = function(name, value) {
|
|
65
|
+
HTMLImageElement.prototype.setAttribute = function (name, value) {
|
|
66
66
|
if (name === 'src') {
|
|
67
67
|
const modifiedValue = replaceClipspaceUrl(value);
|
|
68
68
|
return originalSetAttribute.call(this, name, modifiedValue);
|
|
@@ -75,11 +75,11 @@ function replaceClipspaceUrl(urlString) {
|
|
|
75
75
|
// 拦截上传响应,保存映射并篡改返回值
|
|
76
76
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
77
77
|
const originalFetchApi = api.fetchApi;
|
|
78
|
-
api.fetchApi = async function(url, options) {
|
|
78
|
+
api.fetchApi = async function (url, options) {
|
|
79
79
|
const response = await originalFetchApi.call(this, url, options);
|
|
80
80
|
|
|
81
81
|
const isUploadApi = url === '/upload/image' || url === '/upload/mask'
|
|
82
|
-
|
|
82
|
+
|| url === '/api/upload/image' || url === '/api/upload/mask';
|
|
83
83
|
|
|
84
84
|
if (!isUploadApi || !response.ok) {
|
|
85
85
|
return response;
|
|
@@ -89,7 +89,7 @@ api.fetchApi = async function(url, options) {
|
|
|
89
89
|
|
|
90
90
|
// 检查是否是 OSS 上传响应
|
|
91
91
|
const isOssUpload = data.subfolder?.includes('http://') || data.subfolder?.includes('https://')
|
|
92
|
-
|
|
92
|
+
|| data.name?.startsWith('http://') || data.name?.startsWith('https://');
|
|
93
93
|
|
|
94
94
|
if (!isOssUpload) return response;
|
|
95
95
|
|
|
@@ -118,7 +118,7 @@ api.fetchApi = async function(url, options) {
|
|
|
118
118
|
finalUrl = ossUrl;
|
|
119
119
|
|
|
120
120
|
[`clipspace-mask-${baseId}.png`, `clipspace-paint-${baseId}.png`,
|
|
121
|
-
|
|
121
|
+
`clipspace-painted-${baseId}.png`, `clipspace-painted-masked-${baseId}.png`
|
|
122
122
|
].forEach(v => window.CLIPSPACE_TO_OSS_MAP[v] = ossUrl);
|
|
123
123
|
|
|
124
124
|
} else {
|
|
@@ -204,16 +204,29 @@ function convertClipspacePathsInPrompt(prompt) {
|
|
|
204
204
|
|
|
205
205
|
for (const [inputKey, inputValue] of Object.entries(node.inputs)) {
|
|
206
206
|
if (typeof inputValue === 'string' && inputValue.includes('clipspace')) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
// 1) 特殊情况:clipspace/https://... 或 clipspace/http://...
|
|
208
|
+
const ossUrlMatch = inputValue.match(/clipspace\/(https?:\/\/[^\s]+)/i);
|
|
209
|
+
if (ossUrlMatch) {
|
|
210
|
+
// 移除可能的 [input] 或 [output] 后缀
|
|
211
|
+
let cleanUrl = ossUrlMatch[1].replace(/\s*\[(input|output)\]$/i, '');
|
|
212
|
+
node.inputs[inputKey] = cleanUrl;
|
|
213
|
+
|
|
214
|
+
if (inputKey === 'image' && node.inputs['image_name']) {
|
|
215
|
+
node.inputs['image_name'] = cleanUrl.split('/').pop();
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
// 2) 常规情况:clipspace/xxx.png
|
|
219
|
+
const match = inputValue.match(/clipspace\/([\w-]+\.(?:png|jpg|jpeg|webp|gif))/i);
|
|
220
|
+
if (match) {
|
|
221
|
+
const filename = match[1];
|
|
222
|
+
const ossUrl = findOssUrl(filename);
|
|
211
223
|
|
|
212
|
-
|
|
213
|
-
|
|
224
|
+
if (ossUrl) {
|
|
225
|
+
node.inputs[inputKey] = ossUrl;
|
|
214
226
|
|
|
215
|
-
|
|
216
|
-
|
|
227
|
+
if (inputKey === 'image' && node.inputs['image_name']) {
|
|
228
|
+
node.inputs['image_name'] = ossUrl.split('/').pop();
|
|
229
|
+
}
|
|
217
230
|
}
|
|
218
231
|
}
|
|
219
232
|
}
|
|
@@ -232,7 +245,7 @@ function interceptPasteFromClipspace() {
|
|
|
232
245
|
if (!ComfyApp || !ComfyApp.pasteFromClipspace) return;
|
|
233
246
|
|
|
234
247
|
const originalPasteFromClipspace = ComfyApp.pasteFromClipspace;
|
|
235
|
-
ComfyApp.pasteFromClipspace = function(node) {
|
|
248
|
+
ComfyApp.pasteFromClipspace = function (node) {
|
|
236
249
|
// 调用原始函数
|
|
237
250
|
originalPasteFromClipspace.call(this, node);
|
|
238
251
|
|
|
@@ -244,14 +257,23 @@ function interceptPasteFromClipspace() {
|
|
|
244
257
|
|
|
245
258
|
// 1) 如果是 clipspace 路径格式,替换为 OSS URL
|
|
246
259
|
if (value.includes('clipspace/')) {
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
260
|
+
// 1.1) 特殊情况:clipspace/https://... 或 clipspace/http://...
|
|
261
|
+
// 这种情况是 OSS URL 被错误地加了 clipspace/ 前缀,直接移除前缀
|
|
262
|
+
const ossUrlMatch = value.match(/clipspace\/(https?:\/\/[^\s]+)/i);
|
|
263
|
+
if (ossUrlMatch) {
|
|
264
|
+
// 移除可能的 [input] 或 [output] 后缀
|
|
265
|
+
let cleanUrl = ossUrlMatch[1].replace(/\s*\[(input|output)\]$/i, '');
|
|
266
|
+
imageWidget.value = cleanUrl;
|
|
267
|
+
} else {
|
|
268
|
+
// 1.2) 常规情况:clipspace/xxx.png,提取文件名并查找映射
|
|
269
|
+
const match = value.match(/clipspace\/([\w-]+\.(?:png|jpg|jpeg|webp|gif))(\s\[(input|output)\])?/i);
|
|
270
|
+
if (match) {
|
|
271
|
+
const filename = match[1];
|
|
272
|
+
const ossUrl = findOssUrl(filename);
|
|
273
|
+
|
|
274
|
+
if (ossUrl) {
|
|
275
|
+
imageWidget.value = ossUrl;
|
|
276
|
+
}
|
|
255
277
|
}
|
|
256
278
|
}
|
|
257
279
|
}
|
|
@@ -273,22 +295,31 @@ app.registerExtension({
|
|
|
273
295
|
async setup() {
|
|
274
296
|
const originalGraphToPrompt = app.graphToPrompt;
|
|
275
297
|
|
|
276
|
-
// 在构建 Prompt 之前,先清理所有 widget
|
|
298
|
+
// 在构建 Prompt 之前,先清理所有 widget 的值,去掉多余的后缀和错误的 clipspace 前缀
|
|
277
299
|
function sanitizeGraphWidgets(graph) {
|
|
278
300
|
const nodes = graph?._nodes || [];
|
|
279
301
|
for (const node of nodes) {
|
|
280
302
|
if (!node?.widgets) continue;
|
|
281
303
|
for (const widget of node.widgets) {
|
|
282
304
|
if (typeof widget?.value === 'string') {
|
|
283
|
-
|
|
305
|
+
let value = widget.value;
|
|
306
|
+
// 先处理 clipspace/https://... 格式
|
|
307
|
+
if (value.includes('clipspace/')) {
|
|
308
|
+
const ossUrlMatch = value.match(/clipspace\/(https?:\/\/[^\s]+)/i);
|
|
309
|
+
if (ossUrlMatch) {
|
|
310
|
+
value = ossUrlMatch[1];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// 再移除类型后缀
|
|
314
|
+
widget.value = stripTypeSuffix(value);
|
|
284
315
|
}
|
|
285
316
|
}
|
|
286
317
|
}
|
|
287
318
|
}
|
|
288
319
|
|
|
289
|
-
app.graphToPrompt = async function(...args) {
|
|
320
|
+
app.graphToPrompt = async function (...args) {
|
|
290
321
|
// 预清理,避免 workflow.widgets_values 和 prompt 输入里包含 [input]/[output]
|
|
291
|
-
try { sanitizeGraphWidgets(app.graph); } catch (e) {}
|
|
322
|
+
try { sanitizeGraphWidgets(app.graph); } catch (e) { }
|
|
292
323
|
|
|
293
324
|
const result = await originalGraphToPrompt.apply(this, args);
|
|
294
325
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { app } from "../../scripts/app.js";
|
|
2
2
|
import { $el } from "../../scripts/ui.js";
|
|
3
3
|
const styleMenus = `
|
|
4
|
-
|
|
4
|
+
/* 隐藏Panel内容容器,但排除选择工具箱 */
|
|
5
|
+
.p-panel:not(.selection-toolbox) .p-panel-content-container{
|
|
5
6
|
display: none;
|
|
6
7
|
}
|
|
7
8
|
// .side-tool-bar-container.small-sidebar{
|
|
@@ -28,10 +29,11 @@ const styleMenus = `
|
|
|
28
29
|
#comfyui-body-bottom{
|
|
29
30
|
display: none;
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
+
/* 隐藏左侧的工作流按钮 */
|
|
32
33
|
.p-button.p-component.p-button-icon-only.p-button-text.workflows-tab-button.side-bar-button.p-button-secondary{
|
|
33
34
|
display: none;
|
|
34
35
|
}
|
|
36
|
+
/* 隐藏左侧的输入输出按钮 */
|
|
35
37
|
.p-button.p-component.p-button-icon-only.p-button-text.mtb-inputs-outputs-tab-button.side-bar-button.p-button-secondary{
|
|
36
38
|
display: none;
|
|
37
39
|
}
|
|
@@ -56,9 +58,46 @@ const styleMenus = `
|
|
|
56
58
|
.side-tool-bar-container.small-sidebar .side-bar-button-label{
|
|
57
59
|
display: none;
|
|
58
60
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
/* 隐藏整个comfy-menu-button-wrapper元素 */
|
|
62
|
+
.comfy-menu-button-wrapper{
|
|
63
|
+
display: none;
|
|
64
|
+
}
|
|
65
|
+
/* 隐藏帮助中心按钮 */
|
|
66
|
+
.comfy-help-center-btn{
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
/* 隐藏底部面板(Console)按钮 */
|
|
70
|
+
button[aria-label="底部面板"]{
|
|
71
|
+
display: none;
|
|
72
|
+
}
|
|
73
|
+
/* 隐藏键盘快捷键按钮 */
|
|
74
|
+
button[aria-label^="键盘快捷键"]{
|
|
75
|
+
display: none;
|
|
76
|
+
}
|
|
77
|
+
/* 隐藏右下角按钮组(包含鼠标指针、适应视图、缩放控制、小地图、隐藏链接等按钮) */
|
|
78
|
+
.p-buttongroup.absolute.right-0.bottom-0{
|
|
79
|
+
display: none;
|
|
80
|
+
}
|
|
81
|
+
.pointer-events-auto.relative.w-full.h-10.bg-gradient-to-r.from-blue-600.to-blue-700.flex.items-center.justify-center.px-4 {
|
|
82
|
+
display: none;
|
|
83
|
+
}
|
|
84
|
+
.p-splitterpanel.p-splitterpanel-nested.flex.flex-col .ml-1.flex.pt-1{
|
|
85
|
+
display: none;
|
|
86
|
+
}
|
|
87
|
+
.p-button.p-component.p-button-text.size-8.bg-primary-background.text-white.p-0{
|
|
88
|
+
display: none;
|
|
89
|
+
}
|
|
90
|
+
.p-button.p-component.p-button-secondary.p-button-text.h-8.w-8.px-0{
|
|
91
|
+
display: none;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* 隐藏左侧的资产按钮 */
|
|
95
|
+
.p-button.p-component.p-button-icon-only.p-button-text.assets-tab-button.side-bar-button.p-button-secondary {
|
|
96
|
+
display: none;
|
|
97
|
+
}
|
|
98
|
+
/* 隐藏左侧的模型库按钮 */
|
|
99
|
+
.p-button.p-component.p-button-icon-only.p-button-text.model-library-tab-button.side-bar-button.p-button-secondary{
|
|
100
|
+
display: none;
|
|
62
101
|
}
|
|
63
102
|
`;
|
|
64
103
|
app.registerExtension({
|
|
@@ -158,31 +158,31 @@ app.registerExtension({
|
|
|
158
158
|
|
|
159
159
|
// 重写 add 方法,添加过滤逻辑
|
|
160
160
|
toastStore.add = function(message) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
161
|
+
const detail = (message.detail || '').toLowerCase();
|
|
162
|
+
const summary = (message.summary || '').toLowerCase();
|
|
163
|
+
const text = `${summary} ${detail}`;
|
|
164
|
+
|
|
165
|
+
// 检查是否包含阻止的关键词
|
|
166
|
+
const blockedKeywords = [
|
|
167
|
+
'missing dependencies',
|
|
168
|
+
'comfyui logs',
|
|
169
|
+
'comfyullogs',
|
|
170
|
+
'refer to the comfyui',
|
|
171
|
+
'you may be missing'
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
const shouldBlock = blockedKeywords.some(keyword =>
|
|
175
|
+
text.includes(keyword.toLowerCase())
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// 如果包含阻止的关键词,则不添加 toast
|
|
179
|
+
if (shouldBlock) {
|
|
180
|
+
console.log('Blocked toast:', message);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
// 否则正常添加
|
|
185
|
+
return originalAdd.call(this, message);
|
|
186
186
|
};
|
|
187
187
|
|
|
188
188
|
console.log('Toast blocker activated!');
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { app } from "../../../scripts/app.js";
|
|
2
|
+
|
|
3
|
+
// 简单的链式callback实现
|
|
4
|
+
function chainCallback(originalCallback, newCallback) {
|
|
5
|
+
return function (...args) {
|
|
6
|
+
if (originalCallback) {
|
|
7
|
+
originalCallback.apply(this, args);
|
|
8
|
+
}
|
|
9
|
+
newCallback.apply(this, args);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// 统一的函数:初始化动态输入相关的 widgets
|
|
14
|
+
function initializeDynamicInputs(node) {
|
|
15
|
+
// 只处理目标节点类型
|
|
16
|
+
if (
|
|
17
|
+
node.type !== "BizyAir_Seedream4_5" &&
|
|
18
|
+
node.type !== "BizyAir_NanoBananaPro" &&
|
|
19
|
+
node.type !== "BizyAir_NanoBananaProOfficial"
|
|
20
|
+
) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
node._type = "IMAGE";
|
|
25
|
+
|
|
26
|
+
if (!node.inputs) {
|
|
27
|
+
node.inputs = [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 先检查是否存在 inputcount widget
|
|
31
|
+
let inputCountWidget = node.widgets?.find(
|
|
32
|
+
(w) => w.name === "inputcount"
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// 如果不存在,先创建 inputcount widget(在按钮之前创建,确保显示顺序)
|
|
36
|
+
if (!inputCountWidget) {
|
|
37
|
+
// 计算当前 IMAGE 类型输入数量
|
|
38
|
+
const currentImageInputs = node.inputs.filter(
|
|
39
|
+
(input) => input.type === node._type
|
|
40
|
+
).length;
|
|
41
|
+
// 创建 inputcount widget,默认值为当前输入数量或1
|
|
42
|
+
// 使用 precision: 0 确保是整数类型
|
|
43
|
+
inputCountWidget = node.addWidget(
|
|
44
|
+
"number",
|
|
45
|
+
"inputcount",
|
|
46
|
+
currentImageInputs || 1,
|
|
47
|
+
null,
|
|
48
|
+
{
|
|
49
|
+
min: 1,
|
|
50
|
+
max: 10,
|
|
51
|
+
step: 10, // 旧参数(兼容性),是 step2 的 10 倍
|
|
52
|
+
step2: 1, // 新参数,实际的步长
|
|
53
|
+
precision: 0, // 设置为 0 表示整数
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 检查是否已经存在 "Update inputs" 按钮,避免重复添加
|
|
59
|
+
const updateButton = node.widgets?.find(
|
|
60
|
+
(w) => w.name === "Update inputs"
|
|
61
|
+
);
|
|
62
|
+
if (updateButton) {
|
|
63
|
+
return; // 已经存在,不需要重复添加
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 然后添加 "Update inputs" 按钮(会在 inputcount 之后显示)
|
|
67
|
+
node.addWidget("button", "Update inputs", null, () => {
|
|
68
|
+
if (!node.inputs) {
|
|
69
|
+
node.inputs = [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 查找 inputcount widget
|
|
73
|
+
const inputCountWidget = node.widgets?.find(
|
|
74
|
+
(w) => w.name === "inputcount"
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// 如果仍然找不到,创建它
|
|
78
|
+
if (!inputCountWidget) {
|
|
79
|
+
const currentImageInputs = node.inputs.filter(
|
|
80
|
+
(input) => input.type === node._type
|
|
81
|
+
).length;
|
|
82
|
+
node.addWidget(
|
|
83
|
+
"number",
|
|
84
|
+
"inputcount",
|
|
85
|
+
currentImageInputs || 1,
|
|
86
|
+
null,
|
|
87
|
+
{
|
|
88
|
+
min: 1,
|
|
89
|
+
max: 10,
|
|
90
|
+
step: 10, // 旧参数(兼容性),是 step2 的 10 倍
|
|
91
|
+
step2: 1, // 新参数,实际的步长
|
|
92
|
+
precision: 0, // 设置为 0 表示整数
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const target_number_of_inputs = inputCountWidget.value || 1;
|
|
99
|
+
const num_inputs = node.inputs.filter(
|
|
100
|
+
(input) => input.type === node._type
|
|
101
|
+
).length;
|
|
102
|
+
|
|
103
|
+
if (target_number_of_inputs === num_inputs) {
|
|
104
|
+
return; // already set, do nothing
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (target_number_of_inputs < num_inputs) {
|
|
108
|
+
const inputs_to_remove = num_inputs - target_number_of_inputs;
|
|
109
|
+
for (let i = 0; i < inputs_to_remove; i++) {
|
|
110
|
+
node.removeInput(node.inputs.length - 1);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
for (let i = num_inputs + 1; i <= target_number_of_inputs; ++i) {
|
|
114
|
+
node.addInput(`image_${i}`, node._type, { shape: 7 });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
app.registerExtension({
|
|
121
|
+
name: "bizyair.dynamicImageInputs",
|
|
122
|
+
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
123
|
+
// 只处理目标节点类型
|
|
124
|
+
if (
|
|
125
|
+
nodeData.name !== "BizyAir_Seedream4_5" &&
|
|
126
|
+
nodeData.name !== "BizyAir_NanoBananaPro" &&
|
|
127
|
+
nodeData.name !== "BizyAir_NanoBananaProOfficial"
|
|
128
|
+
) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 使用 chainCallback 设置 onConfigure,确保在节点配置完成后也初始化 widgets
|
|
133
|
+
const originalOnConfigure = nodeType.prototype.onConfigure;
|
|
134
|
+
nodeType.prototype.onConfigure = chainCallback(
|
|
135
|
+
originalOnConfigure,
|
|
136
|
+
function (info) {
|
|
137
|
+
// 在 configure 完成后初始化 widgets
|
|
138
|
+
initializeDynamicInputs(this);
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
nodeCreated(node) {
|
|
143
|
+
// 在节点创建时也初始化 widgets(用于首次创建节点时)
|
|
144
|
+
initializeDynamicInputs(node);
|
|
145
|
+
},
|
|
146
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { app } from "../../../scripts/app.js";
|
|
2
|
+
|
|
3
|
+
// 简单的链式callback实现(类似useChainCallback)
|
|
4
|
+
function chainCallback(originalCallback, newCallback) {
|
|
5
|
+
return function (...args) {
|
|
6
|
+
if (originalCallback) {
|
|
7
|
+
originalCallback.apply(this, args);
|
|
8
|
+
}
|
|
9
|
+
newCallback.apply(this, args);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
app.registerExtension({
|
|
14
|
+
name: "bizyair.hailuo.limitTimeRange",
|
|
15
|
+
nodeCreated(node, app) {
|
|
16
|
+
console.log(node.title);
|
|
17
|
+
// 只处理 BizyAir_Hailuo2_3_T2V 节点
|
|
18
|
+
if (
|
|
19
|
+
node.title !== "☁️BizyAir Hailuo2.3 Image To Video" &&
|
|
20
|
+
node.title !== "☁️BizyAir Hailuo2.3 Text To Video"
|
|
21
|
+
) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
console.log(node.title , `开始处理`);
|
|
25
|
+
// 延迟执行,确保 widget 完全初始化
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
try {
|
|
28
|
+
const resolutionWidget = node.widgets?.find(
|
|
29
|
+
(w) => w.name === "resolution"
|
|
30
|
+
);
|
|
31
|
+
const durationWidget = node.widgets?.find((w) => w.name === "duration");
|
|
32
|
+
|
|
33
|
+
if (!resolutionWidget || !durationWidget) {
|
|
34
|
+
console.warn("[Hailuo2_3_T2V] 未找到 resolution 或 duration widget");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 保存 duration widget 的原始选项值
|
|
39
|
+
const originalDurationValues = durationWidget.options?.values
|
|
40
|
+
? Array.isArray(durationWidget.options.values)
|
|
41
|
+
? [...durationWidget.options.values]
|
|
42
|
+
: typeof durationWidget.options.values === "function"
|
|
43
|
+
? durationWidget.options.values()
|
|
44
|
+
: []
|
|
45
|
+
: [];
|
|
46
|
+
|
|
47
|
+
// 如果没有原始值,无法继续
|
|
48
|
+
if (!originalDurationValues || originalDurationValues.length === 0) {
|
|
49
|
+
console.warn("[Hailuo2_3_T2V] duration widget 没有可用的选项值");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 更新 duration 选项的函数
|
|
54
|
+
const updateDurationOptions = () => {
|
|
55
|
+
const resolutionValue = resolutionWidget.value;
|
|
56
|
+
// 支持 "1080p"、"1080P" 等大小写变体
|
|
57
|
+
const is1080p =
|
|
58
|
+
resolutionValue === "1080p" ||
|
|
59
|
+
resolutionValue === "1080P" ||
|
|
60
|
+
String(resolutionValue).toUpperCase() === "1080P";
|
|
61
|
+
|
|
62
|
+
// 直接修改 widget.options.values 数组
|
|
63
|
+
if (!durationWidget.options) {
|
|
64
|
+
durationWidget.options = {};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (is1080p) {
|
|
68
|
+
// 如果是 1080p,从 values 数组中删除 10
|
|
69
|
+
if (Array.isArray(durationWidget.options.values)) {
|
|
70
|
+
// 找到 10 的索引并删除
|
|
71
|
+
const index = durationWidget.options.values.indexOf(10);
|
|
72
|
+
if (index !== -1) {
|
|
73
|
+
durationWidget.options.values.splice(index, 1);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// 如果不是数组,重新创建数组并过滤掉 10
|
|
77
|
+
durationWidget.options.values = originalDurationValues.filter(
|
|
78
|
+
(val) => val !== 10
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
// 如果不是 1080p,恢复原始值(包括 10)
|
|
83
|
+
durationWidget.options.values = [...originalDurationValues];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 检查当前值是否在新的 values 中,如果不在则调整为第一个可用值
|
|
87
|
+
const currentValue = durationWidget.value;
|
|
88
|
+
const valuesArray = Array.isArray(durationWidget.options.values)
|
|
89
|
+
? durationWidget.options.values
|
|
90
|
+
: [];
|
|
91
|
+
|
|
92
|
+
if (valuesArray.length > 0 && !valuesArray.includes(currentValue)) {
|
|
93
|
+
const newValue = valuesArray[0];
|
|
94
|
+
durationWidget.value = newValue;
|
|
95
|
+
// 触发 callback
|
|
96
|
+
if (durationWidget.callback) {
|
|
97
|
+
durationWidget.callback.call(durationWidget, newValue);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 触发节点和画布更新,确保 UI 刷新
|
|
102
|
+
if (node.setDirtyCanvas) {
|
|
103
|
+
node.setDirtyCanvas(true, true);
|
|
104
|
+
}
|
|
105
|
+
if (node.graph && node.graph.setDirtyCanvas) {
|
|
106
|
+
node.graph.setDirtyCanvas(true, true);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// 保存原始的 resolution callback
|
|
111
|
+
const originalResolutionCallback = resolutionWidget.callback;
|
|
112
|
+
|
|
113
|
+
// 使用 chainCallback 包装 resolution callback,监听变化
|
|
114
|
+
resolutionWidget.callback = chainCallback(
|
|
115
|
+
originalResolutionCallback,
|
|
116
|
+
function (value) {
|
|
117
|
+
// 更新 duration 选项
|
|
118
|
+
updateDurationOptions();
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// 初始化时执行一次,确保选项正确
|
|
123
|
+
updateDurationOptions();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error("[Hailuo2_3_T2V] 初始化时间范围限制失败:", error);
|
|
126
|
+
}
|
|
127
|
+
}, 200);
|
|
128
|
+
},
|
|
129
|
+
});
|
bizydraft/static/js/main.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// 主入口文件,导入所有模块
|
|
2
2
|
import "./disableComfyWebSocket.js";
|
|
3
|
-
import "./
|
|
3
|
+
import "./hookLoadImage.js";
|
|
4
4
|
import "./postEvent.js";
|
|
5
5
|
import "./handleStyle.js";
|
|
6
6
|
import "./clipspaceToOss.js";
|
|
7
|
+
import "./aspectRatio.js";
|
|
8
|
+
import "./imageUpload.js";
|
|
9
|
+
import "./limitTimeRange.js";
|
{bizydraft-0.2.78.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/RECORD
RENAMED
|
@@ -2,8 +2,8 @@ bizydraft/__init__.py,sha256=OM-sKCQrPh25nHVJIX-DgF1raMYyoWLSuyduIAHt0Gs,78
|
|
|
2
2
|
bizydraft/block_nodes.py,sha256=Lqn3oSCaGDHR2OICc8a2iRoRCVVK9v1-9MM3r-qIZgA,1092
|
|
3
3
|
bizydraft/env.py,sha256=VFmGopVL2TGWA6hwxyFhIglCEcQxy6iVvL_raMNd6u4,407
|
|
4
4
|
bizydraft/hijack_nodes.py,sha256=riHsp4DhU60E60bfXUl8kVqjs1QvQWmx_FsgQAdWTa4,4197
|
|
5
|
-
bizydraft/hijack_routes.py,sha256=
|
|
6
|
-
bizydraft/oss_utils.py,sha256=
|
|
5
|
+
bizydraft/hijack_routes.py,sha256=j7i9xAfaWvcu-mSoDISQyEwdERd0y-GFhvY2To7MRTU,5015
|
|
6
|
+
bizydraft/oss_utils.py,sha256=_UzbS4e_MW5UynkQd2JI6edfdWxStm-Kbt6k7CvJJGA,16663
|
|
7
7
|
bizydraft/patch_handlers.py,sha256=cP6gIYBYghWXI72hBbz3BbQHP1O5IvslS8iNK29MEbI,14159
|
|
8
8
|
bizydraft/postload.py,sha256=XFElKcmCajT_oO7SVJJBaN04XcWro54N5HB5cSCxfvI,1308
|
|
9
9
|
bizydraft/prestartup_patch.py,sha256=4FGjmRcDHELjtlQOrfTfk2Un5OS89QIqfq-gEcB9WDs,998
|
|
@@ -11,13 +11,16 @@ bizydraft/resp.py,sha256=8INvKOe5Dgai3peKfqKjrhUoYeuXWXn358w30-_cY-A,369
|
|
|
11
11
|
bizydraft/server.py,sha256=L2zoJgOisr65IRphOyko74AdsLel59gh55peyMaUrO8,2102
|
|
12
12
|
bizydraft/workflow_io.py,sha256=MYhJbpgkv8hrA5k_aolijOTrWpTtu62nzRznA4hv8JE,4298
|
|
13
13
|
bizydraft/static/js/aiAppHandler.js,sha256=OQRhhoqvc8iZeCvHTtdaD2VTYBGzkeAGdCk1UMO2RZs,17525
|
|
14
|
-
bizydraft/static/js/
|
|
14
|
+
bizydraft/static/js/aspectRatio.js,sha256=p--C62sTd2QLywa0KpB4T0QI-n7FXv8dO_6Tkl8vtdk,27943
|
|
15
|
+
bizydraft/static/js/clipspaceToOss.js,sha256=zTXYzop4Gx0k0NA1MiWUA_J4RKq75tA_wQSroBASCyg,16177
|
|
15
16
|
bizydraft/static/js/disableComfyWebSocket.js,sha256=ZDOVlU3v3EvWpMRkD8s_AnO43vuWojVLLjkF2pNEVrA,1957
|
|
16
17
|
bizydraft/static/js/freezeModeHandler.js,sha256=SjpHD2nYymR-E13B0YcqkA6e4WycZOVI3c48Ts9qvWE,18027
|
|
17
|
-
bizydraft/static/js/handleStyle.js,sha256=
|
|
18
|
+
bizydraft/static/js/handleStyle.js,sha256=GPshFVoa70UxLwFQB-kXZldVREE0cEF-BxxIM44ngkc,5436
|
|
18
19
|
bizydraft/static/js/hookLoadMedia.js,sha256=EYDuitzOFvlNzM_e4IdE0-wXHQfnyCx7KrwzoxVTdr0,6363
|
|
19
|
-
bizydraft/static/js/hookLoadModel.js,sha256=
|
|
20
|
-
bizydraft/static/js/
|
|
20
|
+
bizydraft/static/js/hookLoadModel.js,sha256=gY4D77DqVDzpuQZlqgqcUrL0Yho3koyR_lOHLyiqGfc,8204
|
|
21
|
+
bizydraft/static/js/imageUpload.js,sha256=S7YY4jaaZq83epWyT5_s4GOCa2vC_-4MwWMg3HVHyCU,4178
|
|
22
|
+
bizydraft/static/js/limitTimeRange.js,sha256=Bz-qHOfqUZk0zr8HYfuR3AzCYjUJHUvp8CdYLu0o6Ic,4619
|
|
23
|
+
bizydraft/static/js/main.js,sha256=LaIbmXPOsKrXzwsQRaXE7HXXyw_q0FcXX492ik-f0F0,272
|
|
21
24
|
bizydraft/static/js/nodeFocusHandler.js,sha256=24xXbS4Q-GjJdRqf11i-1pBo8MkOJ24F7MHFV44EG6Q,4683
|
|
22
25
|
bizydraft/static/js/nodeParamsFilter.js,sha256=H7lBB0G8HNqoGhOCH1hNXqPU-rPlrFyTxg_f_JgLEMk,4168
|
|
23
26
|
bizydraft/static/js/postEvent.js,sha256=_EyA71m5DwGbhHsuf1amKhpLUBxfBWZaMMxViNhuYzU,43481
|
|
@@ -28,7 +31,7 @@ bizydraft/static/js/workflow_io.js,sha256=FWAjncvWhvy-3nN_legD2fpRwgnIncpRLHU5X0
|
|
|
28
31
|
bizydraft/static/js/hookLoad/configLoader.js,sha256=R1k0GKdEmv4IIxdT2F-oOI9X9I19ECe77P_1tO3XxgY,2525
|
|
29
32
|
bizydraft/static/js/hookLoad/media.js,sha256=iX_zoZ0OzLAdYZ3bn5GpzpnwU-YjcBuEozQt-MwNuwk,17936
|
|
30
33
|
bizydraft/static/js/hookLoad/model.js,sha256=aHvEPt9k3CcrawHSYnQYcvbtTRwIztk-XDRA3lvgXvA,9890
|
|
31
|
-
bizydraft-0.2.
|
|
32
|
-
bizydraft-0.2.
|
|
33
|
-
bizydraft-0.2.
|
|
34
|
-
bizydraft-0.2.
|
|
34
|
+
bizydraft-0.2.82.dev20251209023307.dist-info/METADATA,sha256=aD-Dv6wd_rBGaWBYs62q5ts7qtZad8PV0I9dh1k_tik,180
|
|
35
|
+
bizydraft-0.2.82.dev20251209023307.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
bizydraft-0.2.82.dev20251209023307.dist-info/top_level.txt,sha256=XtoBq6hjZhXIM7aas4GtPDtAiKo8FdLzMABXW8qqQ8M,10
|
|
37
|
+
bizydraft-0.2.82.dev20251209023307.dist-info/RECORD,,
|
{bizydraft-0.2.78.dev20251117024007.dist-info → bizydraft-0.2.82.dev20251209023307.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|