diff --git a/packages/content-handler/src/websites/youtube-handler.ts b/packages/content-handler/src/websites/youtube-handler.ts index a12107f50..8021f467e 100644 --- a/packages/content-handler/src/websites/youtube-handler.ts +++ b/packages/content-handler/src/websites/youtube-handler.ts @@ -18,6 +18,11 @@ export const getYoutubeVideoId = (url: string) => { return videoId } +export const getYoutubePlaylistId = (url: string) => { + const u = new URL(url) + return u.searchParams.get('list') +} + export const escapeTitle = (title: string) => { return _.escape(title) } @@ -33,14 +38,24 @@ export class YoutubeHandler extends ContentHandler { } async preHandle(url: string): Promise { - const videoId = getYoutubeVideoId(url) - if (!videoId) { - return {} + let urlToEncode: string + let src: string + const playlistId = getYoutubePlaylistId(url) + if (playlistId) { + urlToEncode = `https://www.youtube.com/playlist?list=${playlistId}` + src = `https://www.youtube.com/embed/videoseries?list=${playlistId}` + } else { + const videoId = getYoutubeVideoId(url) + if (!videoId) { + return {} + } + urlToEncode = `https://www.youtube.com/watch?v=${videoId}` + src = `https://www.youtube.com/embed/${videoId}` } const oembedUrl = `https://www.youtube.com/oembed?format=json&url=` + - encodeURIComponent(`https://www.youtube.com/watch?v=${videoId}`) + encodeURIComponent(urlToEncode) const oembed = (await axios.get(oembedUrl.toString())).data as { title: string width: number @@ -68,7 +83,7 @@ export class YoutubeHandler extends ContentHandler { - +

${escapedTitle}

diff --git a/packages/content-handler/test/youtube-handler.test.ts b/packages/content-handler/test/youtube-handler.test.ts index 410229691..f08e114cc 100644 --- a/packages/content-handler/test/youtube-handler.test.ts +++ b/packages/content-handler/test/youtube-handler.test.ts @@ -1,6 +1,6 @@ -import { expect } from 'chai' -import 'mocha' -import { escapeTitle, getYoutubeVideoId } from '../src/websites/youtube-handler' +import { expect } from "chai"; +import "mocha"; +import { escapeTitle, getYoutubePlaylistId, getYoutubeVideoId } from "../src/websites/youtube-handler"; describe('getYoutubeVideoId', () => { it('should parse video id out of a URL', async () => { @@ -24,6 +24,36 @@ describe('getYoutubeVideoId', () => { }) }) +describe('getYoutubePlaylistId', () => { + it('should parse playlist id out of a URL', async () => { + expect('PL6D4F6A0D6B0C6A5E').to.eq( + getYoutubePlaylistId( + 'https://www.youtube.com/watch?v=BnSUk0je6oo&t=269s&list=PL6D4F6A0D6B0C6A5E' + ) + ) + expect('RDvFD2gu007dc').to.eq( + getYoutubePlaylistId( + 'https://www.youtube.com/watch?v=vFD2gu007dc&list=RDvFD2gu007dc&start_radio=1' + ) + ) + expect('PL6D4F6A0D6B0C6A5E').to.eq( + getYoutubePlaylistId( + 'https://www.youtube.com/playlist?list=PL6D4F6A0D6B0C6A5E' + ) + ) + expect('PL6D4F6A0D6B0C6A5E').to.eq( + getYoutubePlaylistId( + 'https://www.youtube.com/playlist?list=PL6D4F6A0D6B0C6A5E&feature=share' + ) + ) + expect('PL6D4F6A0D6B0C6A5E').to.eq( + getYoutubePlaylistId( + 'https://www.youtube.com/playlist?list=PL6D4F6A0D6B0C6A5E&feature=share' + ) + ) + }) +}) + describe('escapeTitle', () => { it('escapes the special characters in the title', async () => { expect(escapeTitle("The Stanley's Parable")).to.eq(