GoogleVideo: fix contentUrl
and add more metadata (#1659)
* GoogleVideo: add more metadata * GoogleVideo: fix `contentUrl` `contentUrl` needs to be the url of the video file itself, not the page or some redirect. Copied the way the url is generated in the RSS code.
This commit is contained in:
parent
86d311f45d
commit
2a83c7d8ec
2 changed files with 75 additions and 5 deletions
|
@ -363,7 +363,7 @@ async function getHtml(ctx) {
|
||||||
|
|
||||||
if (claim) {
|
if (claim) {
|
||||||
const ogMetadata = await buildClaimOgMetadata(claimUri, claim);
|
const ogMetadata = await buildClaimOgMetadata(claimUri, claim);
|
||||||
const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim);
|
const googleVideoMetadata = await buildGoogleVideoMetadata(claimUri, claim);
|
||||||
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
|
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ async function getHtml(ctx) {
|
||||||
|
|
||||||
if (claim) {
|
if (claim) {
|
||||||
const ogMetadata = await buildClaimOgMetadata(claimUri, claim, {}, referrerQuery);
|
const ogMetadata = await buildClaimOgMetadata(claimUri, claim, {}, referrerQuery);
|
||||||
const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim);
|
const googleVideoMetadata = await buildGoogleVideoMetadata(claimUri, claim);
|
||||||
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
|
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,22 @@
|
||||||
|
const Mime = require('mime-types');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const removeMd = require('remove-markdown');
|
const removeMd = require('remove-markdown');
|
||||||
|
|
||||||
// TODO: fix relative path for server
|
// TODO: fix relative path for server
|
||||||
|
const { fetchStreamUrl } = require('../fetchStreamUrl');
|
||||||
const { parseURI } = require('../lbryURI');
|
const { parseURI } = require('../lbryURI');
|
||||||
const { OG_IMAGE_URL, SITE_NAME, URL } = require('../../../config.js');
|
const { OG_IMAGE_URL, SITE_NAME, URL } = require('../../../config.js');
|
||||||
const { generateDirectUrl, generateEmbedUrl, getThumbnailCdnUrl, escapeHtmlProperty } = require('../../../ui/util/web');
|
const { generateEmbedUrl, getThumbnailCdnUrl, escapeHtmlProperty } = require('../../../ui/util/web');
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// Utils
|
||||||
|
// ****************************************************************************
|
||||||
|
|
||||||
|
function lbryToOdyseeUrl(claim) {
|
||||||
|
if (claim.canonical_url) {
|
||||||
|
return `${URL}/${claim.canonical_url.replace('lbry://', '').replace(/#/g, ':')}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function truncateDescription(description, maxChars = 200) {
|
function truncateDescription(description, maxChars = 200) {
|
||||||
// Get list of single-codepoint strings
|
// Get list of single-codepoint strings
|
||||||
|
@ -15,11 +27,57 @@ function truncateDescription(description, maxChars = 200) {
|
||||||
return chars.length > maxChars ? truncated + '...' : truncated;
|
return chars.length > maxChars ? truncated + '...' : truncated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// ****************************************************************************
|
||||||
|
|
||||||
|
const Generate = {
|
||||||
|
author: (claim) => {
|
||||||
|
const channelName = claim?.signing_channel?.value?.title || claim?.signing_channel?.name;
|
||||||
|
const channelUrl = lbryToOdyseeUrl(claim.signing_channel);
|
||||||
|
if (channelName && channelUrl) {
|
||||||
|
return { '@type': 'Person', name: channelName, url: channelUrl };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
height: (claim) => {
|
||||||
|
return claim?.value?.video?.height;
|
||||||
|
},
|
||||||
|
|
||||||
|
keywords: (claim) => {
|
||||||
|
const tags = claim?.value?.tags;
|
||||||
|
if (tags) {
|
||||||
|
// Some claims, probably created from cli, have a crazy amount of tags.
|
||||||
|
// Limit that to 10.
|
||||||
|
return tags.slice(0, 10).join(',');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
potentialAction: (claim) => {
|
||||||
|
// https://developers.google.com/search/docs/advanced/structured-data/video?hl=en#seek
|
||||||
|
if ((claim?.value?.video || claim?.value?.audio) && claim.canonical_url) {
|
||||||
|
return {
|
||||||
|
'@type': 'SeekToAction',
|
||||||
|
target: `${lbryToOdyseeUrl(claim)}?t={seek_to_second_number}`,
|
||||||
|
'startOffset-input': 'required name=seek_to_second_number',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
thumbnail: (url) => {
|
||||||
|
// We don't have 'width' and 'height' from the claim :(
|
||||||
|
return { '@type': 'ImageObject', url };
|
||||||
|
},
|
||||||
|
|
||||||
|
width: (claim) => {
|
||||||
|
return claim?.value?.video?.width;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// ****************************************************************************
|
// ****************************************************************************
|
||||||
// buildGoogleVideoMetadata
|
// buildGoogleVideoMetadata
|
||||||
// ****************************************************************************
|
// ****************************************************************************
|
||||||
|
|
||||||
function buildGoogleVideoMetadata(uri, claim) {
|
async function buildGoogleVideoMetadata(uri, claim) {
|
||||||
const { claimName } = parseURI(uri);
|
const { claimName } = parseURI(uri);
|
||||||
const { meta, value } = claim;
|
const { meta, value } = claim;
|
||||||
const media = value && value.video;
|
const media = value && value.video;
|
||||||
|
@ -41,6 +99,10 @@ function buildGoogleVideoMetadata(uri, claim) {
|
||||||
|
|
||||||
const claimThumbnail = escapeHtmlProperty(thumbnail) || getThumbnailCdnUrl(OG_IMAGE_URL) || `${URL}/public/v2-og.png`;
|
const claimThumbnail = escapeHtmlProperty(thumbnail) || getThumbnailCdnUrl(OG_IMAGE_URL) || `${URL}/public/v2-og.png`;
|
||||||
|
|
||||||
|
const fileExt = value.source && value.source.media_type && '.' + Mime.extension(value.source.media_type);
|
||||||
|
const claimStreamUrl =
|
||||||
|
(await fetchStreamUrl(claim.name, claim.claim_id)).replace('/v4/', '/v3/') + (fileExt || '.mp4'); // v3 = mp4 always, v4 may redirect to m3u8;
|
||||||
|
|
||||||
// https://developers.google.com/search/docs/data-types/video
|
// https://developers.google.com/search/docs/data-types/video
|
||||||
const googleVideoMetadata = {
|
const googleVideoMetadata = {
|
||||||
// --- Must ---
|
// --- Must ---
|
||||||
|
@ -52,8 +114,16 @@ function buildGoogleVideoMetadata(uri, claim) {
|
||||||
uploadDate: `${new Date(releaseTime * 1000).toISOString()}`,
|
uploadDate: `${new Date(releaseTime * 1000).toISOString()}`,
|
||||||
// --- Recommended ---
|
// --- Recommended ---
|
||||||
duration: mediaDuration ? moment.duration(mediaDuration * 1000).toISOString() : undefined,
|
duration: mediaDuration ? moment.duration(mediaDuration * 1000).toISOString() : undefined,
|
||||||
contentUrl: generateDirectUrl(claim.name, claim.claim_id),
|
url: lbryToOdyseeUrl(claim),
|
||||||
|
contentUrl: claimStreamUrl,
|
||||||
embedUrl: generateEmbedUrl(claim.name, claim.claim_id),
|
embedUrl: generateEmbedUrl(claim.name, claim.claim_id),
|
||||||
|
// --- Misc ---
|
||||||
|
author: Generate.author(claim),
|
||||||
|
thumbnail: Generate.thumbnail(claimThumbnail),
|
||||||
|
keywords: Generate.keywords(claim),
|
||||||
|
width: Generate.width(claim),
|
||||||
|
height: Generate.height(claim),
|
||||||
|
potentialAction: Generate.potentialAction(claim),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
Loading…
Reference in a new issue