🐛 Fixed YouTube live embeds failing in some situations
ref https://linear.app/tryghost/issue/ONC-197 - YouTube has started responding to video page requests with localised content when requested from certain IPs, with that localised content not containing the required `<link rel="alternate" ...>` tag pointing to the oembed endpoint - we were fetching video pages rather than the oembed endpoint for YouTube Live URLs because they are not recognised by the oembed extraction library we use - by modifying the URL from a live URL to a watch URL before we perform oembed lookup/extraction we are able to bypass the (localised) page fetch and instead grab the oembed content directly
This commit is contained in:
parent
68d8f19d5a
commit
1eab73c76d
@ -373,6 +373,18 @@ class OEmbedService {
|
||||
try {
|
||||
const urlObject = new URL(url);
|
||||
|
||||
// YouTube has started not returning oembed <link>tags for some live URLs
|
||||
// when fetched from an IP address that's in a non-EN region.
|
||||
// We convert live URLs to watch URLs so we can go straight to the
|
||||
// oembed request via a known provider rather than going through the page fetch routine.
|
||||
const ytLiveRegex = /^\/live\/([a-zA-Z0-9_-]+)$/;
|
||||
if (urlObject.hostname === 'www.youtube.com' && ytLiveRegex.test(urlObject.pathname)) {
|
||||
const videoId = ytLiveRegex.exec(urlObject.pathname)[1];
|
||||
urlObject.pathname = '/watch';
|
||||
urlObject.searchParams.set('v', videoId);
|
||||
url = urlObject.toString();
|
||||
}
|
||||
|
||||
// Trimming solves the difference of url validation between `new URL(url)`
|
||||
// and metascraper.
|
||||
url = url.trim();
|
||||
|
@ -172,5 +172,31 @@ describe('oembed-service', function () {
|
||||
assert.equal(response.url, 'https://www.example.com');
|
||||
assert.equal(response.metadata.title, 'Example');
|
||||
});
|
||||
|
||||
it('converts YT live URLs to watch URLs', async function () {
|
||||
nock('https://www.youtube.com')
|
||||
.get('/oembed')
|
||||
.query((query) => {
|
||||
// Ensure the URL is converted to a watch URL and retains existing query params.
|
||||
const actual = query.url;
|
||||
const expected = 'https://youtube.com/watch?param=existing&v=1234';
|
||||
|
||||
assert.equal(actual, expected, 'URL passed to oembed endpoint is incorrect');
|
||||
|
||||
return actual === expected;
|
||||
})
|
||||
.reply(200, {
|
||||
type: 'rich',
|
||||
version: '1.0',
|
||||
title: 'Test Title',
|
||||
author_name: 'Test Author',
|
||||
author_url: 'https://example.com/user/testauthor',
|
||||
html: '<iframe src="https://www.example.com/embed"></iframe>',
|
||||
width: 640,
|
||||
height: null
|
||||
});
|
||||
|
||||
await oembedService.fetchOembedDataFromUrl('https://www.youtube.com/live/1234?param=existing');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user