poster.js (119 lines of code) (raw):
const { BskyAgent, AppBskyFeedPost } = require("@atproto/api");
const timer = ms => new Promise(res => setTimeout(res, ms))
const sharp = require("sharp");
// ### envrionment variables
const dotenv = require('dotenv');
dotenv.config()
// console.log(process.env)
// import dotenv from 'dotenv'
// dotenv.config()
const cheerio = require("cheerio");
const Parser = require("rss-parser");
// const parser = new Parser();
const parser = new Parser({
customFields: {
item: [
['media:content', 'media:content', {keepArray: true}],
]
}
})
accounty = process.env.ACC
passy = process.env.PASS
// rss_feeds = ['https://www.theguardian.com/tracking/commissioningdesk/australia-politics/rss',
// 'https://www.theguardian.com/tracking/commissioningdesk/australia-business/rss',
// 'https://www.theguardian.com/collection/au-alpha/features/feature-stories/rss',
// ]
rss_feeds = ['https://www.theguardian.com/collection/7f0d9448-a9af-40a4-a567-24582060d46a/rss','https://www.theguardian.com/tracking/commissioningdesk/australia-politics/rss',
'https://www.theguardian.com/tracking/commissioningdesk/australia-business/rss'
]
// ### Function to post new posts
async function post(agent, item) {
const dom = await fetch(item.link)
.then((response) => response.text())
.then((html) => cheerio.load(html));
let image_url = null;
const image_url_ = dom('head > meta[property="og:image"]');
if (image_url_) {
image_url = await image_url_.attr("content");
}
const buffer = await fetch(image_url)
.then((response) => response.arrayBuffer())
.then((buffer) => sharp(buffer))
.then((s) =>
s.resize(
s
.resize(800, null, {
fit: "inside",
withoutEnlargement: true,
})
.jpeg({
quality: 80,
progressive: true,
})
.toBuffer()
)
);
const image = await agent.uploadBlob(buffer, { encoding: "image/jpeg" });
let post = {
$type: "app.bsky.feed.post",
text: item.title,
createdAt: new Date().toISOString()
};
post["embed"] = {
external: {
uri: `${item.link}?CMP=aus_bsky`,
title: item.title,
description: item.description,
thumb: image.data.blob,
},
$type: "app.bsky.embed.external",
};
const res = AppBskyFeedPost.validateRecord(post);
if (res.success) {
agent.post(post);
} else {
console.log(res.error);
}
}
// ### This is the actual funciton doing everything
async function do_everything(feeds){
let list_of_stories = []
let already_posted = []
let cursor = "";
// ### Login and validate
const agent = new BskyAgent({ service: "https://bsky.social" });
await agent.login({
identifier: accounty,
password: passy,
});
// ### Grab the already posted stories
await agent.getAuthorFeed({
actor: accounty,
limit: 5,
cursor: cursor,
}).then(response =>
{
cursor = response.cursor
let latest = response.data.feed.map(d => d.post.indexedAt)
console.log(new Date(Math.max.apply(null, latest.map(function(e) {
return new Date(e);
}))))
console.log(new Date())
for (const feed of response.data.feed) {
already_posted.push(feed.post.record.embed.external.uri)
}
}
// ).then(() => console.log("already_posted: ", already_posted)
)
// ### This first grabs the stories
Promise.all(feeds.map(url => parser.parseURL(url)
.then(response =>
{
for (const item of response.items)
{
// let inter_description = null;
// const description_ = dom('head > meta[property="og:description"]');
// if (description_) {
// inter_description = description_.attr("content");
// }
// ### Check to see if it has already been posted
if (!already_posted.includes(item.link + '?CMP=aus_bsky')){
list_of_stories.push({
title: item.title,
link: item.link,
description: item.contentSnippet
})
}
}
})
))
.then(() => {
console.log(list_of_stories.length)
final(agent, list_of_stories)
})
}
const final = async (agent, listicle) => {
for await (const story of listicle) {
post(agent, story);
//await timer(2000)
//console.log(story)
}
}
do_everything(rss_feeds)