feat: ✨ implement ipaq ideas for the I/O sidebar
This commit is contained in:
committed by
Mel Massadian
parent
c7248344cc
commit
940a781f29
+9
-4
@@ -110,11 +110,15 @@ def ACTIONS_getUserVideos(
|
||||
|
||||
def ACTIONS_getUserImages(
|
||||
mode: Literal["input", "output"],
|
||||
target_width: int | str | None = None,
|
||||
count=1000,
|
||||
offset=0,
|
||||
sort: str | None = None,
|
||||
include_subfolders: bool = False,
|
||||
subfolder=None,
|
||||
subfolder: str | None = None,
|
||||
# IIRC I copied this from Comfy base
|
||||
# just keeping it until I properly checked implications
|
||||
salt_urls=False,
|
||||
):
|
||||
# enabled = "MTB_EXPOSE" in os.environ
|
||||
# if not enabled:
|
||||
@@ -122,11 +126,12 @@ def ACTIONS_getUserImages(
|
||||
|
||||
imgs = {}
|
||||
count = count or 1000
|
||||
target_width = int(target_width) if target_width else None
|
||||
|
||||
input_dir = Path(folder_paths.get_input_directory())
|
||||
output_dir = Path(folder_paths.get_output_directory())
|
||||
|
||||
entry_dir = input_dir if mode == "input" else output_dir
|
||||
entry_dir: Path = input_dir if mode == "input" else output_dir
|
||||
if subfolder:
|
||||
entry_dir = entry_dir / subfolder
|
||||
|
||||
@@ -155,9 +160,9 @@ def ACTIONS_getUserImages(
|
||||
|
||||
imgs = {
|
||||
img.name: (
|
||||
f"/mtb/view?filename={img.name}&width=512&type={mode}&subfolder={subfolder or ''}"
|
||||
f"/mtb/view?filename={img.name}{f'&width={target_width}' if target_width and target_width > 0 else ''}&type={mode}&subfolder={subfolder or ''}"
|
||||
f"{img.parent.relative_to(entry_dir) if include_subfolders else ''}"
|
||||
f"&preview=&rand={secrets.randbelow(424242)}"
|
||||
f"&preview={f'&rand={secrets.randbelow(424242)}' if salt_urls else ''}"
|
||||
)
|
||||
for i, img in enumerate(entries)
|
||||
if offset <= i < offset + count
|
||||
|
||||
+118
-42
@@ -3,6 +3,7 @@
|
||||
import { app } from '../../scripts/app.js'
|
||||
import { api } from '../../scripts/api.js'
|
||||
|
||||
import * as mtb_ui from './mtb_ui.js'
|
||||
import * as shared from './comfy_shared.js'
|
||||
|
||||
import {
|
||||
@@ -15,7 +16,13 @@ import {
|
||||
} from './mtb_ui.js'
|
||||
|
||||
const offset = 0
|
||||
|
||||
// These are "global" variables mostly meant to sync user settings.
|
||||
let currentWidth = 200
|
||||
let saltUrls =
|
||||
app.extensionManager.setting.get('mtb.io-sidebar.salt_urls') || false
|
||||
let targetWidth =
|
||||
app.extensionManager.setting.get('mtb.io-sidebar.img-size') || 512
|
||||
let currentMode = 'input'
|
||||
let subfolder = ''
|
||||
let currentSort = 'None'
|
||||
@@ -46,15 +53,19 @@ const updateImage = (node, image) => {
|
||||
* @param {ResultItem} resultItem
|
||||
* @returns {string} - The request URL.
|
||||
*/
|
||||
const resultItemToQuery = (resultItem) =>
|
||||
[
|
||||
const resultItemToQuery = (resultItem) => {
|
||||
const res = [
|
||||
`/mtb/view?filename=${resultItem.filename}`,
|
||||
`width=512`,
|
||||
`type=${resultItem.type}`,
|
||||
`subfolder=${resultItem.subfolder}`,
|
||||
`preview=`,
|
||||
].join('&')
|
||||
'preview=',
|
||||
]
|
||||
if (targetWidth > 0) {
|
||||
res.splice(1, 0, `width=${targetWidth}`)
|
||||
}
|
||||
|
||||
return res.join('&')
|
||||
}
|
||||
/**
|
||||
* Retrieves the unique prompt ID from a history task item.
|
||||
* @param {HistoryTaskItem} historyTaskItem
|
||||
@@ -80,7 +91,7 @@ const getNewOutputUrls = (mostRecentTask) => {
|
||||
const imageOutputs = Object.values(nodeOutputs.images)
|
||||
imageOutputs.forEach(
|
||||
(resultItem) =>
|
||||
(urls[resultItem.filename] = resultItemToQuery(resultItem))
|
||||
(urls[resultItem.filename] = resultItemToQuery(resultItem)),
|
||||
)
|
||||
}
|
||||
// Can process `animated` and `audio` outputs here.
|
||||
@@ -209,7 +220,7 @@ const getUrls = async (subfolder) => {
|
||||
if (currentMode === 'video') {
|
||||
const output = await shared.runAction(
|
||||
'getUserVideos',
|
||||
256,
|
||||
targetWidth,
|
||||
count,
|
||||
offset,
|
||||
currentSort,
|
||||
@@ -219,11 +230,13 @@ const getUrls = async (subfolder) => {
|
||||
const output = await shared.runAction(
|
||||
'getUserImages',
|
||||
currentMode,
|
||||
targetWidth,
|
||||
count,
|
||||
offset,
|
||||
currentSort,
|
||||
false,
|
||||
subfolder,
|
||||
saltUrls,
|
||||
)
|
||||
return output || {}
|
||||
}
|
||||
@@ -236,55 +249,110 @@ if (window?.__COMFYUI_FRONTEND_VERSION__) {
|
||||
|
||||
const sidebar_extension = {
|
||||
name: 'mtb.io-sidebar',
|
||||
// init: async () => {
|
||||
// try {
|
||||
// const res = await api.fetchApi('/mtb/server-info')
|
||||
// const msg = await res.json()
|
||||
// exposed = msg.exposed
|
||||
// } catch (e) {
|
||||
// console.error('Error:', e)
|
||||
// }
|
||||
// },
|
||||
init: () => {
|
||||
let handle
|
||||
const version = window?.__COMFYUI_FRONTEND_VERSION__
|
||||
console.log(`%c ${version}`, 'background: orange; color: white;')
|
||||
|
||||
ensureMTBStyles()
|
||||
|
||||
app.ui.settings.addSetting({
|
||||
settings: [
|
||||
{
|
||||
id: 'mtb.io-sidebar.count',
|
||||
category: ['mtb', 'Input & Output Sidebar', 'count'],
|
||||
|
||||
name: 'Number of images to fetch',
|
||||
type: 'number',
|
||||
defaultValue: 1000,
|
||||
|
||||
tooltip:
|
||||
"This setting affects the input/output sidebar to determine how many images to fetch per pagination (pagination is not yet supported so for now it's the static total)",
|
||||
attrs: {
|
||||
style: {
|
||||
// fontFamily: 'monospace',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'mtb.io-sidebar.salt_urls',
|
||||
category: ['mtb', 'Input & Output Sidebar', 'salt_urls'],
|
||||
name: 'Salt URLs',
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
onChange: (n, o) => {
|
||||
saltUrls = n
|
||||
},
|
||||
})
|
||||
|
||||
app.ui.settings.addSetting({
|
||||
tooltip:
|
||||
'Adds a random query parameter to every urls to always invalidate caching.',
|
||||
},
|
||||
{
|
||||
id: 'mtb.io-sidebar.img-size',
|
||||
category: ['mtb', 'Input & Output Sidebar', 'img-size'],
|
||||
|
||||
name: 'Resize width of shown images',
|
||||
type: 'number',
|
||||
defaultValue: 512,
|
||||
type: (name, setter, value, attrs) => {
|
||||
targetWidth = value
|
||||
const container = mtb_ui.makeElement('div', {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '8px',
|
||||
})
|
||||
|
||||
tooltip: "It's recommended to keep it at 512px. Setting a high enough value will show images of less width in their native resolution.",
|
||||
attrs: {
|
||||
style: {
|
||||
// fontFamily: 'monospace',
|
||||
},
|
||||
console.log({ name, setter, value, attrs })
|
||||
|
||||
const baseId = name.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase()
|
||||
const checkboxId = `${baseId}-checkbox`
|
||||
const numberInputId = `${baseId}-number`
|
||||
|
||||
const isCheckedInitially = value !== -1
|
||||
|
||||
// TODO: better way to get defaultValue?
|
||||
const defaultValue = 512
|
||||
const initialNumberValue = isCheckedInitially ? value : defaultValue
|
||||
|
||||
console.log('recreate')
|
||||
const checkbox = mtb_ui.makeElement(
|
||||
// harder to match styles (.p-toggleswitch-input)
|
||||
// since it uses a div synced to the input...
|
||||
'input',
|
||||
{},
|
||||
container,
|
||||
)
|
||||
checkbox.type = 'checkbox'
|
||||
checkbox.id = checkboxId
|
||||
checkbox.checked = isCheckedInitially
|
||||
|
||||
const numberInput = mtb_ui.makeElement(
|
||||
'input.p-inputtext',
|
||||
{},
|
||||
container,
|
||||
)
|
||||
numberInput.type = 'number'
|
||||
numberInput.id = numberInputId
|
||||
numberInput.value = initialNumberValue
|
||||
numberInput.disabled = !isCheckedInitially
|
||||
numberInput.min = 128
|
||||
|
||||
checkbox.addEventListener('change', () => {
|
||||
let valToSet = -1
|
||||
if (checkbox.checked) {
|
||||
numberInput.disabled = false
|
||||
|
||||
valToSet = Number.parseInt(numberInput.value, 10)
|
||||
if (Number.isNaN(valToSet) || valToSet < numberInput.min) {
|
||||
valToSet = defaultValue
|
||||
numberInput.value = valToSet
|
||||
}
|
||||
} else {
|
||||
numberInput.disabled = true
|
||||
}
|
||||
setter(valToSet)
|
||||
})
|
||||
|
||||
numberInput.addEventListener('input', () => {
|
||||
if (checkbox.checked) {
|
||||
const numValue = Number.parseInt(numberInput.value, 10)
|
||||
if (!Number.isNaN(numValue) && numberInput.value !== '') {
|
||||
setter(numValue)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return container
|
||||
},
|
||||
})
|
||||
app.ui.settings.addSetting({
|
||||
|
||||
tooltip:
|
||||
"If browsing large folders it's recommended to use this to avoid overflow/crash of the webpage. Image will get resized to this target width on the server before being sent to the client.",
|
||||
},
|
||||
|
||||
{
|
||||
id: 'mtb.io-sidebar.sort',
|
||||
category: ['mtb', 'Input & Output Sidebar', 'sort'],
|
||||
name: 'Default sort mode',
|
||||
@@ -304,7 +372,15 @@ if (window?.__COMFYUI_FRONTEND_VERSION__) {
|
||||
'Name',
|
||||
'Name-Reverse',
|
||||
],
|
||||
})
|
||||
},
|
||||
],
|
||||
|
||||
init: () => {
|
||||
let handle
|
||||
const version = window?.__COMFYUI_FRONTEND_VERSION__
|
||||
console.log(`%c ${version}`, 'background: orange; color: white;')
|
||||
|
||||
ensureMTBStyles()
|
||||
|
||||
app.extensionManager.registerSidebarTab({
|
||||
id: 'mtb-inputs-outputs',
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
// NOTE: this will be the LT part of mtb API system
|
||||
// I need to properly publish the source and fix a few things before
|
||||
|
||||
// import { app } from '../../scripts/app.js'
|
||||
// // import { api } from '../../scripts/api.js'
|
||||
//
|
||||
// import * as shared from './comfy_shared.js'
|
||||
// import { createOutliner } from './dist/mtb_inspector.js'
|
||||
//
|
||||
// if (window?.__COMFYUI_FRONTEND_VERSION__) {
|
||||
// const version = window?.__COMFYUI_FRONTEND_VERSION__
|
||||
// console.log(`%c ${version}`, 'background: orange; color: white;')
|
||||
//
|
||||
// const panel = app.extensionManager.registerSidebarTab({
|
||||
// id: 'mtb-nodes',
|
||||
// icon: 'pi pi-bolt',
|
||||
// title: 'MTB',
|
||||
// tooltip: 'MTB: API outliner',
|
||||
// type: 'custom',
|
||||
// // this is run everytime the tab's diplay is toggled on.
|
||||
// render: (el) => {
|
||||
// const outliner = createOutliner(el)
|
||||
// const inputs = shared.getAPIInputs()
|
||||
// console.log('INPUTS', inputs)
|
||||
// outliner.$$set({ inputs })
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
Reference in New Issue
Block a user