Files
vscode/extensions/image-preview/src/audioPreview.ts
Matt Bierner edcf6e24b3 Add built-in video preview (#159623)
Fixes #159106

Also hooks up our service worker to support seeking in local video resources. This requires handling range requests properly
2022-08-31 13:06:06 -07:00

123 lines
4.4 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
import { MediaPreview, reopenAsText } from './mediaPreview';
import { escapeAttribute, getNonce } from './util/dom';
const localize = nls.loadMessageBundle();
class AudioPreviewProvider implements vscode.CustomReadonlyEditorProvider {
public static readonly viewType = 'vscode.audioPreview';
constructor(
private readonly extensionRoot: vscode.Uri,
private readonly binarySizeStatusBarEntry: BinarySizeStatusBarEntry,
) { }
public async openCustomDocument(uri: vscode.Uri) {
return { uri, dispose: () => { } };
}
public async resolveCustomEditor(document: vscode.CustomDocument, webviewEditor: vscode.WebviewPanel): Promise<void> {
new AudioPreview(this.extensionRoot, document.uri, webviewEditor, this.binarySizeStatusBarEntry);
}
}
class AudioPreview extends MediaPreview {
constructor(
private readonly extensionRoot: vscode.Uri,
resource: vscode.Uri,
webviewEditor: vscode.WebviewPanel,
binarySizeStatusBarEntry: BinarySizeStatusBarEntry,
) {
super(extensionRoot, resource, webviewEditor, binarySizeStatusBarEntry);
this._register(webviewEditor.webview.onDidReceiveMessage(message => {
switch (message.type) {
case 'reopen-as-text': {
reopenAsText(resource, webviewEditor.viewColumn);
break;
}
}
}));
this.updateBinarySize();
this.render();
this.updateState();
}
protected async getWebviewContents(): Promise<string> {
const version = Date.now().toString();
const settings = {
src: await this.getResourcePath(this.webviewEditor, this.resource, version),
};
const nonce = getNonce();
const cspSource = this.webviewEditor.webview.cspSource;
return /* html */`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- Disable pinch zooming -->
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<title>Audio Preview</title>
<link rel="stylesheet" href="${escapeAttribute(this.extensionResource('media', 'audioPreview.css'))}" type="text/css" media="screen" nonce="${nonce}">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data: ${cspSource}; media-src ${cspSource}; script-src 'nonce-${nonce}'; style-src ${cspSource} 'nonce-${nonce}';">
<meta id="settings" data-settings="${escapeAttribute(JSON.stringify(settings))}">
</head>
<body class="container loading">
<div class="loading-indicator"></div>
<div class="loading-error">
<p>${localize('preview.audioLoadError', "An error occurred while loading the audio file.")}</p>
<a href="#" class="open-file-link">${localize('preview.audioLoadErrorLink', "Open file using VS Code's standard text/binary editor?")}</a>
</div>
<script src="${escapeAttribute(this.extensionResource('media', 'audioPreview.js'))}" nonce="${nonce}"></script>
</body>
</html>`;
}
private async getResourcePath(webviewEditor: vscode.WebviewPanel, resource: vscode.Uri, version: string): Promise<string | null> {
if (resource.scheme === 'git') {
const stat = await vscode.workspace.fs.stat(resource);
if (stat.size === 0) {
// The file is stored on git lfs
return null;
}
}
// Avoid adding cache busting if there is already a query string
if (resource.query) {
return webviewEditor.webview.asWebviewUri(resource).toString();
}
return webviewEditor.webview.asWebviewUri(resource).with({ query: `version=${version}` }).toString();
}
private extensionResource(...parts: string[]) {
return this.webviewEditor.webview.asWebviewUri(vscode.Uri.joinPath(this.extensionRoot, ...parts));
}
}
export function registerAudioPreviewSupport(context: vscode.ExtensionContext, binarySizeStatusBarEntry: BinarySizeStatusBarEntry): vscode.Disposable {
const provider = new AudioPreviewProvider(context.extensionUri, binarySizeStatusBarEntry);
return vscode.window.registerCustomEditorProvider(AudioPreviewProvider.viewType, provider, {
supportsMultipleEditorsPerDocument: true,
webviewOptions: {
retainContextWhenHidden: true,
}
});
}