228 lines
6.4 KiB
JavaScript
228 lines
6.4 KiB
JavaScript
import Emotes from './Emotes';
|
|
import Message from './Message';
|
|
import PersistentSyncStorage from 'src/helpers/PersistentSyncStorage';
|
|
|
|
|
|
|
|
class ChatWatcher {
|
|
|
|
constructor() {
|
|
this.watchChat = this.watchChat.bind(this);
|
|
this._chatContainer = null;
|
|
this._observer = null;
|
|
this.messages = new Map();
|
|
}
|
|
|
|
init() {
|
|
|
|
return new Promise((res, rej) => {
|
|
this.getChatContainer().then(Emotes.init).then(() => {
|
|
this.addEmotePopup();
|
|
this.watchChat();
|
|
this.parsePreloadedMessages();
|
|
});
|
|
});
|
|
}
|
|
|
|
getChatContainer() {
|
|
// Parent of actual chat (children are messages)
|
|
const checkForContainer = (res, rej) => {
|
|
this._chatContainer = document.querySelector('#items.style-scope.yt-live-chat-item-list-renderer');
|
|
if(this._chatContainer !== null) {
|
|
res();
|
|
} else {
|
|
setTimeout(checkForContainer.bind(this, res, rej), 250);
|
|
}
|
|
};
|
|
return new Promise(checkForContainer);
|
|
}
|
|
|
|
parsePreloadedMessages() {
|
|
const messages = this._chatContainer.children;
|
|
|
|
for(let i = messages.length-1; i >= 0; i--) {
|
|
const node = messages[i];
|
|
if(this.isMessageNode(node)) {
|
|
const message = new Message(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
watchChat() {
|
|
console.log('Chat observer started');
|
|
this._observer = new MutationObserver(mutations => {
|
|
|
|
mutations.forEach(mutation => {
|
|
|
|
|
|
|
|
const { addedNodes, removedNodes } = mutation;
|
|
|
|
// Added nodes
|
|
if(typeof addedNodes !== 'undefined' && addedNodes.length > 0) {
|
|
for(let i = 0, length = addedNodes.length-1; i <= length; i++) {
|
|
const node = addedNodes[i];
|
|
if(this.isMessageNode(node)) {
|
|
this.onNewMessage(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Removed nodes
|
|
if(typeof removedNodes !== 'undefined' && removedNodes.length > 0) {
|
|
for(let i = 0, length = removedNodes.length-1; i <= length; i++) {
|
|
const node = removedNodes[i];
|
|
if(this.isMessageNode(node) && this.isObservedMessage(node)) {
|
|
this.onObservedMessageRemoved(node);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
this._observer.observe(this._chatContainer, {
|
|
childList: true,
|
|
attributes: false,
|
|
characterData: false,
|
|
subtree: false
|
|
});
|
|
}
|
|
|
|
onNewMessage(node) {
|
|
const message = new Message(node);
|
|
|
|
// Don't store message if has 0 emotes
|
|
if(message.hasEmotes) {
|
|
this.messages.set(message.id, message);
|
|
}
|
|
}
|
|
|
|
onObservedMessageRemoved(node) {
|
|
const messageId = node.getAttribute('message-id');
|
|
const message = this.messages.get(messageId);
|
|
if(message != undefined){
|
|
message.destroy();
|
|
}
|
|
|
|
this.messages.delete(messageId);
|
|
}
|
|
|
|
isMessageNode(node) {
|
|
return node.tagName === 'YT-LIVE-CHAT-TEXT-MESSAGE-RENDERER';
|
|
}
|
|
|
|
isObservedMessage(node) {
|
|
return node.getAttribute('message-id') !== null;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
addEmotePopup(){
|
|
|
|
// create emote button
|
|
const emoteButton = document.createElement('button');
|
|
emoteButton.classList.add('emoteButton');
|
|
emoteButton.textContent = '';
|
|
|
|
// append button to action-buttons list
|
|
const chatButtonSelectionList = document.getElementById('action-buttons');
|
|
chatButtonSelectionList.parentNode.insertBefore(emoteButton, chatButtonSelectionList);
|
|
|
|
// create popupDiv
|
|
const popUpDiv = document.createElement('div');
|
|
popUpDiv.classList.add('popup');
|
|
popUpDiv.classList.add('hideElement');
|
|
|
|
function emoteAppend(keysITer){
|
|
|
|
// create divider
|
|
var hr = document.createElement('hr');
|
|
hr.classList.add('emoteDivider');
|
|
|
|
for (let index = 0; index < keysITer.length; index++) {
|
|
const element = keysITer[index];
|
|
var emote_div = document.createElement('emote_div');
|
|
emote_div.innerHTML = (Emotes.get(element).html);
|
|
popUpDiv.appendChild(emote_div);
|
|
}
|
|
popUpDiv.appendChild(hr);
|
|
}
|
|
|
|
// create text
|
|
var bttv_text = document.createElement('h2');
|
|
bttv_text.textContent = "BTTV";
|
|
bttv_text.classList.add('emotePopUpText');
|
|
var franker_text = document.createElement('h2');
|
|
franker_text.textContent = "FrankerFacez";
|
|
franker_text.classList.add('emotePopUpText');
|
|
var twitch_text = document.createElement('h2');
|
|
twitch_text.textContent = "Twitch";
|
|
twitch_text.classList.add('emotePopUpText');
|
|
|
|
|
|
|
|
// need ittr to search each dict and append to dom
|
|
let keysITer = null;
|
|
|
|
keysITer = Array.from(Emotes.specialEmotesDictionary.keys());
|
|
emoteAppend(keysITer);
|
|
|
|
if(PersistentSyncStorage.data.options.enableBTTVEmotes){
|
|
popUpDiv.appendChild(bttv_text);
|
|
keysITer = Array.from(Emotes.bttv_Dictionary.keys());
|
|
emoteAppend(keysITer);
|
|
}
|
|
|
|
if(PersistentSyncStorage.data.options.enableFrankerEmotes){
|
|
popUpDiv.appendChild(franker_text);
|
|
keysITer = Array.from(Emotes.franker_Dictionary.keys());
|
|
emoteAppend(keysITer);
|
|
}
|
|
|
|
if(PersistentSyncStorage.data.options.enableTwitchEmotes){
|
|
popUpDiv.appendChild(twitch_text);
|
|
keysITer = Array.from(Emotes.twitch_Dictionary.keys());
|
|
emoteAppend(keysITer);
|
|
}
|
|
|
|
|
|
|
|
// add div to doc
|
|
chatButtonSelectionList.appendChild(popUpDiv);
|
|
|
|
// listen for popup button
|
|
emoteButton.addEventListener('click', function(){
|
|
popUpDiv.classList.toggle('hideElement');
|
|
console.log('emote popup button clicked');
|
|
});
|
|
|
|
// get input area
|
|
var inputArea = document.querySelector('#input.yt-live-chat-text-input-field-renderer');
|
|
var inputAreaLabel = document.querySelector('#label.yt-live-chat-text-input-field-renderer');
|
|
|
|
// add alt tag to chat
|
|
function emoteToTextArea(){
|
|
inputArea.textContent += this.alt + " ";
|
|
inputArea.focus();
|
|
inputAreaLabel.textContent = "";
|
|
popUpDiv.classList.toggle('hideElement');
|
|
console.log(this.alt + " emote button selected");
|
|
}
|
|
|
|
// listener button for emotes
|
|
var EMOTICONS = document.getElementsByTagName('img');
|
|
for (let index = 0; index < EMOTICONS.length; index++) {
|
|
const element = EMOTICONS[index];
|
|
element.addEventListener('click', emoteToTextArea, false);
|
|
}
|
|
|
|
console.log((keysITer.length+1) + " Emotes Added");
|
|
}// end addEmotePopup
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
}// end chat watcher
|
|
|
|
export default ChatWatcher;
|