From b03a74b5866e248afdb85e7607008f2ac46acaba Mon Sep 17 00:00:00 2001 From: n9k Date: Sun, 27 Feb 2022 04:24:33 +0000 Subject: [PATCH] Show list of watching/non-watching users with js --- anonstream/static/anonstream.js | 114 ++++++++++++++++++++++----- anonstream/static/style.css | 38 ++++++++- anonstream/templates/home.html | 2 +- anonstream/templates/nojs_users.html | 7 +- 4 files changed, 136 insertions(+), 25 deletions(-) diff --git a/anonstream/static/anonstream.js b/anonstream/static/anonstream.js index 68f8e91..a5dc27f 100644 --- a/anonstream/static/anonstream.js +++ b/anonstream/static/anonstream.js @@ -1,5 +1,6 @@ /* token */ -const token = document.body.dataset.token; +const TOKEN = document.body.dataset.token; +const TOKEN_HASH = document.body.dataset.token_hash; /* insert js-only markup */ const jsmarkup_style_color = '' @@ -11,6 +12,17 @@ const jsmarkup_info_float_viewership = '
+

Users in chat

+
+
+
    +
    +
    +
      +
      +`; const jsmarkup_chat_form = `\
      @@ -58,6 +70,10 @@ const insert_jsmarkup = () => {jsmarkup_info_float_viewership const parent = document.getElementById("info_js"); parent.insertAdjacentHTML("beforeend", jsmarkup_info_title); } + if (document.getElementById("chat-users_js") === null) { + const parent = document.getElementById("chat__users"); + parent.insertAdjacentHTML("beforeend", jsmarkup_chat_users); + } if (document.getElementById("chat-messages_js") === null) { const parent = document.getElementById("chat__messages"); parent.insertAdjacentHTML("beforeend", jsmarkup_chat_messages); @@ -78,6 +94,10 @@ const info_title = document.getElementById("info_js__title"); const info_viewership = document.getElementById("info_js__float__viewership"); const info_uptime = document.getElementById("info_js__float__uptime"); const chat_messages = document.getElementById("chat-messages_js"); +const chat_users_watching = document.getElementById("chat-users-watching"); +const chat_users_watching_header = document.getElementById("chat-users-watching-header"); +const chat_users_notwatching = document.getElementById("chat-users-notwatching"); +const chat_users_notwatching_header = document.getElementById("chat-users-notwatching-header"); const create_chat_message = (object) => { const user = users[object.token_hash]; @@ -93,7 +113,7 @@ const create_chat_message = (object) => { chat_message_time.title = `${object.date} ${object.time_seconds}`; chat_message_time.innerText = object.time_minutes; - const chat_message_name = create_chat_message_name(user); + const chat_message_name = create_chat_name(user); const chat_message_tripcode_nbsp = document.createElement("span"); chat_message_tripcode_nbsp.classList.add("for-tripcode"); @@ -120,18 +140,18 @@ const create_chat_message = (object) => { return chat_message; } -const create_chat_message_name = (user) => { - const chat_message_name = document.createElement("span"); - chat_message_name.classList.add("chat-message__name"); - chat_message_name.innerText = get_user_name({user}); +const create_chat_name = (user) => { + const chat_name = document.createElement("span"); + chat_name.classList.add("chat-name"); + chat_name.innerText = get_user_name({user}); //chat_message_name.dataset.color = user.color; // not working in any browser if (!user.broadcaster && user.name === null) { - const chat_message_name_tag = document.createElement("sup"); - chat_message_name_tag.classList.add("chat-message__name__tag"); - chat_message_name_tag.innerText = user.tag; - chat_message_name.insertAdjacentElement("beforeend", chat_message_name_tag); + const chat_name_tag = document.createElement("sup"); + chat_name_tag.classList.add("chat-name__tag"); + chat_name_tag.innerText = user.tag; + chat_name.insertAdjacentElement("beforeend", chat_name_tag); } - return chat_message_name; + return chat_name; } const create_and_add_chat_message = (object) => { const chat_message = create_chat_message(object); @@ -172,7 +192,7 @@ const update_user_colors = (token_hash=null) => { token_hashes = token_hash === null ? Object.keys(users) : [token_hash]; const {to_delete, to_ignore} = tidy_stylesheet({ stylesheet: stylesheet_color, - selector_regex: /\.chat-message\[data-token-hash="([a-z2-7]{26})"\] > \.chat-message__name/, + selector_regex: /\[data-token-hash="([a-z2-7]{26})"\] > \.chat-name/, ignore_condition: (this_token_hash, this_user, css_rule) => { const irrelevant = ignore_other_token_hashes && this_token_hash !== token_hash; const correct_color = equal(css_rule.style.color, this_user.color); @@ -184,7 +204,7 @@ const update_user_colors = (token_hash=null) => { if (!to_ignore.has(this_token_hash)) { const user = users[this_token_hash]; stylesheet_color.insertRule( - `.chat-message[data-token-hash="${this_token_hash}"] > .chat-message__name { color: ${user.color}; }`, + `[data-token-hash="${this_token_hash}"] > .chat-name { color: ${user.color}; }`, stylesheet_color.cssRules.length, ); } @@ -204,8 +224,8 @@ const update_user_names = (token_hash=null) => { const this_token_hash = chat_message.dataset.tokenHash; if (token_hashes.includes(this_token_hash)) { const user = users[this_token_hash]; - const chat_message_name = chat_message.querySelector(".chat-message__name"); - chat_message_name.innerHTML = create_chat_message_name(user).innerHTML; + const chat_message_name = chat_message.querySelector(".chat-name"); + chat_message_name.innerHTML = create_chat_name(user).innerHTML; } } } @@ -330,7 +350,7 @@ const enable_captcha = (digest) => { chat_form_captcha_answer.disabled = false; chat_form_comment.required = false; chat_form_captcha_image.removeAttribute("src"); - chat_form_captcha_image.src = `/captcha.jpg?token=${encodeURIComponent(token)}&digest=${encodeURIComponent(digest)}`; + chat_form_captcha_image.src = `/captcha.jpg?token=${encodeURIComponent(TOKEN)}&digest=${encodeURIComponent(digest)}`; chat_form_submit.disabled = false; chat_form.dataset.captcha = ""; } @@ -387,6 +407,61 @@ const set_viewership = (n) => { info_viewership.innerText = n === null ? "" : `${n} viewers`; } +const update_users_list = () => { + listed_watching = new Set(); + listed_notwatching = new Set(); + + // remove no-longer-known users + for (const element of chat_users_watching.querySelectorAll('.chat-user')) { + const token_hash = element.dataset.tokenHash; + if (!Object.prototype.hasOwnProperty(users, token_hash)) { + element.remove(); + } else { + listed_watching.add(token_hash); + } + } + for (const element of chat_users_notwatching.querySelectorAll('.chat-user')) { + const token_hash = element.dataset.tokenHash; + if (!Object.prototype.hasOwnProperty(users, token_hash)) { + element.remove(); + } else { + listed_notwatching.add(token_hash); + } + } + + // add remaining watching/non-watching users + const insert = (user, token_hash, is_you, chat_users_sublist) => { + const chat_user_name = create_chat_name(user); + const chat_user = document.createElement("li"); + chat_user.classList.add("chat-user"); + chat_user.dataset.tokenHash = token_hash; + chat_user.insertAdjacentElement("beforeend", chat_user_name); + if (is_you) { + const you = document.createElement("span"); + you.innerText = " (You)"; + chat_user.insertAdjacentElement("beforeend", you); + } + chat_users_sublist.insertAdjacentElement("beforeend", chat_user); + } + let watching = 0, notwatching = 0; + for (const token_hash of Object.keys(users)) { + const user = users[token_hash]; + const is_you = token_hash === TOKEN_HASH; + if (user.watching === true && !listed_watching.has(token_hash)) { + insert(user, token_hash, is_you, chat_users_watching); + watching++; + } + if (user.watching === false && !listed_notwatching.has(token_hash)) { + insert(user, token_hash, is_you, chat_users_notwatching); + notwatching++; + } + } + + // show correct numbers + chat_users_watching_header.innerText = `Watching (${watching})`; + chat_users_notwatching_header.innerText = `Not watching (${notwatching})`; +} + const on_websocket_message = (event) => { //console.log("websocket message", event); const receipt = JSON.parse(event.data); @@ -435,11 +510,12 @@ const on_websocket_message = (event) => { default_name = receipt.default; max_chat_scrollback = receipt.scrollback; - // appearances + // update users users = receipt.users; update_user_names(); update_user_colors(); update_user_tripcodes(); + update_users_list() // insert new messages const last = chat_messages.children.length == 0 ? null : chat_messages.children[chat_messages.children.length - 1]; @@ -499,6 +575,7 @@ const on_websocket_message = (event) => { update_user_names(); update_user_colors(); update_user_tripcodes(); + update_users_list() break; case "rem-users": @@ -508,6 +585,7 @@ const on_websocket_message = (event) => { } update_user_colors(); update_user_tripcodes(); + update_users_list() break; case "captcha": @@ -530,7 +608,7 @@ const connect_websocket = () => { } chat_live_ball.style.borderColor = "gold"; chat_live_status.innerHTML = "Waiting... Connecting to chat..."; - ws = new WebSocket(`ws://${document.domain}:${location.port}/live?token=${encodeURIComponent(token)}`); + ws = new WebSocket(`ws://${document.domain}:${location.port}/live?token=${encodeURIComponent(TOKEN)}`); ws.addEventListener("open", (event) => { console.log("websocket open", event); chat_form_submit.disabled = false; diff --git a/anonstream/static/style.css b/anonstream/static/style.css index 66e05cb..24a36e6 100644 --- a/anonstream/static/style.css +++ b/anonstream/static/style.css @@ -181,13 +181,13 @@ noscript { font-size: 10pt; cursor: help; } -.chat-message__name { +.chat-name { overflow-wrap: anywhere; font-weight: bold; /* color: attr("data-color"); */ cursor: default; } -.chat-message__name__tag { +.chat-name__tag { font-family: monospace; font-size: 9pt; vertical-align: top; @@ -203,6 +203,40 @@ noscript { font-size: 9pt; cursor: default; } +#chat__users { + background-color: #121214; + mask-image: linear-gradient(black calc(100% - 0.625rem), transparent calc(100% - 0.125rem)); + overflow: auto; +} +#chat-users_js { + margin-bottom: 0.875rem; +} +#chat-users_js__header { + padding: 0.5rem; + background-color: #2c2c30; + border-bottom: var(--chat-border); +} +#chat-users_js__header > h4 { + margin: 0; + font-weight: normal; + text-align: center; +} +#chat-users_js__main { + margin: 0.5rem 0.75rem; +} +#chat-users-watching-header, +#chat-users-notwatching-header { + margin: 0; +} +#chat-users-watching, +#chat-users-notwatching { + margin: 0; + padding-left: 0.75rem; + list-style: none; +} +.chat-user { + line-height: 1.4375; +} #chat-users_nojs { height: 100%; } diff --git a/anonstream/templates/home.html b/anonstream/templates/home.html index a3c0292..5e5656e 100644 --- a/anonstream/templates/home.html +++ b/anonstream/templates/home.html @@ -4,7 +4,7 @@ - +
      diff --git a/anonstream/templates/nojs_users.html b/anonstream/templates/nojs_users.html index 379b5b0..b66aa92 100644 --- a/anonstream/templates/nojs_users.html +++ b/anonstream/templates/nojs_users.html @@ -8,14 +8,13 @@ min-height: 100%; } body { - margin: 0; - background: linear-gradient(#121214 calc(100% - 0.625rem), #232327 calc(100% - 0.125rem)); + margin: 0 0 0.875rem; color: #ddd; font-family: sans-serif; } #header { padding: 0.5rem; - background-color: #27272a; + background-color: #2c2c30; border-bottom: 1px solid #4a4a4f; } #header > h4 { @@ -35,7 +34,7 @@ list-style: none; } .user { - line-height: 1.5; + line-height: 1.4375; } .user__name { font-weight: bold;