312 lines
12 KiB
JavaScript
312 lines
12 KiB
JavaScript
import * as MastodonAPI from "/JS/MastodonAPI.js";
|
|
import * as BlueskyAPI from "/JS/BlueskyAPI.js";
|
|
import * as TumblrAPI from "/JS/TumblrAPI.js";
|
|
import * as Variables from "/JS/Variables.js";
|
|
|
|
// Buttons
|
|
let Favorite = document.getElementsByClassName("Favorite")[0];
|
|
let Boost = document.getElementsByClassName("Boost")[0];
|
|
let Reply = document.getElementsByClassName("Reply")[0];
|
|
|
|
let FavoriteFlipper = false;
|
|
let BoostFlipper = false;
|
|
let Favoritable = false;
|
|
let Boostable = false;
|
|
|
|
// Variables
|
|
let website = document.location.href.split("website=")[1];
|
|
let post = JSON.parse(localStorage.getItem("post"));
|
|
let ThreadedPost = [];
|
|
|
|
document.getElementsByClassName("Origin")[0].innerHTML = website;
|
|
GetPost();
|
|
|
|
// Fixes a bug where the interpreter sucks ass.
|
|
let EmbedCounter = 0;
|
|
|
|
// Button stuff
|
|
Favorite.onclick = (event) => {
|
|
if (Favoritable == false) {
|
|
return;
|
|
}
|
|
Favoritee();
|
|
}
|
|
|
|
async function Favoritee() {
|
|
Favoritable = false;
|
|
if (website == "Mastodon") {
|
|
await MastodonAPI.CreateFavorite(post.id, post.favourited);
|
|
} else if (website == "Bluesky") {
|
|
await BlueskyAPI.CreateLike(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
|
|
}
|
|
SetFavorite();
|
|
}
|
|
|
|
Boost.onclick = (event) => {
|
|
if (Boostable == false) {
|
|
return;
|
|
}
|
|
Boostee();
|
|
}
|
|
|
|
async function Boostee() {
|
|
Boostable = false;
|
|
if (website == "Mastodon") {
|
|
await MastodonAPI.CreateReblog(post.id, post.reblogged);
|
|
} else if (website == "Bluesky") {
|
|
await BlueskyAPI.CreateRepost(localStorage.getItem(Variables.BlueskyDID), post.post.uri, post.post.cid);
|
|
}
|
|
SetBoost();
|
|
}
|
|
|
|
Reply.onclick = (event) => {
|
|
window.location.href = "/post?website=" + website;
|
|
}
|
|
|
|
// Other post stuff.
|
|
for (let i of document.getElementsByClassName("Regular")) {
|
|
i.onclick = (event) => {
|
|
if (i.classList.contains("Handle")) {
|
|
window.location.href = "/account?website=" + website;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Threads are the thing above the post you clicked.
|
|
async function SetThreadPost(element, i) {
|
|
if (website == "Mastodon") {
|
|
localStorage.setItem("post", JSON.stringify(element));
|
|
} else if (website == "Bluesky") {
|
|
let Temp = await BlueskyAPI.GetPosts(element.uri);
|
|
element.post = Temp.posts[0];
|
|
localStorage.setItem("post", JSON.stringify(element));
|
|
}
|
|
if (i.classList.contains("Handle")) {
|
|
window.location.href = "/account?website=" + website;
|
|
} else {
|
|
window.location.href = "/expanded?website=" + website;
|
|
}
|
|
}
|
|
|
|
// Functions and things.
|
|
async function GetPost() {
|
|
if (website == "Mastodon") {
|
|
document.getElementsByClassName("Handle")[0].innerHTML = post.account.acct;
|
|
// Check for a reblog.
|
|
if (post.reblog != null) {
|
|
document.getElementsByClassName("Handle")[0].innerHTML += " ( R: " + post.reblog + " )";
|
|
}
|
|
document.getElementsByClassName("PostText")[0].innerHTML = post.content;
|
|
// Set the texts. It's opposite because "setting" causes it to switch.
|
|
post = await MastodonAPI.GetStatus(post.id);
|
|
FavoriteFlipper = !(post.favourited);
|
|
BoostFlipper = !(post.reblogged);
|
|
SetFavorite();
|
|
SetBoost();
|
|
// Show the image if it exists.
|
|
if (post.media_attachments.length != 0) {
|
|
for (let i of post.media_attachments) {
|
|
ApplyMedia(i, document.getElementsByClassName("Images")[0]);
|
|
}
|
|
}
|
|
// Now time to see if there are any parents.
|
|
let NumberOfThreads = 0;
|
|
let TemporaryPost = post;
|
|
while (TemporaryPost.in_reply_to_id != null) {
|
|
TemporaryPost = await MastodonReplylFunction(NumberOfThreads, TemporaryPost.in_reply_to_id);
|
|
ThreadedPost.push(TemporaryPost);
|
|
// Any replies? Give them the thing :3
|
|
for (let i of document.getElementsByClassName(NumberOfThreads)) {
|
|
let TempID = NumberOfThreads;
|
|
i.onclick = (event) => {
|
|
SetThreadPost(ThreadedPost[TempID], i);
|
|
}
|
|
}
|
|
NumberOfThreads += 1;
|
|
}
|
|
} else if (website == "Bluesky") {
|
|
// Check for a reblog.
|
|
if (post.hasOwnProperty("reason") && post.reason.$type == "app.bsky.feed.defs#reasonRepost") {
|
|
document.getElementsByClassName("Handle")[0].innerHTML = post.post.author.handle + " ( R: " + post.reason.by.handle + " )";
|
|
} else {
|
|
document.getElementsByClassName("Handle")[0].innerHTML = post.post.author.handle;
|
|
}
|
|
// Text. This will be modified later.
|
|
var Text = await BlueskyAPI.ApplyFacets(post.post.record, post.post.record.text);
|
|
// Place the text.
|
|
Text = Text.replace(/\r?\n|\r/g, "<br/>");
|
|
document.getElementsByClassName("PostText")[0].innerHTML = Text;
|
|
// Show the image if it exists.
|
|
if (post.post.record.hasOwnProperty("embed")) {
|
|
ApplyMedia(post.post.record.embed, document.getElementsByClassName("Images")[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.
|
|
let GetRepo = await BlueskyAPI.GetRecord(localStorage.getItem(Variables.BlueskyDID), "app.bsky.feed.like", post.post.uri.split("/")[post.post.uri.split("/").length - 1]);
|
|
if (GetRepo.hasOwnProperty("error") && GetRepo.error == "RecordNotFound") {
|
|
FavoriteFlipper = true;
|
|
}
|
|
GetRepo = await BlueskyAPI.GetRecord(localStorage.getItem(Variables.BlueskyDID), "app.bsky.feed.repost", post.post.uri.split("/")[post.post.uri.split("/").length - 1]);
|
|
if (GetRepo.hasOwnProperty("error") && GetRepo.error == "RecordNotFound") {
|
|
BoostFlipper = true;
|
|
}
|
|
SetFavorite();
|
|
SetBoost();
|
|
// Now time to see if there are any parents.
|
|
let NumberOfThreads = 0;
|
|
let TemporaryPost = post;
|
|
while (TemporaryPost.reply.parent != null) {
|
|
TemporaryPost = await BlueskyReplyFunction("0", TemporaryPost.reply.parent, TemporaryPost.reply.parent.author).posts[0];
|
|
ThreadedPost.push(TemporaryPost);
|
|
// Any replies? Give them the thing :3
|
|
for (let i of document.getElementsByClassName(NumberOfThreads)) {
|
|
let TempID = NumberOfThreads;
|
|
i.onclick = (event) => {
|
|
SetThreadPost(ThreadedPost[TempID], i);
|
|
}
|
|
}
|
|
NumberOfThreads += 1;
|
|
}
|
|
} else {
|
|
document.getElementsByClassName("PostText")[0].innerHTML = "Nothing to load.";
|
|
}
|
|
}
|
|
|
|
// Because of repeat code, we can put it into it's own function. Hell, more of a thread can be added later.
|
|
async function MastodonReplylFunction(Id, post) {
|
|
let OtherPost = await MastodonAPI.GetStatus(post);
|
|
let ShitHTML = "<header> <h1 class=\"Handle " + Id + "\"> " + OtherPost.account.acct + "</h1> <h2 class=\"Origin " + Id + "\"> " + website + "</h2> </header> <p class=\"PostText " + Id + "\"></p> <div class=\"Images " + Id + "\"></div> <hr/>";
|
|
document.getElementsByTagName("body")[0].insertAdjacentHTML("afterbegin", ShitHTML);
|
|
if (OtherPost.spoiler_text != "") {
|
|
document.getElementsByClassName("PostText " + Id)[0].innerHTML = "WARNING: " + OtherPost.spoiler_text;
|
|
} else {
|
|
document.getElementsByClassName("PostText " + Id)[0].innerHTML = OtherPost.content;
|
|
if (OtherPost.media_attachments.length != 0) {
|
|
for (let i of OtherPost.media_attachments) {
|
|
ApplyMedia(i, document.getElementsByClassName("Images " + Id));
|
|
}
|
|
}
|
|
}
|
|
return OtherPost;
|
|
}
|
|
|
|
async function BlueskyReplyFunction(Id, post, OtherAuthor) {
|
|
let OtherPost = await BlueskyAPI.GetPosts([post.uri]);
|
|
console.log(OtherPost);
|
|
let ShitHTML = "<header> <h1 class=\"Handle " + Id + "\"> " + OtherAuthor.handle + "</h1> <h2 class=\"Origin " + Id + "\"> " + website + "</h2> </header> <p class=\"PostText " + Id + "\"></p> <div class=\"Images " + Id + "\"></div> <hr/>";
|
|
document.getElementsByTagName("body")[0].insertAdjacentHTML("afterbegin", ShitHTML);
|
|
Text = BlueskyAPI.ApplyFacets(OtherPost.value, OtherPost.value.text);
|
|
Text = Text.replace(/\r?\n|\r/g, "<br/>");
|
|
// Sensitive topic :3
|
|
if (OtherPost.value.hasOwnProperty("labels") && OtherPost.value.labels.length != 0) {
|
|
document.getElementsByClassName("PostText " + ClassName)[0].innerHTML = "LABELS APPLIED: ";
|
|
for (let lab of OtherPost.value.labels.values) {
|
|
document.getElementsByClassName("PostText " + Id)[0].innerHTML += lab.val + " ";
|
|
}
|
|
} else {
|
|
document.getElementsByClassName("PostText " + Id)[0].innerHTML = Text;
|
|
if (OtherPost.value.hasOwnProperty("embed")) {
|
|
ApplyMedia(OtherPost.value.embed, document.getElementsByClassName("Images " + Id)[0], OtherAuthor.did);
|
|
}
|
|
}
|
|
return OtherPost;
|
|
}
|
|
|
|
// 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") {
|
|
if (Media.remote_url == null) {
|
|
Element.innerHTML += "<img src=" + Media.url + " alt=\"" + EscapeRegExp(Media.description) + "\"/>";
|
|
} else {
|
|
Element.innerHTML += "<img src=" + Media.remote_url + " alt=\"" + EscapeRegExp(Media.description) + "\"/>";
|
|
}
|
|
} else if (Media.type == "video" || Media.type == "gifv") {
|
|
if (Media.remote_url == null) {
|
|
Element.innerHTML += "<video controls src=" + Media.url + " alt=\"" + EscapeRegExp(Media.description) + "\"></video>";
|
|
} else {
|
|
Element.innerHTML += "<video controls src=" + Media.remote_url + " alt=\"" + EscapeRegExp(Media.description) + "\"></video>";
|
|
}
|
|
}
|
|
} else if (website == "Bluesky") {
|
|
// Record and media embed; They are from seperate posts.
|
|
if (Media.$type == "app.bsky.embed.recordWithMedia") {
|
|
await BlueskyBlobEmbed(Media.media, Element, Author);
|
|
let Texty = await BlueskyAPI.GetPosts([Media.record.record.uri]);
|
|
let Text = BlueskyAPI.ApplyFacets(Texty.posts[0].record, Texty.posts[0].record.text);
|
|
Text = Text.replace(/\r?\n|\r/g, "<br/>");
|
|
Element.innerHTML += "<p class='Embed'>" + Text + "</p><br/>";
|
|
// To stop confusion: this is for the RECORD EMBED! It gets an image from the record embed and puts it there.
|
|
if (Texty.posts[0].record.embed.$type == "app.bsky.embed.images" || Texty.posts[0].record.embed.$type == "app.bsky.embed.video") {
|
|
await BlueskyBlobEmbed(Texty.posts[0].record.embed, Element, Texty.posts[0].author.did);
|
|
}
|
|
// Just a record on it's own.
|
|
} else if (Media.$type == "app.bsky.embed.record") {
|
|
let Texty = await BlueskyAPI.GetPosts([Media.record.uri]);
|
|
let Text = BlueskyAPI.ApplyFacets(Texty.posts[0].record, Texty.posts[0].record.text);
|
|
Text = Text.replace(/\r?\n|\r/g, "<br/>");
|
|
Element.innerHTML += "<p class='Embed'>" + Text + "</p><br/>";
|
|
if (Texty.posts[0].record.embed.$type == "app.bsky.embed.images" || Texty.posts[0].record.embed.$type == "app.bsky.embed.video") {
|
|
await BlueskyBlobEmbed(Texty.posts[0].record.embed, Element, Texty.posts[0].author.did);
|
|
}
|
|
// Image on it's own
|
|
} else if (Media.$type == "app.bsky.embed.images" || Media.$type == "app.bsky.embed.video") {
|
|
await BlueskyBlobEmbed(Media, Element, Author);
|
|
}
|
|
EmbedCounter = 0;
|
|
}
|
|
}
|
|
|
|
// Fucking hell.
|
|
async function BlueskyBlobEmbed(Blob, Element, Author) {
|
|
if (Blob.$type == "app.bsky.embed.images") {
|
|
for (let i of Blob.images) {
|
|
Element.innerHTML += "<img src=\"\" alt=\"\"/>";
|
|
var Blobby = await BlueskyAPI.GetBlob(Author, i.image.ref.$link);
|
|
var ObjectURL = URL.createObjectURL(Blobby);
|
|
let TempElement = Element.getElementsByTagName("img")[EmbedCounter];
|
|
EmbedCounter += 1;
|
|
TempElement.setAttribute("src", ObjectURL);
|
|
TempElement.setAttribute("alt", EscapeRegExp(i.alt));
|
|
}
|
|
// Video embed.
|
|
} else if (Blob.$type == "app.bsky.embed.video") {
|
|
Element.innerHTML += "<video controls src=\"\">Loading...</video>";
|
|
Element = Element.getElementsByTagName("video")[0];
|
|
var Blobby = await BlueskyAPI.GetBlob(Author, Blob.video.ref.$link);
|
|
var ObjectURL = URL.createObjectURL(Blobby);
|
|
Element.setAttribute("src", ObjectURL);
|
|
Element.innerHTML = "";
|
|
}
|
|
}
|
|
|
|
// Setters
|
|
function SetFavorite() {
|
|
FavoriteFlipper = !(FavoriteFlipper);
|
|
if (FavoriteFlipper == false) {
|
|
Favorite.innerHTML = "Favorite!";
|
|
} else {
|
|
Favorite.innerHTML = "Unfavorite...";
|
|
}
|
|
Favoritable = true;
|
|
}
|
|
|
|
function SetBoost() {
|
|
BoostFlipper = !(BoostFlipper);
|
|
if (BoostFlipper == false) {
|
|
Boost.innerHTML = "Boost!";
|
|
} else {
|
|
Boost.innerHTML = "Unboost...";
|
|
}
|
|
Boostable = true;
|
|
}
|
|
|
|
// Functions stolen form elsewhere
|
|
function EscapeRegExp(text) {
|
|
if (text == null) {
|
|
return null;
|
|
}
|
|
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\$&');
|
|
}
|