Skip to content

Commit 33da498

Browse files
committed
Add support for copying the output filepath
On right click, Video Combine nodes now have an option to copy the output filepath. Additionally, if a paste operation is performed afterwards, a Load Video (Path) node is automatically created populated with the copied file path. From my testing, it's not possible to store an indicator to the clipboard (even with web types) to convey in the clipboard that this data was created by a VHS node, so unfortunately, this node creation capability will not persist across reloads.
1 parent bdd9808 commit 33da498

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

videohelpersuite/nodes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,8 @@ def pad(image):
567567
"type": "output" if save_output else "temp",
568568
"format": format,
569569
"frame_rate": frame_rate,
570-
"workflow": first_image_file
570+
"workflow": first_image_file,
571+
"fullpath": output_files[-1],
571572
}
572573
if num_frames == 1 and 'png' in format and '%03d' in file:
573574
previews[0]['format'] = 'image/png'

web/js/VHS.core.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ function addVideoPreview(nodeType) {
886886
previewWidget.parentEl.appendChild(previewWidget.imgEl)
887887
});
888888
}
889+
let copiedPath = undefined
889890
function addPreviewOptions(nodeType) {
890891
chainCallback(nodeType.prototype, "getExtraMenuOptions", function(_, options) {
891892
// The intended way of appending options is returning a list of extra options,
@@ -926,6 +927,19 @@ function addPreviewOptions(nodeType) {
926927
},
927928
}
928929
);
930+
if (previewWidget.value.params.fullpath) {
931+
copiedPath = previewWidget.value.params.fullpath
932+
const blob = new Blob([previewWidget.value.params.fullpath],
933+
{ type: 'text/plain'})
934+
optNew.push({
935+
content: "Copy output filepath",
936+
callback: async () => {
937+
await navigator.clipboard.write([
938+
new ClipboardItem({
939+
'text/plain': blob
940+
})])}
941+
});
942+
}
929943
if (previewWidget.value.params.workflow) {
930944
let wParams = {...previewWidget.value.params,
931945
filename: previewWidget.value.params.workflow}
@@ -1611,6 +1625,55 @@ app.registerExtension({
16111625
return res
16121626
}
16131627
app.graphToPrompt = graphToPrompt
1628+
//Add a handler for pasting video data
1629+
document.addEventListener('paste', async (e) => {
1630+
if (!e.target.classList.contains('litegraph') &&
1631+
!e.target.classList.contains('graph-canvas-container')) {
1632+
return
1633+
}
1634+
let data = e.clipboardData || window.clipboardData
1635+
let filepath = data.getData('text/plain')
1636+
let video
1637+
for (const item of data.items) {
1638+
if (item.type.startsWith('video/')) {
1639+
video = item
1640+
break
1641+
}
1642+
}
1643+
if (filepath && copiedPath == filepath) {
1644+
//Add a Load Video (Path) and populate filepath
1645+
const pastedNode = LiteGraph.createNode('VHS_LoadVideoPath')
1646+
app.graph.add(pastedNode)
1647+
pastedNode.pos[0] = app.canvas.graph_mouse[0]
1648+
pastedNode.pos[1] = app.canvas.graph_mouse[1]
1649+
pastedNode.widgets[0].value = filepath
1650+
pastedNode.widgets[0].callback?.(filepath)
1651+
} else if (video && false) {
1652+
//Disabled due to lack of testing
1653+
//Add a Load Video (Upload), then upload the file, then select the file
1654+
const pastedNode = LiteGraph.createNode('VHS_LoadVideo')
1655+
app.graph.add(pastedNode)
1656+
pastedNode.pos[0] = app.canvas.graph_mouse[0]
1657+
pastedNode.pos[1] = app.canvas.graph_mouse[1]
1658+
const pathWidget = pastedNode.widgets[0]
1659+
//TODO: upload to pasted dir?
1660+
const blob = video.getAsFile()
1661+
const resp = await uploadFile(blob)
1662+
if (resp.status != 200) {
1663+
//upload failed and file can not be added to options
1664+
return;
1665+
}
1666+
const filename = (await resp.json()).name;
1667+
pathWidget.options.values.push(filename);
1668+
pathWidget.value = filename;
1669+
pathWidget.callback?.(filename)
1670+
} else {
1671+
return
1672+
}
1673+
e.preventDefault()
1674+
e.stopImmediatePropagation()
1675+
return false
1676+
}, true)
16141677
},
16151678
async init() {
16161679
if (app.VHSHelp != helpDOM) {

0 commit comments

Comments
 (0)