mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-27 22:49:56 -05:00
🐛 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
2 changed files with 38 additions and 0 deletions
|
@ -373,6 +373,18 @@ class OEmbedService {
|
||||||
try {
|
try {
|
||||||
const urlObject = new URL(url);
|
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)`
|
// Trimming solves the difference of url validation between `new URL(url)`
|
||||||
// and metascraper.
|
// and metascraper.
|
||||||
url = url.trim();
|
url = url.trim();
|
||||||
|
|
|
@ -172,5 +172,31 @@ describe('oembed-service', function () {
|
||||||
assert.equal(response.url, 'https://www.example.com');
|
assert.equal(response.url, 'https://www.example.com');
|
||||||
assert.equal(response.metadata.title, 'Example');
|
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…
Add table
Reference in a new issue