getHtml/routes/rss: fetch streaming_url instead of generating it.

## Issues from the initial attempt
- There are 2 versions of `Lbry` and `buildURI` -- the app and web-server version.  There are subtle differences between them, and for the app case, importing the web-server version results in a query into an invalid URL.
- It changed the function from returning a string to returning a promise.

## Changes
- Since the new function (renamed to `fetchStreamUrl` for clarity) is currently only needed for web-server, I moved it into the `web` folder to avoid misuse in app.
- Await on the promise. Unfortunately, this also means the entire chain of function calls need to be adjusted to be `async`.
This commit is contained in:
infinite-persistence 2022-05-13 18:17:51 +08:00
parent 251187de06
commit de206162f9
No known key found for this signature in database
GPG key ID: B9C3252EDC3D0AA0
7 changed files with 39 additions and 35 deletions

View file

@ -9,7 +9,6 @@ WEB_SERVER_PORT=1337
# -- APIs --- # -- APIs ---
LBRY_WEB_API=https://api.na-backend.odysee.com LBRY_WEB_API=https://api.na-backend.odysee.com
LBRY_WEB_STREAMING_API=https://player.odycdn.com
LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video LBRY_WEB_BUFFER_API=https://collector-service.api.lbry.tv/api/v1/events/video
COMMENT_SERVER_API=https://comments.odysee.tv/api/v2 COMMENT_SERVER_API=https://comments.odysee.tv/api/v2
SEARCH_SERVER_API_ALT=https://recsys.odysee.tv/search SEARCH_SERVER_API_ALT=https://recsys.odysee.tv/search

View file

@ -10,7 +10,6 @@ const config = {
LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API, LBRY_WEB_PUBLISH_API: process.env.LBRY_WEB_PUBLISH_API,
LBRY_WEB_PUBLISH_API_V2: process.env.LBRY_WEB_PUBLISH_API_V2, LBRY_WEB_PUBLISH_API_V2: process.env.LBRY_WEB_PUBLISH_API_V2,
LBRY_API_URL: process.env.LBRY_API_URL, // api.odysee.com', LBRY_API_URL: process.env.LBRY_API_URL, // api.odysee.com',
LBRY_WEB_STREAMING_API: process.env.LBRY_WEB_STREAMING_API, // player.odycdn.com
LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API, LBRY_WEB_BUFFER_API: process.env.LBRY_WEB_BUFFER_API,
SEARCH_SERVER_API: process.env.SEARCH_SERVER_API, SEARCH_SERVER_API: process.env.SEARCH_SERVER_API,
SEARCH_SERVER_API_ALT: process.env.SEARCH_SERVER_API_ALT, SEARCH_SERVER_API_ALT: process.env.SEARCH_SERVER_API_ALT,

View file

@ -1,14 +1,7 @@
const { URL, LBRY_WEB_STREAMING_API, THUMBNAIL_CARDS_CDN_URL } = require('../../config'); const { URL, THUMBNAIL_CARDS_CDN_URL } = require('../../config');
const CONTINENT_COOKIE = 'continent'; const CONTINENT_COOKIE = 'continent';
function generateStreamUrl(claimName, claimId) {
return `${LBRY_WEB_STREAMING_API}/content/claims/${encodeURIComponent(claimName)
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')}/${claimId}/${encodeURIComponent(claimName)}`;
}
function generateEmbedUrl(claimName, claimId, startTime, referralLink) { function generateEmbedUrl(claimName, claimId, startTime, referralLink) {
let urlParams = new URLSearchParams(); let urlParams = new URLSearchParams();
@ -98,7 +91,6 @@ module.exports = {
generateEmbedIframeData, generateEmbedIframeData,
generateEmbedUrl, generateEmbedUrl,
generateEmbedUrlEncoded, generateEmbedUrlEncoded,
generateStreamUrl,
getParameterByName, getParameterByName,
getThumbnailCdnUrl, getThumbnailCdnUrl,
escapeHtmlProperty, escapeHtmlProperty,

15
web/src/fetchStreamUrl.js Normal file
View file

@ -0,0 +1,15 @@
const { lbryProxy: Lbry } = require('../lbry');
const { buildURI } = require('./lbryURI');
async function fetchStreamUrl(claimName, claimId) {
const uri = buildURI({ claimName, claimId });
return await Lbry.get({ uri })
.then(({ streaming_url }) => streaming_url)
.catch((error) => {
return '';
});
}
module.exports = {
fetchStreamUrl,
};

View file

@ -14,12 +14,12 @@ const {
const { const {
generateDirectUrl, generateDirectUrl,
generateEmbedUrl, generateEmbedUrl,
generateStreamUrl,
getParameterByName, getParameterByName,
getThumbnailCdnUrl, getThumbnailCdnUrl,
escapeHtmlProperty, escapeHtmlProperty,
unscapeHtmlProperty, unscapeHtmlProperty,
} = require('../../ui/util/web'); } = require('../../ui/util/web');
const { fetchStreamUrl } = require('./fetchStreamUrl');
const { getJsBundleId } = require('../bundle-id.js'); const { getJsBundleId } = require('../bundle-id.js');
const { lbryProxy: Lbry } = require('../lbry'); const { lbryProxy: Lbry } = require('../lbry');
const { getHomepageJsonV1 } = require('./getHomepageJSON'); const { getHomepageJsonV1 } = require('./getHomepageJSON');
@ -151,7 +151,7 @@ function buildBasicOgMetadata() {
// Metadata used for urls that need claim information // Metadata used for urls that need claim information
// Also has option to override defaults // Also has option to override defaults
// //
function buildClaimOgMetadata(uri, claim, overrideOptions = {}, referrerQuery) { async function buildClaimOgMetadata(uri, claim, overrideOptions = {}, referrerQuery) {
// Initial setup for claim based og metadata // Initial setup for claim based og metadata
const { claimName } = parseURI(uri); const { claimName } = parseURI(uri);
const { meta, value, signing_channel } = claim; const { meta, value, signing_channel } = claim;
@ -181,7 +181,7 @@ function buildClaimOgMetadata(uri, claim, overrideOptions = {}, referrerQuery) {
let imageThumbnail; let imageThumbnail;
if (fee <= 0 && mediaType && mediaType.startsWith('image/')) { if (fee <= 0 && mediaType && mediaType.startsWith('image/')) {
imageThumbnail = generateStreamUrl(claim.name, claim.claim_id); imageThumbnail = await fetchStreamUrl(claim.name, claim.claim_id);
} }
const claimThumbnail = const claimThumbnail =
@ -392,7 +392,7 @@ async function getHtml(ctx) {
const inviteChannel = requestPath.slice(invitePath.length); const inviteChannel = requestPath.slice(invitePath.length);
const inviteChannelUrl = normalizeClaimUrl(inviteChannel); const inviteChannelUrl = normalizeClaimUrl(inviteChannel);
const claim = await resolveClaimOrRedirect(ctx, inviteChannelUrl); const claim = await resolveClaimOrRedirect(ctx, inviteChannelUrl);
const invitePageMetadata = buildClaimOgMetadata(inviteChannelUrl, claim, { const invitePageMetadata = await buildClaimOgMetadata(inviteChannelUrl, claim, {
title: `Join ${claim.name} on ${SITE_NAME}`, title: `Join ${claim.name} on ${SITE_NAME}`,
description: `Join ${claim.name} on ${SITE_NAME}, a content wonderland owned by everyone (and no one).`, description: `Join ${claim.name} on ${SITE_NAME}, a content wonderland owned by everyone (and no one).`,
}); });
@ -414,7 +414,7 @@ async function getHtml(ctx) {
const claim = await resolveClaimOrRedirect(ctx, claimUri, true); const claim = await resolveClaimOrRedirect(ctx, claimUri, true);
if (claim) { if (claim) {
const ogMetadata = buildClaimOgMetadata(claimUri, claim); const ogMetadata = await buildClaimOgMetadata(claimUri, claim);
const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim); const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim);
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata)); return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
} }
@ -438,7 +438,7 @@ async function getHtml(ctx) {
const referrerQuery = escapeHtmlProperty(getParameterByName('r', ctx.request.url)); const referrerQuery = escapeHtmlProperty(getParameterByName('r', ctx.request.url));
if (claim) { if (claim) {
const ogMetadata = buildClaimOgMetadata(claimUri, claim, {}, referrerQuery); const ogMetadata = await buildClaimOgMetadata(claimUri, claim, {}, referrerQuery);
const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim); const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim);
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata)); return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
} }

View file

@ -1,4 +1,4 @@
const { generateStreamUrl } = require('../../ui/util/web'); const { fetchStreamUrl } = require('./fetchStreamUrl');
const { getHtml } = require('./html'); const { getHtml } = require('./html');
const { getOEmbed } = require('./oEmbed'); const { getOEmbed } = require('./oEmbed');
const { getRss } = require('./rss'); const { getRss } = require('./rss');
@ -13,11 +13,9 @@ global.fetch = fetch;
const router = new Router(); const router = new Router();
function getStreamUrl(ctx) { async function getStreamUrl(ctx) {
const { claimName, claimId } = ctx.params; const { claimName, claimId } = ctx.params;
return await fetchStreamUrl(claimName, claimId);
const streamUrl = generateStreamUrl(claimName, claimId);
return streamUrl;
} }
const rssMiddleware = async (ctx) => { const rssMiddleware = async (ctx) => {
@ -43,7 +41,7 @@ router.get(`/$/api/content/v1/get`, async (ctx) => getHomepage(ctx, 1));
router.get(`/$/api/content/v2/get`, async (ctx) => getHomepage(ctx, 2)); router.get(`/$/api/content/v2/get`, async (ctx) => getHomepage(ctx, 2));
router.get(`/$/download/:claimName/:claimId`, async (ctx) => { router.get(`/$/download/:claimName/:claimId`, async (ctx) => {
const streamUrl = getStreamUrl(ctx); const streamUrl = await getStreamUrl(ctx);
const downloadUrl = `${streamUrl}?download=1`; const downloadUrl = `${streamUrl}?download=1`;
ctx.redirect(downloadUrl); ctx.redirect(downloadUrl);
}); });

View file

@ -1,4 +1,4 @@
const { generateStreamUrl } = require('../../ui/util/web'); const { fetchStreamUrl } = require('./fetchStreamUrl');
const { lbryProxy: Lbry } = require('../lbry'); const { lbryProxy: Lbry } = require('../lbry');
const { URL, SITE_NAME, PROXY_URL } = require('../../config.js'); const { URL, SITE_NAME, PROXY_URL } = require('../../config.js');
const Mime = require('mime-types'); const Mime = require('mime-types');
@ -62,7 +62,7 @@ function encodeWithSpecialCharEncode(string) {
return encodeURIComponent(string).replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29'); return encodeURIComponent(string).replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29');
} }
const generateEnclosureForClaimContent = (claim) => { async function generateEnclosureForClaimContent(claim) {
const value = claim.value; const value = claim.value;
if (!value || !value.stream_type) { if (!value || !value.stream_type) {
return undefined; return undefined;
@ -72,27 +72,27 @@ const generateEnclosureForClaimContent = (claim) => {
switch (value.stream_type) { switch (value.stream_type) {
case 'video': case 'video':
return { return {
url: generateStreamUrl(claim.name, claim.claim_id) + (fileExt || '.mp4'), url: (await fetchStreamUrl(claim.name, claim.claim_id)) + (fileExt || '.mp4'),
type: (value.source && value.source.media_type) || 'video/mp4', type: (value.source && value.source.media_type) || 'video/mp4',
size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback. size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback.
}; };
case 'audio': case 'audio':
return { return {
url: generateStreamUrl(claim.name, claim.claim_id) + ((fileExt === '.mpga' ? '.mp3' : fileExt) || '.mp3'), url: (await fetchStreamUrl(claim.name, claim.claim_id)) + ((fileExt === '.mpga' ? '.mp3' : fileExt) || '.mp3'),
type: (value.source && value.source.media_type) || 'audio/mpeg', type: (value.source && value.source.media_type) || 'audio/mpeg',
size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback. size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback.
}; };
case 'image': case 'image':
return { return {
url: generateStreamUrl(claim.name, claim.claim_id) + (fileExt || '.jpeg'), url: (await fetchStreamUrl(claim.name, claim.claim_id)) + (fileExt || '.jpeg'),
type: (value.source && value.source.media_type) || 'image/jpeg', type: (value.source && value.source.media_type) || 'image/jpeg',
size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback. size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback.
}; };
case 'document': case 'document':
case 'software': case 'software':
return { return {
url: generateStreamUrl(claim.name, claim.claim_id), url: await fetchStreamUrl(claim.name, claim.claim_id),
type: (value.source && value.source.media_type) || undefined, type: (value.source && value.source.media_type) || undefined,
size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback. size: (value.source && value.source.size) || 0, // Per spec, 0 is a valid fallback.
}; };
@ -100,7 +100,7 @@ const generateEnclosureForClaimContent = (claim) => {
default: default:
return undefined; return undefined;
} }
}; }
const getLanguageValue = (claim) => { const getLanguageValue = (claim) => {
const { const {
@ -215,7 +215,7 @@ const getFormattedDescription = (claim) => replaceLineFeeds(claim.value.descript
// Generate // Generate
// **************************************************************************** // ****************************************************************************
function generateFeed(feedLink, channelClaim, claimsInChannel) { async function generateFeed(feedLink, channelClaim, claimsInChannel) {
// --- Channel --- // --- Channel ---
let channelTitle = (channelClaim.value && channelClaim.value.title) || channelClaim.name; let channelTitle = (channelClaim.value && channelClaim.value.title) || channelClaim.name;
let channelURL = URL + '/' + channelClaim.canonical_url.replace('lbry://', '').replace(/#/g, ':'); let channelURL = URL + '/' + channelClaim.canonical_url.replace('lbry://', '').replace(/#/g, ':');
@ -245,7 +245,8 @@ function generateFeed(feedLink, channelClaim, claimsInChannel) {
}); });
// --- Content --- // --- Content ---
claimsInChannel.forEach((c) => { for (let i = 0; i < claimsInChannel.length; ++i) {
const c = claimsInChannel[i];
const title = (c.value && c.value.title) || c.name; const title = (c.value && c.value.title) || c.name;
const thumbnailUrl = (c.value && c.value.thumbnail && c.value.thumbnail.url) || ''; const thumbnailUrl = (c.value && c.value.thumbnail && c.value.thumbnail.url) || '';
const thumbnailHtml = thumbnailUrl const thumbnailHtml = thumbnailUrl
@ -264,7 +265,7 @@ function generateFeed(feedLink, channelClaim, claimsInChannel) {
guid: undefined, // defaults to 'url' guid: undefined, // defaults to 'url'
author: undefined, // defaults feed author property author: undefined, // defaults feed author property
date: new Date(date), date: new Date(date),
enclosure: generateEnclosureForClaimContent(c), enclosure: await generateEnclosureForClaimContent(c),
custom_elements: [ custom_elements: [
{ 'itunes:title': title }, { 'itunes:title': title },
{ 'itunes:author': channelTitle }, { 'itunes:author': channelTitle },
@ -273,7 +274,7 @@ function generateFeed(feedLink, channelClaim, claimsInChannel) {
generateItunesExplicitElement(c), generateItunesExplicitElement(c),
], ],
}); });
}); }
return feed; return feed;
} }
@ -289,7 +290,7 @@ async function getRss(ctx) {
} }
const latestClaimsInChannel = await getClaimsFromChannel(channelClaim.claim_id, NUM_ENTRIES); const latestClaimsInChannel = await getClaimsFromChannel(channelClaim.claim_id, NUM_ENTRIES);
const feed = generateFeed(`${URL}${ctx.request.url}`, channelClaim, latestClaimsInChannel); const feed = await generateFeed(`${URL}${ctx.request.url}`, channelClaim, latestClaimsInChannel);
return feed.xml(); return feed.xml();
} }