Skip to content

Instantly share code, notes, and snippets.

@PavlikPolivka
Created December 10, 2021 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PavlikPolivka/81b0f82e97f16009c9050b0995a5d4ce to your computer and use it in GitHub Desktop.
Save PavlikPolivka/81b0f82e97f16009c9050b0995a5d4ce to your computer and use it in GitHub Desktop.
const { TwitterClient } = require('twitter-api-client')
const axios = require('axios')
const sharp = require('sharp')
const Feed = require('rss-to-json')
const Jimp = require('jimp')
const fs = require('fs')
const numberOfFollowers = 3
const widthHeightFollowerImage = 90
function getVariable(name) {
if (fs.existsSync(`${__dirname}/creds.json`)) {
return require(`${__dirname}/creds.json`)[name]
}
return process.env[name]
}
async function uploadBanner() {
console.log(`Uploading to twitter...`)
const base64 = await fs.readFileSync('/tmp/1500x500_final.png', { encoding: 'base64' });
await twitterClient.accountsAndUsers
.accountUpdateProfileBanner({ banner: base64 })
}
async function createBanner(headline) {
const banner = await Jimp.read(`${__dirname}/assets/banner.png`)
const mask = await Jimp.read(`${__dirname}/assets/mask.png`)
const font = await Jimp.loadFont(Jimp.FONT_SANS_32_WHITE)
// build banner
console.log(`Adding followers...`)
await Promise.all([...Array(numberOfFollowers)].map((_, i) => {
return new Promise(async resolve => {
const image = await Jimp.read(`/tmp/${i}.png`)
const x = 600 + i * (widthHeightFollowerImage + 10);
console.log(`Appending image ${i} with x=${x}`)
banner.composite(image, x, 360);
resolve()
})
}))
console.log(`Adding headline...`)
banner.print(font, 380, 250, headline);
await banner.writeAsync('/tmp/1500x500_final.png');
}
async function getLatestArticleHeadline() {
console.log(`Retrieving headline...`)
const rss = await Feed.parse(`${getVariable('RSS_FEED')}`)
const title = rss.items[0].title
console.log(`Retrieved headline: ${title}`)
// add padding left & right to align it properly
const padding = ' '.repeat(Math.ceil((60 - title.length) / 2))
return `${padding}${title}${padding}`;
}
async function saveAvatar(user, path) {
console.log(`Retrieving avatar...`)
const response = await axios({
url: user.profile_image_url_https,
responseType: 'arraybuffer'
})
await sharp(response.data)
.resize(widthHeightFollowerImage, widthHeightFollowerImage)
.toFile(path)
}
async function getImagesOfLatestFollowers() {
console.log(`Retrieving followers...`)
try {
const data = await twitterClient
.accountsAndUsers
.followersList({
screen_name: getVariable('TWITTER_HANDLE'),
count: numberOfFollowers
})
await Promise.all(data.users
.map((user, index) => saveAvatar(user, `/tmp/${index}.png`)))
} catch (err) {
console.log(err)
}
}
const twitterClient = new TwitterClient({
apiKey: getVariable('TWITTER_API_KEY'),
apiSecret: getVariable('TWITTER_API_SECRET_KEY'),
accessToken: getVariable('TWITTER_API_ACCESS_TOKEN'),
accessTokenSecret: getVariable('TWITTER_API_ACCESS_SECRET'),
});
exports.handler = async () => {
await getImagesOfLatestFollowers()
const title = await getLatestArticleHeadline()
await createBanner(title)
await uploadBanner()
return {
statusCode: 200,
body: JSON.stringify({ status: 'ok' }),
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment