Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
42a86eb
loading the lib in the extension doesn't work
KentoNishi Jan 13, 2022
b55c7e5
Starting over, probably with iframe memery
KentoNishi Jan 13, 2022
fcd4950
WIP
KentoNishi Jan 14, 2022
4b68869
yay, it shows for each message!
KentoNishi Jan 14, 2022
da220bf
Use the online host
KentoNishi Jan 14, 2022
ff5acd8
use the iframe-translator package
KentoNishi Jan 15, 2022
86048a5
bump translation package
KentoNishi Jan 15, 2022
cd769a2
fix scrolling issues after TL injection
KentoNishi Jan 15, 2022
1089ee1
hover-to-show
KentoNishi Jan 15, 2022
b18b3c8
fixed reactive feedback loop when seeking video
KentoNishi Jan 15, 2022
3ab6f96
shift the translation icon a little down
KentoNishi Jan 15, 2022
cc5394f
prepping for upgrade
KentoNishi Jan 24, 2022
281eee6
gigantic merge of settings pr
KentoNishi Jan 24, 2022
c8cd8dc
CAN CHANGE THE LANGUAGE!
KentoNishi Jan 24, 2022
5cca3f7
make lang select take effect immediately
KentoNishi Jan 24, 2022
0e752cd
Chinese (Traditional) and Chinese (Simplified)
KentoNishi Jan 24, 2022
75f14be
change dropdown label
KentoNishi Jan 24, 2022
a30b667
some formatting things
KentoNishi Jan 24, 2022
596a679
WIP forceDark
KentoNishi Jan 28, 2022
769e50c
Merge branch 'master' into google-translate
KentoNishi Jan 28, 2022
26cf7af
vite compat changes
KentoNishi Jan 28, 2022
640e2ed
WIP hover animation
KentoNishi Jan 29, 2022
5280a97
click to restore original text
KentoNishi Jan 29, 2022
5bc7402
scroll to bottom when expanding dropdown
KentoNishi Jan 29, 2022
2eecd9a
scroll the page when the checkbox is clicked
KentoNishi Jan 29, 2022
bc3c350
Merge branch 'master' into google-translate
KentoNishi Jan 30, 2022
cfd0f63
Merge branch 'master' into google-translate
KentoNishi Jan 30, 2022
7efa9ff
Merge branch 'master' into google-translate
KentoNishi Feb 2, 2022
54628c5
import type { IframeTranslatorClient }
KentoNishi Feb 8, 2022
c26682c
show {run.text} for `deleted`
KentoNishi Feb 8, 2022
5417595
<span>{run.text}</span>
KentoNishi Feb 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ pnpm-debug.log*
*.pub
*.zip
artifacts
.eslintcache
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"eslint-plugin-promise": "4",
"eslint-plugin-svelte3": "^3.2.0",
"express": "4.17.1",
"iframe-translator": "^0.2.2",
"postcss": "^8.3.6",
"postcss-extend": "^1.0.5",
"postcss-import": "^14.0.2",
Expand Down
25 changes: 20 additions & 5 deletions src/components/Hyperchat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
showProfileIcons,
showUsernames,
showTimestamps,
showUserBadges
showUserBadges,
refreshScroll
} from '../ts/storage';

const welcome = { welcome: true, message: { messageId: 'welcome' } };
Expand Down Expand Up @@ -174,12 +175,19 @@
});
};

afterUpdate(() => {
const onRefresh = () => {
if (isAtBottom) {
scrollToBottom();
}
tick().then(checkAtBottom);
});
};

$: if ($refreshScroll) {
onRefresh();
$refreshScroll = false;
}

afterUpdate(onRefresh);

onDestroy(() => {
port.disconnect();
Expand All @@ -193,7 +201,7 @@
);

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 px-2';
const contentClass = 'content absolute overflow-y-scroll w-full h-full flex-1';
const pinnedClass = 'absolute top-2 inset-x-2';
</script>

Expand All @@ -202,7 +210,7 @@
<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="my-2">
<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)}
Expand Down Expand Up @@ -247,4 +255,11 @@
.content::-webkit-scrollbar-thumb:hover {
background: #555;
}
.hover-highlight {
transition: 0.1s;
background-color: transparent;
}
.hover-highlight:hover {
background-color: #80808040;
}
</style>
11 changes: 7 additions & 4 deletions src/components/Message.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@
($showUserBadges && (moderator || verified || member));
</script>

<div on:click|stopPropagation class="inline-flex flex-row gap-2">
{#if !hideName}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="inline-flex flex-row gap-2 break-words overflow-hidden w-full"
on:click|stopPropagation
>
{#if !hideName && $showProfileIcons}
<img
class="h-5 w-5 inline align-middle rounded-full cursor-auto flex-none"
class:hidden={!$showProfileIcons}
src={message.author.profileIcon.src}
alt={message.author.profileIcon.alt}
/>
Expand All @@ -82,7 +85,7 @@
<Icon class="inline align-middle" small>build</Icon>
{:else if verified}
<Icon
class="inline align-middle text-gray-700 dark:text-gray-500"
class="inline align-middle text-gray-500"
small
>
verified
Expand Down
8 changes: 7 additions & 1 deletion src/components/MessageRuns.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import TranslatedMessage from './TranslatedMessage.svelte';

export let runs: Ytc.ParsedRun[];
export let forceDark = false;
export let deleted = false;
Expand All @@ -21,7 +23,11 @@
>
{#each runs as run}
{#if run.type === 'text'}
{run.text}
{#if deleted}
<span>{run.text}</span>
{:else}
<TranslatedMessage text={run.text} {forceDark} />
{/if}
{:else if run.type === 'link'}
<a
class="inline underline align-middle"
Expand Down
72 changes: 72 additions & 0 deletions src/components/TranslatedMessage.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import { refreshScroll, translatorClient, translateTargetLanguage } from '../ts/storage';
import Icon from './common/Icon.svelte';
import { fade } from 'svelte/transition';

export let forceDark = false;

export let text: string;
let translatedMessage = '';
let translatedLanguage = '';
let showOriginal = false;

$: if ($translateTargetLanguage && $translatorClient) {
$translatorClient.translate(text, $translateTargetLanguage).then(result => {
if (result !== text) {
translatedLanguage = $translateTargetLanguage;
translatedMessage = result;
$refreshScroll = true;
}
});
}

$: showTL = Boolean(translatedMessage && !showOriginal);

$: if ($translateTargetLanguage !== translatedLanguage) {
translatedMessage = '';
translatedLanguage = '';
}

const duration = 100;

$: translatedColor = forceDark ? 'text-translated-dark' : 'dark:text-translated-dark text-translated-light';
$: stockTextColor = forceDark ? 'text-white' : 'dark:text-white text-black';
</script>

<span
class={
showTL ? translatedColor : stockTextColor
}
class:cursor-pointer={translatedMessage}
class:entrance-animation={translatedMessage}
on:click={() => {
if (translatedMessage) {
showOriginal = !showOriginal;
$refreshScroll = true;
}
}}
>
{#if !showTL}
<span in:fade={{ duration: translatedMessage ? duration : 0 }}>
{text}
</span>
{/if}
{#if showTL}
<span in:fade={{ duration }}>
{translatedMessage}
</span>
{/if}
{#if translatedMessage}
<span class="shifted-icon">
<Icon xs={true} block={false}>
translate
</Icon>
</span>
{/if}
</span>

<style>
.shifted-icon :global(.material-icons) {
transform: translateY(1px);
}
</style>
41 changes: 41 additions & 0 deletions src/components/common/DropdownStore.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script lang="ts">
import type { Writable } from 'svelte/store';
import Select from 'smelte/src/components/Select';
import { getDropdownOffsetY } from '../../ts/component-utils';
type DropdownItem = { value: string, text: string } | string;
/** Dropdown label. */
export let name = '';
/** Writable store for value updates. */
export let store: Writable<string>;
/** Dropdown items. */
export let items: DropdownItem[] = [];
/** Dense variant. */
export let dense = false;
/** Parent div used to determine top/bottom */
export let boundingDiv: HTMLElement | null = null;
$: value = $store;
$: store.set(value);
let showList = false;
let div: HTMLElement;
let offsetY = '';
const onShowListChange = async (showList: boolean) => {
if (!showList || !boundingDiv) return;
offsetY = await getDropdownOffsetY(div, boundingDiv);
};
$: onShowListChange(showList);
const classes = 'dropdown-wrapper cursor-pointer relative';
$: optionsClasses = 'dropdown-options absolute left-0 bg-white rounded ' +
'shadow w-full z-20 dark:bg-dark-500 max-h-60 overflow-auto ' + offsetY;
</script>

<div bind:this={div} class={$$props.class ? $$props.class : ''}>
<Select
bind:value
bind:showList
label={name}
{items}
{classes}
{dense}
{optionsClasses}
/>
</div>
3 changes: 3 additions & 0 deletions src/components/settings/InterfaceSettings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import Radio from '../common/RadioGroupStore.svelte';
import Checkbox from '../common/CheckboxStore.svelte';
import dark from 'smelte/src/dark';
import MessageTranslationSettings from './MessageTranslationSettings.svelte';

const darkStore = dark();
$: switch ($theme) {
Expand Down Expand Up @@ -49,3 +50,5 @@
<Checkbox name="Show usernames" store={showUsernames} />
<Checkbox name="Show user badges" store={showUserBadges} />
</Card>

<MessageTranslationSettings />
51 changes: 51 additions & 0 deletions src/components/settings/MessageTranslationSettings.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script lang="ts">
import {
translateTargetLanguage
} from '../../ts/storage';
import DropdownStore from '../common/DropdownStore.svelte';
import Card from '../common/Card.svelte';
import Checkbox from '../common/CheckboxStore.svelte';
import { AvailableLanguages } from 'iframe-translator';
import { writable } from 'svelte/store';
import { onMount, tick } from 'svelte';
const enabled = writable(true);
$: if (!$enabled) {
$translateTargetLanguage = '';
}
onMount(() => {
const unsub = translateTargetLanguage.subscribe(value => {
$enabled = Boolean(value);
setTimeout(() => unsub(), 0);
});
});
const priority = [
'English',
'Japanese',
'Indonesian',
'Korean',
'Spanish',
'Russian',
'French',
'Chinese (Traditional)',
'Chinese (Simplified)'
];

async function scrollToBottom() {
await tick();
window.scrollTo(0, document.body.scrollHeight);
}
</script>

<Card title="Additional Options" icon="tune">
<span on:click={scrollToBottom}>
<Checkbox name="Translate chat messages with Google Translate" store={enabled} />
{#if $enabled}
<DropdownStore name="Target language"
store={translateTargetLanguage}
items={[
...priority,
...AvailableLanguages.filter(e => !priority.includes(e))
]} />
{/if}
</span>
</Card>
4 changes: 2 additions & 2 deletions src/scripts/chat-background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,8 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
chrome.windows.create({
url: request.url,
type: 'popup',
height: 300,
width: 600
height: 420,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

width: 690
}, () => {});
}
});
4 changes: 2 additions & 2 deletions src/ts/chat-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ export const enum Theme {

export const themeItems = [
{ value: Theme.YOUTUBE, label: 'Use YouTube theme' },
{ value: Theme.LIGHT, label: 'Force light theme' },
{ value: Theme.DARK, label: 'Force dark theme' }
{ value: Theme.LIGHT, label: 'Light theme' },
{ value: Theme.DARK, label: 'Dark theme' }
];
32 changes: 32 additions & 0 deletions src/ts/component-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { tick } from 'svelte';

interface Rect { top: number, right: number, bottom: number, left: number }

export const getRelativeRect = (element: HTMLElement, boundingElement: HTMLElement): Rect => {
const rect = element.getBoundingClientRect();
const boundingRect = boundingElement.getBoundingClientRect();
return {
top: rect.top - boundingRect.top,
right: boundingElement.clientWidth - (boundingRect.right - rect.right),
bottom: boundingElement.clientHeight - (boundingRect.bottom - rect.bottom),
left: rect.left - boundingRect.left
};
};

export const getDropdownOffsetY = async (div: HTMLElement, boundingDiv: HTMLElement): Promise<string> => {
await tick();

const wrapper = div.querySelector('.dropdown-wrapper');
const options = wrapper?.querySelector('.dropdown-options');
if (wrapper == null || options == null) {
console.error('Dropdown wrapper or options not found');
return '';
}

const relativeRect = getRelativeRect(wrapper as HTMLElement, boundingDiv);
if (relativeRect.bottom + options.clientHeight > boundingDiv.clientHeight) {
return 'bottom-12';
} else {
return 'top-12';
}
};
30 changes: 29 additions & 1 deletion src/ts/storage.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
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';

export const stores = webExtStores();

export const hcEnabled = stores.addSyncStore('hc.enabled', true);
export const translateTargetLanguage = stores.addSyncStore('hc.translateTargetLanguage', '');
export const translatorClient = readable(null as (null | IframeTranslatorClient), (set) => {
let client: IframeTranslatorClient | null = null;
const destroyIf = (): void => {
if (client !== null) {
client.destroy();
client = null;
}
set(null);
};
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const unsub = translateTargetLanguage.subscribe(async ($translateTargetLanguage) => {
if (!$translateTargetLanguage) {
destroyIf();
return;
}
if (client) return;
client = await getClient();
set(client);
});
return () => {
unsub();
destroyIf();
};
});
export const refreshScroll = writable(false);
export const theme = stores.addSyncStore('hc.theme', Theme.YOUTUBE);

export const showProfileIcons = stores.addSyncStore('hc.messages.showProfileIcons', false);
export const showUsernames = stores.addSyncStore('hc.messages.showUsernames', true);
export const showTimestamps = stores.addSyncStore('hc.messages.showTimestamps', false);
Expand Down
Loading