Skip to content

Commit

Permalink
Merge pull request #59 from LiveTL/member-only
Browse files Browse the repository at this point in the history
  • Loading branch information
KentoNishi authored Mar 12, 2022
2 parents 2a54e13 + 6f54416 commit d38e77c
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 45 deletions.
69 changes: 47 additions & 22 deletions src/components/Hyperchat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@
paramsTabId,
paramsFrameId,
paramsIsReplay,
Theme
Theme,
YoutubeEmojiRenderMode
} from '../ts/chat-constants';
import { responseIsAction } from '../ts/chat-utils';
import { isAllEmoji, isChatMessage, isPrivileged, responseIsAction } from '../ts/chat-utils';
import Button from 'smelte/src/components/Button';
import {
theme,
showOnlyMemberChat,
showProfileIcons,
showUsernames,
showTimestamps,
showUserBadges,
refreshScroll
refreshScroll,
emojiRenderMode
} from '../ts/storage';
const welcome = { welcome: true, message: { messageId: 'welcome' } };
Expand All @@ -39,6 +42,24 @@
let ytDark = false;
const smelteDark = dark();
type MessageBlocker = (a: Chat.MessageAction) => boolean;
const memberOnlyBlocker: MessageBlocker = (a) => (
$showOnlyMemberChat && isChatMessage(a) && !isPrivileged(a.message.author.types)
);
const emojiSpamBlocker: MessageBlocker = (a) => (
isChatMessage(a) &&
$emojiRenderMode !== YoutubeEmojiRenderMode.SHOW_ALL &&
isAllEmoji(a)
);
const messageBlockers = [memberOnlyBlocker, emojiSpamBlocker];
const shouldShowMessage = (m: Chat.MessageAction): boolean => (
!messageBlockers.some(blocker => blocker(m))
);
const isWelcome = (m: Chat.MessageAction | Welcome): m is Welcome =>
'welcome' in m;
Expand All @@ -65,10 +86,10 @@
// On replays' initial data, only show messages with negative timestamp
if (isInitial && isReplay) {
messageActions.push(...messagesAction.messages.filter(
(a) => a.message.timestamp.startsWith('-')
(a) => a.message.timestamp.startsWith('-') && shouldShowMessage(a)
));
} else {
messageActions.push(...messagesAction.messages);
messageActions.push(...messagesAction.messages.filter(shouldShowMessage));
}
if (!isInitial) checkTruncateMessages();
};
Expand Down Expand Up @@ -111,7 +132,7 @@
pinned = null;
break;
case 'forceUpdate':
messageActions = [...action.messages];
messageActions = [...action.messages].filter(shouldShowMessage);
break;
}
};
Expand Down Expand Up @@ -201,27 +222,31 @@
);
const containerClass = 'h-screen w-screen text-black dark:text-white dark:bg-black dark:bg-opacity-25';
const contentClass = 'content absolute overflow-y-scroll w-full h-full flex-1';
const pinnedClass = 'absolute top-2 inset-x-2';
const isSuperchat = (action: Chat.MessageAction) => (action.message.superChat || action.message.superSticker);
const isMembership = (action: Chat.MessageAction) => (action.message.membership);
</script>

<svelte:window on:resize={scrollToBottom} on:load={onLoad} />

<div class={containerClass} style="font-size: 13px">
<div class={contentClass} bind:this={div} on:scroll={checkAtBottom}>
{#each messageActions as action (action.message.messageId)}
<div class={isWelcome(action) ? 'm-2' : 'p-1 m-1 hover-highlight flex rounded'}>
{#if isWelcome(action)}
<WelcomeMessage />
{:else if (action.message.superChat || action.message.superSticker)}
<PaidMessage message={action.message} />
{:else if action.message.membership}
<MembershipItem message={action.message} />
{:else}
<Message message={action.message} deleted={action.deleted} />
{/if}
</div>
{/each}
<div class="absolute w-full h-full flex justify-end flex-col">
<div bind:this={div} on:scroll={checkAtBottom} class="content overflow-y-scroll">
{#each messageActions as action (action.message.messageId)}
<div class="{isWelcome(action) ? '' : 'hover-highlight rounded'} p-1.5 w-full block">
{#if isWelcome(action)}
<WelcomeMessage />
{:else if isSuperchat(action)}
<PaidMessage message={action.message} />
{:else if isMembership(action)}
<MembershipItem message={action.message} />
{:else}
<Message message={action.message} deleted={action.deleted} />
{/if}
</div>
{/each}
</div>
</div>
{#if pinned}
<div class={pinnedClass}>
Expand Down Expand Up @@ -256,7 +281,7 @@
background: #555;
}
.hover-highlight {
transition: 0.1s;
/* transition: 0.1s; */
background-color: transparent;
}
.hover-highlight:hover {
Expand Down
30 changes: 18 additions & 12 deletions src/components/MessageRuns.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
import type { Theme } from '../ts/chat-constants';
import TranslatedMessage from './TranslatedMessage.svelte';
import {
emojiRenderMode
} from '../ts/storage';
import { YoutubeEmojiRenderMode } from '../ts/chat-constants';
export let runs: Ytc.ParsedRun[];
export let forceDark = false;
Expand Down Expand Up @@ -39,18 +43,20 @@
>
{run.text}
</a>
{:else if run.type === 'emoji' && run.standardEmoji}
<span
class="cursor-auto align-middle text-base"
>
{run.alt}
</span>
{:else if run.type === 'emoji' && run.src}
<img
class="h-5 w-5 inline mx-0.5 align-middle"
src={run.src}
alt={run.alt}
/>
{:else if run.type === 'emoji' && $emojiRenderMode !== YoutubeEmojiRenderMode.HIDE_ALL}
{#if run.standardEmoji}
<span
class="cursor-auto align-middle text-base"
>
{run.alt}
</span>
{:else if run.src}
<img
class="h-5 w-5 inline mx-0.5 align-middle"
src={run.src}
alt={run.alt}
/>
{/if}
{/if}
{/each}
</span>
10 changes: 5 additions & 5 deletions src/components/WelcomeMessage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,21 @@
</span>
</div>
{#if showChangelog}
<p class="leading-tight mt-1.5">
<p class="leading-tight mt-1.5 flex flex-row">
<span href="/" on:click={(e) => {
$lastClosedVersion = version;
$refreshScroll = true;
e.preventDefault();
}}
class="inline-block align-middle cursor-pointer">
class="inline-block align-middle cursor-pointer pt-0.5">
<Icon xs>
close
</Icon>
</span>
<strong class="mr-0.5">
<span class="mr-0.5">
New in v{version}:
</strong>
<Changelog />
<Changelog />
</span>
</p>
{/if}
</div>
25 changes: 22 additions & 3 deletions src/components/changelog/Changelog.svelte
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
Introducing automatic chat message translation (via Google Translate)!
You can enable the feature in the settings menu.
<i>Special thanks to tenchou for the idea!</i>
<br />
<ul class="list-disc list-inside">
<strong>On today's KFP menu:</strong>
<li class="ml-3.5">
Show only messages from channel members
</li>
<li class="ml-3.5">
Hide emoji-only spam messages or hide all emotes
</li>
</ul>
<ul class="list-disc list-inside">
<strong>What's cooking in the usual room:</strong>
<li class="ml-3.5">
Fixing message translation language selection
</li>
<li class="ml-3.5">
Reducing live chat message delays
</li>
<li class="ml-3.5">
Fixing colored emoji rendering issues
</li>
</ul>
21 changes: 19 additions & 2 deletions src/components/settings/InterfaceSettings.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
<script lang="ts">
import {
theme,
showOnlyMemberChat,
showProfileIcons,
showTimestamps,
showUsernames,
showUserBadges
showUserBadges,
emojiRenderMode
} from '../../ts/storage';
import { Theme, themeItems } from '../../ts/chat-constants';
import { Theme, themeItems, emojiRenderItems } from '../../ts/chat-constants';
import Card from '../common/Card.svelte';
import Radio from '../common/RadioGroupStore.svelte';
import Checkbox from '../common/CheckboxStore.svelte';
import dark from 'smelte/src/dark';
import MessageTranslationSettings from './MessageTranslationSettings.svelte';
const willChangeOnNextChunkMessage = (
'Changes will take effect when the next chat message chunk arrives.'
);
const darkStore = dark();
$: switch ($theme) {
case Theme.DARK:
Expand Down Expand Up @@ -51,4 +58,14 @@
<Checkbox name="Show user badges" store={showUserBadges} />
</Card>

<Card title="Emojis" icon="emoji_emotions">
<i>{willChangeOnNextChunkMessage}</i>
<Radio store={emojiRenderMode} items={emojiRenderItems} vertical />
</Card>

<Card title="Filters" icon="filter_list">
<i>{willChangeOnNextChunkMessage}</i>
<Checkbox name="Show only member chat messages" store={showOnlyMemberChat} />
</Card>

<MessageTranslationSettings />
12 changes: 12 additions & 0 deletions src/ts/chat-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ export const themeItems = [
{ value: Theme.LIGHT, label: 'Light theme' },
{ value: Theme.DARK, label: 'Dark theme' }
];

export enum YoutubeEmojiRenderMode {
SHOW_ALL = 'SHOW_ALL',
BLOCK_SPAM = 'BLOCK_SPAM',
HIDE_ALL = 'HIDE_ALL'
}

export const emojiRenderItems = [
{ value: YoutubeEmojiRenderMode.SHOW_ALL, label: 'Show all emojis' },
{ value: YoutubeEmojiRenderMode.BLOCK_SPAM, label: 'Hide emoji-only messages' },
{ value: YoutubeEmojiRenderMode.HIDE_ALL, label: 'Hide all emojis and emoji-only messages' }
];
9 changes: 9 additions & 0 deletions src/ts/chat-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ export const isValidFrameInfo = (f: Chat.UncheckedFrameInfo, port?: Chat.Port):
const actionTypes = new Set(['messages', 'bonk', 'delete', 'pin', 'unpin', 'playerProgress', 'forceUpdate']);
export const responseIsAction = (r: Chat.BackgroundResponse): r is Chat.Actions =>
actionTypes.has(r.type);

const privilegedTypes = new Set(['member', 'moderator', 'owner']);
export const isPrivileged = (types: string[]): boolean =>
types.some(privilegedTypes.has.bind(privilegedTypes));

export const isChatMessage = (a: Chat.MessageAction): boolean =>
!a.message.superChat && !a.message.superSticker && !a.message.membership;

export const isAllEmoji = (a: Chat.MessageAction): boolean => !a.message.message.some(run => run.type !== 'emoji');
4 changes: 3 additions & 1 deletion src/ts/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { webExtStores } from 'svelte-webext-stores';
import { readable, writable } from 'svelte/store';
import { getClient } from 'iframe-translator';
import type { IframeTranslatorClient } from 'iframe-translator';
import { Theme } from './chat-constants';
import { Theme, YoutubeEmojiRenderMode } from './chat-constants';

export const stores = webExtStores();

Expand Down Expand Up @@ -39,3 +39,5 @@ export const showUsernames = stores.addSyncStore('hc.messages.showUsernames', tr
export const showTimestamps = stores.addSyncStore('hc.messages.showTimestamps', false);
export const showUserBadges = stores.addSyncStore('hc.messages.showUserBadges', true);
export const lastClosedVersion = stores.addSyncStore('hc.lastClosedVersion', '');
export const showOnlyMemberChat = stores.addSyncStore('hc.showOnlyMemberChat', false);
export const emojiRenderMode = stores.addSyncStore('hc.emojiRenderMode', YoutubeEmojiRenderMode.SHOW_ALL);

0 comments on commit d38e77c

Please sign in to comment.