diff --git a/src/ext/UWContent.ts b/src/ext/UWContent.ts new file mode 100644 index 0000000..45d91e1 --- /dev/null +++ b/src/ext/UWContent.ts @@ -0,0 +1,134 @@ +import Debug from './conf/Debug'; +import ExtensionMode from '../common/enums/ExtensionMode.enum'; +import Settings from './lib/Settings'; +import ActionHandler from './lib/ActionHandler'; +import Comms from './lib/comms/Comms'; +import CommsClient from './lib/comms/CommsClient'; +import PageInfo from './lib/video-data/PageInfo'; +import Logger, { baseLoggingOptions } from './lib/Logger'; + +export default class UWContent { + pageInfo: PageInfo; + comms: CommsClient; + settings: Settings; + actionHandler: ActionHandler; + logger: Logger; + + commsHandlers: { + [x: string]: ((a: any, b?: any) => void | Promise)[] + } = { + 'get-current-zoom': [() => this.pageInfo.requestCurrentZoom()], + 'set-ar': [(message) => this.pageInfo.setAr({type: message.arg, ratio: message.customArg}, message.playing)], + 'set-alignment': [(message) => { + this.pageInfo.setVideoAlignment(message.arg, message.playing); + this.pageInfo.restoreAr(); + }], + 'set-stretch': [(message) => this.pageInfo.setStretchMode(message.arg, message.playing, message.customArg)], + 'set-keyboard': [(message) => this.pageInfo.setKeyboardShortcutsEnabled(message.arg)], + 'autoar-start': [(message) => { + if (message.enabled !== false) { + this.pageInfo.initArDetection(message.playing); + this.pageInfo.startArDetection(message.playing); + } else { + this.pageInfo.stopArDetection(message.playing); + } + }], + 'pause-processing': [(message) => this.pageInfo.pauseProcessing(message.playing)], + 'resume-processing': [(message) => this.pageInfo.resumeProcessing(message.autoArStatus, message.playing)], + 'set-zoom': [(message) => this.pageInfo.setZoom(message.arg, true, message.playing)], + 'change-zoom': [(message) => this.pageInfo.zoomStep(message.arg, message.playing)], + 'mark-player': [(message) => this.pageInfo.markPlayer(message.name, message.color)], + 'unmark-player': [() => this.pageInfo.unmarkPlayer()], + 'autoar-set-manual-tick': [(message) => this.pageInfo.setManualTick(message.arg)], + 'autoar-tick': [() => this.pageInfo.tick()], + 'set-ar-persistence': [(message) => this.pageInfo.setArPersistence(message.arg)], + } + + constructor(){ + } + + reloadSettings() { + this.logger.log('info', 'debug', 'Things happened in the popup. Will reload extension settings.'); + this.init(); + } + + async init(){ + if (Debug.debug) { + console.log("[uw::main] loading configuration ..."); + } + + // logger init is the first thing that needs to run + try { + if (!this.logger) { + + this.logger = new Logger(); + await this.logger.init(baseLoggingOptions); + + // show popup if logging to file is enabled + if (this.logger.isLoggingAllowed() && this.logger.isLoggingToFile()) { + console.info("[uw::init] Logging is allowed! Initalizing vue and UI!"); + + // CommsClient is not initiated yet, so we use static comms to send the command + Comms.sendMessage({cmd: 'show-logger'}); + } + } + } catch (e) { + console.error("logger init failed!", e) + } + + // init() is re-run any time settings change + if (this.comms) { + this.comms.destroy(); + } + if (!this.settings) { + this.settings = new Settings({ + onSettingsChanged: () => this.reloadSettings(), + logger: this.logger + }); + await this.settings.init(); + } + + this.comms = new CommsClient('content-main-port', this.logger, this.commsHandlers); + + // če smo razširitev onemogočili v nastavitvah, ne naredimo ničesar + // If extension is soft-disabled, don't do shit + + var extensionMode = this.settings.getExtensionMode(); + + this.logger.log('info', 'debug', "[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full')); + + const isSiteDisabled = extensionMode === ExtensionMode.Disabled + + if (isSiteDisabled) { + if (this.settings.getExtensionMode('@global') === ExtensionMode.Disabled) { + this.logger.log('info', 'debug', "[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED") + return; + } + } + + try { + if (this.pageInfo) { + this.logger.log('info', 'debug', '[uw.js::setup] An instance of pageInfo already exists and will be destroyed.'); + this.pageInfo.destroy(); + } + this.pageInfo = new PageInfo(this.comms, this.settings, this.logger, extensionMode, isSiteDisabled); + this.logger.log('info', 'debug', "[uw.js::setup] pageInfo initialized."); + + this.logger.log('info', 'debug', "[uw.js::setup] will try to initate ActionHandler."); + + // start action handler only if extension is enabled for this site + if (!isSiteDisabled) { + if (this.actionHandler) { + this.actionHandler.destroy(); + } + this.actionHandler = new ActionHandler(this.pageInfo); + this.actionHandler.init(); + + this.logger.log('info', 'debug', "[uw.js::setup] ActionHandler initiated."); + } + + } catch (e) { + this.logger.log('error', 'debug', "[uw::init] FAILED TO START EXTENSION. Error:", e); + } + } +} diff --git a/src/ext/UWServer.ts b/src/ext/UWServer.ts new file mode 100644 index 0000000..3653bb7 --- /dev/null +++ b/src/ext/UWServer.ts @@ -0,0 +1,307 @@ +import Debug from './conf/Debug.js'; +import BrowserDetect from './conf/BrowserDetect'; +import CommsServer from './lib/comms/CommsServer'; +import Settings from './lib/Settings'; +import Logger, { baseLoggingOptions } from './lib/Logger'; + +import { sleep } from '../common/js/utils'; + +import { browser } from 'webextension-polyfill-ts'; + +export default class UWServer { + settings: Settings; + logger: Logger; + comms: CommsServer; + + ports: any[] = []; + hasVideos: boolean; + currentSite: string = ''; + videoTabs: any; + currentTabId: number = 0; + + selectedSubitem: any = { + 'siteSettings': undefined, + 'videoSettings': undefined, + } + + + private gcTimeout: any; + uiLoggerInitialized: boolean = false; + + constructor() { + this.setup(); + } + + async setup() { + // logger is the first thing that goes up + + const loggingOptions = { + isBackgroundScript: true, + allowLogging: true, + useConfFromStorage: true, + logAll: true, + fileOptions: { + enabled: true, + }, + consoleOptions: { + enabled: true + } + }; + this.logger = new Logger(); + await this.logger.init(loggingOptions); + + this.settings = new Settings({logger: this.logger}); + await this.settings.init(); + this.comms = new CommsServer(this); + this.comms.subscribe('show-logger', async () => await this.initUiAndShowLogger()); + this.comms.subscribe('init-vue', async () => await this.initUi()); + this.comms.subscribe('uwui-vue-initialized', () => this.uiLoggerInitialized = true); + this.comms.subscribe('emit-logs', () => {}); // we don't need to do anything, this gets forwarded to UI content script as is + + browser.tabs.onActivated.addListener((m) => {this.onTabSwitched(m)}); + } + + async _promisifyTabsGet(browserObj, tabId){ + return new Promise( (resolve, reject) => { + browserObj.tabs.get(tabId, (tab) => resolve(tab)); + }); + } + + async injectCss(css, sender) { + try { + if (BrowserDetect.firefox || BrowserDetect.edge) { + browser.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); + } else if (BrowserDetect.anyChromium) { + chrome.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); + } + } catch (e) { + this.logger.log('error','debug', '[UwServer::injectCss] Error while injecting css:', {error: e, css, sender}); + } + } + async removeCss(css, sender) { + try { + browser.tabs.removeCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); + } catch (e) { + this.logger.log('error','debug', '[UwServer::injectCss] Error while removing css:', {error: e, css, sender}); + } + } + + async replaceCss(oldCss, newCss, sender) { + if (oldCss !== newCss) { + this.injectCss(newCss, sender); + this.removeCss(oldCss, sender); + } + } + + extractHostname(url){ + var hostname; + + if (!url) { + return ""; + } + + // extract hostname + if (url.indexOf("://") > -1) { //find & remove protocol (http, ftp, etc.) and get hostname + hostname = url.split('/')[2]; + } + else { + hostname = url.split('/')[0]; + } + + hostname = hostname.split(':')[0]; //find & remove port number + hostname = hostname.split('?')[0]; //find & remove "?" + + return hostname; + } + + async onTabSwitched(activeInfo){ + this.hasVideos = false; + + try { + this.currentTabId = activeInfo.tabId; // just for readability + + let tab; + if (BrowserDetect.firefox) { + tab = await browser.tabs.get(this.currentTabId); + } else if (BrowserDetect.anyChromium) { + tab = await this._promisifyTabsGet(chrome, this.currentTabId); + } + + this.currentSite = this.extractHostname(tab.url); + this.logger.log('info', 'debug', '[UwServer::onTabSwitched] user switched tab. New site:', this.currentSite); + } catch(e) { + this.logger.log('error', 'debug', '[UwServer::onTabSwitched] there was a problem getting currnet site:', e) + } + + this.selectedSubitem = { + 'siteSettings': undefined, + 'videoSettings': undefined, + } + //TODO: change extension icon based on whether there's any videos on current page + } + + registerVideo(sender) { + this.logger.log('info', 'comms', '[UWServer::registerVideo] Registering video.\nsender:', sender); + + const tabHostname = this.extractHostname(sender.tab.url); + const frameHostname = this.extractHostname(sender.url); + + // preveri za osirotele/zastarele vrednosti ter jih po potrebi izbriši + // check for orphaned/outdated values and remove them if neccessary + if (this.videoTabs[sender.tab.id]?.host != tabHostname) { + delete this.videoTabs[sender.tab.id] + } else if(this.videoTabs[sender.tab.id]?.frames[sender.frameId]?.host != frameHostname) { + delete this.videoTabs[sender.tab.id].frames[sender.frameId]; + } + + if (this.videoTabs[sender.tab.id]) { + this.videoTabs[sender.tab.id].frames[sender.frameId] = { + id: sender.frameId, + host: frameHostname, + url: sender.url, + registerTime: Date.now(), + } + } else { + this.videoTabs[sender.tab.id] = { + id: sender.tab.id, + host: tabHostname, + url: sender.tab.url, + frames: {} + }; + this.videoTabs[sender.tab.id].frames[sender.frameId] = { + id: sender.frameId, + host: frameHostname, + url: sender.url, + registerTime: Date.now(), + } + } + + this.logger.log('info', 'comms', '[UWServer::registerVideo] Video registered. current videoTabs:', this.videoTabs); + } + + unregisterVideo(sender) { + this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Unregistering video.\nsender:', sender); + if (this.videoTabs[sender.tab.id]) { + if ( Object.keys(this.videoTabs[sender.tab.id].frames).length <= 1) { + delete this.videoTabs[sender.tab.id] + } else { + if(this.videoTabs[sender.tab.id].frames[sender.frameId]) { + delete this.videoTabs[sender.tab.id].frames[sender.frameId]; + } + } + } + this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Video has been unregistered. Current videoTabs:', this.videoTabs); + } + + setSelectedTab(menu, subitem) { + this.logger.log('info', 'comms', '[UwServer::setSelectedTab] saving selected tab for', menu, ':', subitem); + this.selectedSubitem[menu] = subitem; + } + + async initUi() { + try { + if (BrowserDetect.firefox) { + await browser.tabs.executeScript({ + file: '/ext/uw-ui.js', + allFrames: true, + }); + } else if (BrowserDetect.anyChromium) { + await new Promise( resolve => + chrome.tabs.executeScript({ + file: '/ext/uw-ui.js', + allFrames: true, + }, () => resolve()) + ); + } + + } catch (e) { + this.logger.log('ERROR', 'uwbg', 'UI initialization failed. Reason:', e); + } + } + + async initUiAndShowLogger() { + // this implementation is less than optimal and very hacky, but it should work + // just fine for our use case. + this.uiLoggerInitialized = false; + + await this.initUi(); + + await new Promise( async (resolve, reject) => { + // if content script doesn't give us a response within 5 seconds, something is + // obviously wrong and we stop waiting, + + // oh and btw, resolve/reject do not break the loops, so we need to do that + // ourselves: + // https://stackoverflow.com/questions/55207256/will-resolve-in-promise-loop-break-loop-iteration + let isRejected = false; + setTimeout( async () => {isRejected = true; reject()}, 5000); + + // check whether UI has been initiated on the FE. If it was, we resolve the + // promise and off we go + while (!isRejected) { + if (this.uiLoggerInitialized) { + resolve(); + return; // remember the bit about resolve() not breaking the loop? + } + await sleep(100); + } + }) + } + + async getCurrentTab() { + return (await browser.tabs.query({active: true, currentWindow: true}))[0]; + } + + async getVideoTab() { + // friendly reminder: if current tab doesn't have a video, + // there won't be anything in this.videoTabs[this.currentTabId] + + const ctab = await this.getCurrentTab(); + + if (!ctab || !ctab.id) { + return { + host: 'INVALID SITE', + frames: [], + } + } + + if (this.videoTabs[ctab.id]) { + // if video is older than PageInfo's video rescan period (+ 4000ms of grace), + // we clean it up from videoTabs[tabId].frames array. + const ageLimit = Date.now() - this.settings.active.pageInfo.timeouts.rescan - 4000; + try { + for (const key in this.videoTabs[ctab.id].frames) { + if (this.videoTabs[ctab.id].frames[key].registerTime < ageLimit) { + delete this.videoTabs[ctab.id].frames[key]; + } + } + } catch (e) { + // something went wrong. There's prolly no frames. + return { + host: this.extractHostname(ctab.url), + frames: [], + selected: this.selectedSubitem + } + } + + return { + ...this.videoTabs[ctab.id], + host: this.extractHostname(ctab.url), + selected: this.selectedSubitem + }; + } + + // return something more or less empty if this tab doesn't have + // a video registered for it + return { + host: this.extractHostname(ctab.url), + frames: [], + selected: this.selectedSubitem + } + } + + // chrome shitiness mitigation + sendUnmarkPlayer(message) { + this.comms.sendUnmarkPlayer(message); + } +} diff --git a/src/ext/uw-bg.js b/src/ext/uw-bg.js index 1f5f0de..724ab0b 100644 --- a/src/ext/uw-bg.js +++ b/src/ext/uw-bg.js @@ -1,18 +1,9 @@ -import Debug from './conf/Debug.js'; -import BrowserDetect from './conf/BrowserDetect'; -import CommsServer from './lib/comms/CommsServer'; -import Settings from './lib/Settings'; -import Logger from './lib/Logger'; +/** + * NOTE: we cannot get rid of this js file. I tried for 30 seconds and I couldn't get + * extension to work unless I kept this part of extension out of the ts file. + */ -import { sleep } from '../common/js/utils'; - -// we need vue in bg script, so we can get vuex. -// and we need vuex so popup will be initialized -// after the first click without resorting to ugly, -// dirty hacks -import Vue from 'vue'; -import Vuex from 'vuex'; -import VuexWebExtensions from 'vuex-webextensions'; +import UWServer from './UWServer'; var BgVars = { arIsActive: true, @@ -20,315 +11,7 @@ var BgVars = { currentSite: "" } -class UWServer { - - constructor() { - this.ports = []; - this.arIsActive = true; - this.hasVideos = false; - this.currentSite = ""; - this.setup(); - - this.videoTabs = {}; - this.currentTabId = 0; - this._gctimeout = undefined; - - this.selectedSubitem = { - 'siteSettings': undefined, - 'videoSettings': undefined, - } - - this.uiLoggerInitialized = false; - } - - async setup() { - // logger is the first thing that goes up - const loggingOptions = { - isBackgroundScript: true, - allowLogging: true, - useConfFromStorage: true, - logAll: true, - fileOptions: { - enabled: true, - }, - consoleOptions: { - enabled: true - } - }; - this.logger = new Logger(); - await this.logger.init(loggingOptions); - - this.settings = new Settings({logger: this.logger}); - await this.settings.init(); - this.comms = new CommsServer(this); - this.comms.subscribe('show-logger', async () => await this.initUiAndShowLogger()); - this.comms.subscribe('init-vue', async () => await this.initUi()); - this.comms.subscribe('uwui-vue-initialized', () => this.uiLoggerInitialized = true); - this.comms.subscribe('emit-logs', () => {}); // we don't need to do anything, this gets forwarded to UI content script as is - - - if(BrowserDetect.firefox) { - browser.tabs.onActivated.addListener((m) => {this.onTabSwitched(m)}); - } else if (BrowserDetect.anyChromium) { - chrome.tabs.onActivated.addListener((m) => {this.onTabSwitched(m)}); - } - } - - async _promisifyTabsGet(browserObj, tabId){ - return new Promise( (resolve, reject) => { - browserObj.tabs.get(tabId, (tab) => resolve(tab)); - }); - } - - async injectCss(css, sender) { - try { - if (BrowserDetect.firefox || BrowserDetect.edge) { - browser.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); - } else if (BrowserDetect.anyChromium) { - chrome.tabs.insertCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); - } - } catch (e) { - this.logger.log('error','debug', '[UwServer::injectCss] Error while injecting css:', {error: e, css, sender}); - } - } - async removeCss(css, sender) { - try { - if (BrowserDetect.firefox || BrowserDetect.edge) { - browser.tabs.removeCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); - } else if (BrowserDetect.anyChromium) { - // this doesn't work currently, but hopefully chrome will get this feature in the future - chrome.tabs.removeCSS(sender.tab.id, {code: css, cssOrigin: 'user', frameId: sender.frameId}); - } - } catch (e) { - this.logger.log('error','debug', '[UwServer::injectCss] Error while removing css:', {error: e, css, sender}); - } - } - - async replaceCss(oldCss, newCss, sender) { - if (oldCss !== newCss) { - this.injectCss(newCss, sender); - this.removeCss(oldCss, sender); - } - } - - extractHostname(url){ - var hostname; - - if (!url) { - return ""; - } - - // extract hostname - if (url.indexOf("://") > -1) { //find & remove protocol (http, ftp, etc.) and get hostname - hostname = url.split('/')[2]; - } - else { - hostname = url.split('/')[0]; - } - - hostname = hostname.split(':')[0]; //find & remove port number - hostname = hostname.split('?')[0]; //find & remove "?" - - return hostname; - } - - async onTabSwitched(activeInfo){ - this.hasVideos = false; - - try { - this.currentTabId = activeInfo.tabId; // just for readability - - let tab; - if (BrowserDetect.firefox) { - tab = await browser.tabs.get(this.currentTabId); - } else if (BrowserDetect.anyChromium) { - tab = await this._promisifyTabsGet(chrome, this.currentTabId); - } - - this.currentSite = this.extractHostname(tab.url); - this.logger.log('info', 'debug', '[UwServer::onTabSwitched] user switched tab. New site:', this.currentSite); - } catch(e) { - this.logger.log('error', 'debug', '[UwServer::onTabSwitched] there was a problem getting currnet site:', e) - } - - this.selectedSubitem = { - 'siteSettings': undefined, - 'videoSettings': undefined, - } - //TODO: change extension icon based on whether there's any videos on current page - } - - registerVideo(sender) { - this.logger.log('info', 'comms', '[UWServer::registerVideo] Registering video.\nsender:', sender); - - const tabHostname = this.extractHostname(sender.tab.url); - const frameHostname = this.extractHostname(sender.url); - - // preveri za osirotele/zastarele vrednosti ter jih po potrebi izbriši - // check for orphaned/outdated values and remove them if neccessary - if (this.videoTabs[sender.tab.id]?.host != tabHostname) { - delete this.videoTabs[sender.tab.id] - } else if(this.videoTabs[sender.tab.id]?.frames[sender.frameId]?.host != frameHostname) { - delete this.videoTabs[sender.tab.id].frames[sender.frameId]; - } - - if (this.videoTabs[sender.tab.id]) { - this.videoTabs[sender.tab.id].frames[sender.frameId] = { - id: sender.frameId, - host: frameHostname, - url: sender.url, - registerTime: Date.now(), - } - } else { - this.videoTabs[sender.tab.id] = { - id: sender.tab.id, - host: tabHostname, - url: sender.tab.url, - frames: {} - }; - this.videoTabs[sender.tab.id].frames[sender.frameId] = { - id: sender.frameId, - host: frameHostname, - url: sender.url, - registerTime: Date.now(), - } - } - - this.logger.log('info', 'comms', '[UWServer::registerVideo] Video registered. current videoTabs:', this.videoTabs); - } - - unregisterVideo(sender) { - this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Unregistering video.\nsender:', sender); - if (this.videoTabs[sender.tab.id]) { - if ( Object.keys(this.videoTabs[sender.tab.id].frames).length <= 1) { - delete this.videoTabs[sender.tab.id] - } else { - if(this.videoTabs[sender.tab.id].frames[sender.frameId]) { - delete this.videoTabs[sender.tab.id].frames[sender.frameId]; - } - } - } - this.logger.log('info', 'comms', '[UwServer::unregisterVideo] Video has been unregistered. Current videoTabs:', this.videoTabs); - } - - setSelectedTab(menu, subitem) { - this.logger.log('info', 'comms', '[UwServer::setSelectedTab] saving selected tab for', menu, ':', subitem); - this.selectedSubitem[menu] = subitem; - } - - async initUi() { - try { - if (BrowserDetect.firefox) { - await browser.tabs.executeScript({ - file: '/ext/uw-ui.js', - allFrames: true, - }); - } else if (BrowserDetect.anyChromium) { - await new Promise( resolve => - chrome.tabs.executeScript({ - file: '/ext/uw-ui.js', - allFrames: true, - }, () => resolve()) - ); - } - - } catch (e) { - this.logger.log('ERROR', 'uwbg', 'UI initialization failed. Reason:', e); - } - } - - async initUiAndShowLogger() { - // this implementation is less than optimal and very hacky, but it should work - // just fine for our use case. - this.uiLoggerInitialized = false; - - await this.initUi(); - - await new Promise( async (resolve, reject) => { - // if content script doesn't give us a response within 5 seconds, something is - // obviously wrong and we stop waiting, - - // oh and btw, resolve/reject do not break the loops, so we need to do that - // ourselves: - // https://stackoverflow.com/questions/55207256/will-resolve-in-promise-loop-break-loop-iteration - let isRejected = false; - setTimeout( async () => {isRejected = true; reject()}, 5000); - - // check whether UI has been initiated on the FE. If it was, we resolve the - // promise and off we go - while (!isRejected) { - if (this.uiLoggerInitialized) { - resolve(); - return; // remember the bit about resolve() not breaking the loop? - } - await sleep(100); - } - }) - } - - async getCurrentTab() { - if (BrowserDetect.firefox) { - return (await browser.tabs.query({active: true, currentWindow: true}))[0]; - } else if (BrowserDetect.anyChromium) { - return new Promise((resolve, reject) => chrome.tabs.query({active: true, currentWindow: true}, (x) => resolve(x[0]))); - } - } - - async getVideoTab() { - // friendly reminder: if current tab doesn't have a video, - // there won't be anything in this.videoTabs[this.currentTabId] - - const ctab = await this.getCurrentTab(); - - if (!ctab || !ctab.id) { - return { - host: 'INVALID SITE', - frames: [], - } - } - - if (this.videoTabs[ctab.id]) { - // if video is older than PageInfo's video rescan period (+ 4000ms of grace), - // we clean it up from videoTabs[tabId].frames array. - const ageLimit = Date.now() - this.settings.active.pageInfo.timeouts.rescan - 4000; - try { - for (const key in this.videoTabs[ctab.id].frames) { - if (this.videoTabs[ctab.id].frames[key].registerTime < ageLimit) { - delete this.videoTabs[ctab.id].frames[key]; - } - } - } catch (e) { - // something went wrong. There's prolly no frames. - return { - host: this.extractHostname(ctab.url), - frames: [], - selected: this.selectedSubitem - } - } - - return { - ...this.videoTabs[ctab.id], - host: this.extractHostname(ctab.url), - selected: this.selectedSubitem - }; - } - - // return something more or less empty if this tab doesn't have - // a video registered for it - return { - host: this.extractHostname(ctab.url), - frames: [], - selected: this.selectedSubitem - } - } - - // chrome shitiness mitigation - sendUnmarkPlayer(message) { - this.comms.sendUnmarkPlayer(message); - } -} - -var server = new UWServer(); +const server = new UWServer(); window.sendUnmarkPlayer = (message) => { server.sendUnmarkPlayer(message) diff --git a/src/ext/uw.js b/src/ext/uw.js index 351ec0d..70d14af 100644 --- a/src/ext/uw.js +++ b/src/ext/uw.js @@ -1,13 +1,10 @@ -import Debug from './conf/Debug'; -import BrowserDetect from './conf/BrowserDetect'; -import ExtensionMode from '../common/enums/ExtensionMode.enum'; -import Settings from './lib/Settings'; -import ActionHandler from './lib/ActionHandler'; -import Comms from './lib/comms/Comms'; -import CommsClient from './lib/comms/CommsClient'; -import PageInfo from './lib/video-data/PageInfo'; -import Logger from './lib/Logger'; +/** + * NOTE: we cannot get rid of this js file. I tried for 30 seconds and I couldn't get + * extension to work unless I kept this part of extension out of the ts file. + */ +import UWContent from './UWContent'; +import BrowserDetect from './conf/BrowserDetect'; if(process.env.CHANNEL !== 'stable'){ console.warn("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n"); @@ -27,161 +24,5 @@ if (BrowserDetect.edge) { HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; } -class UW { - constructor(){ - this.pageInfo = undefined; - this.comms = undefined; - this.settings = undefined; - this.actionHandler = undefined; - this.logger = undefined; - this.uiInitiated = false; - - this.commsHandlers = { - 'get-current-zoom': [() => this.pageInfo.requestCurrentZoom()], - 'set-ar': [(message) => this.pageInfo.setAr({type: message.arg, ratio: message.customArg}, message.playing)], - 'set-alignment': [(message) => { - this.pageInfo.setVideoAlignment(message.arg, message.playing); - this.pageInfo.restoreAr(); - }], - 'set-stretch': [(message) => this.pageInfo.setStretchMode(message.arg, message.playing, message.customArg)], - 'set-keyboard': [(message) => this.pageInfo.setKeyboardShortcutsEnabled(message.arg)], - 'autoar-start': [(message) => { - if (message.enabled !== false) { - this.pageInfo.initArDetection(message.playing); - this.pageInfo.startArDetection(message.playing); - } else { - this.pageInfo.stopArDetection(message.playing); - } - }], - 'pause-processing': [(message) => this.pageInfo.pauseProcessing(message.playing)], - 'resume-processing': [(message) => this.pageInfo.resumeProcessing(message.autoArStatus, message.playing)], - 'set-zoom': [(message) => this.pageInfo.setZoom(message.arg, true, message.playing)], - 'change-zoom': [(message) => this.pageInfo.zoomStep(message.arg, message.playing)], - 'mark-player': [(message) => this.pageInfo.markPlayer(message.name, message.color)], - 'unmark-player': [() => this.pageInfo.unmarkPlayer()], - 'autoar-set-manual-tick': [(message) => this.pageInfo.setManualTick(message.arg)], - 'autoar-tick': [() => this.pageInfo.tick()], - 'set-ar-persistence': [() => this.pageInfo.setArPersistence(message.arg)], - } - } - - reloadSettings() { - this.logger.log('info', 'debug', 'Things happened in the popup. Will reload extension settings.'); - this.init(); - } - - async init(){ - if (Debug.debug) { - console.log("[uw::main] loading configuration ..."); - } - - // logger init is the first thing that needs to run - try { - if (!this.logger) { - const loggingOptions = { - isContentScript: true, - allowLogging: true, - useConfFromStorage: true, - fileOptions: { - enabled: false - }, - consoleOptions: { - "enabled": true, - "debug": true, - "init": true, - "settings": true, - "keyboard": true, - "mousemove": false, - "actionHandler": true, - "comms": true, - "playerDetect": true, - "resizer": true, - "scaler": true, - "stretcher": true, - // "videoRescan": true, - // "playerRescan": true, - "arDetect": true, - "arDetect_verbose": true - }, - allowBlacklistedOrigins: { - 'periodicPlayerCheck': false, - 'periodicVideoStyleChangeCheck': false, - 'handleMouseMove': false - } - }; - this.logger = new Logger(); - await this.logger.init(loggingOptions); - - // show popup if logging to file is enabled - if (this.logger.isLoggingAllowed() && this.logger.isLoggingToFile()) { - console.info("[uw::init] Logging is allowed! Initalizing vue and UI!"); - - // CommsClient is not initiated yet, so we use static comms to send the command - Comms.sendMessage({cmd: 'show-logger'}); - } - } - } catch (e) { - console.error("logger init failed!", e) - } - - // init() is re-run any time settings change - if (this.comms) { - this.comms.destroy(); - } - if (!this.settings) { - this.settings = new Settings({ - onSettingsChanged: () => this.reloadSettings(), - logger: this.logger - }); - await this.settings.init(); - } - - this.comms = new CommsClient('content-main-port', this.logger, this.commsHandlers); - - // če smo razširitev onemogočili v nastavitvah, ne naredimo ničesar - // If extension is soft-disabled, don't do shit - - var extensionMode = this.settings.getExtensionMode(); - - this.logger.log('info', 'debug', "[uw::init] Extension mode:" + (extensionMode < 0 ? "disabled" : extensionMode == '1' ? 'basic' : 'full')); - - const isSiteDisabled = extensionMode === ExtensionMode.Disabled - - if (isSiteDisabled) { - if (this.settings.getExtensionMode('@global') === ExtensionMode.Disabled) { - this.logger.log('info', 'debug', "[uw::init] EXTENSION DISABLED, THEREFORE WONT BE STARTED") - return; - } - } - - try { - if (this.pageInfo) { - this.logger.log('info', 'debug', '[uw.js::setup] An instance of pageInfo already exists and will be destroyed.'); - this.pageInfo.destroy(); - } - this.pageInfo = new PageInfo(this.comms, this.settings, this.logger, extensionMode, isSiteDisabled); - this.logger.log('info', 'debug', "[uw.js::setup] pageInfo initialized."); - - this.logger.log('info', 'debug', "[uw.js::setup] will try to initate ActionHandler."); - - // start action handler only if extension is enabled for this site - if (!isSiteDisabled) { - if (this.actionHandler) { - this.actionHandler.destroy(); - } - this.actionHandler = new ActionHandler(this.pageInfo); - this.actionHandler.init(); - - this.logger.log('info', 'debug', "[uw.js::setup] ActionHandler initiated."); - } - - } catch (e) { - this.logger.log('error', 'debug', "[uw::init] FAILED TO START EXTENSION. Error:", e); - } - } - - -} - -var main = new UW(); +const main = new UWContent(); main.init();