mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-04-08 02:52:39 -05:00
Initial custom embed provider for Twitter
refs https://github.com/TryGhost/Team/issues/1001 We fall back to existing behaviour if no API key is present, or if there is an error communicating with the Twitter API. We're also currently requesting all the data, which will be thinned down once we understand what we need. This also includes a custom renderer for embeds of type "twitter" which will be used to output the custom HTML for emails
This commit is contained in:
parent
c4021b6eb4
commit
e6856f6ac6
5 changed files with 99 additions and 5 deletions
|
@ -3,13 +3,24 @@ const externalRequest = require('../../lib/request-external');
|
|||
|
||||
const OEmbed = require('../../services/oembed');
|
||||
const oembed = new OEmbed({config, externalRequest});
|
||||
|
||||
const NFT = require('../../services/nft-oembed');
|
||||
const nft = new NFT({
|
||||
config: {
|
||||
apiKey: config.get('opensea').privateReadOnlyApiKey
|
||||
}
|
||||
});
|
||||
|
||||
const Twitter = require('../../services/twitter-embed');
|
||||
const twitter = new Twitter({
|
||||
config: {
|
||||
bearerToken: config.get('twitter').privateReadOnlyToken
|
||||
},
|
||||
logging: require('@tryghost/logging')
|
||||
});
|
||||
|
||||
oembed.registerProvider(nft);
|
||||
oembed.registerProvider(twitter);
|
||||
|
||||
module.exports = {
|
||||
docName: 'oembed',
|
||||
|
|
80
core/server/services/twitter-embed.js
Normal file
80
core/server/services/twitter-embed.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
const {extract} = require('oembed-parser');
|
||||
|
||||
/**
|
||||
* @typedef {import('./oembed').ICustomProvider} ICustomProvider
|
||||
* @typedef {import('./oembed').IExternalRequest} IExternalRequest
|
||||
*/
|
||||
|
||||
const TWITTER_PATH_REGEX = /\/status\/(\d+)/;
|
||||
|
||||
/**
|
||||
* @implements ICustomProvider
|
||||
*/
|
||||
class TwitterOEmbedProvider {
|
||||
/**
|
||||
* @param {object} dependencies
|
||||
*/
|
||||
constructor(dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} url
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async canSupportRequest(url) {
|
||||
return url.host === 'twitter.com' && TWITTER_PATH_REGEX.test(url.pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {URL} url
|
||||
* @param {IExternalRequest} externalRequest
|
||||
*
|
||||
* @returns {Promise<object>}
|
||||
*/
|
||||
async getOEmbedData(url, externalRequest) {
|
||||
const [match, tweetId] = url.pathname.match(TWITTER_PATH_REGEX);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @type {object} */
|
||||
const oembedData = await extract(url.href);
|
||||
|
||||
if (this.dependencies.config.bearerToken) {
|
||||
const query = {
|
||||
expansions: ['attachments.poll_ids', 'attachments.media_keys', 'author_id', 'entities.mentions.username', 'geo.place_id', 'in_reply_to_user_id', 'referenced_tweets.id', 'referenced_tweets.id.author_id'],
|
||||
'media.fields': ['duration_ms', 'height', 'media_key', 'preview_image_url', 'type', 'url', 'width', 'public_metrics', 'alt_text'],
|
||||
'place.fields': ['contained_within', 'country', 'country_code', 'full_name', 'geo', 'id', 'name', 'place_type'],
|
||||
'poll.fields': ['duration_minutes', 'end_datetime', 'id', 'options', 'voting_status'],
|
||||
'tweet.fields': ['attachments', 'author_id', 'context_annotations', 'conversation_id', 'created_at', 'entities', 'geo', 'id', 'in_reply_to_user_id', 'lang', 'public_metrics', 'possibly_sensitive', 'referenced_tweets', 'reply_settings', 'source', 'text', 'withheld'],
|
||||
'user.fields': ['created_at', 'description', 'entities', 'id', 'location', 'name', 'pinned_tweet_id', 'profile_image_url', 'protected', 'public_metrics', 'url', 'username', 'verified', 'withheld']
|
||||
};
|
||||
|
||||
const queryString = Object.keys(query).map((key) => {
|
||||
return `${key}=${query[key].join(',')}`;
|
||||
}).join('&');
|
||||
|
||||
try {
|
||||
const result = await externalRequest(`https://api.twitter.com/2/tweets/${tweetId}?${queryString}`, {
|
||||
responseType: 'json',
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.dependencies.config.bearerToken}`
|
||||
}
|
||||
});
|
||||
|
||||
const body = JSON.parse(result.body);
|
||||
|
||||
oembedData.tweet_data = body.data;
|
||||
} catch (err) {
|
||||
this.dependencies.logging.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
oembedData.type = 'twitter';
|
||||
|
||||
return oembedData;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TwitterOEmbedProvider;
|
|
@ -136,5 +136,8 @@
|
|||
},
|
||||
"opensea": {
|
||||
"privateReadOnlyApiKey": null
|
||||
},
|
||||
"twitter": {
|
||||
"privateReadOnlyToken": null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
"@tryghost/job-manager": "0.8.13",
|
||||
"@tryghost/kg-card-factory": "3.1.0",
|
||||
"@tryghost/kg-default-atoms": "3.1.0",
|
||||
"@tryghost/kg-default-cards": "5.8.5",
|
||||
"@tryghost/kg-default-cards": "5.9.0",
|
||||
"@tryghost/kg-markdown-html-renderer": "5.1.0",
|
||||
"@tryghost/kg-mobiledoc-html-renderer": "5.3.0",
|
||||
"@tryghost/limit-service": "1.0.0",
|
||||
|
|
|
@ -1422,10 +1422,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@tryghost/kg-default-atoms/-/kg-default-atoms-3.1.0.tgz#4daff7104c1f261b1b816dd75ae4104009f9c1e6"
|
||||
integrity sha512-FfROzVgqJWqJ7cVdS9dcALz7rnzNfV8zcrymAJrDTHDsqzAdMfSLe1tNQRm8zas9pyZLsD8zBGmLxG9dr4WFSA==
|
||||
|
||||
"@tryghost/kg-default-cards@5.8.5":
|
||||
version "5.8.5"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/kg-default-cards/-/kg-default-cards-5.8.5.tgz#e203ea584ac6d82b1481cd87f916968e0d7ce1ee"
|
||||
integrity sha512-j+dqm9CgRux87aakWw9TngRoOVtj88WaD6GC4BcfImdTwc0T2tF8IymiuMGkTA+5ZnV6B5qB4MBg/HIke1C0Nw==
|
||||
"@tryghost/kg-default-cards@5.9.0":
|
||||
version "5.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/kg-default-cards/-/kg-default-cards-5.9.0.tgz#2dbd1bf0545376e505fde69fc4fd525241662283"
|
||||
integrity sha512-w2zfY/tYmf/uTfgzGajLBavoTCQ1XEN+GaLY7v6GeGPkbLIMsAIW4DG9WdR73P5Sq7sDrTQ5fKoUcI195cEE1g==
|
||||
dependencies:
|
||||
"@tryghost/kg-markdown-html-renderer" "^5.1.0"
|
||||
"@tryghost/url-utils" "^2.0.0"
|
||||
|
|
Loading…
Add table
Reference in a new issue