Merge branch 'master' into stable

This commit is contained in:
Tamius Han 2020-03-09 22:08:20 +01:00
commit ce6a22d31b
16 changed files with 439 additions and 226 deletions

View File

@ -16,6 +16,7 @@
"resizer",
"textbox",
"videodata",
"vuex",
"youtube"
],
"cSpell.ignoreWords": [

View File

@ -13,7 +13,14 @@ QoL improvements for me:
* logging: allow to enable logging at will and export said logs to a file
### v4.4.5 (current)
### v4.4.6 (current)
* Ensured that Vue part of the content script (logger UI) only loads when necessary in order to fix breakage on certain sites (#96).
* Disabling (or enabling, if running in whitelist-only mode) specific sites used to not work (#91). This issue appears to have been fixed.
* Default stretch mode for sites is now probably being observed, too (#94).
* It's been almost a month and Chrome Web Store still hasn't finished the review of the 4.4.4.1 (and 4.4.4.2) revisions because when it comes to incompetence, it's hard to expect anything less from Google. I've did some proverbial yelling at the support in hopes that Chrome version will finally see an update (disclaimer: when I said yelling I really mean a polite request, because support staff doesn't deserve abuse because a different department is utter shite at doing their jobs).
### v4.4.5
* Extension no longer requires `allTabs` and `webNavigation` permissions
* Some CSS on the debugger popup was not scoped, causing issues with some sites.

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "ultravidify",
"version": "4.4.5",
"version": "4.4.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "ultravidify",
"version": "4.4.5",
"version": "4.4.6",
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
"author": "Tamius Han <tamius.han@gmail.com>",
"scripts": {

View File

@ -156,7 +156,6 @@ class Settings {
try {
updateFn(this.active, this.getDefaultSettings());
} catch (e) {
console.log("!!!!", e)
this.logger.log('error', 'settings', '[Settings::applySettingsPatches] Failed to execute update function. Keeping settings object as-is. Error:', e);
}
}

View File

@ -5,7 +5,7 @@ import EdgeStatus from './edge-detect/enums/EdgeStatusEnum';
import EdgeDetectPrimaryDirection from './edge-detect/enums/EdgeDetectPrimaryDirectionEnum';
import EdgeDetectQuality from './edge-detect/enums/EdgeDetectQualityEnum';
import GuardLine from './GuardLine';
import DebugCanvas from './DebugCanvas';
// import DebugCanvas from './DebugCanvas';
import VideoAlignment from '../../../common/enums/video-alignment.enum';
import AspectRatio from '../../../common/enums/aspect-ratio.enum';

View File

@ -2,15 +2,13 @@ import Debug from '../../conf/Debug';
import BrowserDetect from '../../conf/BrowserDetect';
class CommsClient {
constructor(name, settings, logger) {
constructor(name, logger, commands) {
this.logger = logger;
if (BrowserDetect.firefox) {
this.port = browser.runtime.connect({name: name});
} else if (BrowserDetect.chrome) {
this.port = chrome.runtime.connect({name: name});
} else if (BrowserDetect.edge) {
this.port = browser.runtime.connect({name: name})
}
this.logger.onLogEnd(
@ -24,46 +22,15 @@ class CommsClient {
}
);
var ths = this;
this._listener = m => ths.processReceivedMessage(m);
this._listener = m => this.processReceivedMessage(m);
this.port.onMessage.addListener(this._listener);
this.settings = settings;
this.pageInfo = undefined;
this.commsId = (Math.random() * 20).toFixed(0);
this.commands = {
'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)],
};
this.commands = commands;
}
destroy() {
this.pageInfo = null;
this.settings = null;
if (!BrowserDetect.edge) { // edge is a very special browser made by outright morons.
this.port.onMessage.removeListener(this._listener);
}
@ -77,32 +44,9 @@ class CommsClient {
}
}
setPageInfo(pageInfo){
this.pageInfo = pageInfo;
this.logger.log('info', 'debug', `[CommsClient::setPageInfo] <${this.commsId}>`, "setting pageinfo");
var ths = this;
this._listener = m => ths.processReceivedMessage(m);
if (!BrowserDetect.edge) {
this.port.onMessage.removeListener(this._listener);
}
this.port.onMessage.addListener(this._listener);
}
processReceivedMessage(message){
this.logger.log('info', 'comms', `[CommsClient.js::processMessage] <${this.commsId}> Received message from background script!`, message);
if (!this.pageInfo || !this.settings.active) {
this.logger.log('info', 'comms', `[CommsClient.js::processMessage] <${this.commsId}> this.pageInfo (or settings) not defined. Extension is probably disabled for this site.\npageInfo:`, this.pageInfo,
"\nsettings.active:", this.settings.active,
"\nnobj:", this
);
return;
}
if (this.commands[message.cmd]) {
for (const c of this.commands[message.cmd]) {
c(message);
@ -110,10 +54,6 @@ class CommsClient {
}
}
async sleep(n){
return new Promise( (resolve, reject) => setTimeout(resolve, n) );
}
async sendMessage_nonpersistent(message){
message = JSON.parse(JSON.stringify(message)); // vue quirk. We should really use vue store instead
@ -165,13 +105,7 @@ class CommsClient {
registerVideo(){
this.logger.log('info', 'comms', `[CommsClient::registerVideo] <${this.commsId}>`, "Registering video for current page.");
if (this.pageInfo) {
if (this.pageInfo.hasVideo()) {
this.port.postMessage({cmd: "has-video"});
}
} else {
// this.port.postMessage({cmd: "has-video"});
}
this.port.postMessage({cmd: "has-video"});
}
sendPerformanceUpdate(message){
@ -185,7 +119,7 @@ class CommsClient {
announceZoom(scale){
this.port.postMessage({cmd: "announce-zoom", zoom: scale});
this.registerVideo()
this.registerVideo();
}

View File

@ -9,14 +9,12 @@ class CommsServer {
this.ports = [];
this.popupPort = null;
var ths = this;
if (BrowserDetect.firefox) {
browser.runtime.onConnect.addListener(p => ths.onConnect(p));
browser.runtime.onMessage.addListener((m, sender) => ths.processReceivedMessage_nonpersistent(m, sender));
browser.runtime.onConnect.addListener(p => this.onConnect(p));
browser.runtime.onMessage.addListener((m, sender) => this.processReceivedMessage_nonpersistent(m, sender));
} else {
chrome.runtime.onConnect.addListener(p => ths.onConnect(p));
chrome.runtime.onMessage.addListener((m, sender, callback) => ths.processReceivedMessage_nonpersistent(m, sender, callback));
chrome.runtime.onConnect.addListener(p => this.onConnect(p));
chrome.runtime.onMessage.addListener((m, sender, callback) => this.processReceivedMessage_nonpersistent(m, sender, callback));
}
// commands — functions that handle incoming messages
@ -133,6 +131,14 @@ class CommsServer {
}
}
subscribe(command, callback) {
if (!this.commands[command]) {
this.commands[command] = [callback];
} else {
this.commands[command].push(callback);
}
}
async getCurrentTabHostname() {
const activeTab = await this._getActiveTab();
@ -158,9 +164,11 @@ class CommsServer {
}
sendToAll(message){
for(var p of this.ports){
for(var frame in p){
p[frame].postMessage(message);
for(const tab of this.ports){
for(const frame in tab){
for (const port in tab[frame]) {
tab[frame][port].postMessage(message);
}
}
}
}
@ -178,6 +186,12 @@ class CommsServer {
}
}
async sendToContentScripts(message, tab, frame) {
for (const port in this.ports[tab][frame]) {
this.ports[tab][frame][port].postMessage(message);
}
}
async sendToFrame(message, tab, frame) {
this.logger.log('info', 'comms', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
@ -196,7 +210,7 @@ class CommsServer {
this.logger.log('info', 'comms', `%c[CommsServer::sendToFrame] attempting to send message to tab ${tab}, frame ${frame}`, "background: #dda; color: #11D", message);
try {
this.ports[tab][frame].postMessage(message);
this.sendToContentScripts(message, tab, frame);
} catch (e) {
this.logger.log('error', 'comms', `%c[CommsServer::sendToFrame] Sending message failed. Reason:`, "background: #dda; color: #11D", e);
}
@ -205,73 +219,85 @@ class CommsServer {
async sendToActive(message) {
this.logger.log('info', 'comms', "%c[CommsServer::sendToActive] trying to send a message to active tab. Message:", "background: #dda; color: #11D", message);
var tabs = await this._getActiveTab();
const tabs = await this._getActiveTab();
this.logger.log('info', 'comms', "[CommsServer::_sendToActive] currently active tab(s)?", tabs);
for (var key in this.ports[tabs[0].id]) {
this.logger.log('info', 'comms', "key?", key, this.ports[tabs[0].id]);
for (const frame in this.ports[tabs[0].id]) {
this.logger.log('info', 'comms', "key?", frame, this.ports[tabs[0].id]);
}
for (var key in this.ports[tabs[0].id]) {
this.ports[tabs[0].id][key].postMessage(message);
for (const frame in this.ports[tabs[0].id]) {
this.sendToContentScripts(message, tabs[0].id, frame);
}
}
onConnect(port){
var ths = this;
// poseben primer | special case
if (port.name === 'popup-port') {
this.popupPort = port;
this.popupPort.onMessage.addListener( (m,p) => ths.processReceivedMessage(m,p));
this.popupPort.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
return;
}
var tabId = port.sender.tab.id;
var frameId = port.sender.frameId;
if(! this.ports[tabId]){
if (! this.ports[tabId]){
this.ports[tabId] = {};
}
this.ports[tabId][frameId] = port;
this.ports[tabId][frameId].onMessage.addListener( (m,p) => ths.processReceivedMessage(m, p));
this.ports[tabId][frameId].onDisconnect.addListener( (p) => {
delete ths.ports[p.sender.tab.id][p.sender.frameId];
if(Object.keys(ths.ports[p.sender.tab.id]).length === 0){
ths.ports[tabId] = undefined;
if (! this.ports[tabId][frameId]) {
this.ports[tabId][frameId] = {};
}
this.ports[tabId][frameId][port.name] = port;
this.ports[tabId][frameId][port.name].onMessage.addListener( (m,p) => this.processReceivedMessage(m, p));
this.ports[tabId][frameId][port.name].onDisconnect.addListener( (p) => {
try {
delete this.ports[p.sender.tab.id][p.sender.frameId][port.name];
} catch (e) {
// no biggie if the thing above doesn't exist.
}
if (Object.keys(this.ports[tabId][frameId].length === 0)) {
delete this.ports[tabId][frameId];
if(Object.keys(this.ports[p.sender.tab.id]).length === 0) {
delete this.ports[tabId];
}
}
});
}
execCmd(message, portOrSender, sendResponse) {
async execCmd(message, portOrSender, sendResponse) {
this.logger.log(
'info', 'comms', '[CommsServer.js::execCmd] Received message', message,
". Port/sender:", portOrSender, "sendResponse:", sendResponse, "\nThere is ", this.commands[message.cmd]?.length ?? 0,
" command(s) for action", message.cmd
);
for (const c of this.commands[message.cmd]) {
c(message, portOrSender, sendResponse);
if (this.commands[message.cmd]) {
for (const c of this.commands[message.cmd]) {
try {
await c(message, portOrSender, sendResponse);
} catch (e) {
this.logger.log('error', 'debug', "[CommsServer.js::execCmd] failed to execute command.", e)
}
}
}
}
handleMessage(message, portOrSender, sendResponse) {
async handleMessage(message, portOrSender, sendResponse) {
await this.execCmd(message, portOrSender, sendResponse);
if (message.forwardToContentScript) {
this.logger.log('info', 'comms', "[CommsServer.js::processReceivedMessage] Message has 'forward to content script' flag set. Forwarding message as is. Message:", message);
this.sendToFrame(message, message.targetTab, message.targetFrame);
return;
}
if (message.forwardToAll) {
this.logger.log('info', 'comms', "[CommsServer.js::processReceivedMessage] Message has 'forward to all' flag set. Forwarding message as is. Message:", message);
this.sendToAll(message);
return;
}
if (message.forwardToActive) {
this.logger.log('info', 'comms', "[CommsServer.js::processReceivedMessage] Message has 'forward to active' flag set. Forwarding message as is. Message:", message);
this.sendToActive(message);
return;
}
this.execCmd(message, portOrSender, sendResponse);
}
async processReceivedMessage(message, port){

View File

@ -40,7 +40,7 @@ class PageInfo {
}
// try getting default crop immediately.
const cropModePersistence = this.settings.getDefaultCropPersistenceMode(window.location.host);
// const cropModePersistence = this.settings.getDefaultCropPersistenceMode(window.location.host);
// try {
// if (cropModePersistence === CropModePersistence.Forever) {

View File

@ -4,6 +4,16 @@ import CommsServer from './lib/comms/CommsServer';
import Settings from './lib/Settings';
import Logger from './lib/Logger';
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';
var BgVars = {
arIsActive: true,
hasVideos: false,
@ -27,6 +37,8 @@ class UWServer {
'siteSettings': undefined,
'videoSettings': undefined,
}
this.uiLoggerInitialized = false;
}
async setup() {
@ -49,12 +61,15 @@ class UWServer {
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);
var ths = this;
if(BrowserDetect.firefox) {
browser.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
browser.tabs.onActivated.addListener(function(m) {this.onTabSwitched(m)});
} else if (BrowserDetect.chrome) {
chrome.tabs.onActivated.addListener(function(m) {ths.onTabSwitched(m)});
chrome.tabs.onActivated.addListener(function(m) {this.onTabSwitched(m)});
}
}
@ -98,6 +113,10 @@ class UWServer {
extractHostname(url){
var hostname;
if (!url) {
return "<no url>";
}
// extract hostname
if (url.indexOf("://") > -1) { //find & remove protocol (http, ftp, etc.) and get hostname
hostname = url.split('/')[2];
@ -198,6 +217,56 @@ class UWServer {
this.selectedSubitem[menu] = subitem;
}
async initUi() {
try {
if (BrowserDetect.firefox) {
await browser.tabs.executeScript({
file: '/ext/uw-ui.js',
allFrames: true,
});
} else if (BrowserDetect.chrome) {
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];
@ -212,8 +281,6 @@ class UWServer {
const ctab = await this.getCurrentTab();
console.log('Current tab:', ctab);
if (!ctab || !ctab.id) {
return {
host: 'INVALID SITE',

233
src/ext/uw-ui.js Normal file
View File

@ -0,0 +1,233 @@
// vue dependency imports
import Vue from 'vue';
import Vuex from 'vuex';
import VuexWebExtensions from 'vuex-webextensions';
import LoggerUi from '../csui/LoggerUi';
// extension classes
import Logger from './lib/Logger';
import Settings from './lib/Settings';
import CommsClient from './lib/comms/CommsClient';
import Comms from './lib/comms/Comms';
class UwUi {
constructor() {
this.vueInitiated = false;
this.loggerUiInitiated = false;
this.playerUiInitiated = false;
this.vuexStore = null;
this.commsHandlers = {
'show-logger': [() => this.showLogger()],
'hide-logger': [() => this.hideLogger()],
}
}
async init() {
// IMPORTANT NOTICE — we do not check for whether extension is enabled or not,
// since this script only gets executed either:
// * as a direct result of user action (logger UI)
// * if video/player is detected (which can only happen if extension is enabled
// for that particular site)
// NOTE: we need to setup logger and comms _before_ initializing vue (unless we're starting)
// because logger settings say we should
// setup logger
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);
if (this.logger.isLoggingAllowed()) {
console.info("[uw::init] Logging is allowed! Initalizing vue and UI!");
this.initVue();
this.initLoggerUi();
this.logger.setVuexStore(this.vuexStore);
}
// show popup if logging to file is enabled
if (this.logger.isLoggingToFile()) {
console.info('[uw::init] Logging to file is enabled. Will show popup!');
try {
this.vuexStore.dispatch('uw-show-logger');
} catch (e) {
console.error('[uw::init] Failed to open popup!', e)
}
}
}
} catch (e) {
console.error("logger initialization failed. Error:", e);
}
// we also need to know settings (there's UI-related things in the settings — or rather, there will be UI-related things
// in settings once in-player UI is implemented
// If comms exist, we need to destroy it
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-ui-port', this.logger, this.commsHandlers);
// initialize vuejs, but only once (check handled in initVue())
// we need to initialize this _after_ initializing comms.
this.initVue();
}
initVue() {
// never init twice
if (this.vueInitiated) {
// let background script know it can proceed with sending 'show-logger' command.
Comms.sendMessage({cmd: 'uwui-vue-initialized'});
return;
}
Vue.prototype.$browser = global.browser;
Vue.use(Vuex);
this.vuexStore = new Vuex.Store({
plugins: [VuexWebExtensions({
persistentStates: [
'uwLog',
'showLogger',
],
})],
state: {
uwLog: '',
showLogger: false,
},
mutations: {
'uw-set-log'(state, payload) {
state['uwLog'] = payload;
},
'uw-show-logger'(state) {
state['showLogger'] = true;
},
'uw-hide-logger'(state) {
state['showLogger'] = false;
}
},
actions: {
'uw-set-log' ({commit}, payload) {
commit('uw-set-log', payload);
},
'uw-show-logger'({commit}) {
commit('uw-show-logger');
},
'uw-hide-logger'({commit}) {
commit('uw-hide-logger');
}
}
});
// make sure we don't init twice
this.vueInitiated = true;
// let background script know it can proceed with sending 'show-logger' command.
Comms.sendMessage({cmd: 'uwui-vue-initialized'});
}
async initLoggerUi() {
const random = Math.round(Math.random() * 69420);
const uwid = `uw-ui-root-${random}`;
const rootDiv = document.createElement('div');
rootDiv.setAttribute("style", "position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; background-color: #ff0000;");
rootDiv.setAttribute("id", uwid);
document.body.appendChild(rootDiv);
try {
new Vue({
el: `#${uwid}`,
components: {
LoggerUi: LoggerUi
},
store: this.vuexStore,
render(h) {
return h('logger-ui');
}
});
} catch (e) {
console.error("Error while initiating vue:", e)
}
this.loggerUiInitiated = true;
}
async showLogger() {
if (!this.loggerUiInitiated) {
await this.initLoggerUi();
}
try {
this.vuexStore.dispatch('uw-show-logger');
} catch (e) {
console.error('Failed to dispatch vuex store', e)
}
}
hideLogger() {
if (this.vueInitiated && this.vuexStore !== undefined) {
this.vuexStore.dispatch('uw-hide-logger');
}
}
}
// leave a mark, so this script won't get executed more than once on a given page
const markerId = 'ultrawidify-marker-5aeaf521-7afe-447f-9a17-3428f62d0970';
// if this script has already been executed, don't execute it again.
if (! document.getElementById(markerId)) {
const markerDiv = document.createElement('div');
markerDiv.setAttribute("style", "display: none");
markerDiv.setAttribute('id', markerId);
document.body.appendChild(markerDiv);
const uwui = new UwUi();
uwui.init();
} else {
// let background script know it can proceed with sending 'show-logger' command.
Comms.sendMessage({cmd: 'uwui-vue-initialized'});
}

View File

@ -7,13 +7,6 @@ import CommsClient from './lib/comms/CommsClient';
import PageInfo from './lib/video-data/PageInfo';
import Logger from './lib/Logger';
// vue dependency imports
import Vue from 'vue';
import Vuex from 'vuex';
import VuexWebExtensions from 'vuex-webextensions';
global.browser = require('webextension-polyfill');
import LoggerUi from '../csui/LoggerUi';
if(Debug.debug){
console.log("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀɪɪʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
@ -40,9 +33,35 @@ class UW {
this.settings = undefined;
this.actionHandler = undefined;
this.logger = undefined;
this.vuexStore = {};
this.uiInitiated = false;
this.vueInitiated = 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() {
@ -94,9 +113,6 @@ class UW {
if (this.logger.isLoggingAllowed()) {
console.info("[uw::init] Logging is allowed! Initalizing vue and UI!");
this.initVue();
this.initUi();
this.logger.setVuexStore(this.vuexStore);
}
// show popup if logging to file is enabled
@ -114,17 +130,10 @@ class UW {
}
// init() is re-run any time settings change
if (this.pageInfo) {
// if this executes, logger must have been initiated at some point before this point
this.logger.log('info', 'debug', "[uw::init] Destroying existing pageInfo", this.pageInfo);
this.pageInfo.destroy();
}
if (this.comms) {
this.comms.destroy();
}
if (!this.settings) {
var ths = this;
this.settings = new Settings({
onSettingsChanged: () => this.reloadSettings(),
logger: this.logger
@ -132,12 +141,8 @@ class UW {
await this.settings.init();
}
this.comms = new CommsClient('content-client-port', this.settings, this.logger);
this.comms = new CommsClient('content-main-port', this.logger, this.commsHandlers);
// add showPopup, hidePopup listener to comms
this.comms.subscribe('show-logger', () => this.showLogger());
this.comms.subscribe('hide-logger', () => this.hideLogger());
// če smo razširitev onemogočili v nastavitvah, ne naredimo ničesar
// If extension is soft-disabled, don't do shit
@ -157,7 +162,6 @@ class UW {
try {
this.pageInfo = new PageInfo(this.comms, this.settings, this.logger, extensionMode, isSiteDisabled);
this.logger.log('info', 'debug', "[uw.js::setup] pageInfo initialized.");
this.comms.setPageInfo(this.pageInfo);
this.logger.log('info', 'debug', "[uw.js::setup] will try to initate ActionHandler.");
@ -174,85 +178,7 @@ class UW {
}
}
initVue() {
Vue.prototype.$browser = global.browser;
Vue.use(Vuex);
this.vuexStore = new Vuex.Store({
plugins: [VuexWebExtensions({
persistentStates: [
'uwLog',
'showLogger',
],
})],
state: {
uwLog: '',
showLogger: false,
},
mutations: {
'uw-set-log'(state, payload) {
state['uwLog'] = payload;
},
'uw-show-logger'(state) {
state['showLogger'] = true;
},
'uw-hide-logger'(state) {
state['showLogger'] = false;
}
},
actions: {
'uw-set-log' ({commit}, payload) {
commit('uw-set-log', payload);
},
'uw-show-logger'({commit}) {
commit('uw-show-logger');
},
'uw-hide-logger'({commit}) {
commit('uw-hide-logger');
}
}
})
}
initUi() {
console.log("CREATING UI");
const random = Math.round(Math.random() * 69420);
const uwid = `uw-ui-root-${random}`;
const rootDiv = document.createElement('div');
rootDiv.setAttribute("style", "position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999999; background-color: #ff0000;");
rootDiv.setAttribute("id", uwid);
document.body.appendChild(rootDiv);
new Vue({
el: `#${uwid}`,
components: {
LoggerUi
},
store: this.vuexStore,
render(h) {
return h('logger-ui');
}
})
}
showLogger() {
if (! this.vueInitiated) {
this.initVue();
}
if (!this.uiInitiated) {
this.initUi();
}
this.vuexStore.dispatch('uw-show-logger');
}
hideLogger() {
// if either of these two is false, then we know that UI doesn't exist
// since UI doesn't exist, we don't need to dispatch uw-hide-logger
if (this.vueInitiated && this.uiInitiated) {
this.vuexStore.dispatch('uw-hide-logger');
}
}
}
var main = new UW();

View File

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Ultrawidify",
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
"version": "4.4.5",
"version": "4.4.6",
"applications": {
"gecko": {
"id": "{cf02b1a7-a01a-4e37-a609-516a283f1ed3}"

View File

@ -157,7 +157,7 @@ export default {
},
methods: {
async openOptionsPage() {
browser.runtime.openOptionsPage();
(browser ?? chrome).runtime.openOptionsPage();
},
execAction(action) {
this.exec.exec(action, 'page', this.frame);

View File

@ -2,12 +2,31 @@
<div>
<h2>What's new</h2>
<p>Full changelog for older versions <a href="https://github.com/tamius-han/ultrawidify/blob/master/CHANGELOG.md">is available here</a>.</p>
<p class="label">4.4.5</p>
<p class="label">4.4.6</p>
<ul>
<li>Extension no longer requires <code>allTabs</code> and <code>webNavigation</code> permissions</li>
<li>Some CSS on the logger popup was not scoped, causing display issues with some sites (<a href="https://github.com/tamius-han/ultrawidify/issues/92">#92</a>)</li>
<li>Fix some additional issues with video alignment when changing videos on autoplay</li>
<li>Ensured that Vue part of the content script (logger UI) only loads when necessary in order to fix breakage on certain sites (<a href="https://github.com/tamius-han/ultrawidify/issues/96">#96</a>).</li>
<li>Disabling (or enabling, if running in whitelist-only mode) specific sites used to not work (<a href="https://github.com/tamius-han/ultrawidify/issues/91">#91</a>). This issue appears to have been fixed.</li>
<li>Default stretch mode for sites is now probably being observed, too (<a href="https://github.com/tamius-han/ultrawidify/issues/94">#94</a>).
</ul>
<template v-if="BrowserDetect.chrome">
<p>Due to factors beyond my control, Chrome version of this extension has missed the last three patches.</p>
<ul>
<li><b>4.4.5</b>
<ul>
<li>Extension no longer requires <code>allTabs</code> and <code>webNavigation</code> permissions</li>
<li>Some CSS on the logger popup was not scoped, causing display issues with some sites (<a href="https://github.com/tamius-han/ultrawidify/issues/92">#92</a>)</li>
<li>Fix some additional issues with video alignment when changing videos on autoplay</li>
</ul></li>
<li><b>4.4.4<small>.1, .2</small></b>
<ul>
<li><b>[4.4.4.1]</b> There were multiple reports about popup being broken. This issue should be resolved.</li>
<li><b>[4.4.4.1]</b> Setting global/site defaults should no longer require page reloads.</li>
<li><b>[4.4.4.2]</b> Fix problem with video being offset while switching between full screen and non-fullscreen non-theater mode on Youtube</li>
</ul></li>
</ul>
</template>
</div>
</template>
<script>

View File

@ -12,6 +12,7 @@ const config = {
context: __dirname + '/src',
entry: {
'ext/uw': './ext/uw.js',
'ext/uw-ui': './ext/uw-ui.js',
'ext/uw-bg': './ext/uw-bg.js',
'popup/popup': './popup/popup.js',
'options/options': './options/options.js',