diff --git a/JS/BlueskyAPI.js b/JS/BlueskyAPI.js
index e979cb7..fb04879 100644
--- a/JS/BlueskyAPI.js
+++ b/JS/BlueskyAPI.js
@@ -9,15 +9,14 @@ export async function GetTimeline(Cursor) {
return "";
}
- let PDS = localStorage.getItem(Variables.BlueskyPDS);
let DPoP;
let request;
if (Cursor == "") {
- DPoP = await ClientDPoPPDS("GET", PDS + "/xrpc/app.bsky.feed.getTimeline");
- request = fetch(PDS + "/xrpc/app.bsky.feed.getTimeline", {method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
+ DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline");
+ request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline", {method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
} else {
- DPoP = await ClientDPoPPDS("GET", PDS + "/xrpc/app.bsky.feed.getTimeline?cursor=" + Cursor);
- request = fetch(PDS + "/xrpc/app.bsky.feed.getTimeline?cursor=" + Cursor, {method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
+ DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline?cursor=" + Cursor);
+ request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline?cursor=" + Cursor, {method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
}
let body = await request.then((response) => response.json());
let status = await request.then((response) => response.status);
@@ -29,6 +28,32 @@ export async function GetTimeline(Cursor) {
return body;
}
+// Gets a "public" timeline (essentially a feed by bsky.app where you can discover posts).
+export async function GetPublicTimeline(Cursor) {
+ if (localStorage.getItem(Variables.BlueskyAccessToken) == null) {
+ console.log("No access token!");
+ return "";
+ }
+
+ let DPoP;
+ let request;
+ if (Cursor == "") {
+ DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getFeed?feed=at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot");
+ request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getFeed?feed=at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot", {method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
+ } else {
+ DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline?feed=at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot&cursor=" + Cursor);
+ request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getTimeline?feed=at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot&cursor=" + Cursor, {method: "GET", headers: {"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 GetFeed(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) {
@@ -36,9 +61,8 @@ export async function GetPosts(URIs) {
return "";
}
- let PDS = localStorage.getItem(Variables.BlueskyPDS);
- let DPoP = await ClientDPoPPDS("GET", PDS + "/xrpc/app.bsky.feed.getPosts?uris=" + URIs);
- let request = fetch(PDS + "/xrpc/app.bsky.feed.getPosts?uris=" + URIs, { method: "GET", headers: {"Authorization": "DPoP " + localStorage.getItem(Variables.BlueskyAccessToken), "DPoP": DPoP}});
+ let DPoP = await ClientDPoPPDS("GET", localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getPosts?uris=" + URIs);
+ let request = fetch(localStorage.getItem(Variables.BlueskyPDS) + "/xrpc/app.bsky.feed.getPosts?uris=" + URIs, { method: "GET", headers: {"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"));
@@ -220,10 +244,10 @@ export async function CreateRecord(Repo, Collection, Record, RKey) {
// Applyers
export function ApplyFacets(record, text) {
- var StringArray = [];
- var SplitAreas = [0];
- var Hrefs = [];
- var TempText = "";
+ let StringArray = [];
+ let SplitAreas = [0];
+ let Hrefs = [];
+ let TempText = "";
if (record.hasOwnProperty("facets")) {
// First, append split areas.
for (let i of record.facets) {
@@ -237,9 +261,9 @@ export function ApplyFacets(record, text) {
// Last minute append.
SplitAreas.push(text.length);
// Remove emoji regex
- var EmojiRegex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;
- var EmojiObjects = text.match(EmojiRegex);
- var SubtractNumber = 0;
+ let EmojiRegex = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu;
+ let EmojiObjects = text.match(EmojiRegex);
+ let SubtractNumber = 0;
if (EmojiObjects != null) {
SubtractNumber = EmojiObjects.length * 2;
}
@@ -327,7 +351,7 @@ export async function ClientDPoPToken(POSTorGET, RequestURL) {
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
// Header
- var Header = {typ: "dpop+jwt", alg: "ES256", jwk:
+ let Header = {typ: "dpop+jwt", alg: "ES256", jwk:
await crypto.subtle.exportKey("jwk", PublicKey)
.then(function(response) {
delete response["key_ops"];
@@ -336,7 +360,7 @@ export async function ClientDPoPToken(POSTorGET, RequestURL) {
return response})
};
// Payload
- var Payload = {};
+ let Payload = {};
Payload.iss = "https://fedi.crowdedgames.group/oauth/client-metadata.json";
Payload.jti = crypto.randomUUID();
Payload.htm = POSTorGET;
@@ -344,9 +368,9 @@ export async function ClientDPoPToken(POSTorGET, RequestURL) {
Payload.iat = Math.floor(new Date(Date.now()).getTime() / 1000);
Payload.nonce = localStorage.getItem(Variables.BlueskyNonce);
- var sHeader = JSON.stringify(Header);
- var sPayload = JSON.stringify(Payload);
- var JWT = KJUR.jws.JWS.sign("ES256", sHeader, sPayload,
+ let sHeader = JSON.stringify(Header);
+ let sPayload = JSON.stringify(Payload);
+ let JWT = KJUR.jws.JWS.sign("ES256", sHeader, sPayload,
await crypto.subtle.exportKey("jwk", PrivateKey)
.then(function(response) {
delete response["key_ops"];
@@ -362,7 +386,7 @@ export async function ClientDPoPPDS(POSTorGET, RequestURL) {
let PrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(localStorage.getItem(Variables.BlueskyPrivateKey)), {name: "ECDSA", namedCurve: "P-256"}, true, ["sign"]);
// Header
- var Header = {typ: "dpop+jwt", alg: "ES256", jwk:
+ let Header = {typ: "dpop+jwt", alg: "ES256", jwk:
await crypto.subtle.exportKey("jwk", PublicKey)
.then(function(response) {
delete response["key_ops"];
@@ -371,7 +395,7 @@ export async function ClientDPoPPDS(POSTorGET, RequestURL) {
return response})
};
// Payload
- var Payload = {};
+ let Payload = {};
Payload.iss = "https://fedi.crowdedgames.group/oauth/client-metadata.json";
Payload.jti = crypto.randomUUID();
Payload.htm = POSTorGET;
@@ -380,9 +404,9 @@ export async function ClientDPoPPDS(POSTorGET, RequestURL) {
Payload.nonce = localStorage.getItem(Variables.BlueskyNonce);
Payload.ath = await CreatePKCECodeChallenge(localStorage.getItem(Variables.BlueskyAccessToken));
- var sHeader = JSON.stringify(Header);
- var sPayload = JSON.stringify(Payload);
- var JWT = KJUR.jws.JWS.sign("ES256", sHeader, sPayload,
+ let sHeader = JSON.stringify(Header);
+ let sPayload = JSON.stringify(Payload);
+ let JWT = KJUR.jws.JWS.sign("ES256", sHeader, sPayload,
await crypto.subtle.exportKey("jwk", PrivateKey)
.then(function(response) {
delete response["key_ops"];
diff --git a/JS/MastodonAPI.js b/JS/MastodonAPI.js
index a136993..a4f00be 100644
--- a/JS/MastodonAPI.js
+++ b/JS/MastodonAPI.js
@@ -4,23 +4,32 @@ export const Scopes = "read write follow push";
// Getters
// Gets the public timeline.
-export async function GetPublicTimeline(Local = false, Remote = false, Website) {
+export async function GetPublicTimeline(Local = false, Remote = false, Website, Cursor) {
// Variables can be found in `setting.js`
let Timeline;
- if (Local == true && Remote == true) {
- console.error("Don't set both Local and Remote timelines to true.");
- return Timeline;
- }
- if (Local == true) {
- Timeline = await fetch(Website + "/api/v1/timelines/public?local=true")
- .then((response) => response.json());
- } else if (Remote == true) {
- Timeline = await fetch(Website + "/api/v1/timelines/public?remote=true")
- .then((response) => response.json());
+ if (Cursor == "") {
+ if (Remote == true && Local == false) {
+ Timeline = await fetch(Website + "/api/v1/timelines/public?remote=true")
+ .then((response) => response.json());
+ } else if (Local == true && Remote == false) {
+ Timeline = await fetch(Website + "/api/v1/timelines/public?local=true")
+ .then((response) => response.json());
+ } else {
+ Timeline = await fetch(Website + "/api/v1/timelines/public")
+ .then((response) => response.json());
+ }
} else {
- Timeline = await fetch(Website + "/api/v1/timelines/public")
- .then((response) => response.json());
+ if (Remote == true && Local == false) {
+ Timeline = await fetch(Website + "/api/v1/timelines/public?remote=true&max_id=" + Cursor)
+ .then((response) => response.json());
+ } else if (Local == true && Remote == false) {
+ Timeline = await fetch(Website + "/api/v1/timelines/public?local=true&max_id=" + Cursor)
+ .then((response) => response.json());
+ } else {
+ Timeline = await fetch(Website + "/api/v1/timelines/public?max_id=" + Cursor)
+ .then((response) => response.json());
+ }
}
return Timeline;
}
diff --git a/JS/index.js b/JS/index.js
index 8beb3db..f9d7ee4 100644
--- a/JS/index.js
+++ b/JS/index.js
@@ -14,22 +14,27 @@ let BrowserWidth = window.innerWidth;
let BrowserHeight = window.innerHeight;
let ArrowsButton = document.getElementsByClassName("Arrow");
+
let SettingButton = document.getElementsByClassName("Setting")[0];
let MailButton = document.getElementsByClassName("Mail")[0];
let PostingButton = document.getElementsByClassName("Posting")[0];
+let FeedButton = document.getElementsByClassName("Feed")[0];
// Sounds
const ButtonSound = new Audio("Audio/button-305770.mp3");
const WarningClick = new Audio("Audio/button-pressed-38129.mp3");
const BackgroundMusic = new Audio("Audio/soft-piano-music-312509.mp3");
+// Discoverability
+let Discover = false;
+
// Update a timer
function UpdateTime() {
let TimeNow = new Date();
let Hour = TimeNow.getHours();
let Minute = TimeNow.getMinutes();
- var WebsiteTime = document.getElementsByClassName("Time")[0]
+ let WebsiteTime = document.getElementsByClassName("Time")[0]
WebsiteTime.innerHTML = "";
if (Hour < 10) {
WebsiteTime.innerHTML = WebsiteTime.innerHTML + "0" + Hour;
@@ -149,12 +154,20 @@ async function PosterContainerUpdate(Direction) {
// Mastodon gaining of timeline.
if (localStorage.getItem(Variables.MastodonWebsite) == null) {
- // The default website is Wetdry :3
console.log("No Mastodon instance. multiplying mastodon posts by 2...");
Lim = Lim * 2;
Mastodon = false;
} else if (MastodonLoadedFeed == 0) {
- MastodonLoadedFeed = await MastodonAPI.GetTimeline("");
+ // If discover is turned on...
+ if (Discover == true) {
+ if (localStorage.getItem("Remote") != null) {
+ MastodonLoadedFeed = await MastodonAPI.GetPublicTimeline(true, true, localStorage.getItem(Variables.MastodonWebsite), "");
+ } else {
+ MastodonLoadedFeed = await MastodonAPI.GetPublicTimeline(true, false, localStorage.getItem(Variables.MastodonWebsite), "");
+ }
+ } else {
+ MastodonLoadedFeed = await MastodonAPI.GetTimeline("");
+ }
}
// Bluesky gaining of timeline.
if (localStorage.getItem(Variables.BlueskyPDS) == null) {
@@ -162,7 +175,11 @@ async function PosterContainerUpdate(Direction) {
Lim = Lim * 2;
Bluesky = false;
} else if (BlueskyLoadedFeed.length == 0) {
- BlueskyLoadedFeed = await BlueskyAPI.GetTimeline("").then((response) => response.feed);
+ if (Discover == true) {
+ BlueskyLoadedFeed = await BlueskyAPI.GetPublicTimeline("").then((response) => response.feed);
+ } else {
+ BlueskyLoadedFeed = await BlueskyAPI.GetTimeline("").then((response) => response.feed);
+ }
}
if (Direction == "Forward") {
CurrentThing = CurrentThing + Lim;
@@ -192,7 +209,16 @@ async function PosterContainerUpdate(Direction) {
WebsiteAPIType.push("Mastodon");
i.getElementsByClassName("PostContent")[0].innerHTML = "";
if (MastodonLoadedFeed[CurrentThing + counter] == undefined) {
- let TempFeed = await MastodonAPI.GetTimeline(MastodonLoadedFeed[CurrentThing + counter - 1].id);
+ let TempFeed;
+ if (Discover == true) {
+ if (localStorage.getItem("Remote") != null) {
+ TempFeed = await MastodonAPI.GetPublicTimeline(true, true, localStorage.getItem(Variables.MastodonWebsite), MastodonLoadedFeed[CurrentThing + counter - 1].id);
+ } else {
+ TempFeed = await MastodonAPI.GetPublicTimeline(true, false, localStorage.getItem(Variables.MastodonWebsite), MastodonLoadedFeed[CurrentThing + counter - 1].id);
+ }
+ } else {
+ TempFeed = await MastodonAPI.GetTimeline(MastodonLoadedFeed[CurrentThing + counter - 1].id);
+ }
MastodonLoadedFeed = MastodonLoadedFeed.concat(TempFeed);
}
// Check for images. Reblog roundabout fix included.
@@ -238,7 +264,12 @@ async function PosterContainerUpdate(Direction) {
WebsiteAPIType.push("Bluesky");
i.getElementsByClassName("PostContent")[0].innerHTML = "";
if (BlueskyLoadedFeed[CurrentThing + counter] == undefined) {
- let TempFeed = await BlueskyAPI.GetTimeline(BlueskyLoadedFeed[CurrentThing + counter - 1].post.indexedAt).then((response) => response.feed)
+ let TempFeed;
+ if (Discover == true) {
+ BlueskyLoadedFeed = await BlueskyAPI.GetPublicTimeline(BlueskyLoadedFeed[CurrentThing + counter - 1].post.indexedAt).then((response) => response.feed);
+ } else {
+ TempFeed = await BlueskyAPI.GetTimeline(BlueskyLoadedFeed[CurrentThing + counter - 1].post.indexedAt).then((response) => response.feed);
+ }
BlueskyLoadedFeed = BlueskyLoadedFeed.concat(TempFeed);
}
// check for "already seen" posts, then put it as a seen post.
@@ -273,7 +304,7 @@ async function PosterContainerUpdate(Direction) {
i.getElementsByClassName("Username")[0].innerHTML = BlueskyLoadedFeed[CurrentThing + counter].post.author.handle;
}
// Apply correct facets.
- var TempText = await BlueskyAPI.ApplyFacets(BlueskyLoadedFeed[CurrentThing + counter].post.record, BlueskyLoadedFeed[CurrentThing + counter].post.record.text);
+ let TempText = await BlueskyAPI.ApplyFacets(BlueskyLoadedFeed[CurrentThing + counter].post.record, BlueskyLoadedFeed[CurrentThing + counter].post.record.text);
TempText = TempText.replace(/\r?\n|\r/g, "
");
i.getElementsByClassName("PostContent")[0].innerHTML += TempText;
break;
@@ -316,3 +347,12 @@ MailButton.onclick = (event) => {
PostingButton.onclick = (event) => {
window.location.href = "./HTML/post.html";
}
+
+FeedButton.onclick = (event) => {
+ Discover = !(Discover);
+ MastodonLoadedFeed = [];
+ BlueskyLoadedFeed = [];
+ CurrentThing = 0;
+ PosterContainerUpdate();
+
+}
diff --git a/JS/setting.js b/JS/setting.js
index 9b98a20..045b1a5 100644
--- a/JS/setting.js
+++ b/JS/setting.js
@@ -5,7 +5,6 @@ import * as YoutubeAPI from "./YoutubeAPI.js";
import * as Variables from "./Variables.js";
// Settings buttons
-let LocalButton = document.getElementsByClassName("Local")[0];
let RemoteButton = document.getElementsByClassName("Remote")[0];
// Website Stuff
@@ -25,16 +24,7 @@ let YoutubeLogoutButton = document.getElementsByClassName("Logout Youtube")[0];
// original link
let Origin = location.origin + "/HTML/setting.html"
-// Change weather the timelines are public or remote
-LocalButton.onclick = (event) => {
- // Toggle the Variable
- if (localStorage.getItem("Local") != null) {
- localStorage.removeItem("Local");
- } else {
- localStorage.setItem("Local", "true");
- }
-}
-
+// Allow the user to change if Remote is a thing or not.
RemoteButton.onclick = (event) => {
// Toggle the Variable
if (localStorage.getItem("Remote") != null) {
diff --git a/index.html b/index.html
index a17da89..993d7f1 100644
--- a/index.html
+++ b/index.html
@@ -301,10 +301,10 @@