Invidious/YouTube video template

Hello everyone!

I’ve been playing a bit with Silverbullet and I like it a lot. I’m streamlining some of the cases that I’d like to use on my notes and one of them are adding YouTube videos (not embed but a thumbnail + link). In my specific case I’d like videos that are retrieved and linked to an Indivious instance to avoid the cluttered and add-filled YouTube.

I created an small space-script that retrieves the video name, thumbnail and links it. This custom function input can be a YouTube URL, Indivious URL or just the video id. Add this snipplet of code to a page, reload (Control+Alt+r) and start using it as a template.

I used https://inv.tux.pizza as the instance, but you can use your own self-hosted one or any of the public instances (Invidious Instances - Invidious Documentation).


const INVIDIOUS_INSTANCE = 'https://inv.tux.pizza'

async function invFetchVideoTitle(videoid) {
    const apiUrl = `${INVIDIOUS_INSTANCE}/api/v1/videos/${videoid}`;

    try {
        const response = await fetch(apiUrl);
        if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
        }
        const data = await response.json();
        return data.title.replace(/[#\[\]{}*]/g, '');
    } catch (error) {
        console.error('Error fetching video title:', error);
        return null;
    }
}

function invGetVideoThumbnail(videoid) {
    return `${INVIDIOUS_INSTANCE}/vi/${videoid}/0.jpg`
}

function invGetVideoLink(videoid) {
    return `${INVIDIOUS_INSTANCE}/watch?v=${videoid}`
}

function invExtractYouTubeVideoID(url_or_videoid) {
    const ytRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
    const ytMatch = url_or_videoid.match(ytRegex);
    if (ytMatch) {
        return ytMatch[1];
    }
  
    const invRegex = /(?:https?:\/\/)?[\w.-]+\/watch\?v=([a-zA-Z0-9_-]{11})/;
    const invMatch = url_or_videoid.match(invRegex);
    if (invMatch) {
        return invMatch[1];
    }

    return url_or_videoid;
  }

  
async function invGetVideoMarkdown(url_or_videoid) {
    videoid = invExtractYouTubeVideoID(url_or_videoid);
    title = await invFetchVideoTitle(videoid);
    thumb = invGetVideoThumbnail(videoid);
    link = invGetVideoLink(videoid);
    return `![${title}](${thumb})\n[${title}](${link})`
}

silverbullet.registerFunction({name: "youtube"}, async (videoid) => {
    return invGetVideoMarkdown(videoid);
  });

Example usage:

{{youtube("https://www.youtube.com/watch?v=F8EMW5pXFFM")}}

This would look like this on a page:

I hope this is useful or at least that helps you to learn a bit on how to develop these custom functions (they’re quite powerful).

Best,
Pablo

3 Likes

Nice! Link unfurling does something similar already for Youtube, e.g. putting a Youtube “naked” url in your page, and then running Link: Unfurl will offer to replace it with an embed. While it’s technically possible to extend this functionality from space script as well via event listening, I like this solution too :+1:

I’ll explore changing the unfurl behavior as well.

Templates can be good for queries to structured data , that might happen to have a video, but the unfurl is more appropriate to my intended usage.