summaryrefslogtreecommitdiff
path: root/priv
diff options
context:
space:
mode:
Diffstat (limited to 'priv')
-rw-r--r--priv/discord_activity.html.eex44
-rw-r--r--priv/static/discordActivity.js113
-rw-r--r--priv/static/discord_activity.js20
-rw-r--r--priv/static/room/displayState.js5
4 files changed, 155 insertions, 27 deletions
diff --git a/priv/discord_activity.html.eex b/priv/discord_activity.html.eex
index 83bda0d..5278400 100644
--- a/priv/discord_activity.html.eex
+++ b/priv/discord_activity.html.eex
@@ -1,3 +1,4 @@
+<% home_url = "/.proxy/?#{Mediasync.Constants.query_param_discord_activity_inner()}" %>
<!DOCTYPE html>
<html lang="en">
<head>
@@ -6,25 +7,58 @@
<meta name="robots" content="noindex, nofollow">
<title>discord activity | mediasync</title>
<style>
+ :root {
+ --instance-room-info-height: 20svh;
+ --instance-room-info-remainder: calc(100svh - var(--instance-room-info-height));
+ }
+
body {
overflow: hidden;
+ background-color: black;
+ color: white;
+ font-family: monospace;
}
iframe {
border: none;
}
html, body, iframe {
margin: 0;
- width: 100%;
- height: 100%;
+ width: 100svw;
+ height: 100svh;
+ }
+
+ iframe.at-home {
+ height: var(--instance-room-info-remainder);
+ }
+
+ div#instance-room-info {
+ display: none;
+ overflow: auto;
+ }
+
+ body:has(> iframe.at-home) > div#instance-room-info {
+ display: block;
+ height: var(--instance-room-info-height);
+ border-bottom: 1px solid white;
}
</style>
</head>
-<body>
- <iframe src="/.proxy/?<%= Mediasync.Constants.query_param_discord_activity_inner() %>"></iframe>
+<body data-csrf-token="<%= Plug.CSRFProtection.get_csrf_token() %>">
+ <div id="instance-room-info">
+ <span style="font-weight: bold;">currently hosting:</span>
+ <div id="instance-room-info-content"></div>
+ </div>
+ </div>
+ <iframe src="<%= home_url %>" style="display: none;" class="at-home" name="activity-inner-iframe"></iframe>
<script>
const DISCORD_CLIENT_ID = "<%= Application.fetch_env!(:mediasync, :discord_client_id) %>";
+ const ACCESS_TOKEN_URL = "/.proxy/discord_activity/access_token?<%= Mediasync.Constants.query_param_discord_activity_inner() %>";
+ const HOME_URL = "<%= home_url %>";
+ const roomUrl = (roomId) => {
+ return `/.proxy/room/${roomId}?<%= Mediasync.Constants.query_param_discord_activity_inner() %>`;
+ };
</script>
<script src="/static/discord-embedded-app-sdk/Discord.js" type="module"></script>
- <script src="/static/discord_activity.js" type="module"></script>
+ <script src="/static/discordActivity.js" type="module"></script>
</body>
</html>
diff --git a/priv/static/discordActivity.js b/priv/static/discordActivity.js
new file mode 100644
index 0000000..7ec4872
--- /dev/null
+++ b/priv/static/discordActivity.js
@@ -0,0 +1,113 @@
+import { DiscordSDK } from "/static/discord-embedded-app-sdk/Discord.js";
+
+const discordSdk = new DiscordSDK(DISCORD_CLIENT_ID);
+
+const updateInstanceRoomInfo = () => {
+ const contentEl = document.getElementById("instance-room-info-content");
+
+ const defaultContents = document.createElement("i");
+ defaultContents.innerText = "none yet";
+ if (!contentEl.hasChildNodes()) {
+ contentEl.replaceChildren(defaultContents);
+ }
+
+ fetch(
+ `/.proxy/discord_activity/rooms_for_instance?discord_activity_inner&instance_id=${discordSdk.instanceId}`,
+ )
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`Fetching instance room info failed with status code ${response.status}`);
+ }
+ return response.json();
+ })
+ .then((json) => {
+ let docFragment = new DocumentFragment();
+ if (json.length === 0) {
+ docFragment.appendChild(defaultContents);
+ } else {
+ const listEl = docFragment.appendChild(document.createElement("ul"));
+ for (const roomInfo of json) {
+ const item = listEl.appendChild(document.createElement("li"));
+ item.innerText = roomInfo["host_username"] + " ";
+ const form = item.appendChild(document.createElement("form"));
+ form.action = roomUrl(roomInfo["room_id"]);
+ form.target = "activity-inner-iframe";
+ form.style.display = "inline";
+ const hiddenInput = form.appendChild(document.createElement("input"));
+ hiddenInput.type = "hidden";
+ hiddenInput.name = "discord_activity_inner";
+ const submitInput = form.appendChild(document.createElement("input"));
+ submitInput.type = "submit";
+ submitInput.value = "join";
+ }
+ }
+ contentEl.replaceChildren(docFragment);
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+};
+
+updateInstanceRoomInfo();
+const INSTANCE_ROOM_INFO_INTERVAL = 3000;
+let instanceRoomInfoIntervalId = setInterval(updateInstanceRoomInfo, INSTANCE_ROOM_INFO_INTERVAL);
+
+const iframe = document.querySelector("iframe");
+// It doesn't matter if the iframe's initial loading finishes before this is added
+iframe.addEventListener("load", (_) => {
+ clearInterval(instanceRoomInfoIntervalId);
+
+ const locationURL = new URL(iframe.contentWindow.location);
+ const locationPath = locationURL.pathname + locationURL.search;
+ if (locationPath === HOME_URL) {
+ instanceRoomInfoIntervalId = setInterval(updateInstanceRoomInfo, INSTANCE_ROOM_INFO_INTERVAL);
+ iframe.className = "at-home";
+ } else {
+ iframe.className = "";
+ }
+});
+
+discordSdk
+ .ready()
+ .then(() => {
+ return discordSdk.commands.authorize({
+ client_id: DISCORD_CLIENT_ID,
+ response_type: "code",
+ state: "",
+ prompt: "none",
+ scope: ["identify"],
+ });
+ })
+ .then((result) => {
+ const { code } = result;
+
+ return fetch(ACCESS_TOKEN_URL, {
+ body: new URLSearchParams([["code", code]]),
+ headers: {
+ "content-type": "application/x-www-form-urlencoded",
+ "x-csrf-token": document.body.dataset.csrfToken,
+ },
+ method: "POST",
+ });
+ })
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`Getting access token failed with status code ${response.status}`);
+ }
+ // Note: the access token should now be in the session cookie as well
+ return response.text();
+ })
+ .then((accessToken) => {
+ return discordSdk.commands.authenticate({ access_token: accessToken });
+ })
+ .then((authenticationResult) => {
+ if (authenticationResult === null) {
+ throw new Error("Authenticating with Discord client failed");
+ }
+ iframe.style.display = null;
+ })
+ .catch((error) => {
+ console.error(error);
+ const CLOSE_ABNORMAL = 1006;
+ discordSdk.close(CLOSE_ABNORMAL, "Could not obtain authorizations required to run this app.");
+ });
diff --git a/priv/static/discord_activity.js b/priv/static/discord_activity.js
deleted file mode 100644
index 344c30d..0000000
--- a/priv/static/discord_activity.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { DiscordSDK } from "/static/discord-embedded-app-sdk/Discord.js";
-
-const discordSdk = new DiscordSDK(DISCORD_CLIENT_ID);
-
-discordSdk
- .ready()
- .then(() => {
- console.log("Mediasync: Discord SDK ready.");
- return discordSdk.commands.authorize({
- client_id: DISCORD_CLIENT_ID,
- response_type: "code",
- state: "",
- prompt: "none",
- scope: ["identify"],
- });
- })
- .then((result) => {
- const { code } = result;
- console.log(code);
- });
diff --git a/priv/static/room/displayState.js b/priv/static/room/displayState.js
index 3a5e923..a2da229 100644
--- a/priv/static/room/displayState.js
+++ b/priv/static/room/displayState.js
@@ -9,7 +9,7 @@
fetch(STATE_URL)
.then((response) => {
if (!response.ok) {
- throw new Error(`Error: fetching state returned ${response.status}`);
+ throw new Error(`Fetching room state failed with status code ${response.status}`);
}
return response.json();
})
@@ -17,7 +17,8 @@
const viewersConnected = json.viewersConnected;
stateElement.dataset.text = `total viewers: ${viewersConnected}`;
})
- .catch((_) => {
+ .catch((error) => {
+ console.error(error);
stateElement.dataset.text = STATE_ELEMENT_INITIAL_TEXT;
});
}