Skip to content

Instantly share code, notes, and snippets.

@spaghetti-source
Created November 29, 2023 19:24
Show Gist options
  • Save spaghetti-source/985fa3949c808a4ca16777e0dfcf0978 to your computer and use it in GitHub Desktop.
Save spaghetti-source/985fa3949c808a4ca16777e0dfcf0978 to your computer and use it in GitHub Desktop.
const {BskyAgent, RichText, AppBskyFeedPost} = require("@atproto/api")
let Parser = require('rss-parser')
let parser = new Parser()
const entities = require("entities");
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
const settings = [
{
account: "arxiv-stat-ml.bsky.social",
password: "xxxx-xxxx-xxxx-xxxx",
url: "https://export.arxiv.org/rss/stat.ML",
endsWith: "[stat.ML])"
},
{
account: "arxiv-stat-me.bsky.social",
password: "xxxx-xxxx-xxxx-xxxx",
url: "https://export.arxiv.org/rss/stat.ME",
endsWith: "[stat.ME])"
},
{
account: "arxiv-math-ac.bsky.social",
password: "xxxx-xxxx-xxxx-xxxx",
url: "https://export.arxiv.org/rss/math.AC",
endsWith: "[math.AC])"
},
// ... omit
]
async function get_feeds(url, endsWith) {
const feed = await parser.parseURL(url);
let output = [];
for (const item of feed.items) {
if (item.title.endsWith(endsWith)) {
const raw_authors = item.creator.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "")
const authors = entities.decodeHTML(raw_authors.trim())
// const author_list = decode(raw_authors).trim().split(",")
// if (author_list.length >= 8) {
// authors = author_list[0] + " et.al."
// } else {
// authors = author_list.join(",")
// }
output.push({
authors: authors,
title: item.title,
link: item.link
});
}
}
return output;
}
async function post(agent, item, execute=true) {
const content_length = item.link.length + item.title.length;
let authors = item.authors;
console.log(authors.length);
console.log(content_length);
if (authors.length + content_length > 300) {
authors = authors.slice(0, 300 - content_length - 5) + "..."
console.log("[INFO] truncate");
}
rt = new RichText({text: authors + "\n" + item.title + "\n" + item.link});
await rt.detectFacets(agent)
const post = {
$type: 'app.bsky.feed.post',
text: rt.text,
facets: rt.facets,
createdAt: new Date().toISOString()
}
const res = AppBskyFeedPost.validateRecord(post)
if (res.success) {
console.log(post)
if (execute) {
await agent.post(post);
await sleep(10000);
}
} else {
console.log(res.error)
}
}
async function main(setting, execute=true) {
console.log(setting.account)
const agent = new BskyAgent({ service: "https://bsky.social" });
await agent.login({
identifier: setting.account,
password: setting.password,
});
let processed = new Set();
let cursor = "";
for (let i = 0; i < 3; ++i) {
const response = await agent.getAuthorFeed({
actor: setting.account,
limit: 100,
cursor: cursor,
});
cursor = response.cursor;
for (const feed of response.data.feed) {
const lines = feed.post.record.text.split("\n");
processed.add(lines[1]);
processed.add(lines[2]);
}
}
for (const feed of await get_feeds(setting.url, setting.endsWith)) {
console.log(feed);
if (!processed.has(feed.title) && !processed.has(feed.link)) {
console.log("post " + feed.title);
await post(agent, feed, execute);
} else {
console.log("skipped " + feed.title);
}
}
}
/*
async function entrypoint() {
for (const setting of settings) {
await main(setting, false);
}
}
entrypoint()
*/
const functions = require('@google-cloud/functions-framework');
functions.http('entrypoint', async (req, res) => {
for (const setting of settings) {
console.log("process " + setting.url);
await main(setting);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment