From cd1954f9ad8d30ef043fef9d7afd2270d7e1c011 Mon Sep 17 00:00:00 2001 From: tycrek Date: Sun, 27 Jun 2021 16:23:28 -0600 Subject: [PATCH] moved OpenGraph & oEmbed into main file; removed express-useragent --- ass.js | 44 ++++++++++++----------- ogp.js | 90 ----------------------------------------------- package-lock.json | 14 -------- package.json | 1 - utils.js | 22 ++++++++---- views/view.pug | 10 ++++++ 6 files changed, 49 insertions(+), 132 deletions(-) delete mode 100644 ogp.js diff --git a/ass.js b/ass.js index ecaee33..731a6cc 100755 --- a/ass.js +++ b/ass.js @@ -20,12 +20,11 @@ const fetch = require('node-fetch'); const marked = require('marked'); const { DateTime } = require('luxon'); const { WebhookClient, MessageEmbed } = require('discord.js'); -const OpenGraph = require('./ogp'); const Thumbnail = require('./thumbnails'); const Vibrant = require('./vibrant'); const Hash = require('./hash'); const { uploadLocal, uploadS3, deleteS3 } = require('./storage'); -const { path, saveData, log, verify, getTrueHttp, getTrueDomain, renameFile, generateToken, generateId, formatBytes, formatTimestamp, arrayEquals, getS3url, getDirectUrl, getResourceColor, downloadTempS3, sanitize } = require('./utils'); +const { path, saveData, log, verify, getTrueHttp, getTrueDomain, renameFile, generateToken, generateId, formatBytes, formatTimestamp, arrayEquals, getS3url, getDirectUrl, getSafeExt, getResourceColor, downloadTempS3, sanitize, replaceholder } = require('./utils'); const { CODE_NO_CONTENT, CODE_BAD_REQUEST, CODE_UNAUTHORIZED, CODE_NOT_FOUND } = require('./MagicNumbers.json'); //#endregion @@ -240,27 +239,30 @@ function startup() { app.get('/:resourceId', (req, res) => { const { resourceId } = req.ass; const fileData = data[resourceId]; - - const requiredItems = { - randomId: fileData.randomId, - originalname: escape(fileData.originalname), - mimetype: fileData.mimetype, - size: fileData.size, - timestamp: fileData.timestamp, - opengraph: fileData.opengraph, - vibrant: fileData.vibrant, - }; - - // If the client is a social bot (such as Discord or Instagram), send an Open Graph embed - if (req.useragent.isBot) res.type('html').send(new OpenGraph(getTrueHttp(), getTrueDomain(), resourceId, requiredItems).build()); - else res.render('view', { - title: requiredItems.originalname, + const isVideo = fileData.mimetype.includes('video'); + + // Build OpenGraph meta tags + const og = fileData.opengraph, ogs = ['']; + og.title && (ogs.push(``)); + og.description && (ogs.push(``)); + og.author && (ogs.push(``)); + og.color && (ogs.push(``)); + !isVideo && (ogs.push(``)); + + // Send the view to the client + res.render('view', { + isVideo, + title: escape(fileData.originalname), uploader: users[fileData.token].username, timestamp: formatTimestamp(fileData.timestamp), size: formatBytes(fileData.size), color: getResourceColor(fileData.opengraph.color || null, fileData.vibrant), - isVideo: fileData.mimetype.includes('video'), resourceAttr: { src: getDirectUrl(resourceId) }, + discordUrl: `${getDirectUrl(resourceId)}${getSafeExt(fileData.mimetype)}`, + oembedUrl: `${getTrueHttp()}${getTrueDomain()}/${resourceId}/oembed.json`, + ogtype: isVideo ? 'video.other' : 'image', + urlType: `og:${isVideo ? 'video' : 'image'}`, + opengraph: replaceholder(ogs.join('\n'), fileData) }); }); @@ -305,10 +307,10 @@ function startup() { res.type('json').send({ version: '1.0', type: mimetype.includes('video') ? 'video' : 'photo', - author_name: opengraph.author, author_url: opengraph.authorUrl, - provider_name: opengraph.provider, - provider_url: opengraph.providerUrl + provider_url: opengraph.providerUrl, + author_name: replaceholder(opengraph.author || '', data[resourceId]), + provider_name: replaceholder(opengraph.provider || '', data[resourceId]) }); }); diff --git a/ogp.js b/ogp.js deleted file mode 100644 index 4639c6b..0000000 --- a/ogp.js +++ /dev/null @@ -1,90 +0,0 @@ -const Mustache = require('mustache'); -const { homepage, version } = require('./package.json'); -const { formatBytes, getDirectUrl, getResourceColor, formatTimestamp, getSafeExt } = require('./utils'); - -// https://ogp.me/ -class OpenGraph { - http; - domain; - resourceId; - randomId; - - filename; - type; - size; - timestamp; - vibrant; - - title; - description; - author; - color; - - constructor(http, domain, resourceId, { randomId, originalname, mimetype, size, timestamp, opengraph, vibrant }) { - this.http = http; - this.domain = domain; - this.resourceId = resourceId; - this.randomId = randomId; - - this.type = mimetype; - this.filename = originalname; - this.size = size; - this.timestamp = timestamp; - this.vibrant = vibrant; - - this.title = opengraph.title || ''; - this.description = opengraph.description || ''; - this.author = opengraph.author || ''; - this.color = opengraph.color || ''; - } - - build() { - let resourceUrl = getDirectUrl(this.resourceId) + getSafeExt(this.type); - return Mustache.render(html, { - homepage, - version, - - http: this.http, - domain: this.domain, - resourceId: this.resourceId, - resourceUrl, - - media: `<${this.type.includes('video') ? 'video' : 'img'} src="${resourceUrl}" style="height: 50vh;">`, - ogtype: this.type.includes('video') ? 'video.other' : 'image', - type: this.type.includes('video') ? 'video' : 'image', - title: (this.title.length != 0) ? `` : '', - description: (this.description.length != 0) ? `` : '', - site: (this.author.length != 0) ? `` : '', - color: (this.color.length != 0) ? `` : '', - card: !this.type.includes('video') ? `` : '', - }) - .replace(new RegExp('&size', 'g'), formatBytes(this.size)) - .replace(new RegExp('&filename', 'g'), this.filename) - .replace(new RegExp('×tamp', 'g'), formatTimestamp(this.timestamp)); - } -} - -const html = ` - - - ass - - - - {{{title}}} - {{{description}}} - {{{site}}} - {{{color}}} - {{{card}}} - - - - - Open Graph response for ass {{{version}}} -
- {{{media}}} - - -`; - -module.exports = OpenGraph; diff --git a/package-lock.json b/package-lock.json index 4e777c0..3d8b131 100755 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "escape-html": "^1.0.3", "express": "^4.17.1", "express-rate-limit": "^5.2.6", - "express-useragent": "^1.0.15", "ffmpeg-static": "^4.3.0", "fs-extra": "^9.1.0", "helmet": "^4.6.0", @@ -1278,14 +1277,6 @@ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.2.6.tgz", "integrity": "sha512-nE96xaxGfxiS5jP3tD3kIW1Jg9yQgX0rXCs3rCkZtmbWHEGyotwaezkLj7bnB41Z0uaOLM8W4AX6qHao4IZ2YA==" }, - "node_modules/express-useragent": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/express-useragent/-/express-useragent-1.0.15.tgz", - "integrity": "sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg==", - "engines": { - "node": ">=4.5" - } - }, "node_modules/eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -3868,11 +3859,6 @@ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.2.6.tgz", "integrity": "sha512-nE96xaxGfxiS5jP3tD3kIW1Jg9yQgX0rXCs3rCkZtmbWHEGyotwaezkLj7bnB41Z0uaOLM8W4AX6qHao4IZ2YA==" }, - "express-useragent": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/express-useragent/-/express-useragent-1.0.15.tgz", - "integrity": "sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg==" - }, "eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", diff --git a/package.json b/package.json index 79e3f1f..854a0ea 100755 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "escape-html": "^1.0.3", "express": "^4.17.1", "express-rate-limit": "^5.2.6", - "express-useragent": "^1.0.15", "ffmpeg-static": "^4.3.0", "fs-extra": "^9.1.0", "helmet": "^4.6.0", diff --git a/utils.js b/utils.js index 4d81bb9..d9ecd10 100755 --- a/utils.js +++ b/utils.js @@ -48,6 +48,20 @@ function formatTimestamp(timestamp) { return DateTime.fromMillis(timestamp).toLocaleString(DateTime.DATETIME_MED); } +function formatBytes(bytes, decimals = 2) { // skipcq: JS-0074 + if (bytes === 0) return '0 Bytes'; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const i = Math.floor(Math.log(bytes) / Math.log(KILOBYTES)); + return parseFloat((bytes / Math.pow(KILOBYTES, i)).toFixed(decimals < 0 ? 0 : decimals)).toString().concat(` ${sizes[i]}`); +} + +function replaceholder(data, { size, timestamp, originalname }) { + return data + .replace(new RegExp('&size', 'g'), formatBytes(size)) + .replace(new RegExp('&filename', 'g'), originalname) + .replace(new RegExp('×tamp', 'g'), formatTimestamp(timestamp)); +} + const idModes = { zws: 'zws', // Zero-width spaces (see: https://zws.im/) og: 'original', // Use original uploaded filename @@ -68,6 +82,8 @@ module.exports = { getDirectUrl, getResourceColor, formatTimestamp, + formatBytes, + replaceholder, getSafeExt, randomHexColour, sanitize, @@ -86,12 +102,6 @@ module.exports = { }), generateToken: () => token(), generateId: (mode, length, gfyLength, originalName) => (GENERATORS.has(mode) ? GENERATORS.get(mode)({ length, gfyLength }) : originalName), - formatBytes: (bytes, decimals = 2) => { // skipcq: JS-0074 - if (bytes === 0) return '0 Bytes'; - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - const i = Math.floor(Math.log(bytes) / Math.log(KILOBYTES)); - return parseFloat((bytes / Math.pow(KILOBYTES, i)).toFixed(decimals < 0 ? 0 : decimals)).toString().concat(` ${sizes[i]}`); - }, arrayEquals: (arr1, arr2) => arr1.length === arr2.length && arr1.slice().sort().every((value, index) => value === arr2.slice().sort()[index]), downloadTempS3: (file) => new Promise((resolve, reject) => fetch(getS3url(file.randomId, file.mimetype)) diff --git a/views/view.pug b/views/view.pug index 14c4193..d9602a3 100644 --- a/views/view.pug +++ b/views/view.pug @@ -8,6 +8,16 @@ html style: include css/img.css style. img, video { border-color: #{color}; } + + // Open Graph (https://ogp.me/) + meta(property='og:type' content=ogtype) + meta(property=urlType content=discordUrl) + . + !{opengraph} + + // oEmbed (https://oembed.com/) + link(href=oembedUrl title='oEmbed' rel='alternate' type='application/json+oembed') + body #container #content