Skip to content

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 IIFE

delogo_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)

alt text
alt text
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()
  }
})()