Skip to content

Commit

Permalink
Reinstate the EventAPI (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnatoleAM authored Sep 18, 2021
1 parent 71cef26 commit 494e9ac
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 34 deletions.
112 changes: 90 additions & 22 deletions src/Background/Background.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
// YouTube Upgrade Popup
chrome.runtime.onInstalled.addListener(() => {
chrome.permissions.contains({
origins: ['*://*.youtube.com/*']
}, granted => {
if (granted) {
return undefined;
}
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { EventAPI } from 'src/Global/Events/EventAPI';

chrome.storage.local.get(items => {
if (items.yt_permissions_requested) {
const activeTabs = new Map<number, TabWithChannels>();
const eventAPI = new EventAPI();

{
// YouTube Upgrade Popup
chrome.runtime.onInstalled.addListener(() => {
chrome.permissions.contains({
origins: ['*://*.youtube.com/*']
}, granted => {
if (granted) {
return undefined;
}

chrome.windows.create({
url: 'yt_upgrade/yt_upgrade.html',
width: 800,
height: 700,
focused: true,
type: 'popup'
}, () => {
chrome.storage.local.set({ yt_permissions_requested: true });
chrome.storage.local.get(items => {
if (items.yt_permissions_requested) {
return undefined;
}

chrome.windows.create({
url: 'yt_upgrade/yt_upgrade.html',
width: 800,
height: 700,
focused: true,
type: 'popup'
}, () => {
chrome.storage.local.set({ yt_permissions_requested: true });
});
});
});
});
});
}

// Run YouTube Content Script
const activeTabs = new Map<number, chrome.tabs.Tab>();
// Run YouTube Content Script & Handle tabs
chrome.tabs.onUpdated.addListener((tabId, i, t) => {
if (!i.status || !t.url) {
return undefined;
}
activeTabs.set(tabId, t);
if (!activeTabs.has(tabId)) {
activeTabs.set(tabId, {
...t,
eventAPI: {
channel: '',
subscriber: null
}
});
}

const loc = new URL(t.url);
if (ytHostnameRegex.test(loc.host)) {
Expand All @@ -41,7 +57,59 @@ chrome.tabs.onUpdated.addListener((tabId, i, t) => {
}
});
chrome.tabs.onRemoved.addListener(tabId => {
const t = activeTabs.get(tabId);
if (!!t && t.eventAPI) {
t.eventAPI.subscriber?.unsubscribe();
eventAPI.removeChannel(t.eventAPI.channel);
}

activeTabs.delete(tabId);
});
const ytHostnameRegex = /([a-z0-9]+[.])*youtube[.]com/;

// Event API
{
chrome.runtime.onMessage.addListener(({ name, channelName }, { tab }) => {
if (!name?.startsWith('EVENTAPI:')) {
return undefined;
}

// Get active tab
const t = activeTabs.get(tab?.id as number);
if (!t) {
return undefined;
}
if (t.eventAPI.subscriber && !t.eventAPI.subscriber.closed) {
t.eventAPI.subscriber.unsubscribe();
}

if (name === 'EVENTAPI:REMOVE_CHANNEL') {
if (t.eventAPI.channel) {
eventAPI.removeChannel(t.eventAPI.channel);
}

return undefined;
}
// Add the channel to state.
// Also add it to the tab's channel list so it can be cleared
// oncce the tab is closed.
t.eventAPI.channel = channelName;
t.eventAPI.subscriber = eventAPI.emoteEvent.pipe(
filter(({ channel }) => channel === channelName)
).subscribe({
next(event) {
chrome.tabs.sendMessage(t.id as number, { name: 'EVENTAPI:EMOTE_EVENT', event });
}
});

eventAPI.addChannel(channelName);
activeTabs.set(t.id as number, t);
});
}

interface TabWithChannels extends chrome.tabs.Tab {
eventAPI: {
channel: string;
subscriber: Subscription | null;
};
}
18 changes: 18 additions & 0 deletions src/Content/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export class App {
settings.change.subscribe({
next: change => this.sendMessageDown('ConfigChange', change)
});

chrome.runtime.onMessage.addListener(({ name, event }) => {
if (name !== 'EVENTAPI:EMOTE_EVENT') {
return undefined;
}

this.sendMessageDown('ChannelEmoteUpdate', event);
});
}

passExtensionData(): void {
Expand All @@ -34,6 +42,16 @@ export class App {
settings.apply({ [data.key]: data.value });
}

@PageScriptListener('EventAPI:AddChannel')
addChannelToEventAPISubscriptions(channelName: string): void {
chrome.runtime.sendMessage({ name: 'EVENTAPI:ADD_CHANNEL', channelName });
}

@PageScriptListener('EventAPI:RemoveChannel')
removehannelFromEventAPISubscriptions(): void {
chrome.runtime.sendMessage({ name: 'EVENTAPI:REMOVE_CHANNEL' });
}

/**
* Send a message to the page script layer
*
Expand Down
16 changes: 5 additions & 11 deletions src/Global/Events/EventAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DataStructure } from '@typings/typings/DataStructure';
import { Subject } from 'rxjs';
import { Config } from 'src/Config';
import { broadcastExtensionMessage, ExtensionRuntimeMessage, getRunningContext } from 'src/Global/Util';
import { getRunningContext } from 'src/Global/Util';
import { Logger } from 'src/Logger';
import { version } from 'public/manifest.v3.json';

Expand All @@ -13,15 +13,7 @@ export class EventAPI {

emoteEvent = new Subject<EventAPI.EmoteEventUpdate>();

constructor() {
if (this.ctx === 'content') {
chrome.runtime.onMessage.addListener((msg: ExtensionRuntimeMessage) => {
if (msg.tag === 'EventAPI:Message/ChannelEmotes') {
this.emoteEvent.next(msg.data);
}
});
}
}
constructor() {}

/**
* Create a connection to the Event API
Expand Down Expand Up @@ -82,7 +74,7 @@ export class EventAPI {
return undefined;
}

broadcastExtensionMessage('EventAPI:Message/ChannelEmotes', data, undefined);
this.emoteEvent.next(data);
}

/**
Expand All @@ -105,6 +97,7 @@ export class EventAPI {
// Add to list & connect
this.channels.add(channelName);
this.connect();
Logger.Get().info(`<EVENTS> Added channel: ${channelName}`);
}
}

Expand All @@ -119,6 +112,7 @@ export class EventAPI {
removeChannel(channelName: string): void {
if (this.ctx === 'background') {
this.channels.delete(channelName);
Logger.Get().info(`<EVENTS> Removed channel: ${channelName}`);

// User must have at least one channel left to reconnect
if (this.channels.size > 0) {
Expand Down
47 changes: 46 additions & 1 deletion src/Sites/twitch.tv/twitch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AvatarManager } from 'src/Sites/twitch.tv/Runtime/Avatars';
import { SiteApp } from 'src/Sites/app/SiteApp';
import { map } from 'rxjs/operators';
import { MessagePatcher } from 'src/Sites/twitch.tv/Util/MessagePatcher';
import type { EventAPI } from 'src/Global/Events/EventAPI';

export class TwitchPageScript {
site = new SiteApp();
Expand Down Expand Up @@ -82,6 +83,7 @@ export class TwitchPageScript {
inputManager.listen();
this.isActorVIP = controller.props.isCurrentUserVIP;
this.isActorModerator = controller.props.isCurrentUserModerator;
this.site.sendMessageUp('EventAPI:AddChannel', login);
});
};

Expand All @@ -98,9 +100,13 @@ export class TwitchPageScript {
setInterval(async () => {
let channelName = this.getCurrentChannelFromURL();
if (channelName !== this.currentChannel) {
this.currentChannel = channelName;
Logger.Get().info(`Changing channel from ${this.currentChannel} to ${channelName}`);
this.currentChannel = channelName;
controller = await this.awaitChatController();

// Unsubscribe from events in previous channel
this.site.sendMessageUp('EventAPI:RemoveChannel', {});

this.currentChannelSet = null;
channelName = controller.props.channelLogin;
channelID = controller.props.channelID;
Expand Down Expand Up @@ -189,6 +195,45 @@ export class TwitchPageScript {
}
}

@PageScriptListener('ChannelEmoteUpdate')
whenEventAPISendsAnEventAboutChannelEmotesChanging(event: EventAPI.EmoteEventUpdate): void {
const action = event.action;
const set = page.site.emoteStore.sets.get(page.site.currentChannel);
if (!set) {
return;
}
if (event.channel !== page.currentChannel) {
return;
}

switch (action) {
case 'ADD':
page.chatListener.sendSystemMessage(`${event.actor} added the emote "${event.emote.name}"`);
set.push([{ ...event.emote, id: event.emote_id }], false);
break;
case 'REMOVE':
page.chatListener.sendSystemMessage(`${event.actor} removed the emote "${event.name}"`);
set.deleteEmote(event.emote_id);
break;
case 'UPDATE':
const emote = set.getEmoteByID(event.emote_id);
if (!emote) {
break;
}
const oldName = String(emote.name);

emote.setName(event.name);
set.deleteEmote(event.emote_id);
set.push([emote.resolve()], false);
page.chatListener.sendSystemMessage(`${event.actor} renamed the emote "${oldName}" to "${event.name}"`);
break;
default:
break;
}

page.site.tabCompleteDetector?.updateEmotes();
}

}

let page: TwitchPageScript;
Expand Down

0 comments on commit 494e9ac

Please sign in to comment.