feat: implement and recognize vimeo macro

This commit is contained in:
2026-02-15 17:49:59 +01:00
parent 5047463a93
commit 0aeeda616e
4 changed files with 106 additions and 1 deletions

View File

@@ -39,6 +39,21 @@ export const macroConfigs: MacroConfig[] = [
return undefined; return undefined;
}, },
}, },
{
name: 'vimeo',
description: 'Embeds a Vimeo video player',
requiredParams: ['id'],
validate: (params) => {
if (!params.id) {
return 'Vimeo macro requires an "id" parameter (the video ID)';
}
// Vimeo IDs are numeric
if (!/^\d+$/.test(params.id)) {
return 'Invalid Vimeo video ID format (should be numeric)';
}
return undefined;
},
},
{ {
name: 'gallery', name: 'gallery',
description: 'Renders an image gallery from linked media files', description: 'Renders an image gallery from linked media files',

View File

@@ -430,9 +430,12 @@ export class ImportExecutionEngine extends EventEmitter {
const wxrPost = analyzed.wxrPost; const wxrPost = analyzed.wxrPost;
const db = getDatabase().getLocal(); const db = getDatabase().getLocal();
// Convert Vimeo iframes to [[vimeo]] macros BEFORE markdown conversion
const contentWithVimeo = this.convertVimeoIframes(wxrPost.content);
// Transform WordPress shortcodes [shortcode] to [[shortcode]] BEFORE markdown conversion // Transform WordPress shortcodes [shortcode] to [[shortcode]] BEFORE markdown conversion
// (TurndownService escapes brackets, so we must transform first) // (TurndownService escapes brackets, so we must transform first)
const contentWithShortcodes = this.transformShortcodes(wxrPost.content); const contentWithShortcodes = this.transformShortcodes(contentWithVimeo);
// Convert HTML content to Markdown // Convert HTML content to Markdown
let transformedContent = this.convertToMarkdown(contentWithShortcodes); let transformedContent = this.convertToMarkdown(contentWithShortcodes);
@@ -779,6 +782,16 @@ export class ImportExecutionEngine extends EventEmitter {
return markdown.replace(uploadsUrlPattern, 'media/$1'); return markdown.replace(uploadsUrlPattern, 'media/$1');
} }
/**
* Convert Vimeo iframes to [[vimeo id=...]] macros.
* Matches <iframe src="...player.vimeo.com/video/ID..."> and converts to [[vimeo id=ID]]
*/
private convertVimeoIframes(content: string): string {
// Match Vimeo iframe embeds: <iframe src="http(s)://player.vimeo.com/video/12345...">
const vimeoIframeRegex = /<iframe[^>]*src=["']https?:\/\/player\.vimeo\.com\/video\/(\d+)[^"']*["'][^>]*><\/iframe>/gi;
return content.replace(vimeoIframeRegex, '[[vimeo id=$1]]');
}
/** /**
* Transform WordPress shortcodes [shortcode] to [[shortcode]] * Transform WordPress shortcodes [shortcode] to [[shortcode]]
*/ */

View File

@@ -12,6 +12,7 @@
// Import all macro definitions - they self-register on import // Import all macro definitions - they self-register on import
import './gallery'; import './gallery';
import './youtube'; import './youtube';
import './vimeo';
import './photo_archive'; import './photo_archive';
// Add new macro imports here: // Add new macro imports here:

View File

@@ -0,0 +1,76 @@
/**
* Vimeo Macro
*
* Embeds a Vimeo video player.
*
* Usage: [[vimeo id=12155835]]
*
* Parameters:
* - id (required): Vimeo video ID
* - title: Accessible title for the iframe
*/
import { registerMacro } from '../registry';
import type { MacroDefinition, MacroParams, MacroRenderContext } from '../types';
const vimeoMacro: MacroDefinition = {
name: 'vimeo',
description: 'Embeds a Vimeo video player',
validate(params: MacroParams): string | undefined {
if (!params.id) {
return 'Vimeo macro requires an "id" parameter (the video ID)';
}
// Vimeo IDs are numeric
if (!/^\d+$/.test(params.id)) {
return 'Invalid Vimeo video ID format (should be numeric)';
}
return undefined;
},
editorPreview(params: MacroParams): string {
const id = params.id || '?';
const title = params.title;
return title ? `▶ Vimeo: ${title}` : `▶ Vimeo: ${id}`;
},
render(params: MacroParams, context: MacroRenderContext): string {
const { id, title = 'Vimeo video' } = params;
const embedUrl = `https://player.vimeo.com/video/${id}`;
if (context.isPreview) {
// In preview, show a placeholder with Vimeo branding
return `
<div class="macro-vimeo vimeo-preview">
<div class="vimeo-thumbnail">
<div class="vimeo-play-overlay">
<span class="vimeo-play-button">▶</span>
</div>
<span class="vimeo-title">${title} (Vimeo: ${id})</span>
</div>
</div>
`;
}
// Production render - full iframe embed
return `
<div class="macro-vimeo">
<div class="vimeo-container">
<iframe
src="${embedUrl}"
title="${title}"
frameborder="0"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen
></iframe>
</div>
</div>
`;
},
};
// Self-register
registerMacro(vimeoMacro);
export default vimeoMacro;