diff --git a/JS/BlueskyAPI.js b/JS/BlueskyAPI.js
index da94bff..4b5716a 100644
--- a/JS/BlueskyAPI.js
+++ b/JS/BlueskyAPI.js
@@ -1,5 +1,8 @@
import * as Variables from "./Variables.js";
+
+// Getters
+// This gets the timeline. The cursor is a time in Z form.
export async function GetTimeline(Cursor) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
@@ -26,6 +29,7 @@ export async function GetTimeline(Cursor) {
return body;
}
+// This gets the post. If there are multiple URIs, they must be within an array.
export async function GetPosts(URIs) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
@@ -52,6 +56,27 @@ export async function GetBlob(DID, CID) {
return body;
}
+// Gets a record. The repo is the account DID, the collection is the type of record, and the key is the little bit at the end.
+export async function GetRecord(Repo, Collection, RKey) {
+ let RequestBody = {
+ "repo": Repo,
+ "collection": Collection,
+ "rkey": RKey
+ }
+ let DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/com.atproto.repo.getRecord?repo=" + Repo + "&collection=" + Collection + "&rkey=" + RKey);
+ let request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/com.atproto.repo.getRecord?repo=" + Repo + "&collection=" + Collection + "&rkey=" + RKey, { method: "GET", 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 DeleteRecord(Repo, Collection, RKey);
+ }
+ return body;
+}
+
+// Creators
+// This creates a post. Requires the DID of the account and the Text for the record.
export async function CreatePost(DID, Text) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
@@ -72,6 +97,7 @@ export async function CreatePost(DID, Text) {
return body;
}
+// Creates a reply post. The RootID is always the first post, the ReplyID is the post you are replying to.
export async function CreateReplyPost(DID, Text, ReplyID, RootID) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
@@ -102,7 +128,8 @@ export async function CreateReplyPost(DID, Text, ReplyID, RootID) {
return body;
}
-export async function SetThreadGate(DID, Post, VisibilitySettings) {
+// Creates a Thread Gate for who can reply. Requires the account DID, a post, and a list of who is allowed.
+export async function CreateThreadGate(DID, Post, VisibilitySettings) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
return "";
@@ -117,7 +144,8 @@ export async function SetThreadGate(DID, Post, VisibilitySettings) {
return body;
}
-export async function SendLike(DID, RefURI, RefCID) {
+// Create a like and send it to the server.
+export async function CreateLike(DID, RefURI, RefCID) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
return "";
@@ -142,7 +170,8 @@ export async function SendLike(DID, RefURI, RefCID) {
return body;
}
-export async function SendRepost(DID, RefURI, RefCID) {
+// Create a repost and send it to the server.
+export async function CreateRepost(DID, RefURI, RefCID) {
if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
console.log("No access token!");
return "";
@@ -167,24 +196,7 @@ export async function SendRepost(DID, RefURI, RefCID) {
return body;
}
-export async function GetRecord(Repo, Collection, RKey) {
- let RequestBody = {
- "repo": Repo,
- "collection": Collection,
- "rkey": RKey
- }
- let DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/com.atproto.repo.getRecord?repo=" + Repo + "&collection=" + Collection + "&rkey=" + RKey);
- let request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/com.atproto.repo.getRecord?repo=" + Repo + "&collection=" + Collection + "&rkey=" + RKey, { method: "GET", 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 DeleteRecord(Repo, Collection, RKey);
- }
- return body;
-}
-
+// Creates a record. Universal way of making things.
export async function CreateRecord(Repo, Collection, Record, RKey) {
let RequestBody = {
"repo": Repo,
@@ -206,6 +218,8 @@ export async function CreateRecord(Repo, Collection, Record, RKey) {
return body;
}
+// Deleters
+// Removes a record. Can be a like, a repost, a post, etc.
export async function DeleteRecord(Repo, Collection, RKey) {
let RequestBody = {
"repo": Repo,
@@ -224,6 +238,7 @@ export async function DeleteRecord(Repo, Collection, RKey) {
return body;
}
+// Things to get this to work.
// Component 1/4
export async function GetPDSWellKnown() {
return await fetch("https://bsky.social/.well-known/oauth-authorization-server", {method: "GET"})
diff --git a/JS/MastodonAPI.js b/JS/MastodonAPI.js
index 4950e41..a136993 100644
--- a/JS/MastodonAPI.js
+++ b/JS/MastodonAPI.js
@@ -2,6 +2,7 @@ import * as Variables from "./Variables.js";
export const Scopes = "read write follow push";
+// Getters
// Gets the public timeline.
export async function GetPublicTimeline(Local = false, Remote = false, Website) {
// Variables can be found in `setting.js`
@@ -77,6 +78,7 @@ export async function GetNotifications() {
.then((response) => response.json());
}
+// A status is just a post. It gets it.
export async function GetStatus(ID) {
if (localStorage.getItem(Variables.MastodonAccessToken) == null) {
console.log("No access token!");
@@ -88,6 +90,7 @@ export async function GetStatus(ID) {
.then((response) => response.json());
}
+// Creators
// Make a status
export async function CreateStatus(Text, Visibility = "public") {
if (localStorage.getItem(Variables.MastodonAccessToken) == null) {
@@ -133,7 +136,7 @@ export async function CreateReplyStatus(Text, Visibility = "public", ReplyID) {
return body;
}
-export async function SendFavorite(ID, IsFavorited) {
+export async function CreateFavorite(ID, IsFavorited) {
if (localStorage.getItem(Variables.MastodonAccessToken) == null) {
console.log("No access token!");
return "";
@@ -148,7 +151,7 @@ export async function SendFavorite(ID, IsFavorited) {
}
}
-export async function SendReblog(ID, IsReblogged) {
+export async function CreateReblog(ID, IsReblogged) {
if (localStorage.getItem(Variables.MastodonAccessToken) == null) {
console.log("No access token!");
return "";
@@ -163,6 +166,7 @@ export async function SendReblog(ID, IsReblogged) {
}
}
+// Things to make this work
// 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 3423ec1..7544d1a 100644
--- a/JS/expanded.js
+++ b/JS/expanded.js
@@ -21,18 +21,18 @@ GetPost();
// Button stuff
Favorite.onclick = (event) => {
if (website == "Mastodon") {
- MastodonAPI.SendFavorite(post.id, post.favourited);
+ MastodonAPI.CreateFavorite(post.id, post.favourited);
} else if (website == "Bluesky") {
- BlueskyAPI.SendLike(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
+ BlueskyAPI.CreateLike(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
}
SetFavorite();
}
Boost.onclick = (event) => {
if (website == "Mastodon") {
- MastodonAPI.SendReblog(post.id, post.reblogged);
+ MastodonAPI.CreateReblog(post.id, post.reblogged);
} else if (website == "Bluesky") {
- BlueskyAPI.SendRepost(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
+ BlueskyAPI.CreateRepost(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
}
SetBoost();
}
@@ -50,7 +50,7 @@ async function GetPost() {
document.getElementsByClassName("Handle Regular")[0].innerHTML = post.reblog.account.username + " ( R: " + post.account.username + " )";
if (post.reblog.media_attachments.length != 0) {
for (let i of post.reblog.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images Regular")[0]);
+ await ApplyMedia(i, document.getElementsByClassName("Images Regular")[0]);
}
}
} else {
@@ -59,7 +59,7 @@ async function GetPost() {
// Show the image if it exists.
if (post.media_attachments.length != 0) {
for (let i of post.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images Regular")[0]);
+ await ApplyMedia(i, document.getElementsByClassName("Images Regular")[0]);
}
}
}
@@ -72,38 +72,22 @@ async function GetPost() {
if (post.in_reply_to_id != null) {
var AnotherPost = await MastodonAPI.GetStatus(post.in_reply_to_id);
document.getElementsByClassName("Origin Parent")[0].innerHTML = website;
- if (AnotherPost.reblog != null) {
- document.getElementsByClassName("PostText Parent")[0].innerHTML = AnotherPost.reblog.content;
- if (AnotherPost.reblog.media_attachments.length != 0) {
- for (let i of AnotherPost.reblog.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images Parent")[0]);
- }
- }
- } else {
- document.getElementsByClassName("PostText Parent")[0].innerHTML = AnotherPost.content;
- if (AnotherPost.media_attachments.length != 0) {
- for (let i of AnotherPost.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images Parent")[0]);
- }
+ document.getElementsByClassName("Handle Parent")[0].innerHTML = AnotherPost.account.username;
+ document.getElementsByClassName("PostText Parent")[0].innerHTML = AnotherPost.content;
+ if (AnotherPost.media_attachments.length != 0) {
+ for (let i of AnotherPost.media_attachments) {
+ await ApplyMedia(i, document.getElementsByClassName("Images Parent")[0]);
}
}
// Now time to see if there are any grandparents
if (AnotherPost.in_reply_to_id != null) {
var AnotherAnotherPost = await MastodonAPI.GetStatus(AnotherPost.in_reply_to_id);
document.getElementsByClassName("Origin GrandParent")[0].innerHTML = website;
- if (AnotherAnotherPost.reblog != null) {
- document.getElementsByClassName("PostText GrandParent")[0].innerHTML = AnotherAnotherPost.reblog.content;
- if (AnotherAnotherPost.reblog.media_attachments.length != 0) {
- for (let i of AnotherAnotherPost.reblog.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images GrandParent")[0]);
- }
- }
- } else {
- document.getElementsByClassName("PostText GrandParent")[0].innerHTML = AnotherAnotherPost.content;
- if (AnotherAnotherPost.media_attachments.length != 0) {
- for (let i of AnotherAnotherPost.media_attachments) {
- await CreateMedia(i, document.getElementsByClassName("Images GrandParent")[0]);
- }
+ document.getElementsByClassName("Handle GrandParent")[0].innerHTML = AnotherAnotherPost.account.username;
+ document.getElementsByClassName("PostText GrandParent")[0].innerHTML = AnotherAnotherPost.content;
+ if (AnotherAnotherPost.media_attachments.length != 0) {
+ for (let i of AnotherAnotherPost.media_attachments) {
+ await ApplyMedia(i, document.getElementsByClassName("Images GrandParent")[0]);
}
}
}
@@ -116,27 +100,13 @@ async function GetPost() {
document.getElementsByClassName("Handle Regular")[0].innerHTML = post.post.author.handle;
}
// Text. This will be modified later.
- var Text = post.post.record.text;
- // Check for facets. Facets are things that change what the text does or looks like.
- if (post.post.record.hasOwnProperty("facets")) {
- for (let i of post.post.record.facets) {
- if (i.features[0].$type == "app.bsky.richtext.facet#link") {
- var EmojiRegex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;
- var EmojiObjects = Text.match(EmojiRegex);
- var SubtractNumber = 0;
- if (EmojiObjects != null) {
- SubtractNumber = EmojiObjects.length * 2;
- }
- Text = Text.substring(0, i.index.byteStart - SubtractNumber) + "" + Text.substring(i.index.byteStart - SubtractNumber, i.index.byteEnd - SubtractNumber) + "" + Text.substring(i.index.byteEnd - SubtractNumber, Text.length - 1);
- }
- }
- }
+ var Text = ApplyFacets(post.post.record, post.post.record.text);
// Place the text.
Text = Text.replace(/\r?\n|\r/g, "
");
document.getElementsByClassName("PostText Regular")[0].innerHTML = Text;
// Show the image if it exists.
if (post.post.record.hasOwnProperty("embed")) {
- await CreateMedia(post.post.record, document.getElementsByClassName("Images Regular")[0], post.post.author.did);
+ await ApplyMedia(post.post.record, document.getElementsByClassName("Images Regular")[0], post.post.author.did);
}
// We don't need to update the post with new information. The repos are seperate.
// Set the texts. It's opposite because "setting" causes it to switch.
@@ -155,11 +125,11 @@ async function GetPost() {
var AnotherPost = await BlueskyAPI.GetRecord(post.reply.parent.uri.split("/")[2], post.reply.parent.uri.split("/")[3], post.reply.parent.uri.split("/")[4]);
document.getElementsByClassName("Origin Parent")[0].innerHTML = website;
document.getElementsByClassName("Handle Parent")[0].innerHTML = post.reply.parent.author.handle;
- Text = AnotherPost.value.text;
+ Text = ApplyFacets(AnotherPost.value, AnotherPost.value.text);
Text = Text.replace(/\r?\n|\r/g, "
");
document.getElementsByClassName("PostText Parent")[0].innerHTML = Text;
if (AnotherPost.value.hasOwnProperty("embed")) {
- await CreateMedia(AnotherPost.value, document.getElementsByClassName("Images Parent")[0], post.reply.parent.author.did);
+ await ApplyMedia(AnotherPost.value, document.getElementsByClassName("Images Parent")[0], post.reply.parent.author.did);
}
// Now time to see if there are any grandparents.
@@ -167,11 +137,11 @@ async function GetPost() {
var AnotherAnotherPost = await BlueskyAPI.GetRecord(AnotherPost.value.reply.parent.uri.split("/")[2], AnotherPost.value.reply.parent.uri.split("/")[3], AnotherPost.value.reply.parent.uri.split("/")[4]);
document.getElementsByClassName("Origin GrandParent")[0].innerHTML = website;
document.getElementsByClassName("Handle GrandParent")[0].innerHTML = post.reply.grandparentAuthor.handle;
- Text = AnotherAnotherPost.value.text;
+ Text = ApplyFacets(AnotherAnotherPost.value, AnotherAnotherPost.value.text);
Text = Text.replace(/\r?\n|\r/g, "
");
document.getElementsByClassName("PostText GrandParent")[0].innerHTML = Text;
if (AnotherAnotherPost.value.hasOwnProperty("embed")) {
- await CreateMedia(AnotherAnotherPost.value, document.getElementsByClassName("Images GrandParent")[0], post.reply.grandparentAuthor.did);
+ await ApplyMedia(AnotherAnotherPost.value, document.getElementsByClassName("Images GrandParent")[0], post.reply.grandparentAuthor.did);
}
}
}
@@ -180,7 +150,9 @@ async function GetPost() {
}
}
-async function CreateMedia(Media, Element, Author = undefined) {
+// Applyers. Essentially applies a thing to an operation.
+// Finds any associated media and applies it to the post.
+async function ApplyMedia(Media, Element, Author = undefined) {
// Check to see if the image is on the same server.
if (website == "Mastodon") {
if (Media.type == "image") {
@@ -199,8 +171,9 @@ async function CreateMedia(Media, Element, Author = undefined) {
} else if (website == "Bluesky") {
if (Media.embed.$type == "app.bsky.embed.record") {
var Texty = await BlueskyAPI.GetPosts([Media.embed.record.uri]);
- console.log(Texty);
- Element.innerHTML += "
" + Texty.posts[0].record.text + "
" + Text + "