serve static assets on urls with file extension #538
38 changed files with 779 additions and 612 deletions
|
@ -19,10 +19,10 @@ var AssetPreview = function AssetPreview(_ref) {
|
||||||
fileExt = _ref$claimData.fileExt,
|
fileExt = _ref$claimData.fileExt,
|
||||||
contentType = _ref$claimData.contentType,
|
contentType = _ref$claimData.contentType,
|
||||||
thumbnail = _ref$claimData.thumbnail;
|
thumbnail = _ref$claimData.thumbnail;
|
||||||
var directSourceLink = "asset/".concat(name, "/").concat(claimId);
|
var embedUrl = "/".concat(claimId, "/").concat(name, ".").concat(fileExt);
|
||||||
var showUrlLink = "/".concat(claimId, "/").concat(name);
|
var showUrl = "/".concat(claimId, "/").concat(name);
|
||||||
return _react.default.createElement(_reactRouterDom.Link, {
|
return _react.default.createElement(_reactRouterDom.Link, {
|
||||||
to: showUrlLink
|
to: showUrl
|
||||||
}, function () {
|
}, function () {
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
|
@ -31,7 +31,7 @@ var AssetPreview = function AssetPreview(_ref) {
|
||||||
case 'image/gif':
|
case 'image/gif':
|
||||||
return _react.default.createElement("img", {
|
return _react.default.createElement("img", {
|
||||||
className: 'asset-preview-image',
|
className: 'asset-preview-image',
|
||||||
src: directSourceLink,
|
src: embedUrl,
|
||||||
alt: name
|
alt: name
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ function (_React$Component) {
|
||||||
contentType = _this$props$asset$cla2.contentType,
|
contentType = _this$props$asset$cla2.contentType,
|
||||||
fileExt = _this$props$asset$cla2.fileExt,
|
fileExt = _this$props$asset$cla2.fileExt,
|
||||||
thumbnail = _this$props$asset$cla2.thumbnail;
|
thumbnail = _this$props$asset$cla2.thumbnail;
|
||||||
|
var sourceUrl = "/".concat(claimId, "/").concat(name, ".").concat(fileExt);
|
||||||
return _react.default.createElement("div", {
|
return _react.default.createElement("div", {
|
||||||
className: 'asset-display'
|
className: 'asset-display'
|
||||||
}, status === _asset_display_states.LOCAL_CHECK && _react.default.createElement("div", null, _react.default.createElement("p", null, "Checking to see if Spee.ch has your asset locally...")), status === _asset_display_states.UNAVAILABLE && _react.default.createElement("div", null, _react.default.createElement("p", null, "Sit tight, we're searching the LBRY blockchain for your asset!"), _react.default.createElement(_ProgressBar.default, {
|
}, status === _asset_display_states.LOCAL_CHECK && _react.default.createElement("div", null, _react.default.createElement("p", null, "Checking to see if Spee.ch has your asset locally...")), status === _asset_display_states.UNAVAILABLE && _react.default.createElement("div", null, _react.default.createElement("p", null, "Sit tight, we're searching the LBRY blockchain for your asset!"), _react.default.createElement(_ProgressBar.default, {
|
||||||
|
@ -82,7 +83,7 @@ function (_React$Component) {
|
||||||
case 'image/gif':
|
case 'image/gif':
|
||||||
return _react.default.createElement("img", {
|
return _react.default.createElement("img", {
|
||||||
className: "asset-image",
|
className: "asset-image",
|
||||||
src: "/asset/".concat(name, "/").concat(claimId),
|
src: sourceUrl,
|
||||||
alt: name
|
alt: name
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -92,11 +93,11 @@ function (_React$Component) {
|
||||||
controls: true,
|
controls: true,
|
||||||
poster: thumbnail
|
poster: thumbnail
|
||||||
}, _react.default.createElement("source", {
|
}, _react.default.createElement("source", {
|
||||||
src: "/asset/".concat(name, "/").concat(claimId)
|
src: sourceUrl
|
||||||
}), _react.default.createElement("p", null, "Your browser does not support the ", _react.default.createElement("code", null, "video"), " element."));
|
}), _react.default.createElement("p", null, "Your browser does not support the ", _react.default.createElement("code", null, "video"), " element."));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return _react.default.createElement("p", null, "Unsupported file type");
|
return _react.default.createElement("p", null, "Unsupported content type");
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ function (_React$Component) {
|
||||||
}),
|
}),
|
||||||
content: _react.default.createElement(_ClickToCopy.default, {
|
content: _react.default.createElement(_ClickToCopy.default, {
|
||||||
id: 'short-link',
|
id: 'short-link',
|
||||||
value: "".concat(host, "/").concat(shortId, "/").concat(name, ".").concat(fileExt)
|
value: "".concat(host, "/").concat(shortId, "/").concat(name)
|
||||||
})
|
})
|
||||||
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_RowLabeled.default, {
|
||||||
label: _react.default.createElement(_Label.default, {
|
label: _react.default.createElement(_Label.default, {
|
||||||
|
@ -102,9 +102,9 @@ function (_React$Component) {
|
||||||
id: 'embed-text-image',
|
id: 'embed-text-image',
|
||||||
value: "<img src=\"".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/>")
|
value: "<img src=\"".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt, "\"/>")
|
||||||
}))
|
}))
|
||||||
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement(_reactRouterDom.Link, {
|
})), _react.default.createElement(_Row.default, null, _react.default.createElement(_SpaceBetween.default, null, _react.default.createElement("a", {
|
||||||
className: "link--primary",
|
className: "link--primary",
|
||||||
to: "/".concat(shortId, "/").concat(name, ".").concat(fileExt)
|
href: "".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt)
|
||||||
}, "Direct Link"), _react.default.createElement("a", {
|
}, "Direct Link"), _react.default.createElement("a", {
|
||||||
className: 'link--primary',
|
className: 'link--primary',
|
||||||
href: "".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt),
|
href: "".concat(host, "/").concat(claimId, "/").concat(name, ".").concat(fileExt),
|
||||||
|
|
|
@ -11,24 +11,6 @@ var _view = _interopRequireDefault(require("./view"));
|
||||||
|
|
||||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
var mapStateToProps = function mapStateToProps(_ref) {
|
var _default = (0, _reactRedux.connect)(null, null)(_view.default);
|
||||||
var site = _ref.site;
|
|
||||||
var defaultDescription = site.defaultDescription,
|
|
||||||
defaultThumbnail = site.defaultThumbnail,
|
|
||||||
siteDescription = site.description,
|
|
||||||
siteHost = site.host,
|
|
||||||
siteTitle = site.title,
|
|
||||||
siteTwitter = site.twitter;
|
|
||||||
return {
|
|
||||||
defaultDescription: defaultDescription,
|
|
||||||
defaultThumbnail: defaultThumbnail,
|
|
||||||
siteDescription: siteDescription,
|
|
||||||
siteHost: siteHost,
|
|
||||||
siteTitle: siteTitle,
|
|
||||||
siteTwitter: siteTwitter
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var _default = (0, _reactRedux.connect)(mapStateToProps, null)(_view.default);
|
|
||||||
|
|
||||||
exports.default = _default;
|
exports.default = _default;
|
|
@ -11,11 +11,11 @@ var _reactHelmet = _interopRequireDefault(require("react-helmet"));
|
||||||
|
|
||||||
var _propTypes = _interopRequireDefault(require("prop-types"));
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
||||||
|
|
||||||
var _pageTitle = require("../../utils/pageTitle");
|
var _createPageTitle = _interopRequireDefault(require("../../utils/createPageTitle"));
|
||||||
|
|
||||||
var _metaTags = require("../../utils/metaTags");
|
var _createMetaTags = _interopRequireDefault(require("../../utils/createMetaTags"));
|
||||||
|
|
||||||
var _canonicalLink = require("../../utils/canonicalLink");
|
var _createCanonicalLink = _interopRequireDefault(require("../../utils/createCanonicalLink"));
|
||||||
|
|
||||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
@ -49,33 +49,19 @@ function (_React$Component) {
|
||||||
_createClass(SEO, [{
|
_createClass(SEO, [{
|
||||||
key: "render",
|
key: "render",
|
||||||
value: function render() {
|
value: function render() {
|
||||||
// props from state
|
// props from parent
|
||||||
var _this$props = this.props,
|
var _this$props = this.props,
|
||||||
defaultDescription = _this$props.defaultDescription,
|
asset = _this$props.asset,
|
||||||
defaultThumbnail = _this$props.defaultThumbnail,
|
channel = _this$props.channel,
|
||||||
siteDescription = _this$props.siteDescription,
|
pageUri = _this$props.pageUri;
|
||||||
siteHost = _this$props.siteHost,
|
|
||||||
siteTitle = _this$props.siteTitle,
|
|
||||||
siteTwitter = _this$props.siteTwitter; // props from parent
|
|
||||||
|
|
||||||
var _this$props2 = this.props,
|
|
||||||
asset = _this$props2.asset,
|
|
||||||
channel = _this$props2.channel,
|
|
||||||
pageUri = _this$props2.pageUri;
|
|
||||||
var pageTitle = this.props.pageTitle; // create page title, tags, and canonical link
|
var pageTitle = this.props.pageTitle; // create page title, tags, and canonical link
|
||||||
|
|
||||||
pageTitle = (0, _pageTitle.createPageTitle)(siteTitle, pageTitle);
|
pageTitle = (0, _createPageTitle.default)(pageTitle);
|
||||||
var metaTags = (0, _metaTags.createMetaTags)({
|
var metaTags = (0, _createMetaTags.default)({
|
||||||
siteDescription: siteDescription,
|
|
||||||
siteHost: siteHost,
|
|
||||||
siteTitle: siteTitle,
|
|
||||||
siteTwitter: siteTwitter,
|
|
||||||
asset: asset,
|
asset: asset,
|
||||||
channel: channel,
|
channel: channel
|
||||||
defaultDescription: defaultDescription,
|
|
||||||
defaultThumbnail: defaultThumbnail
|
|
||||||
});
|
});
|
||||||
var canonicalLink = (0, _canonicalLink.createCanonicalLink)(asset, channel, pageUri, siteHost); // render results
|
var canonicalLink = (0, _createCanonicalLink.default)(asset, channel, pageUri); // render results
|
||||||
|
|
||||||
return _react.default.createElement(_reactHelmet.default, {
|
return _react.default.createElement(_reactHelmet.default, {
|
||||||
title: pageTitle,
|
title: pageTitle,
|
||||||
|
|
105
client/build/utils/createAssetMetaTags.js
Normal file
105
client/build/utils/createAssetMetaTags.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var _siteConfig = _interopRequireDefault(require("@config/siteConfig.json"));
|
||||||
|
|
||||||
|
var _determineContentTypeFromExtension = _interopRequireDefault(require("./determineContentTypeFromExtension"));
|
||||||
|
|
||||||
|
var _createMetaTagsArray = _interopRequireDefault(require("./createMetaTagsArray"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var _siteConfig$details = _siteConfig.default.details,
|
||||||
|
host = _siteConfig$details.host,
|
||||||
|
siteTitle = _siteConfig$details.title,
|
||||||
|
twitter = _siteConfig$details.twitter,
|
||||||
|
_siteConfig$assetDefa = _siteConfig.default.assetDefaults,
|
||||||
|
defaultDescription = _siteConfig$assetDefa.description,
|
||||||
|
defaultThumbnail = _siteConfig$assetDefa.thumbnail;
|
||||||
|
var VIDEO = 'VIDEO';
|
||||||
|
var IMAGE = 'IMAGE';
|
||||||
|
var GIF = 'GIF';
|
||||||
|
|
||||||
|
var determineMediaType = function determineMediaType(contentType) {
|
||||||
|
switch (contentType) {
|
||||||
|
case 'image/jpg':
|
||||||
|
case 'image/jpeg':
|
||||||
|
case 'image/png':
|
||||||
|
return IMAGE;
|
||||||
|
|
||||||
|
case 'image/gif':
|
||||||
|
return GIF;
|
||||||
|
|
||||||
|
case 'video/mp4':
|
||||||
|
case 'video/webm':
|
||||||
|
return VIDEO;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var createAssetMetaTags = function createAssetMetaTags(asset) {
|
||||||
|
var claimData = asset.claimData;
|
||||||
|
var contentType = claimData.contentType;
|
||||||
|
var showUrl = "".concat(host, "/").concat(claimData.claimId, "/").concat(claimData.name);
|
||||||
|
var serveUrl = "".concat(host, "/").concat(claimData.claimId, "/").concat(claimData.name, ".").concat(claimData.fileExt);
|
||||||
|
var ogTitle = claimData.title || claimData.name;
|
||||||
|
var ogDescription = claimData.description || defaultDescription;
|
||||||
|
var ogThumbnailContentType = (0, _determineContentTypeFromExtension.default)(claimData.thumbnail);
|
||||||
|
var ogThumbnail = claimData.thumbnail || defaultThumbnail; // {property: 'og:title'] = ogTitle},
|
||||||
|
|
||||||
|
var metaTags = {
|
||||||
|
'og:title': ogTitle,
|
||||||
|
'twitter:title': ogTitle,
|
||||||
|
'og:description': ogDescription,
|
||||||
|
'twitter:description': ogDescription,
|
||||||
|
'og:url': showUrl,
|
||||||
|
'og:site_name': siteTitle,
|
||||||
|
'twitter:site': twitter,
|
||||||
|
'fb:app_id': '1371961932852223'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (determineMediaType(contentType) === VIDEO) {
|
||||||
|
var videoEmbedUrl = "".concat(host, "/video-embed/").concat(claimData.name, "/").concat(claimData.claimId); // card type tags
|
||||||
|
|
||||||
|
metaTags['og:type'] = 'video.other';
|
||||||
|
metaTags['twitter:card'] = 'player';
|
||||||
|
metaTags['twitter:player'] = videoEmbedUrl;
|
||||||
|
metaTags['twitter:player:width'] = 600;
|
||||||
|
metaTags['twitter:text:player_width'] = 600;
|
||||||
|
metaTags['twitter:player:height'] = 350;
|
||||||
|
metaTags['twitter:player:stream'] = serveUrl;
|
||||||
|
metaTags['twitter:player:stream:content_type'] = contentType; // video tags
|
||||||
|
|
||||||
|
metaTags['og:video'] = serveUrl;
|
||||||
|
metaTags['og:video:secure_url'] = serveUrl;
|
||||||
|
metaTags['og:video:type'] = contentType; // image tags
|
||||||
|
|
||||||
|
metaTags['og:image'] = ogThumbnail;
|
||||||
|
metaTags['og:image:width'] = 600;
|
||||||
|
metaTags['og:image:height'] = 315;
|
||||||
|
metaTags['og:image:type'] = ogThumbnailContentType;
|
||||||
|
metaTags['twitter:image'] = ogThumbnail;
|
||||||
|
} else {
|
||||||
|
// card type tags
|
||||||
|
metaTags['og:type'] = 'article';
|
||||||
|
metaTags['twitter:card'] = 'summary_large_image'; // image tags
|
||||||
|
|
||||||
|
metaTags['og:image'] = serveUrl;
|
||||||
|
metaTags['og:image'] = serveUrl;
|
||||||
|
metaTags['og:image:width'] = 600;
|
||||||
|
metaTags['og:image:height'] = 315;
|
||||||
|
metaTags['og:image:type'] = contentType;
|
||||||
|
metaTags['twitter:image'] = serveUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0, _createMetaTagsArray.default)(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createAssetMetaTags;
|
||||||
|
exports.default = _default;
|
51
client/build/utils/createBasicMetaTags.js
Normal file
51
client/build/utils/createBasicMetaTags.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var _siteConfig = _interopRequireDefault(require("@config/siteConfig.json"));
|
||||||
|
|
||||||
|
var _determineContentTypeFromExtension = _interopRequireDefault(require("./determineContentTypeFromExtension.js"));
|
||||||
|
|
||||||
|
var _createMetaTagsArray = _interopRequireDefault(require("./createMetaTagsArray"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var _siteConfig$details = _siteConfig.default.details,
|
||||||
|
description = _siteConfig$details.description,
|
||||||
|
host = _siteConfig$details.host,
|
||||||
|
title = _siteConfig$details.title,
|
||||||
|
twitter = _siteConfig$details.twitter,
|
||||||
|
thumbnail = _siteConfig.default.assetDefaults.thumbnail;
|
||||||
|
|
||||||
|
var createBasicMetaTags = function createBasicMetaTags() {
|
||||||
|
var metaTags = {
|
||||||
|
// page details
|
||||||
|
'og:title': title,
|
||||||
|
'twitter:title': title,
|
||||||
|
'og:description': description,
|
||||||
|
'twitter:description': description,
|
||||||
|
// url
|
||||||
|
'og:url': host,
|
||||||
|
// site id
|
||||||
|
'og:site_name': title,
|
||||||
|
'twitter:site': twitter,
|
||||||
|
'fb:app_id': '1371961932852223',
|
||||||
|
// card type
|
||||||
|
'og:type': 'article',
|
||||||
|
'twitter:card': 'summary_large_image',
|
||||||
|
// image
|
||||||
|
'og:image': thumbnail,
|
||||||
|
'og:image:width': 600,
|
||||||
|
'og:image:height': 315,
|
||||||
|
'og:image:type': (0, _determineContentTypeFromExtension.default)(thumbnail),
|
||||||
|
'twitter:image': thumbnail,
|
||||||
|
'twitter:image:alt': 'Spee.ch Logo'
|
||||||
|
};
|
||||||
|
return (0, _createMetaTagsArray.default)(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createBasicMetaTags;
|
||||||
|
exports.default = _default;
|
55
client/build/utils/createCanonicalLink.js
Normal file
55
client/build/utils/createCanonicalLink.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var _siteConfig = _interopRequireDefault(require("@config/siteConfig.json"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var host = _siteConfig.default.details.host;
|
||||||
|
|
||||||
|
var createBasicCanonicalLink = function createBasicCanonicalLink(page) {
|
||||||
|
return "".concat(host, "/").concat(page);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createAssetCanonicalLink = function createAssetCanonicalLink(asset) {
|
||||||
|
var channelName, certificateId, name, claimId;
|
||||||
|
|
||||||
|
if (asset.claimData) {
|
||||||
|
var _asset$claimData = asset.claimData;
|
||||||
|
channelName = _asset$claimData.channelName;
|
||||||
|
certificateId = _asset$claimData.certificateId;
|
||||||
|
name = _asset$claimData.name;
|
||||||
|
claimId = _asset$claimData.claimId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelName) {
|
||||||
|
return "".concat(host, "/").concat(channelName, ":").concat(certificateId, "/").concat(name);
|
||||||
This is the babel transpiled code :) This is the babel transpiled code :)
once I merge the www.spee.ch and spee.ch repos we should be able to keep this out of version control once I merge the www.spee.ch and spee.ch repos we should be able to keep this out of version control
|
|||||||
|
}
|
||||||
|
|
||||||
|
return "".concat(host, "/").concat(claimId, "/").concat(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createChannelCanonicalLink = function createChannelCanonicalLink(channel) {
|
||||||
|
var name = channel.name,
|
||||||
|
longId = channel.longId;
|
||||||
|
return "".concat(host, "/").concat(name, ":").concat(longId);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createCanonicalLink = function createCanonicalLink(asset, channel, page) {
|
||||||
|
if (asset) {
|
||||||
|
return createAssetCanonicalLink(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel) {
|
||||||
|
return createChannelCanonicalLink(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createBasicCanonicalLink(page);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createCanonicalLink;
|
||||||
|
exports.default = _default;
|
53
client/build/utils/createChannelMetaTags.js
Normal file
53
client/build/utils/createChannelMetaTags.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = exports.createChannelMetaTags = void 0;
|
||||||
|
|
||||||
|
var _siteConfig = _interopRequireDefault(require("@config/siteConfig.json"));
|
||||||
|
|
||||||
|
var _determineContentTypeFromExtension = _interopRequireDefault(require("./determineContentTypeFromExtension"));
|
||||||
|
|
||||||
|
var _createMetaTagsArray = _interopRequireDefault(require("./createMetaTagsArray"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var _siteConfig$details = _siteConfig.default.details,
|
||||||
|
host = _siteConfig$details.host,
|
||||||
|
siteTitle = _siteConfig$details.title,
|
||||||
|
twitter = _siteConfig$details.twitter,
|
||||||
|
defaultThumbnail = _siteConfig.default.assetDefaults.thumbnail;
|
||||||
|
|
||||||
|
var createChannelMetaTags = function createChannelMetaTags(channel) {
|
||||||
|
var name = channel.name,
|
||||||
|
longId = channel.longId;
|
||||||
|
var metaTags = {
|
||||||
|
// page detail tags
|
||||||
|
'og:title': "".concat(name, " on ").concat(siteTitle),
|
||||||
|
'twitter:title': "".concat(name, " on ").concat(siteTitle),
|
||||||
|
'og:description': "".concat(name, ", a channel on ").concat(siteTitle),
|
||||||
|
'twitter:description': "".concat(name, ", a channel on ").concat(siteTitle),
|
||||||
|
// url
|
||||||
|
'og:url': "".concat(host, "/").concat(name, ":").concat(longId),
|
||||||
|
// site info
|
||||||
|
'og:site_name': siteTitle,
|
||||||
|
'twitter:site': twitter,
|
||||||
|
'fb:app_id': '1371961932852223',
|
||||||
|
// card type tags
|
||||||
|
'og:type': 'article',
|
||||||
|
'twitter:card': 'summary_large_image',
|
||||||
|
// image tags
|
||||||
|
'og:image': defaultThumbnail,
|
||||||
|
'og:image:width': 600,
|
||||||
|
'og:image:height': 315,
|
||||||
|
'og:image:type': (0, _determineContentTypeFromExtension.default)(defaultThumbnail),
|
||||||
|
'twitter:image': defaultThumbnail,
|
||||||
|
'twitter:image:alt': 'Spee.ch Logo'
|
||||||
|
};
|
||||||
|
return (0, _createMetaTagsArray.default)(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.createChannelMetaTags = createChannelMetaTags;
|
||||||
|
var _default = createChannelMetaTags;
|
||||||
|
exports.default = _default;
|
32
client/build/utils/createMetaTags.js
Normal file
32
client/build/utils/createMetaTags.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var _createAssetMetaTags = _interopRequireDefault(require("./createAssetMetaTags"));
|
||||||
|
|
||||||
|
var _createChannelMetaTags = _interopRequireDefault(require("./createChannelMetaTags.js"));
|
||||||
|
|
||||||
|
var _createBasicMetaTags = _interopRequireDefault(require("./createBasicMetaTags.js"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var createMetaTags = function createMetaTags(_ref) {
|
||||||
|
var asset = _ref.asset,
|
||||||
|
channel = _ref.channel;
|
||||||
|
|
||||||
|
if (asset) {
|
||||||
|
return (0, _createAssetMetaTags.default)(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel) {
|
||||||
|
return (0, _createChannelMetaTags.default)(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0, _createBasicMetaTags.default)();
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createMetaTags;
|
||||||
|
exports.default = _default;
|
24
client/build/utils/createMetaTagsArray.js
Normal file
24
client/build/utils/createMetaTagsArray.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var createMetaTagsArray = function createMetaTagsArray(metaTagsObject) {
|
||||||
|
var metaTagsArray = [];
|
||||||
|
|
||||||
|
for (var key in metaTagsObject) {
|
||||||
|
if (metaTagsObject.hasOwnProperty(key)) {
|
||||||
|
metaTagsArray.push({
|
||||||
|
property: key,
|
||||||
|
content: metaTagsObject[key]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return metaTagsArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createMetaTagsArray;
|
||||||
|
exports.default = _default;
|
23
client/build/utils/createPageTitle.js
Normal file
23
client/build/utils/createPageTitle.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var _siteConfig = _interopRequireDefault(require("@config/siteConfig.json"));
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||||
|
|
||||||
|
var siteTitle = _siteConfig.default.details.title;
|
||||||
|
|
||||||
|
var createPageTitle = function createPageTitle(pageTitle) {
|
||||||
|
if (!pageTitle) {
|
||||||
|
return "".concat(siteTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "".concat(siteTitle, " - ").concat(pageTitle);
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = createPageTitle;
|
||||||
|
exports.default = _default;
|
35
client/build/utils/determineContentTypeFromExtension.js
Normal file
35
client/build/utils/determineContentTypeFromExtension.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
exports.default = void 0;
|
||||||
|
|
||||||
|
var determineContentTypeFromExtension = function determineContentTypeFromExtension(thumbnail) {
|
||||||
|
if (thumbnail) {
|
||||||
|
var fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
||||||
|
|
||||||
|
switch (fileExt) {
|
||||||
|
case 'jpeg':
|
||||||
|
case 'jpg':
|
||||||
|
return 'image/jpg';
|
||||||
|
|
||||||
|
case 'png':
|
||||||
|
return 'image/png';
|
||||||
|
|
||||||
|
case 'gif':
|
||||||
|
return 'image/gif';
|
||||||
|
|
||||||
|
case 'mp4':
|
||||||
|
return 'video/mp4';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
var _default = determineContentTypeFromExtension;
|
||||||
|
exports.default = _default;
|
|
@ -5,270 +5,25 @@ Object.defineProperty(exports, "__esModule", {
|
||||||
});
|
});
|
||||||
exports.createMetaTags = void 0;
|
exports.createMetaTags = void 0;
|
||||||
|
|
||||||
var determineOgThumbnailContentType = function determineOgThumbnailContentType(thumbnail) {
|
var createAssetMetaTags = require('createAssetMetaTags.js');
|
||||||
if (thumbnail) {
|
|
||||||
var fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
|
||||||
|
|
||||||
switch (fileExt) {
|
var createChannelMetaTags = require('createChannelMetaTags.js');
|
||||||
case 'jpeg':
|
|
||||||
case 'jpg':
|
|
||||||
return 'image/jpeg';
|
|
||||||
|
|
||||||
case 'png':
|
var createBasicMetaTags = require('createBasicMetaTags.js');
|
||||||
return 'image/png';
|
|
||||||
|
|
||||||
case 'gif':
|
var createMetaTags = function createMetaTags(_ref) {
|
||||||
return 'image/gif';
|
var asset = _ref.asset,
|
||||||
|
channel = _ref.channel;
|
||||||
case 'mp4':
|
|
||||||
return 'video/mp4';
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 'image/jpeg';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
var createBasicMetaTags = function createBasicMetaTags(_ref) {
|
|
||||||
var siteHost = _ref.siteHost,
|
|
||||||
siteDescription = _ref.siteDescription,
|
|
||||||
siteTitle = _ref.siteTitle,
|
|
||||||
siteTwitter = _ref.siteTwitter,
|
|
||||||
defaultThumbnail = _ref.defaultThumbnail;
|
|
||||||
return [{
|
|
||||||
property: 'og:title',
|
|
||||||
content: siteTitle
|
|
||||||
}, {
|
|
||||||
property: 'twitter:title',
|
|
||||||
content: siteTitle
|
|
||||||
}, {
|
|
||||||
property: 'og:url',
|
|
||||||
content: siteHost
|
|
||||||
}, {
|
|
||||||
property: 'og:site_name',
|
|
||||||
content: siteTitle
|
|
||||||
}, {
|
|
||||||
property: 'og:description',
|
|
||||||
content: siteDescription
|
|
||||||
}, {
|
|
||||||
property: 'twitter:description',
|
|
||||||
content: siteDescription
|
|
||||||
}, {
|
|
||||||
property: 'twitter:site',
|
|
||||||
content: siteTwitter
|
|
||||||
}, {
|
|
||||||
property: 'twitter:card',
|
|
||||||
content: 'summary_large_image'
|
|
||||||
}, {
|
|
||||||
property: 'og:image',
|
|
||||||
content: defaultThumbnail
|
|
||||||
}, {
|
|
||||||
property: 'twitter:image',
|
|
||||||
content: defaultThumbnail
|
|
||||||
}, {
|
|
||||||
property: 'og:image:type',
|
|
||||||
content: 'image/jpeg'
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
|
|
||||||
var createChannelMetaTags = function createChannelMetaTags(_ref2) {
|
|
||||||
var siteHost = _ref2.siteHost,
|
|
||||||
siteTitle = _ref2.siteTitle,
|
|
||||||
siteTwitter = _ref2.siteTwitter,
|
|
||||||
channel = _ref2.channel;
|
|
||||||
var name = channel.name,
|
|
||||||
longId = channel.longId;
|
|
||||||
return [{
|
|
||||||
property: 'og:title',
|
|
||||||
content: "".concat(name, " on ").concat(siteTitle)
|
|
||||||
}, {
|
|
||||||
property: 'twitter:title',
|
|
||||||
content: "".concat(name, " on ").concat(siteTitle)
|
|
||||||
}, {
|
|
||||||
property: 'og:url',
|
|
||||||
content: "".concat(siteHost, "/").concat(name, ":").concat(longId)
|
|
||||||
}, {
|
|
||||||
property: 'og:site_name',
|
|
||||||
content: siteTitle
|
|
||||||
}, {
|
|
||||||
property: 'og:description',
|
|
||||||
content: "".concat(name, ", a channel on ").concat(siteTitle)
|
|
||||||
}, {
|
|
||||||
property: 'twitter:site',
|
|
||||||
content: siteTwitter
|
|
||||||
}, {
|
|
||||||
property: 'twitter:card',
|
|
||||||
content: 'summary'
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
|
|
||||||
var createAssetMetaTags = function createAssetMetaTags(_ref3) {
|
|
||||||
var siteHost = _ref3.siteHost,
|
|
||||||
siteTitle = _ref3.siteTitle,
|
|
||||||
siteTwitter = _ref3.siteTwitter,
|
|
||||||
asset = _ref3.asset,
|
|
||||||
defaultDescription = _ref3.defaultDescription,
|
|
||||||
defaultThumbnail = _ref3.defaultThumbnail;
|
|
||||||
var claimData = asset.claimData;
|
|
||||||
var contentType = claimData.contentType;
|
|
||||||
var videoEmbedUrl = "".concat(siteHost, "/video-embed/").concat(claimData.name, "/").concat(claimData.claimId);
|
|
||||||
var showUrl = "".concat(siteHost, "/").concat(claimData.claimId, "/").concat(claimData.name);
|
|
||||||
var source = "".concat(siteHost, "/asset/").concat(claimData.name, "/").concat(claimData.claimId);
|
|
||||||
var ogTitle = claimData.title || claimData.name;
|
|
||||||
var ogDescription = claimData.description || defaultDescription;
|
|
||||||
var ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
|
||||||
var ogThumbnail = claimData.thumbnail || defaultThumbnail;
|
|
||||||
var metaTags = [{
|
|
||||||
property: 'og:title',
|
|
||||||
content: ogTitle
|
|
||||||
}, {
|
|
||||||
property: 'twitter:title',
|
|
||||||
content: ogTitle
|
|
||||||
}, {
|
|
||||||
property: 'og:url',
|
|
||||||
content: showUrl
|
|
||||||
}, {
|
|
||||||
property: 'og:site_name',
|
|
||||||
content: siteTitle
|
|
||||||
}, {
|
|
||||||
property: 'og:description',
|
|
||||||
content: ogDescription
|
|
||||||
}, {
|
|
||||||
property: 'twitter:description',
|
|
||||||
content: ogDescription
|
|
||||||
}, {
|
|
||||||
property: 'og:image:width',
|
|
||||||
content: 600
|
|
||||||
}, {
|
|
||||||
property: 'og:image:height',
|
|
||||||
content: 315
|
|
||||||
}, {
|
|
||||||
property: 'twitter:site',
|
|
||||||
content: siteTwitter
|
|
||||||
}];
|
|
||||||
|
|
||||||
if (contentType === 'video/mp4' || contentType === 'video/webm') {
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:video',
|
|
||||||
content: source
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:video:secure_url',
|
|
||||||
content: source
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:video:type',
|
|
||||||
content: contentType
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:image',
|
|
||||||
content: ogThumbnail
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:image',
|
|
||||||
content: ogThumbnail
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:image:type',
|
|
||||||
content: ogThumbnailContentType
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:type',
|
|
||||||
content: 'video.other'
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:card',
|
|
||||||
content: 'player'
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:player',
|
|
||||||
content: videoEmbedUrl
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:player:width',
|
|
||||||
content: 600
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:text:player_width',
|
|
||||||
content: 600
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:player:height',
|
|
||||||
content: 337
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:player:stream',
|
|
||||||
content: source
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:player:stream:content_type',
|
|
||||||
content: contentType
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:image',
|
|
||||||
content: source
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:image',
|
|
||||||
content: source
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:image:type',
|
|
||||||
content: contentType
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'og:type',
|
|
||||||
content: 'article'
|
|
||||||
});
|
|
||||||
metaTags.push({
|
|
||||||
property: 'twitter:card',
|
|
||||||
content: 'summary_large_image'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return metaTags;
|
|
||||||
};
|
|
||||||
|
|
||||||
var createMetaTags = function createMetaTags(_ref4) {
|
|
||||||
var siteDescription = _ref4.siteDescription,
|
|
||||||
siteHost = _ref4.siteHost,
|
|
||||||
siteTitle = _ref4.siteTitle,
|
|
||||||
siteTwitter = _ref4.siteTwitter,
|
|
||||||
asset = _ref4.asset,
|
|
||||||
channel = _ref4.channel,
|
|
||||||
defaultDescription = _ref4.defaultDescription,
|
|
||||||
defaultThumbnail = _ref4.defaultThumbnail;
|
|
||||||
|
|
||||||
if (asset) {
|
if (asset) {
|
||||||
return createAssetMetaTags({
|
return createAssetMetaTags(asset);
|
||||||
siteHost: siteHost,
|
|
||||||
siteTitle: siteTitle,
|
|
||||||
siteTwitter: siteTwitter,
|
|
||||||
asset: asset,
|
|
||||||
defaultDescription: defaultDescription,
|
|
||||||
defaultThumbnail: defaultThumbnail
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
return createChannelMetaTags({
|
return createChannelMetaTags(channel);
|
||||||
siteHost: siteHost,
|
|
||||||
siteTitle: siteTitle,
|
|
||||||
siteTwitter: siteTwitter,
|
|
||||||
channel: channel
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return createBasicMetaTags({
|
return createBasicMetaTags();
|
||||||
siteDescription: siteDescription,
|
|
||||||
siteHost: siteHost,
|
|
||||||
siteTitle: siteTitle,
|
|
||||||
siteTwitter: siteTwitter,
|
|
||||||
defaultThumbnail: defaultThumbnail
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.createMetaTags = createMetaTags;
|
exports.createMetaTags = createMetaTags;
|
|
@ -2,10 +2,10 @@ import React from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
const AssetPreview = ({ defaultThumbnail, claimData: { name, claimId, fileExt, contentType, thumbnail } }) => {
|
const AssetPreview = ({ defaultThumbnail, claimData: { name, claimId, fileExt, contentType, thumbnail } }) => {
|
||||||
const directSourceLink = `asset/${name}/${claimId}`;
|
const embedUrl = `/${claimId}/${name}.${fileExt}`;
|
||||||
const showUrlLink = `/${claimId}/${name}`;
|
const showUrl = `/${claimId}/${name}`;
|
||||||
return (
|
return (
|
||||||
<Link to={showUrlLink} >
|
<Link to={showUrl} >
|
||||||
{(() => {
|
{(() => {
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
|
@ -15,7 +15,7 @@ const AssetPreview = ({ defaultThumbnail, claimData: { name, claimId, fileExt, c
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
className={'asset-preview-image'}
|
className={'asset-preview-image'}
|
||||||
src={directSourceLink}
|
src={embedUrl}
|
||||||
alt={name}
|
alt={name}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,6 +9,7 @@ class AssetDisplay extends React.Component {
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const { status, error, asset: { claimData: { name, claimId, contentType, fileExt, thumbnail } } } = this.props;
|
const { status, error, asset: { claimData: { name, claimId, contentType, fileExt, thumbnail } } } = this.props;
|
||||||
|
const sourceUrl = `/${claimId}/${name}.${fileExt}`;
|
||||||
return (
|
return (
|
||||||
<div className={'asset-display'}>
|
<div className={'asset-display'}>
|
||||||
{(status === LOCAL_CHECK) &&
|
{(status === LOCAL_CHECK) &&
|
||||||
|
@ -39,7 +40,7 @@ class AssetDisplay extends React.Component {
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
className='asset-image'
|
className='asset-image'
|
||||||
src={`/asset/${name}/${claimId}`}
|
src={sourceUrl}
|
||||||
alt={name}
|
alt={name}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -50,14 +51,14 @@ class AssetDisplay extends React.Component {
|
||||||
controls poster={thumbnail}
|
controls poster={thumbnail}
|
||||||
>
|
>
|
||||||
<source
|
<source
|
||||||
src={`/asset/${name}/${claimId}`}
|
src={sourceUrl}
|
||||||
/>
|
/>
|
||||||
<p>Your browser does not support the <code>video</code> element.</p>
|
<p>Your browser does not support the <code>video</code> element.</p>
|
||||||
</video>
|
</video>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<p>Unsupported file type</p>
|
<p>Unsupported content type</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|
|
@ -50,7 +50,7 @@ class AssetInfo extends React.Component {
|
||||||
content={
|
content={
|
||||||
<ClickToCopy
|
<ClickToCopy
|
||||||
id={'short-link'}
|
id={'short-link'}
|
||||||
value={`${host}/${shortId}/${name}.${fileExt}`}
|
value={`${host}/${shortId}/${name}`}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -81,12 +81,12 @@ class AssetInfo extends React.Component {
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<SpaceBetween>
|
<SpaceBetween>
|
||||||
<Link
|
<a
|
||||||
className='link--primary'
|
className='link--primary'
|
||||||
to={`/${shortId}/${name}.${fileExt}`}
|
href={`${host}/${claimId}/${name}.${fileExt}`}
|
||||||
>
|
>
|
||||||
Direct Link
|
Direct Link
|
||||||
</Link>
|
</a>
|
||||||
<a
|
<a
|
||||||
className={'link--primary'}
|
className={'link--primary'}
|
||||||
href={`${host}/${claimId}/${name}.${fileExt}`}
|
href={`${host}/${claimId}/${name}.${fileExt}`}
|
||||||
|
|
|
@ -1,16 +1,4 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import View from './view';
|
import View from './view';
|
||||||
|
|
||||||
const mapStateToProps = ({ site }) => {
|
export default connect(null, null)(View);
|
||||||
const { defaultDescription, defaultThumbnail, description: siteDescription, host: siteHost, title: siteTitle, twitter: siteTwitter } = site;
|
|
||||||
return {
|
|
||||||
defaultDescription,
|
|
||||||
defaultThumbnail,
|
|
||||||
siteDescription,
|
|
||||||
siteHost,
|
|
||||||
siteTitle,
|
|
||||||
siteTwitter,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(View);
|
|
||||||
|
|
|
@ -2,30 +2,22 @@ import React from 'react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { createPageTitle } from '../../utils/pageTitle';
|
import createPageTitle from '../../utils/createPageTitle';
|
||||||
import { createMetaTags } from '../../utils/metaTags';
|
import createMetaTags from '../../utils/createMetaTags';
|
||||||
import { createCanonicalLink } from '../../utils/canonicalLink';
|
import createCanonicalLink from '../../utils/createCanonicalLink';
|
||||||
|
|
||||||
class SEO extends React.Component {
|
class SEO extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
// props from state
|
|
||||||
const { defaultDescription, defaultThumbnail, siteDescription, siteHost, siteTitle, siteTwitter } = this.props;
|
|
||||||
// props from parent
|
// props from parent
|
||||||
const { asset, channel, pageUri } = this.props;
|
const { asset, channel, pageUri } = this.props;
|
||||||
let { pageTitle } = this.props;
|
let { pageTitle } = this.props;
|
||||||
// create page title, tags, and canonical link
|
// create page title, tags, and canonical link
|
||||||
pageTitle = createPageTitle(siteTitle, pageTitle);
|
pageTitle = createPageTitle(pageTitle);
|
||||||
const metaTags = createMetaTags({
|
const metaTags = createMetaTags({
|
||||||
siteDescription,
|
|
||||||
siteHost,
|
|
||||||
siteTitle,
|
|
||||||
siteTwitter,
|
|
||||||
asset,
|
asset,
|
||||||
channel,
|
channel,
|
||||||
defaultDescription,
|
|
||||||
defaultThumbnail,
|
|
||||||
});
|
});
|
||||||
const canonicalLink = createCanonicalLink(asset, channel, pageUri, siteHost);
|
const canonicalLink = createCanonicalLink(asset, channel, pageUri);
|
||||||
// render results
|
// render results
|
||||||
return (
|
return (
|
||||||
<Helmet
|
<Helmet
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
const createBasicCanonicalLink = (page, siteHost) => {
|
|
||||||
return `${siteHost}/${page}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createAssetCanonicalLink = (asset, siteHost) => {
|
|
||||||
let channelName, certificateId, name, claimId;
|
|
||||||
if (asset.claimData) {
|
|
||||||
({ channelName, certificateId, name, claimId } = asset.claimData);
|
|
||||||
};
|
|
||||||
if (channelName) {
|
|
||||||
return `${siteHost}/${channelName}:${certificateId}/${name}`;
|
|
||||||
};
|
|
||||||
return `${siteHost}/${claimId}/${name}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createChannelCanonicalLink = (channel, siteHost) => {
|
|
||||||
const { name, longId } = channel;
|
|
||||||
return `${siteHost}/${name}:${longId}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createCanonicalLink = (asset, channel, page, siteHost) => {
|
|
||||||
if (asset) {
|
|
||||||
return createAssetCanonicalLink(asset, siteHost);
|
|
||||||
}
|
|
||||||
if (channel) {
|
|
||||||
return createChannelCanonicalLink(channel, siteHost);
|
|
||||||
}
|
|
||||||
return createBasicCanonicalLink(page, siteHost);
|
|
||||||
};
|
|
93
client/src/utils/createAssetMetaTags.js
Normal file
93
client/src/utils/createAssetMetaTags.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import siteConfig from '@config/siteConfig.json';
|
||||||
|
import determineContentTypeFromExtension from './determineContentTypeFromExtension';
|
||||||
|
import createMetaTagsArray from './createMetaTagsArray';
|
||||||
|
|
||||||
|
const {
|
||||||
|
details: {
|
||||||
|
host,
|
||||||
|
title: siteTitle,
|
||||||
|
twitter,
|
||||||
|
},
|
||||||
|
assetDefaults: {
|
||||||
|
description: defaultDescription,
|
||||||
|
thumbnail: defaultThumbnail,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
|
const VIDEO = 'VIDEO';
|
||||||
|
const IMAGE = 'IMAGE';
|
||||||
|
const GIF = 'GIF';
|
||||||
|
|
||||||
|
const determineMediaType = (contentType) => {
|
||||||
|
switch (contentType) {
|
||||||
|
case 'image/jpg':
|
||||||
|
case 'image/jpeg':
|
||||||
|
case 'image/png':
|
||||||
|
return IMAGE;
|
||||||
|
case 'image/gif':
|
||||||
|
return GIF;
|
||||||
|
case 'video/mp4':
|
||||||
|
case 'video/webm':
|
||||||
|
return VIDEO;
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAssetMetaTags = (asset) => {
|
||||||
|
const { claimData } = asset;
|
||||||
|
const { contentType } = claimData;
|
||||||
|
const showUrl = `${host}/${claimData.claimId}/${claimData.name}`;
|
||||||
|
const serveUrl = `${host}/${claimData.claimId}/${claimData.name}.${claimData.fileExt}`;
|
||||||
|
const ogTitle = claimData.title || claimData.name;
|
||||||
|
const ogDescription = claimData.description || defaultDescription;
|
||||||
|
const ogThumbnailContentType = determineContentTypeFromExtension(claimData.thumbnail);
|
||||||
|
const ogThumbnail = claimData.thumbnail || defaultThumbnail;
|
||||||
|
// {property: 'og:title'] = ogTitle},
|
||||||
|
const metaTags = {
|
||||||
|
'og:title' : ogTitle,
|
||||||
|
'twitter:title' : ogTitle,
|
||||||
|
'og:description' : ogDescription,
|
||||||
|
'twitter:description': ogDescription,
|
||||||
|
'og:url' : showUrl,
|
||||||
|
'og:site_name' : siteTitle,
|
||||||
|
'twitter:site' : twitter,
|
||||||
|
'fb:app_id' : '1371961932852223',
|
||||||
|
};
|
||||||
|
if (determineMediaType(contentType) === VIDEO) {
|
||||||
|
const videoEmbedUrl = `${host}/video-embed/${claimData.name}/${claimData.claimId}`;
|
||||||
|
// card type tags
|
||||||
|
metaTags['og:type'] = 'video.other';
|
||||||
|
metaTags['twitter:card'] = 'player';
|
||||||
|
metaTags['twitter:player'] = videoEmbedUrl;
|
||||||
|
metaTags['twitter:player:width'] = 600;
|
||||||
|
metaTags['twitter:text:player_width'] = 600;
|
||||||
|
metaTags['twitter:player:height'] = 350;
|
||||||
|
metaTags['twitter:player:stream'] = serveUrl;
|
||||||
|
metaTags['twitter:player:stream:content_type'] = contentType;
|
||||||
|
// video tags
|
||||||
|
metaTags['og:video'] = serveUrl;
|
||||||
|
metaTags['og:video:secure_url'] = serveUrl;
|
||||||
|
metaTags['og:video:type'] = contentType;
|
||||||
|
// image tags
|
||||||
|
metaTags['og:image'] = ogThumbnail;
|
||||||
|
metaTags['og:image:width'] = 600;
|
||||||
|
metaTags['og:image:height'] = 315;
|
||||||
|
metaTags['og:image:type'] = ogThumbnailContentType;
|
||||||
|
metaTags['twitter:image'] = ogThumbnail;
|
||||||
|
} else {
|
||||||
|
// card type tags
|
||||||
|
metaTags['og:type'] = 'article';
|
||||||
|
metaTags['twitter:card'] = 'summary_large_image';
|
||||||
|
// image tags
|
||||||
|
metaTags['og:image'] = serveUrl;
|
||||||
|
metaTags['og:image'] = serveUrl;
|
||||||
|
metaTags['og:image:width'] = 600;
|
||||||
|
metaTags['og:image:height'] = 315;
|
||||||
|
metaTags['og:image:type'] = contentType;
|
||||||
|
metaTags['twitter:image'] = serveUrl;
|
||||||
|
}
|
||||||
|
return createMetaTagsArray(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createAssetMetaTags;
|
44
client/src/utils/createBasicMetaTags.js
Normal file
44
client/src/utils/createBasicMetaTags.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import siteConfig from '@config/siteConfig.json';
|
||||||
|
import determineContentTypeFromExtension from './determineContentTypeFromExtension.js';
|
||||||
|
import createMetaTagsArray from './createMetaTagsArray';
|
||||||
|
|
||||||
|
const {
|
||||||
|
details: {
|
||||||
|
description,
|
||||||
|
host,
|
||||||
|
title,
|
||||||
|
twitter,
|
||||||
|
},
|
||||||
|
assetDefaults: {
|
||||||
|
thumbnail,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
|
const createBasicMetaTags = () => {
|
||||||
|
const metaTags = {
|
||||||
|
// page details
|
||||||
|
'og:title' : title,
|
||||||
|
'twitter:title' : title,
|
||||||
|
'og:description' : description,
|
||||||
|
'twitter:description': description,
|
||||||
|
// url
|
||||||
|
'og:url' : host,
|
||||||
|
// site id
|
||||||
|
'og:site_name' : title,
|
||||||
|
'twitter:site' : twitter,
|
||||||
|
'fb:app_id' : '1371961932852223',
|
||||||
|
// card type
|
||||||
|
'og:type' : 'article',
|
||||||
|
'twitter:card' : 'summary_large_image',
|
||||||
|
// image
|
||||||
|
'og:image' : thumbnail,
|
||||||
|
'og:image:width' : 600,
|
||||||
|
'og:image:height' : 315,
|
||||||
|
'og:image:type' : determineContentTypeFromExtension(thumbnail),
|
||||||
|
'twitter:image' : thumbnail,
|
||||||
|
'twitter:image:alt' : 'Spee.ch Logo',
|
||||||
|
};
|
||||||
|
return createMetaTagsArray(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createBasicMetaTags;
|
39
client/src/utils/createCanonicalLink.js
Normal file
39
client/src/utils/createCanonicalLink.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import siteConfig from '@config/siteConfig.json';
|
||||||
|
|
||||||
|
const {
|
||||||
|
details: {
|
||||||
|
host,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
|
const createBasicCanonicalLink = (page) => {
|
||||||
|
return `${host}/${page}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAssetCanonicalLink = (asset) => {
|
||||||
|
let channelName, certificateId, name, claimId;
|
||||||
|
if (asset.claimData) {
|
||||||
|
({ channelName, certificateId, name, claimId } = asset.claimData);
|
||||||
|
}
|
||||||
|
if (channelName) {
|
||||||
|
return `${host}/${channelName}:${certificateId}/${name}`;
|
||||||
|
}
|
||||||
|
return `${host}/${claimId}/${name}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createChannelCanonicalLink = (channel) => {
|
||||||
|
const { name, longId } = channel;
|
||||||
|
return `${host}/${name}:${longId}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createCanonicalLink = (asset, channel, page) => {
|
||||||
|
if (asset) {
|
||||||
|
return createAssetCanonicalLink(asset);
|
||||||
|
}
|
||||||
|
if (channel) {
|
||||||
|
return createChannelCanonicalLink(channel);
|
||||||
|
}
|
||||||
|
return createBasicCanonicalLink(page);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createCanonicalLink;
|
44
client/src/utils/createChannelMetaTags.js
Normal file
44
client/src/utils/createChannelMetaTags.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import siteConfig from '@config/siteConfig.json';
|
||||||
|
import determineContentTypeFromExtension from './determineContentTypeFromExtension';
|
||||||
|
import createMetaTagsArray from './createMetaTagsArray';
|
||||||
|
|
||||||
|
const {
|
||||||
|
details: {
|
||||||
|
host,
|
||||||
|
title: siteTitle,
|
||||||
|
twitter,
|
||||||
|
},
|
||||||
|
assetDefaults: {
|
||||||
|
thumbnail: defaultThumbnail,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
|
export const createChannelMetaTags = (channel) => {
|
||||||
|
const { name, longId } = channel;
|
||||||
|
const metaTags = {
|
||||||
|
// page detail tags
|
||||||
|
'og:title' : `${name} on ${siteTitle}`,
|
||||||
|
'twitter:title' : `${name} on ${siteTitle}`,
|
||||||
|
'og:description' : `${name}, a channel on ${siteTitle}`,
|
||||||
|
'twitter:description': `${name}, a channel on ${siteTitle}`,
|
||||||
|
// url
|
||||||
|
'og:url' : `${host}/${name}:${longId}`,
|
||||||
|
// site info
|
||||||
|
'og:site_name' : siteTitle,
|
||||||
|
'twitter:site' : twitter,
|
||||||
|
'fb:app_id' : '1371961932852223',
|
||||||
|
// card type tags
|
||||||
|
'og:type' : 'article',
|
||||||
|
'twitter:card' : 'summary_large_image',
|
||||||
|
// image tags
|
||||||
|
'og:image' : defaultThumbnail,
|
||||||
|
'og:image:width' : 600,
|
||||||
|
'og:image:height' : 315,
|
||||||
|
'og:image:type' : determineContentTypeFromExtension(defaultThumbnail),
|
||||||
|
'twitter:image' : defaultThumbnail,
|
||||||
|
'twitter:image:alt' : 'Spee.ch Logo',
|
||||||
|
};
|
||||||
|
return createMetaTagsArray(metaTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createChannelMetaTags;
|
15
client/src/utils/createMetaTags.js
Normal file
15
client/src/utils/createMetaTags.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import createAssetMetaTags from './createAssetMetaTags';
|
||||||
|
import createChannelMetaTags from './createChannelMetaTags.js';
|
||||||
|
import createBasicMetaTags from './createBasicMetaTags.js';
|
||||||
|
|
||||||
|
const createMetaTags = ({ asset, channel }) => {
|
||||||
|
if (asset) {
|
||||||
|
return createAssetMetaTags(asset);
|
||||||
|
}
|
||||||
|
if (channel) {
|
||||||
|
return createChannelMetaTags(channel);
|
||||||
|
}
|
||||||
|
return createBasicMetaTags();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createMetaTags;
|
14
client/src/utils/createMetaTagsArray.js
Normal file
14
client/src/utils/createMetaTagsArray.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
const createMetaTagsArray = (metaTagsObject) => {
|
||||||
|
let metaTagsArray = [];
|
||||||
|
for (let key in metaTagsObject) {
|
||||||
|
if (metaTagsObject.hasOwnProperty(key)) {
|
||||||
|
metaTagsArray.push({
|
||||||
|
property: key,
|
||||||
|
content : metaTagsObject[key],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metaTagsArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createMetaTagsArray;
|
16
client/src/utils/createPageTitle.js
Normal file
16
client/src/utils/createPageTitle.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import siteConfig from '@config/siteConfig.json';
|
||||||
|
|
||||||
|
const {
|
||||||
|
details: {
|
||||||
|
title: siteTitle,
|
||||||
|
},
|
||||||
|
} = siteConfig;
|
||||||
|
|
||||||
|
const createPageTitle = (pageTitle) => {
|
||||||
|
if (!pageTitle) {
|
||||||
|
return `${siteTitle}`;
|
||||||
|
}
|
||||||
|
return `${siteTitle} - ${pageTitle}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createPageTitle;
|
21
client/src/utils/determineContentTypeFromExtension.js
Normal file
21
client/src/utils/determineContentTypeFromExtension.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const determineContentTypeFromExtension = (thumbnail) => {
|
||||||
|
if (thumbnail) {
|
||||||
|
const fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
||||||
|
switch (fileExt) {
|
||||||
|
case 'jpeg':
|
||||||
|
case 'jpg':
|
||||||
|
return 'image/jpg';
|
||||||
|
case 'png':
|
||||||
|
return 'image/png';
|
||||||
|
case 'gif':
|
||||||
|
return 'image/gif';
|
||||||
|
case 'mp4':
|
||||||
|
return 'video/mp4';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
export default determineContentTypeFromExtension;
|
|
@ -1,122 +0,0 @@
|
||||||
const determineOgThumbnailContentType = (thumbnail) => {
|
|
||||||
if (thumbnail) {
|
|
||||||
const fileExt = thumbnail.substring(thumbnail.lastIndexOf('.'));
|
|
||||||
switch (fileExt) {
|
|
||||||
case 'jpeg':
|
|
||||||
case 'jpg':
|
|
||||||
return 'image/jpeg';
|
|
||||||
case 'png':
|
|
||||||
return 'image/png';
|
|
||||||
case 'gif':
|
|
||||||
return 'image/gif';
|
|
||||||
case 'mp4':
|
|
||||||
return 'video/mp4';
|
|
||||||
default:
|
|
||||||
return 'image/jpeg';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const createBasicMetaTags = ({siteHost, siteDescription, siteTitle, siteTwitter, defaultThumbnail}) => {
|
|
||||||
return [
|
|
||||||
{property: 'og:title', content: siteTitle},
|
|
||||||
{property: 'twitter:title', content: siteTitle},
|
|
||||||
{property: 'og:url', content: siteHost},
|
|
||||||
{property: 'og:site_name', content: siteTitle},
|
|
||||||
{property: 'og:description', content: siteDescription},
|
|
||||||
{property: 'twitter:description', content: siteDescription},
|
|
||||||
{property: 'twitter:site', content: siteTwitter},
|
|
||||||
{property: 'twitter:card', content: 'summary_large_image'},
|
|
||||||
{property: 'og:image', content: defaultThumbnail},
|
|
||||||
{property: 'twitter:image', content: defaultThumbnail},
|
|
||||||
{property: 'og:image:type', content: 'image/jpeg'},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const createChannelMetaTags = ({siteHost, siteTitle, siteTwitter, channel}) => {
|
|
||||||
const { name, longId } = channel;
|
|
||||||
return [
|
|
||||||
{property: 'og:title', content: `${name} on ${siteTitle}`},
|
|
||||||
{property: 'twitter:title', content: `${name} on ${siteTitle}`},
|
|
||||||
{property: 'og:url', content: `${siteHost}/${name}:${longId}`},
|
|
||||||
{property: 'og:site_name', content: siteTitle},
|
|
||||||
{property: 'og:description', content: `${name}, a channel on ${siteTitle}`},
|
|
||||||
{property: 'twitter:site', content: siteTwitter},
|
|
||||||
{property: 'twitter:card', content: 'summary'},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const createAssetMetaTags = ({siteHost, siteTitle, siteTwitter, asset, defaultDescription, defaultThumbnail}) => {
|
|
||||||
const { claimData } = asset;
|
|
||||||
const { contentType } = claimData;
|
|
||||||
const videoEmbedUrl = `${siteHost}/video-embed/${claimData.name}/${claimData.claimId}`;
|
|
||||||
const showUrl = `${siteHost}/${claimData.claimId}/${claimData.name}`;
|
|
||||||
const source = `${siteHost}/asset/${claimData.name}/${claimData.claimId}`;
|
|
||||||
const ogTitle = claimData.title || claimData.name;
|
|
||||||
const ogDescription = claimData.description || defaultDescription;
|
|
||||||
const ogThumbnailContentType = determineOgThumbnailContentType(claimData.thumbnail);
|
|
||||||
const ogThumbnail = claimData.thumbnail || defaultThumbnail;
|
|
||||||
const metaTags = [
|
|
||||||
{property: 'og:title', content: ogTitle},
|
|
||||||
{property: 'twitter:title', content: ogTitle},
|
|
||||||
{property: 'og:url', content: showUrl},
|
|
||||||
{property: 'og:site_name', content: siteTitle},
|
|
||||||
{property: 'og:description', content: ogDescription},
|
|
||||||
{property: 'twitter:description', content: ogDescription},
|
|
||||||
{property: 'og:image:width', content: 600},
|
|
||||||
{property: 'og:image:height', content: 315},
|
|
||||||
{property: 'twitter:site', content: siteTwitter},
|
|
||||||
];
|
|
||||||
if (contentType === 'video/mp4' || contentType === 'video/webm') {
|
|
||||||
metaTags.push({property: 'og:video', content: source});
|
|
||||||
metaTags.push({property: 'og:video:secure_url', content: source});
|
|
||||||
metaTags.push({property: 'og:video:type', content: contentType});
|
|
||||||
metaTags.push({property: 'og:image', content: ogThumbnail});
|
|
||||||
metaTags.push({property: 'twitter:image', content: ogThumbnail});
|
|
||||||
metaTags.push({property: 'og:image:type', content: ogThumbnailContentType});
|
|
||||||
metaTags.push({property: 'og:type', content: 'video.other'});
|
|
||||||
metaTags.push({property: 'twitter:card', content: 'player'});
|
|
||||||
metaTags.push({property: 'twitter:player', content: videoEmbedUrl});
|
|
||||||
metaTags.push({property: 'twitter:player:width', content: 600});
|
|
||||||
metaTags.push({property: 'twitter:text:player_width', content: 600});
|
|
||||||
metaTags.push({property: 'twitter:player:height', content: 337});
|
|
||||||
metaTags.push({property: 'twitter:player:stream', content: source});
|
|
||||||
metaTags.push({property: 'twitter:player:stream:content_type', content: contentType});
|
|
||||||
} else {
|
|
||||||
metaTags.push({property: 'og:image', content: source});
|
|
||||||
metaTags.push({property: 'twitter:image', content: source});
|
|
||||||
metaTags.push({property: 'og:image:type', content: contentType});
|
|
||||||
metaTags.push({property: 'og:type', content: 'article'});
|
|
||||||
metaTags.push({property: 'twitter:card', content: 'summary_large_image'});
|
|
||||||
}
|
|
||||||
return metaTags;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createMetaTags = ({ siteDescription, siteHost, siteTitle, siteTwitter, asset, channel, defaultDescription, defaultThumbnail }) => {
|
|
||||||
if (asset) {
|
|
||||||
return createAssetMetaTags({
|
|
||||||
siteHost,
|
|
||||||
siteTitle,
|
|
||||||
siteTwitter,
|
|
||||||
asset,
|
|
||||||
defaultDescription,
|
|
||||||
defaultThumbnail,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (channel) {
|
|
||||||
return createChannelMetaTags({
|
|
||||||
siteHost,
|
|
||||||
siteTitle,
|
|
||||||
siteTwitter,
|
|
||||||
channel,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return createBasicMetaTags({
|
|
||||||
siteDescription,
|
|
||||||
siteHost,
|
|
||||||
siteTitle,
|
|
||||||
siteTwitter,
|
|
||||||
defaultThumbnail,
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,6 +0,0 @@
|
||||||
export const createPageTitle = (siteTitle, pageTitle) => {
|
|
||||||
if (!pageTitle) {
|
|
||||||
return `${siteTitle}`;
|
|
||||||
}
|
|
||||||
return `${siteTitle} - ${pageTitle}`;
|
|
||||||
};
|
|
|
@ -27,6 +27,7 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
ip,
|
ip,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
|
files,
|
||||||
});
|
});
|
||||||
// check for disabled publishing
|
// check for disabled publishing
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
|
@ -36,14 +37,14 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// define variables
|
// define variables
|
||||||
let channelName, channelId, channelPassword, description, fileName, filePath, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
|
let channelName, channelId, channelPassword, description, fileName, filePath, fileExtension, fileType, gaStartTime, license, name, nsfw, thumbnail, thumbnailFileName, thumbnailFilePath, thumbnailFileType, title;
|
||||||
// record the start time of the request
|
// record the start time of the request
|
||||||
gaStartTime = Date.now();
|
gaStartTime = Date.now();
|
||||||
// validate the body and files of the request
|
// validate the body and files of the request
|
||||||
try {
|
try {
|
||||||
// validateApiPublishRequest(body, files);
|
// validateApiPublishRequest(body, files);
|
||||||
({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
|
({name, nsfw, license, title, description, thumbnail} = parsePublishApiRequestBody(body));
|
||||||
({fileName, filePath, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
|
({fileName, filePath, fileExtension, fileType, thumbnailFileName, thumbnailFilePath, thumbnailFileType} = parsePublishApiRequestFiles(files));
|
||||||
({channelName, channelId, channelPassword} = body);
|
({channelName, channelId, channelPassword} = body);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
|
@ -76,8 +77,9 @@ const claimPublish = ({ body, files, headers, ip, originalUrl, user, tor }, res)
|
||||||
data : {
|
data : {
|
||||||
name,
|
name,
|
||||||
claimId : result.claim_id,
|
claimId : result.claim_id,
|
||||||
url : `${host}/${result.claim_id}/${name}`,
|
url : `${host}/${result.claim_id}/${name}`, // for backwards compatability with app
|
||||||
embedUrl: `${host}/asset/${name}/${result.claim_id}`,
|
showUrl : `${host}/${result.claim_id}/${name}`,
|
||||||
|
serveUrl: `${host}/${result.claim_id}/${name}${fileExtension}`,
|
||||||
lbryTx : result,
|
lbryTx : result,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const path = require('path');
|
||||||
const validateFileTypeAndSize = require('./validateFileTypeAndSize.js');
|
const validateFileTypeAndSize = require('./validateFileTypeAndSize.js');
|
||||||
|
|
||||||
const parsePublishApiRequestFiles = ({file, thumbnail}) => {
|
const parsePublishApiRequestFiles = ({file, thumbnail}) => {
|
||||||
|
@ -33,6 +34,7 @@ const parsePublishApiRequestFiles = ({file, thumbnail}) => {
|
||||||
return {
|
return {
|
||||||
fileName : file.name,
|
fileName : file.name,
|
||||||
filePath : file.path,
|
filePath : file.path,
|
||||||
|
fileExtension : path.extname(file.path),
|
||||||
fileType : file.type,
|
fileType : file.type,
|
||||||
thumbnailFileName: (thumbnail ? thumbnail.name : null),
|
thumbnailFileName: (thumbnail ? thumbnail.name : null),
|
||||||
thumbnailFilePath: (thumbnail ? thumbnail.path : null),
|
thumbnailFilePath: (thumbnail ? thumbnail.path : null),
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
const EMBED = 'EMBED';
|
const SERVE = 'SERVE';
|
||||||
const BROWSER = 'BROWSER';
|
const SHOW = 'SHOW';
|
||||||
const SOCIAL = 'SOCIAL';
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
EMBED,
|
SERVE,
|
||||||
BROWSER,
|
SHOW,
|
||||||
SOCIAL,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const logger = require('winston');
|
||||||
|
|
||||||
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||||
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
|
|
||||||
|
@ -6,7 +8,7 @@ const lbryUri = require('../utils/lbryUri.js');
|
||||||
const determineRequestType = require('../utils/determineRequestType.js');
|
const determineRequestType = require('../utils/determineRequestType.js');
|
||||||
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||||
|
|
||||||
const { EMBED } = require('../constants/request_types.js');
|
const { SHOW } = require('../constants/request_types.js');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -16,29 +18,32 @@ const { EMBED } = require('../constants/request_types.js');
|
||||||
|
|
||||||
const serveByClaim = (req, res) => {
|
const serveByClaim = (req, res) => {
|
||||||
const { headers, ip, originalUrl, params } = req;
|
const { headers, ip, originalUrl, params } = req;
|
||||||
// decide if this is a show request
|
|
||||||
let hasFileExtension;
|
|
||||||
try {
|
try {
|
||||||
|
let isChannel, hasFileExtension, claimName;
|
||||||
|
|
||||||
|
({ isChannel } = lbryUri.parseIdentifier(params.claim));
|
||||||
|
if (isChannel) {
|
||||||
|
logger.debug('channel request:', { headers, ip, originalUrl, params });
|
||||||
|
return handleShowRender(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
||||||
|
if (determineRequestType(hasFileExtension, headers) === SHOW) {
|
||||||
|
logger.debug('show request:', { headers, ip, originalUrl, params });
|
||||||
|
return handleShowRender(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
({ claimName } = lbryUri.parseClaim(params.claim));
|
||||||
|
logger.debug('serve request:', { headers, ip, originalUrl, params });
|
||||||
|
getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
|
||||||
|
|
||||||
|
sendGAServeEvent(headers, ip, originalUrl);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
// determine request type
|
|
||||||
let requestType = determineRequestType(hasFileExtension, headers);
|
|
||||||
if (requestType !== EMBED) {
|
|
||||||
return handleShowRender(req, res);
|
|
||||||
}
|
|
||||||
// parse the claim
|
|
||||||
let claimName;
|
|
||||||
try {
|
|
||||||
({claimName} = lbryUri.parseClaim(params.claim));
|
|
||||||
} catch (error) {
|
|
||||||
return res.status(400).json({success: false, message: error.message});
|
|
||||||
}
|
|
||||||
// send google analytics
|
|
||||||
sendGAServeEvent(headers, ip, originalUrl);
|
|
||||||
// get the claim Id and then serve the asset
|
|
||||||
getClaimIdAndServeAsset(null, null, claimName, null, originalUrl, ip, res);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = serveByClaim;
|
module.exports = serveByClaim;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const logger = require('winston');
|
||||||
|
|
||||||
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
const { sendGAServeEvent } = require('../../../utils/googleAnalytics');
|
||||||
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
const handleShowRender = require('../../../render/build/handleShowRender.js');
|
||||||
|
|
||||||
|
@ -7,7 +9,7 @@ const determineRequestType = require('../utils/determineRequestType.js');
|
||||||
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
const getClaimIdAndServeAsset = require('../utils/getClaimIdAndServeAsset.js');
|
||||||
const flipClaimNameAndId = require('../utils/flipClaimNameAndId.js');
|
const flipClaimNameAndId = require('../utils/flipClaimNameAndId.js');
|
||||||
|
|
||||||
const { EMBED } = require('../constants/request_types.js');
|
const { SHOW } = require('../constants/request_types.js');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -17,40 +19,32 @@ const { EMBED } = require('../constants/request_types.js');
|
||||||
|
|
||||||
const serverByIdentifierAndClaim = (req, res) => {
|
const serverByIdentifierAndClaim = (req, res) => {
|
||||||
const { headers, ip, originalUrl, params } = req;
|
const { headers, ip, originalUrl, params } = req;
|
||||||
// parse request
|
|
||||||
let hasFileExtension;
|
|
||||||
try {
|
try {
|
||||||
|
let hasFileExtension, claimName, isChannel, channelName, channelClaimId, claimId;
|
||||||
|
|
||||||
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
||||||
} catch (error) {
|
if (determineRequestType(hasFileExtension, headers) === SHOW) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
logger.debug('show request:', { headers, ip, originalUrl, params });
|
||||||
}
|
return handleShowRender(req, res);
|
||||||
// determine request type
|
}
|
||||||
let requestType = determineRequestType(hasFileExtension, headers);
|
|
||||||
if (requestType !== EMBED) {
|
|
||||||
return handleShowRender(req, res);
|
|
||||||
}
|
|
||||||
// parse the claim
|
|
||||||
let claimName;
|
|
||||||
try {
|
|
||||||
({ claimName } = lbryUri.parseClaim(params.claim));
|
({ claimName } = lbryUri.parseClaim(params.claim));
|
||||||
} catch (error) {
|
|
||||||
return res.status(400).json({success: false, message: error.message});
|
|
||||||
}
|
|
||||||
// parse the identifier
|
|
||||||
let isChannel, channelName, channelClaimId, claimId;
|
|
||||||
try {
|
|
||||||
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
|
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
|
||||||
|
|
||||||
|
if (!isChannel) {
|
||||||
|
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug('serve request:', { headers, ip, originalUrl, params });
|
||||||
|
getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
|
||||||
|
|
||||||
|
sendGAServeEvent(headers, ip, originalUrl);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({success: false, message: error.message});
|
return res.status(400).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
// for backwards compatability, flip claim name and claim id if necessary
|
|
||||||
if (!isChannel) {
|
|
||||||
[claimId, claimName] = flipClaimNameAndId(claimId, claimName);
|
|
||||||
}
|
|
||||||
// send google analytics
|
|
||||||
sendGAServeEvent(headers, ip, originalUrl);
|
|
||||||
// get the claim Id and then serve the asset
|
|
||||||
getClaimIdAndServeAsset(channelName, channelClaimId, claimName, claimId, originalUrl, ip, res);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = serverByIdentifierAndClaim;
|
module.exports = serverByIdentifierAndClaim;
|
||||||
|
|
|
@ -1,60 +1,16 @@
|
||||||
const logger = require('winston');
|
const { SERVE, SHOW } = require('../constants/request_types.js');
|
||||||
const { EMBED, BROWSER, SOCIAL } = require('../constants/request_types.js');
|
|
||||||
|
|
||||||
function headersMatchesSocialBotList (headers) {
|
|
||||||
const userAgent = headers['user-agent'];
|
|
||||||
const socialBotList = [
|
|
||||||
'facebookexternalhit',
|
|
||||||
'Twitterbot',
|
|
||||||
];
|
|
||||||
for (let i = 0; i < socialBotList.length; i++) {
|
|
||||||
if (userAgent.includes(socialBotList[i])) {
|
|
||||||
logger.debug('request is from social bot:', socialBotList[i]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clientAcceptsHtml ({accept}) {
|
|
||||||
return accept && accept.match(/text\/html/);
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestIsFromBrowser (headers) {
|
|
||||||
return headers['user-agent'] && headers['user-agent'].match(/Mozilla/);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clientWantsAsset ({accept, range}) {
|
function clientWantsAsset ({accept, range}) {
|
||||||
const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/) && !accept.match(/text\/\*/);
|
const imageIsWanted = accept && accept.match(/image\/.*/) && !accept.match(/text\/html/);
|
||||||
const videoIsWanted = accept && range;
|
const videoIsWanted = accept && accept.match(/video\/.*/) && !accept.match(/text\/html/);
|
||||||
return imageIsWanted || videoIsWanted;
|
return imageIsWanted || videoIsWanted;
|
||||||
}
|
}
|
||||||
|
|
||||||
const determineRequestType = (hasFileExtension, headers) => {
|
const determineRequestType = (hasFileExtension, headers) => {
|
||||||
let responseType;
|
if (hasFileExtension || clientWantsAsset(headers)) {
|
||||||
logger.debug('headers:', headers);
|
return SERVE;
|
||||||
// return early with 'show' if headers match the list
|
|
||||||
if (headersMatchesSocialBotList(headers)) {
|
|
||||||
return SOCIAL;
|
|
||||||
}
|
}
|
||||||
// if request is not from a social bot...
|
return SHOW;
|
||||||
if (hasFileExtension) {
|
|
||||||
// assume embed,
|
|
||||||
responseType = EMBED;
|
|
||||||
// but change to browser if client accepts html.
|
|
||||||
if (clientAcceptsHtml(headers)) {
|
|
||||||
responseType = BROWSER;
|
|
||||||
}
|
|
||||||
// if request does not have file extentsion...
|
|
||||||
} else {
|
|
||||||
// assume browser,
|
|
||||||
responseType = BROWSER;
|
|
||||||
// but change to embed if someone embeded a show url...
|
|
||||||
if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) {
|
|
||||||
responseType = EMBED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return responseType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = determineRequestType;
|
module.exports = determineRequestType;
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
const serveByClaim = require('../../controllers/assets/serveByClaim');
|
const serveByClaim = require('../../controllers/assets/serveByClaim');
|
||||||
const serveByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
const serveByIdentifierAndClaim = require('../../controllers/assets/serveByIdentifierAndClaim');
|
||||||
const serveAsset = require('../../controllers/assets/serveAsset');
|
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
app.get('/asset/:claimName/:claimId/', serveAsset);
|
|
||||||
app.get('/:identifier/:claim', serveByIdentifierAndClaim);
|
app.get('/:identifier/:claim', serveByIdentifierAndClaim);
|
||||||
app.get('/:claim', serveByClaim);
|
app.get('/:claim', serveByClaim);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<video controls>
|
<video controls>
|
||||||
<source src="{{host}}/asset/{{name}}/{{claimId}}" type="video/mp4">
|
<source src="{{host}}/{{claimId}}/{{name}}.mp4" type="video/mp4">
|
||||||
Your browser does not support video
|
Your browser does not support video
|
||||||
</video>
|
</video>
|
||||||
|
|
Loading…
Reference in a new issue
use template strings?
e.g.