From d6902f47623b12b7cd54c985f26b14e5e44d3001 Mon Sep 17 00:00:00 2001 From: CatAClock Date: Sun, 11 May 2025 10:06:29 -0700 Subject: [PATCH] boosting and liking are good for Mastodon. Bluesky doesn't allow for undoing it yet --- JS/BlueskyAPI.js | 66 +++++++++++++++++++++++++++++++++++++++++++++++ JS/MastodonAPI.js | 30 +++++++++++++++++++++ JS/expanded.js | 51 +++++++++++++++++++++++++++++++++--- 3 files changed, 144 insertions(+), 3 deletions(-) diff --git a/JS/BlueskyAPI.js b/JS/BlueskyAPI.js index 91d5f07..3f4f380 100644 --- a/JS/BlueskyAPI.js +++ b/JS/BlueskyAPI.js @@ -141,6 +141,72 @@ export async function CreateReplyPost(DID, Text, ReplyID, RootID) { return body; } +export async function SendLike(DID, RefURI, RefCID) { + if (localStorage.getItem(Variables.BlueskyAccessToken) == null) { + console.log("No access token!"); + return ""; + } + let StrongRef = { + "$type": "com.atproto.repo.strongRef", + "uri": RefURI, + "cid": RefCID + } + let PDS = localStorage.getItem(Variables.BlueskyPDS); + let Json = { + "$type": "app.bsky.feed.like", + "subject": StrongRef, + "createdAt": new Date(Date.now()).toISOString() + } + let RequestBody = { + "repo": DID, + "collection": "app.bsky.feed.like", + "record": Json + } + let DPoP = await ClientDPoPPDS("POST", PDS + "/xrpc/com.atproto.repo.createRecord"); + let request = fetch(PDS + "/xrpc/com.atproto.repo.createRecord", { body: JSON.stringify(RequestBody), method: "POST", headers: {"Content-Type": "application/json", "Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}}); + let body = await request.then((response) => response.json()); + let status = await request.then((response) => response.status); + let header = await request.then((response) => response.headers.get("dpop-nonce")); + if (status == 401) { + await HandleError(body, header); + body = await CreatePost(DID, Text); + } + return body; +} + +export async function SendRepost(DID, RefURI, RefCID) { + if (localStorage.getItem(Variables.BlueskyAccessToken) == null) { + console.log("No access token!"); + return ""; + } + let StrongRef = { + "$type": "com.atproto.repo.strongRef", + "uri": RefURI, + "cid": RefCID + } + let PDS = localStorage.getItem(Variables.BlueskyPDS); + let Json = { + "$type": "app.bsky.feed.repost", + "subject": StrongRef, + "createdAt": new Date(Date.now()).toISOString() + } + let RequestBody = { + "repo": DID, + "collection": "app.bsky.feed.repost", + "record": Json + } + let DPoP = await ClientDPoPPDS("POST", PDS + "/xrpc/com.atproto.repo.createRecord"); + let request = fetch(PDS + "/xrpc/com.atproto.repo.createRecord", { body: JSON.stringify(RequestBody), method: "POST", headers: {"Content-Type": "application/json", "Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}}); + let body = await request.then((response) => response.json()); + let status = await request.then((response) => response.status); + let header = await request.then((response) => response.headers.get("dpop-nonce")); + if (status == 401) { + await HandleError(body, header); + body = await CreatePost(DID, Text); + } + return body; +} + export async function SetThreadGate(DID, Post, VisibilitySettings) { if (localStorage.getItem(Variables.BlueskyAccessToken) == null) { console.log("No access token!"); diff --git a/JS/MastodonAPI.js b/JS/MastodonAPI.js index 40397ad..6ce89e1 100644 --- a/JS/MastodonAPI.js +++ b/JS/MastodonAPI.js @@ -134,6 +134,36 @@ export async function CreateReplyStatus(Text, Visibility = "public", ReplyID) { return body; } +export async function SendFavorite(ID, IsFavorited) { + if (localStorage.getItem(Variables.MastodonAccessToken) == null) { + console.log("No access token!"); + return ""; + } + let Website = localStorage.getItem(Variables.MastodonWebsite); + if (IsFavorited == false) { + return await fetch(Website + "/api/v1/statuses/" + ID + "/favourite", {method: "POST", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}}) + .then((response) => response.json()); + } else { + return await fetch(Website + "/api/v1/statuses/" + ID + "/unfavourite", {method: "POST", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}}) + .then((response) => response.json()); + } +} + +export async function SendReblog(ID, IsReblogged) { + if (localStorage.getItem(Variables.MastodonAccessToken) == null) { + console.log("No access token!"); + return ""; + } + let Website = localStorage.getItem(Variables.MastodonWebsite); + if (IsReblogged == false) { + return await fetch(Website + "/api/v1/statuses/" + ID + "/reblog", {method: "POST", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}}) + .then((response) => response.json()); + } else { + return await fetch(Website + "/api/v1/statuses/" + ID + "/unreblog", {method: "POST", headers: {"Authorization": localStorage.getItem(Variables.MastodonTokenType) + " " + localStorage.getItem(Variables.MastodonAccessToken)}}) + .then((response) => response.json()); + } +} + // The first step to using the app. export async function HandleAuthentication(Website) { // See if the user is smart enough to put https. diff --git a/JS/expanded.js b/JS/expanded.js index 108bb79..f20e352 100644 --- a/JS/expanded.js +++ b/JS/expanded.js @@ -8,6 +8,9 @@ let Favorite = document.getElementsByClassName("Favorite")[0]; let Boost = document.getElementsByClassName("Boost")[0]; let Reply = document.getElementsByClassName("Reply")[0]; +let FavoriteFlipper = false; +let BoostFlipper = false; + // Variables let website = document.location.href.split("website=")[1]; let post = JSON.parse(localStorage.getItem("post")); @@ -17,11 +20,21 @@ GetPost(); // Button stuff Favorite.onclick = (event) => { - + if (website == "Mastodon") { + MastodonAPI.SendFavorite(post.id, post.favourited); + } else if (website == "Bluesky") { + BlueskyAPI.SendLike(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid); + } + SetFavorite(); } Boost.onclick = (event) => { - + if (website == "Mastodon") { + MastodonAPI.SendReblog(post.id, post.reblogged); + } else if (website == "Bluesky") { + BlueskyAPI.SendRepost(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid); + } + SetBoost(); } Reply.onclick = (event) => { @@ -30,7 +43,6 @@ Reply.onclick = (event) => { // Functions and things. async function GetPost() { - console.log(post); if (website == "Mastodon") { // Check for a reblog. if (post.reblog != null) { @@ -46,6 +58,13 @@ async function GetPost() { document.getElementsByClassName("Images")[0].innerHTML = document.getElementsByClassName("Images")[0].innerHTML + "" + i.description + ""; } } + // Update the post to see if there is new information. + post = await MastodonAPI.GetStatus(post.id); + // Set the texts. + FavoriteFlipper = !(post.favourite); + BoostFlipper = !(post.reblogged); + SetFavorite(); + SetBoost(); } else if (website == "Bluesky") { // Check for a reblog. if (post.hasOwnProperty("reason") && post.reason.$type == "app.bsky.feed.defs#reasonRepost") { @@ -61,7 +80,33 @@ async function GetPost() { document.getElementsByClassName("Images")[0].innerHTML = document.getElementsByClassName("Images")[0].innerHTML + "" + i.alt + ""; } } + // Update the post to see if there is new information. + post = await BlueskyAPI.GetPosts(post.post.uri); + post = { + "post": post.posts[0] + } + console.log(post); + // Set the texts. + // TODO! } else { document.getElementsByClassName("PostText")[0].innerHTML = "Nothing to load."; } } + +function SetFavorite() { + if (FavoriteFlipper == false) { + Favorite.innerHTML = "Favorite!"; + } else { + Favorite.innerHTML = "Unfavorite..."; + } + FavoriteFlipper = !(FavoriteFlipper); +} + +function SetBoost() { + if (BoostFlipper == false) { + Boost.innerHTML = "Boost!"; + } else { + Boost.innerHTML = "Unboost..."; + } + BoostFlipper = !(BoostFlipper); +}