import { ContentHandler, PreHandleResult } from '../content-handler' import axios from 'axios' import _ from 'underscore' const YOUTUBE_URL_MATCH = /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w-]+\?v=|embed\/|v\/)?)([\w-]+)(\S+)?$/ export const getYoutubeVideoId = (url: string) => { const u = new URL(url) const videoId = u.searchParams.get('v') if (!videoId) { const match = url.toString().match(YOUTUBE_URL_MATCH) if (match === null || match.length < 6 || !match[5]) { return undefined } return match[5] } return videoId } export const escapeTitle = (title: string) => { return _.escape(title) } export class YoutubeHandler extends ContentHandler { constructor() { super() this.name = 'Youtube' } shouldPreHandle(url: string): boolean { return YOUTUBE_URL_MATCH.test(url.toString()) } async preHandle(url: string): Promise { const videoId = getYoutubeVideoId(url) if (!videoId) { return {} } const oembedUrl = `https://www.youtube.com/oembed?format=json&url=` + encodeURIComponent(`https://www.youtube.com/watch?v=${videoId}`) const oembed = (await axios.get(oembedUrl.toString())).data as { title: string width: number height: number thumbnail_url: string author_name: string author_url: string } // escape html entities in title const title = oembed.title const escapedTitle = escapeTitle(title) const ratio = oembed.width / oembed.height const thumbnail = oembed.thumbnail_url const height = 350 const width = height * ratio const authorName = _.escape(oembed.author_name) const content = ` ${escapedTitle}

${escapedTitle}

` return { content, title } } }