Add subscribe to RSS button to Ao3 works

This commit is contained in:
2023-10-25 00:45:06 +02:00
commit 3629a07e1b

130
ao3-subscribe.user.js Normal file
View File

@@ -0,0 +1,130 @@
// ==UserScript==
// @name ao3 subscribe to feed
// @version 1
// @require http://crypto.stanford.edu/sjcl/sjcl.js
// @grant GM.getValue
// @grant GM.setValue
// @include https://archiveofourown.org/works/*
// ==/UserScript==
// User script for Firefox
// Password management
async function decodeOrPrompt(targVar, userPrompt, setValVarName, encKey) {
if (targVar) {
targVar = unStoreAndDecrypt(targVar, encKey);
}
else {
targVar = prompt(
userPrompt + ' not set for ' + location.hostname + '. Please enter it now:',
''
);
await GM.setValue(setValVarName, encryptAndStore(targVar, encKey));
}
return targVar;
}
function encryptAndStore(clearText, encKey) {
return JSON.stringify(sjcl.encrypt(encKey, clearText));
}
function unStoreAndDecrypt(jsonObj, encKey) {
return sjcl.decrypt(encKey, JSON.parse(jsonObj));
}
async function getCredentials() {
var encKey = await GM.getValue("encKey", "");
var usr = await GM.getValue("ttrssUser", "");
var pword = await GM.getValue("ttrssPass", "");
if (!encKey) {
encKey = prompt(
'Script key not set for ' + location.hostname + '. Please enter a random string:',
''
);
await GM.setValue("encKey", encKey);
usr = pword = ""; // New key makes prev stored values (if any) unable to decode.
}
usr = await decodeOrPrompt(usr, "TTRSS user", "ttrssUser", encKey);
pword = await decodeOrPrompt(pword, "TTRSS password", "ttrssPass", encKey);
return { usr: usr, pword: pword };
}
// Function to add a button to the <ul> element
function addSubscriptionButton() {
const ulElement = document.querySelector("ul.work");
if (ulElement) {
const newLi = document.createElement("li");
const button = document.createElement("button");
button.textContent = "Subscribe to RSS";
button.onclick = async function () {
// Extract work_id from the URL
const workIdMatch = window.location.href.match(/works\/(\d+)/);
if (workIdMatch) {
const workId = workIdMatch[1];
const rssURL = `https://nas.franpenedo.com/rss-bridge/?action=display&bridge=AO3Bridge&context=Work&id=${workId}&format=atom`;
// Call the login method to get a session ID
try {
const sessionID = await loginToTinyTinyRSS();
// Subscribe to the RSS feed using the session ID
try {
await subscribeToFeed(rssURL, sessionID);
alert("Subscribed successfully!");
} catch (error) {
alert("Error subscribing to feed: " + error);
}
} catch (error) {
alert("Error logging in: " + error);
}
} else {
alert("Unable to extract work_id from the URL.");
}
};
newLi.appendChild(button);
ulElement.appendChild(newLi);
}
}
// Function to simulate a login to Tiny Tiny RSS
async function loginToTinyTinyRSS() {
const creds = await getCredentials();
const loginResponse = await fetch("https://news.nas.franpenedo.com/api/", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: JSON.stringify({ op: "login", user: creds.usr, password: creds.pword }),
});
const data = await loginResponse.json();
if (data.content.hasOwnProperty("session_id")) {
return data.content.session_id;
} else {
console.log(data);
throw new Error("Login failed");
}
}
// Function to subscribe to an RSS feed in Tiny Tiny RSS
async function subscribeToFeed(feedURL, sessionID) {
const subscribeResponse = await fetch("https://news.nas.franpenedo.com/api/", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: JSON.stringify({ op: "subscribeToFeed", feed_url: feedURL, category_id: 11, sid: sessionID }),
});
const subscribeData = await subscribeResponse.json();
if (subscribeData.content.status.code !== 1) {
console.log(subscribeData);
throw new Error("Subscription failed");
}
}
// Call the function to add the button
addSubscriptionButton();