[oEmbed] some changes and fixes (#392)
* Fix query selection * Fix xml format * Fix link url and author_url * Refactor repeated components * Refactor repeated embed iframe string * Add support for passing referrer queries to src * Change iframe id from lbry to odysee * Improve replace logic understanding * Fix URL Co-authored-by: Thomas Zarebczan <tzarebczan@users.noreply.github.com>
This commit is contained in:
parent
787ebd9588
commit
c492204e26
9 changed files with 136 additions and 110 deletions
|
@ -89,6 +89,9 @@ const config = {
|
|||
|
||||
};
|
||||
|
||||
config.SDK_API_PATH = `${config.LBRY_WEB_API}/api/v1`;
|
||||
config.PROXY_URL = `${config.SDK_API_PATH}/proxy`;
|
||||
|
||||
config.URL_DEV = `http://localhost:${config.WEBPACK_WEB_PORT}`;
|
||||
config.URL_LOCAL = `http://localhost:${config.WEB_SERVER_PORT}`;
|
||||
config.FAVICON = `/public/favicon-spaceman.png`;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { Lbryio } from 'lbryinc';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import * as RENDER_MODES from 'constants/file_render_modes';
|
||||
import { SDK_API_PATH } from './index';
|
||||
import { SDK_API_PATH } from 'config';
|
||||
|
||||
// --- GA ---
|
||||
// - Events: 500 max (cannot be deleted).
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as ICONS from 'constants/icons';
|
|||
import { FormField } from 'component/common/form';
|
||||
import Button from 'component/button';
|
||||
import React, { useRef } from 'react';
|
||||
import { generateEmbedUrl } from 'util/web';
|
||||
import { generateEmbedUrl, generateEmbedIframeData } from 'util/web';
|
||||
|
||||
type Props = {
|
||||
copyable: string,
|
||||
|
@ -22,7 +22,7 @@ export default function EmbedTextArea(props: Props) {
|
|||
const input = useRef();
|
||||
|
||||
const streamUrl = generateEmbedUrl(name, claimId, includeStartTime, startTime, referralCode);
|
||||
let embedText = `<iframe id="lbry-iframe" width="560" height="315" src="${streamUrl}" allowfullscreen></iframe>`;
|
||||
const { html: embedText } = generateEmbedIframeData(streamUrl);
|
||||
|
||||
function copyToClipboard() {
|
||||
const topRef = input.current;
|
||||
|
|
10
ui/index.jsx
10
ui/index.jsx
|
@ -35,7 +35,7 @@ import {
|
|||
doAuthTokenRefresh,
|
||||
} from 'util/saved-passwords';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
import { LBRY_WEB_API, DEFAULT_LANGUAGE, LBRY_API_URL } from 'config';
|
||||
import { PROXY_URL, DEFAULT_LANGUAGE, LBRY_API_URL } from 'config';
|
||||
|
||||
// Import 3rd-party styles before ours for the current way we are code-splitting.
|
||||
import 'scss/third-party.scss';
|
||||
|
@ -64,13 +64,7 @@ if (process.env.SDK_API_URL) {
|
|||
console.warn('SDK_API_URL env var is deprecated. Use SDK_API_HOST instead'); // @eslint-disable-line
|
||||
}
|
||||
|
||||
let sdkAPIHost = process.env.SDK_API_HOST || process.env.SDK_API_URL;
|
||||
sdkAPIHost = LBRY_WEB_API;
|
||||
|
||||
export const SDK_API_PATH = `${sdkAPIHost}/api/v1`;
|
||||
const proxyURL = `${SDK_API_PATH}/proxy`;
|
||||
|
||||
Lbry.setDaemonConnectionString(proxyURL);
|
||||
Lbry.setDaemonConnectionString(PROXY_URL);
|
||||
|
||||
Lbry.setOverride(
|
||||
'publish',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { URL, LBRY_WEB_STREAMING_API } = require('../../config');
|
||||
const { URL, LBRY_WEB_STREAMING_API, THUMBNAIL_CARDS_CDN_URL } = require('../../config');
|
||||
|
||||
const CONTINENT_COOKIE = 'continent';
|
||||
|
||||
|
@ -25,6 +25,14 @@ function generateEmbedUrl(claimName, claimId, includeStartTime, startTime, refer
|
|||
.replace(/\)/g, '%29')}/${claimId}?${urlParams.toString()}`;
|
||||
}
|
||||
|
||||
function generateEmbedIframeData(src) {
|
||||
const width = '560';
|
||||
const height = '315';
|
||||
const html = `<iframe id="odysee-iframe" width="${width}" height="${height}" src="${src}" allowfullscreen></iframe>`;
|
||||
|
||||
return { html, width, height };
|
||||
}
|
||||
|
||||
function generateDownloadUrl(claimName, claimId) {
|
||||
return `${URL}/$/download/${claimName}/${claimId}`;
|
||||
}
|
||||
|
@ -33,5 +41,34 @@ function generateDirectUrl(claimName, claimId) {
|
|||
return `${URL}/$/stream/${claimName}/${claimId}`;
|
||||
}
|
||||
|
||||
function getThumbnailCdnUrl(url) {
|
||||
if (
|
||||
!THUMBNAIL_CARDS_CDN_URL ||
|
||||
!url ||
|
||||
(url && (url.includes('https://twitter-card') || url.includes('https://cards.odysee.com')))
|
||||
) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
const encodedURL = Buffer.from(url).toString('base64');
|
||||
return `${THUMBNAIL_CARDS_CDN_URL}${encodedURL}.jpg`;
|
||||
}
|
||||
}
|
||||
|
||||
function getParameterByName(name, url) {
|
||||
var match = RegExp('[?&]' + name + '=([^&]*)').exec(url);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
// module.exports needed since the web server imports this function
|
||||
module.exports = { generateStreamUrl, generateEmbedUrl, generateDownloadUrl, generateDirectUrl, CONTINENT_COOKIE };
|
||||
module.exports = {
|
||||
CONTINENT_COOKIE,
|
||||
generateDirectUrl,
|
||||
generateDownloadUrl,
|
||||
generateEmbedIframeData,
|
||||
generateEmbedUrl,
|
||||
generateStreamUrl,
|
||||
getParameterByName,
|
||||
getThumbnailCdnUrl,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { SDK_API_PATH } from 'ui';
|
||||
import { SDK_API_PATH } from 'config';
|
||||
import { useEffect } from 'react';
|
||||
import { getAuthToken } from 'util/saved-passwords';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
const {
|
||||
FAVICON,
|
||||
LBRY_WEB_API,
|
||||
OG_HOMEPAGE_TITLE,
|
||||
OG_IMAGE_URL,
|
||||
OG_TITLE_SUFFIX,
|
||||
PROXY_URL,
|
||||
SITE_CANONICAL_URL,
|
||||
SITE_DESCRIPTION,
|
||||
SITE_NAME,
|
||||
SITE_TITLE,
|
||||
THUMBNAIL_CARDS_CDN_URL,
|
||||
URL,
|
||||
} = require('../../config.js');
|
||||
|
||||
const { CATEGORY_METADATA } = require('./category-metadata');
|
||||
const { generateEmbedUrl, generateStreamUrl, generateDirectUrl } = require('../../ui/util/web');
|
||||
const {
|
||||
generateDirectUrl,
|
||||
generateEmbedUrl,
|
||||
generateStreamUrl,
|
||||
getParameterByName,
|
||||
getThumbnailCdnUrl,
|
||||
} = require('../../ui/util/web');
|
||||
const { getJsBundleId } = require('../bundle-id.js');
|
||||
const { lbryProxy: Lbry } = require('../lbry');
|
||||
const { parseURI, normalizeClaimUrl } = require('./lbryURI');
|
||||
|
@ -24,28 +29,11 @@ const path = require('path');
|
|||
const removeMd = require('remove-markdown');
|
||||
|
||||
const jsBundleId = getJsBundleId();
|
||||
const SDK_API_PATH = `${LBRY_WEB_API}/api/v1`;
|
||||
const PROXY_URL = `${SDK_API_PATH}/proxy`;
|
||||
Lbry.setDaemonConnectionString(PROXY_URL);
|
||||
|
||||
const BEGIN_STR = '<!-- VARIABLE_HEAD_BEGIN -->';
|
||||
const FINAL_STR = '<!-- VARIABLE_HEAD_END -->';
|
||||
|
||||
function getThumbnailCdnUrl(url) {
|
||||
if (
|
||||
!THUMBNAIL_CARDS_CDN_URL ||
|
||||
!url ||
|
||||
(url && (url.includes('https://twitter-card') || url.includes('https://cards.odysee.com')))
|
||||
) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
const encodedURL = Buffer.from(url).toString('base64');
|
||||
return `${THUMBNAIL_CARDS_CDN_URL}${encodedURL}.jpg`;
|
||||
}
|
||||
}
|
||||
|
||||
function insertToHead(fullHtml, htmlToInsert) {
|
||||
const beginIndex = fullHtml.indexOf(BEGIN_STR);
|
||||
const finalIndex = fullHtml.indexOf(FINAL_STR);
|
||||
|
@ -148,7 +136,7 @@ function buildBasicOgMetadata() {
|
|||
// Metadata used for urls that need claim information
|
||||
// Also has option to override defaults
|
||||
//
|
||||
function buildClaimOgMetadata(uri, claim, overrideOptions = {}) {
|
||||
function buildClaimOgMetadata(uri, claim, overrideOptions = {}, referrerQuery) {
|
||||
// Initial setup for claim based og metadata
|
||||
const { claimName } = parseURI(uri);
|
||||
const { meta, value, signing_channel } = claim;
|
||||
|
@ -187,6 +175,7 @@ function buildClaimOgMetadata(uri, claim, overrideOptions = {}) {
|
|||
const title = overrideOptions.title || claimTitle;
|
||||
const description = overrideOptions.description || claimDescription;
|
||||
const cleanDescription = removeMd(description);
|
||||
const claimPath = `${URL}/${claim.canonical_url.replace('lbry://', '').replace('#', ':')}`;
|
||||
|
||||
let head = '';
|
||||
|
||||
|
@ -209,17 +198,16 @@ function buildClaimOgMetadata(uri, claim, overrideOptions = {}) {
|
|||
head += `<meta property="og:type" content="website"/>`;
|
||||
head += `<meta property="og:title" content="${title}"/>`;
|
||||
head += `<meta name="twitter:title" content="${title}"/>`;
|
||||
// below should be canonical_url, but not provided by chainquery yet
|
||||
head += `<meta property="og:url" content="${URL}/${claim.name}:${claim.claim_id}"/>`;
|
||||
head += `<meta name="twitter:url" content="${URL}/${claim.name}:${claim.claim_id}"/>`;
|
||||
head += `<meta property="og:url" content="${claimPath}"/>`;
|
||||
head += `<meta name="twitter:url" content="${claimPath}"/>`;
|
||||
head += `<meta property="fb:app_id" content="1673146449633983" />`;
|
||||
head += `<link rel="canonical" content="${SITE_CANONICAL_URL || URL}/${claim.name}:${claim.claim_id}"/>`;
|
||||
head += `<link rel="canonical" content="${claimPath}"/>`;
|
||||
head += `<link rel="alternate" type="application/json+oembed" href="${URL}/$/oembed?url=${encodeURIComponent(
|
||||
`${URL}/${claim.canonical_url}`
|
||||
)}&format=json" title="${title}" />`;
|
||||
claimPath
|
||||
)}&format=json${referrerQuery ? `&r=${referrerQuery}` : ''}" title="${title}" />`;
|
||||
head += `<link rel="alternate" type="text/xml+oembed" href="${URL}/$/oembed?url=${encodeURIComponent(
|
||||
`${URL}/${claim.canonical_url}`
|
||||
)}&format=xml" title="${title}" />`;
|
||||
claimPath
|
||||
)}&format=xml${referrerQuery ? `&r=${referrerQuery}` : ''}" title="${title}" />`;
|
||||
|
||||
if (mediaType && (mediaType.startsWith('video/') || mediaType.startsWith('audio/'))) {
|
||||
const videoUrl = generateEmbedUrl(claim.name, claim.claim_id);
|
||||
|
@ -381,9 +369,10 @@ async function getHtml(ctx) {
|
|||
if (!requestPath.includes('$')) {
|
||||
const claimUri = normalizeClaimUrl(requestPath.slice(1));
|
||||
const claim = await resolveClaimOrRedirect(ctx, claimUri);
|
||||
const referrerQuery = getParameterByName('r', ctx.request.url);
|
||||
|
||||
if (claim) {
|
||||
const ogMetadata = buildClaimOgMetadata(claimUri, claim);
|
||||
const ogMetadata = buildClaimOgMetadata(claimUri, claim, {}, referrerQuery);
|
||||
const googleVideoMetadata = buildGoogleVideoMetadata(claimUri, claim);
|
||||
return insertToHead(html, ogMetadata.concat('\n', googleVideoMetadata));
|
||||
}
|
||||
|
|
|
@ -1,49 +1,26 @@
|
|||
const { URL, SITE_NAME, PROXY_URL, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH } = require('../../config.js');
|
||||
|
||||
const {
|
||||
URL,
|
||||
SITE_NAME,
|
||||
LBRY_WEB_API,
|
||||
THUMBNAIL_CARDS_CDN_URL,
|
||||
THUMBNAIL_HEIGHT,
|
||||
THUMBNAIL_WIDTH,
|
||||
} = require('../../config.js');
|
||||
|
||||
const { generateEmbedUrl } = require('../../ui/util/web');
|
||||
generateEmbedIframeData,
|
||||
generateEmbedUrl,
|
||||
getParameterByName,
|
||||
getThumbnailCdnUrl,
|
||||
} = require('../../ui/util/web');
|
||||
const { lbryProxy: Lbry } = require('../lbry');
|
||||
const { normalizeURI } = require('./lbryURI');
|
||||
|
||||
const SDK_API_PATH = `${LBRY_WEB_API}/api/v1`;
|
||||
const proxyURL = `${SDK_API_PATH}/proxy`;
|
||||
Lbry.setDaemonConnectionString(proxyURL);
|
||||
Lbry.setDaemonConnectionString(PROXY_URL);
|
||||
|
||||
// ****************************************************************************
|
||||
// Fetch claim info
|
||||
// ****************************************************************************
|
||||
|
||||
function getThumbnailCdnUrl(url) {
|
||||
if (
|
||||
!THUMBNAIL_CARDS_CDN_URL ||
|
||||
!url ||
|
||||
(url && (url.includes('https://twitter-card') || url.includes('https://cards.odysee.com')))
|
||||
) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
const encodedURL = Buffer.from(url).toString('base64');
|
||||
return `${THUMBNAIL_CARDS_CDN_URL}${encodedURL}.jpg`;
|
||||
}
|
||||
}
|
||||
|
||||
async function getClaim(requestUrl) {
|
||||
const path = requestUrl.replace(URL, '').substring(1);
|
||||
const uri = requestUrl.replace(`${URL}/`, 'lbry://');
|
||||
|
||||
let uri;
|
||||
let claim;
|
||||
let error;
|
||||
|
||||
try {
|
||||
uri = normalizeURI(path);
|
||||
|
||||
const response = await Lbry.resolve({ urls: [uri] });
|
||||
if (response && response[uri] && !response[uri].error) {
|
||||
claim = response[uri];
|
||||
|
@ -67,17 +44,17 @@ async function getClaim(requestUrl) {
|
|||
// Generate
|
||||
// ****************************************************************************
|
||||
|
||||
function generateOEmbedData(claim) {
|
||||
function generateOEmbedData(claim, referrerQuery) {
|
||||
const { value, signing_channel: authorClaim } = claim;
|
||||
|
||||
const claimTitle = value.title;
|
||||
const authorName = authorClaim ? authorClaim.value.title || authorClaim.name : 'Anonymous';
|
||||
const authorUrlPath = authorClaim && authorClaim.canonical_url.replace('lbry://', '');
|
||||
const authorUrlPath = authorClaim && authorClaim.canonical_url.replace('lbry://', '').replace('#', ':');
|
||||
const authorUrl = authorClaim ? `${URL}/${authorUrlPath}` : null;
|
||||
const thumbnailUrl = value && value.thumbnail && value.thumbnail.url && getThumbnailCdnUrl(value.thumbnail.url);
|
||||
const videoUrl = generateEmbedUrl(claim.name, claim.claim_id);
|
||||
const videoWidth = value.video && value.video.width;
|
||||
const videoHeight = value.video && value.video.height;
|
||||
const videoUrl = generateEmbedUrl(claim.name, claim.claim_id) + (referrerQuery ? `r=${referrerQuery}` : '');
|
||||
|
||||
const { html, width, height } = generateEmbedIframeData(videoUrl);
|
||||
|
||||
return {
|
||||
type: 'video',
|
||||
|
@ -90,40 +67,68 @@ function generateOEmbedData(claim) {
|
|||
thumbnail_url: thumbnailUrl,
|
||||
thumbnail_width: THUMBNAIL_WIDTH,
|
||||
thumbnail_height: THUMBNAIL_HEIGHT,
|
||||
html: `<iframe id="lbry-iframe" width="560" height="315" src="${videoUrl}" allowfullscreen></iframe>`,
|
||||
width: videoWidth,
|
||||
height: videoHeight,
|
||||
html: html,
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
}
|
||||
|
||||
function generateXmlData(oEmbedData) {
|
||||
const {
|
||||
type,
|
||||
version,
|
||||
title,
|
||||
author_name,
|
||||
author_url,
|
||||
provider_name,
|
||||
provider_url,
|
||||
thumbnail_url,
|
||||
thumbnail_width,
|
||||
thumbnail_height,
|
||||
html,
|
||||
width,
|
||||
height,
|
||||
} = oEmbedData;
|
||||
|
||||
return (
|
||||
'<?xml version="1.0" encoding="utf-8"?>' +
|
||||
'<oembed>' +
|
||||
`<type>${type}</type>` +
|
||||
`<version>${version}</version>` +
|
||||
`<title>${title}</title>` +
|
||||
`<author_name>${author_name}</author_name>` +
|
||||
`<author_url>${author_url}</author_url>` +
|
||||
`<provider_name>${provider_name}</provider_name>` +
|
||||
`<provider_url>${provider_url}</provider_url>` +
|
||||
`<thumbnail_url>${thumbnail_url}</thumbnail_url>` +
|
||||
`<thumbnail_width>${thumbnail_width}</thumbnail_width>` +
|
||||
`<thumbnail_height>${thumbnail_height}</thumbnail_height>` +
|
||||
`<html>${html}</html>` +
|
||||
`<width>${width}</width>` +
|
||||
`<height>${height}</height>` +
|
||||
'<oembed>'
|
||||
);
|
||||
}
|
||||
|
||||
async function getOEmbed(ctx) {
|
||||
const path = ctx.request.url;
|
||||
const urlQuery = '?url=';
|
||||
const formatQuery = '&format=';
|
||||
const requestUrl = ctx.request.url;
|
||||
const urlQuery = getParameterByName('url', requestUrl);
|
||||
|
||||
const requestUrl = decodeURIComponent(
|
||||
path.substring(
|
||||
path.indexOf(urlQuery) + urlQuery.length,
|
||||
path.indexOf('&') > path.indexOf(urlQuery) ? path.indexOf('&') : path.length
|
||||
)
|
||||
);
|
||||
const requestFormat = path.substring(
|
||||
path.indexOf(formatQuery) + formatQuery.length,
|
||||
path.indexOf('&') > path.indexOf(formatQuery) ? path.indexOf('&') : path.length
|
||||
);
|
||||
|
||||
const isXml = requestFormat === 'xml';
|
||||
|
||||
const { claim, error } = await getClaim(requestUrl);
|
||||
const { claim, error } = await getClaim(urlQuery);
|
||||
if (error) return error;
|
||||
|
||||
const oEmbedData = generateOEmbedData(claim);
|
||||
const referrerQuery = getParameterByName('r', requestUrl);
|
||||
const oEmbedData = generateOEmbedData(claim, referrerQuery);
|
||||
|
||||
if (isXml) {
|
||||
ctx.set('Content-Type', 'text/xml+oembed');
|
||||
return oEmbedData.xml();
|
||||
const formatQuery = getParameterByName('format', requestUrl);
|
||||
if (formatQuery === 'xml') {
|
||||
ctx.set('Content-Type', 'application/xml');
|
||||
const xmlData = generateXmlData(oEmbedData);
|
||||
|
||||
return xmlData;
|
||||
}
|
||||
ctx.set('Content-Type', 'application/json+oembed');
|
||||
|
||||
ctx.set('Content-Type', 'application/json');
|
||||
return oEmbedData;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
const { generateStreamUrl } = require('../../ui/util/web');
|
||||
const { lbryProxy: Lbry } = require('../lbry');
|
||||
const { URL, SITE_NAME, LBRY_WEB_API } = require('../../config.js');
|
||||
const { URL, SITE_NAME, PROXY_URL } = require('../../config.js');
|
||||
const Mime = require('mime-types');
|
||||
const Rss = require('rss');
|
||||
|
||||
const SDK_API_PATH = `${LBRY_WEB_API}/api/v1`;
|
||||
const proxyURL = `${SDK_API_PATH}/proxy`;
|
||||
Lbry.setDaemonConnectionString(proxyURL);
|
||||
Lbry.setDaemonConnectionString(PROXY_URL);
|
||||
|
||||
const NUM_ENTRIES = 500;
|
||||
|
||||
|
|
Loading…
Reference in a new issue