Opening Command Line (External HTML → VSCODE)
js
// extension.ts
context.subscriptions.push(
vscode.commands.registerCommand('ffmpegScriptTool.start', () => {
const panel = vscode.window.createWebviewPanel(
"ffmpegScriptTool",
'ffmpeg script tool',
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true
},
);
// Tool page URL
const toolUrl = 'http://localhost:5173/ffmpegtool/';
panel.webview.html = getIframeContentWithBridge(toolUrl);
handleWebviewMessages(panel, context);
})
);
// HTML generator for remote iframe
function getIframeContentWithBridge(remoteUrl: string): string {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tool</title>
<style>
body, html { margin: 0; padding: 0; height: 100%; overflow: hidden; background-color: transparent; }
iframe { width: 100%; height: 100%; border: none; display: block; }
</style>
<script>
const vscode = acquireVsCodeApi();
window.addEventListener('message', (event) => {
const iframe = document.getElementById('contentFrame');
if (iframe && event.source === iframe.contentWindow) {
vscode.postMessage(event.data);
} else {
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(event.data, '*');
}
}
});
</script>
</head>
<body>
<iframe
id="contentFrame"
src="${remoteUrl}"
frameborder="0"
allow="autoplay; fullscreen; clipboard-read; clipboard-write; encrypted-media; picture-in-picture"
allowfullscreen
></iframe>
</body>
</html>`;
}
function handleWebviewMessages(panel: vscode.WebviewPanel, context: vscode.ExtensionContext) {
panel.webview.onDidReceiveMessage(
async (message) => {
switch (message.command) {
case 'runCommand':
const workspaceFolders = vscode.workspace.workspaceFolders;
let cwd: string | undefined;
if (workspaceFolders && workspaceFolders.length > 0) {
cwd = workspaceFolders[0].uri.fsPath;
} else {
cwd = process.env.HOME || process.env.USERPROFILE;
}
if (message.mode === 'background') {
const result = await executeShellCommand(message.text, cwd);
panel.webview.postMessage({ command: 'commandResult', result: result });
} else {
await executeInTerminal(message.text, cwd);
panel.webview.postMessage({ command: 'commandResult', result: 'Command executed in terminal' });
}
break;
}
},
undefined,
context.subscriptions
);
}vscode-bridge
js
// vscodeBridge.js
(function () {
/**
* Helper function to send messages to the VSCode extension.
* @param {object} message The message object to send.
*/
function postMessageToVSCode(message) {
// Check if running inside an iframe (like a VSCode webview)
if (window.parent !== window) {
console.log('Sending message to VSCode:', message)
window.parent.postMessage(message, '*')
}
else {
console.warn('Not in a VSCode webview environment. Message not sent:', message)
}
}
/**
* VSCodeBridge provides utilities for communicating with a VSCode extension.
*/
const VSCodeBridge = {
/**
* Sends a message to the VSCode extension.
* @param {object} message The message object.
*/
sendToVSCode: postMessageToVSCode,
/**
* Registers a callback function to handle messages received from the VSCode extension.
* @param {function(object): void} callback The function to call when a message is received.
*/
onMessage(callback) {
window.addEventListener('message', (event) => {
// Ensure the message is from the parent window (the VSCode webview host)
if (event.source === window.parent) {
console.log('Received message from VSCode:', event.data)
callback(event.data)
}
})
}
}
// Expose VSCodeBridge globally for other scripts to use
window.VSCodeBridge = VSCodeBridge
/**
* Handles the result received from a VSCode command execution.
* This function can be customized by the main page to update its UI, etc.
* @param {any} result The result data from VSCode.
*/
window.handleCommandResult = function (result) {
console.log('FFmpeg Command Result:', result)
// Example: Update a dedicated result element on the page
const resultElement = document.getElementById('outputResult') // You might need to add this element to your HTML
if (resultElement) {
resultElement.textContent = `Command Execution Result: ${JSON.stringify(result)}`
resultElement.style.color = 'green'
setTimeout(() => resultElement.textContent = '', 5000) // Clear after 5 seconds
}
// Dispatch a custom event for other parts of the page to react to
const event = new CustomEvent('vscode-command-result', { detail: result })
document.dispatchEvent(event)
}
window.runFFmpegCommand = function () {
// Get the value of the input element
const inputElement = document.getElementById('ffmpegCommandInput')
if (inputElement && inputElement.value.trim()) {
const command = inputElement.value.trim()
postMessageToVSCode({
command: 'runCommand', // This command ID should be handled by your VSCode extension
text: command
})
const btn = document.querySelector('button[onclick="runFFmpegCommand()"]')
if (btn) {
const oldText = btn.innerHTML
btn.innerHTML = '🚀 Running...'
setTimeout(() => btn.innerHTML = oldText, 3000) // Reset button text after a delay
}
}
else {
console.warn('FFmpeg command is empty or input element not found.')
// Optional: Show error message to user
alert('Please enter an FFmpeg command in the input field.')
}
}
// --- Initialization Logic ---
document.addEventListener('DOMContentLoaded', () => {
const isVSCodeEnvironment = window.parent !== window
// Hide the "Run On Vscode" button if the page is not running within a VSCode webview
const runOnVscodeButton = document.querySelector('button[onclick="runFFmpegCommand()"]')
if (runOnVscodeButton && !isVSCodeEnvironment) {
runOnVscodeButton.style.display = 'none'
}
// Listen for messages from VSCode specifically for command results
VSCodeBridge.onMessage((message) => {
if (message.command === 'commandResult') {
window.handleCommandResult(message.result)
}
// Add any other specific message handling logic here if your extension sends other commands
})
})
})() // End of IIFEdelogo_overlay.html
js
<!-- Include VS Code communication script -->
<script src="/script/vscode-bridge.js"></script>html
<!-- Change output element id to ffmpegCommandInput -->
<textarea id="ffmpegCommandInput" readonly>Waiting to generate...</textarea>
<!-- Add elements at appropriate positions -->
<button class="btn btn-copy" onclick="runFFmpegCommand()">📋 Run On Vscode</button>
<div id="outputResult" style="margin-top: 10px; font-size: 0.9em; color: green;"></div>Viewing Videos (VSCODE → Internal HTML)
Navigation Bar

navbar.js
js
/**
* navbar.js
* Function: Automatically generates navigation bar, injects styles, and handles VS Code communication logic
*/
(function () {
// 1. Configure CSS styles
const cssStyles = `
/* Navigation bar styles */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background-color: var(--vscode-editor-background);
border-bottom: 1px solid var(--vscode-panel-border);
position: sticky;
top: 0;
z-index: 100;
font-family: var(--vscode-font-family);
}
.nav-left {
display: flex;
align-items: baseline;
gap: 10px;
}
.nav-subtitle {
font-size: 13px;
color: var(--vscode-descriptionForeground);
margin-left: 10px;
}
/* VS Code style button styles */
.vscode-btn {
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 6px 14px;
font-size: 13px;
cursor: pointer;
border-radius: 2px;
display: flex;
align-items: center;
gap: 5px;
outline: none;
}
.vscode-btn:hover {
background-color: var(--vscode-button-hoverBackground);
}
/* General class to prevent content from being obscured */
.container-padding {
padding-top: 20px;
}
`
// 2. Configure HTML structure
const navHtml = `
<div class="nav-left">
<button id="btnOpenAgicodeHub" class="vscode-btn">AgiCodeHub</button>
<button id="btnOpenFFmpegTool" class="vscode-btn">FFmpeg Tool</button>
<button id="btnOpenBrowsers" class="vscode-btn">Browsers ↗</button>
<span id="navFileName" class="nav-subtitle"></span>
</div>
<div class="nav-right">
<button id="btnOpenExternal" class="vscode-btn">Open in External Player ↗</button>
</div>
`
// 3. Initialization function
function initNavbar() {
// --- A. Inject CSS ---
const styleSheet = document.createElement('style')
styleSheet.innerText = cssStyles
document.head.appendChild(styleSheet)
// --- B. Insert HTML ---
const navElement = document.createElement('nav')
navElement.className = 'navbar'
navElement.innerHTML = navHtml
// Insert at the first position in body
document.body.insertBefore(navElement, document.body.firstChild)
// --- C. Initialize VS Code API ---
let vscode
try {
// Prevent errors from repeated calls to acquireVsCodeApi
vscode = window.vscode || acquireVsCodeApi()
window.vscode = vscode // Save as global state
}
catch (e) {
console.warn('VS Code API not found (running in browser?)')
// Simulate API for browser testing
vscode = { postMessage: msg => console.log('Simulated PostMessage:', msg) }
}
// --- D. Bind button events ---
const actions = {
btnOpenExternal: 'openExternal',
btnOpenBrowsers: 'openBrowsers',
btnOpenFFmpegTool: 'openFFmpegTool',
btnOpenAgicodeHub: 'openAgicodeHub'
}
Object.keys(actions).forEach((btnId) => {
const btn = document.getElementById(btnId)
if (btn) {
btn.addEventListener('click', () => {
vscode.postMessage({ command: actions[btnId] })
})
}
})
// --- E. Listen for messages (filename updates & video playback) ---
window.addEventListener('message', (event) => {
const message = event.data
if (message.command === 'loadVideoUrl') {
const videoUrl = message.url
const fileName = message.fileName
// 1. Update filename on navigation bar
const navFileName = document.getElementById('navFileName')
if (navFileName)
navFileName.innerText = fileName
// 2. Update other elements on the page (if any)
const fileInfo = document.getElementById('fileInfo')
if (fileInfo)
fileInfo.innerHTML = `<strong>Playing:</strong> ${fileName}`
// 3. Handle video playback (try to find element with ID video1 on the page)
const video1 = document.getElementById('video1')
if (video1) {
video1.src = videoUrl
video1.play().catch((e) => {
console.warn('Autoplay blocked:', e)
})
}
}
})
}
// Execute after DOM is loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initNavbar)
}
else {
initNavbar()
}
})()
