Compare commits
3 Commits
f7f046ea53
...
60dd1193ab
Author | SHA1 | Date | |
---|---|---|---|
60dd1193ab | |||
2bc95af73c | |||
178bb65b4a |
@ -86,6 +86,7 @@
|
|||||||
:settings="settings"
|
:settings="settings"
|
||||||
:eventBus="eventBus"
|
:eventBus="eventBus"
|
||||||
:siteSettings="siteSettings"
|
:siteSettings="siteSettings"
|
||||||
|
:hosts="activeHosts"
|
||||||
></PopupVideoSettings>
|
></PopupVideoSettings>
|
||||||
<BaseExtensionSettings
|
<BaseExtensionSettings
|
||||||
v-if="selectedTab === 'extensionSettings'"
|
v-if="selectedTab === 'extensionSettings'"
|
||||||
@ -93,7 +94,7 @@
|
|||||||
:eventBus="eventBus"
|
:eventBus="eventBus"
|
||||||
:siteSettings="siteSettings"
|
:siteSettings="siteSettings"
|
||||||
:site="site.host"
|
:site="site.host"
|
||||||
:frames="activeFrames"
|
:hosts="activeHosts"
|
||||||
>
|
>
|
||||||
</BaseExtensionSettings>
|
</BaseExtensionSettings>
|
||||||
<ChangelogPanel
|
<ChangelogPanel
|
||||||
@ -171,6 +172,7 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.tabs.find(x => x.id === 'changelog').highlight = !this.settings.active?.whatsNewChecked;
|
this.tabs.find(x => x.id === 'changelog').highlight = !this.settings.active?.whatsNewChecked;
|
||||||
|
this.requestSite();
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
try {
|
try {
|
||||||
@ -191,6 +193,8 @@ export default {
|
|||||||
{
|
{
|
||||||
source: this,
|
source: this,
|
||||||
function: (config, context) => {
|
function: (config, context) => {
|
||||||
|
console.log('set-current-site | this.site:', this.site, 'config.site:', config.site);
|
||||||
|
|
||||||
if (this.site) {
|
if (this.site) {
|
||||||
if (!this.site.host) {
|
if (!this.site.host) {
|
||||||
// dunno why this fix is needed, but sometimes it is
|
// dunno why this fix is needed, but sometimes it is
|
||||||
@ -207,10 +211,20 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loadFrames(this.site);
|
this.loadHostnames();
|
||||||
|
this.loadFrames();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
this.eventBus.subscribe(
|
||||||
|
'open-popup-settings',
|
||||||
|
{
|
||||||
|
source: this,
|
||||||
|
function: (config) => {
|
||||||
|
this.selectTab(config.tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
this.comms = new CommsClient('popup-port', this.logger, this.eventBus);
|
this.comms = new CommsClient('popup-port', this.logger, this.eventBus);
|
||||||
this.eventBus.setComms(this.comms);
|
this.eventBus.setComms(this.comms);
|
||||||
@ -274,11 +288,6 @@ export default {
|
|||||||
try {
|
try {
|
||||||
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
|
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
|
||||||
// CSM.port.postMessage({command: 'get-current-site'});
|
// CSM.port.postMessage({command: 'get-current-site'});
|
||||||
this.eventBus.send(
|
|
||||||
'probe-video',
|
|
||||||
{},
|
|
||||||
{ comms: {forwardTo: 'active'} }
|
|
||||||
);
|
|
||||||
this.eventBus.send(
|
this.eventBus.send(
|
||||||
'get-current-site',
|
'get-current-site',
|
||||||
{},
|
{},
|
||||||
@ -299,13 +308,15 @@ export default {
|
|||||||
isDefaultFrame(frameId) {
|
isDefaultFrame(frameId) {
|
||||||
return frameId === '__playing' || frameId === '__all';
|
return frameId === '__playing' || frameId === '__all';
|
||||||
},
|
},
|
||||||
|
loadHostnames() {
|
||||||
|
this.activeHosts = this.site.hostnames;
|
||||||
|
},
|
||||||
loadFrames() {
|
loadFrames() {
|
||||||
this.activeFrames = [{
|
this.activeFrames = [{
|
||||||
host: this.site.host,
|
host: this.site.host,
|
||||||
isIFrame: false, // not used tho. Maybe one day
|
isIFrame: false, // not used tho. Maybe one day
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
for (const frame in this.site.frames) {
|
for (const frame in this.site.frames) {
|
||||||
if (!this.activeFrames.find(x => x.host === this.site.frames[frame].host)) {
|
if (!this.activeFrames.find(x => x.host === this.site.frames[frame].host)) {
|
||||||
this.activeFrames.push({
|
this.activeFrames.push({
|
||||||
|
@ -367,6 +367,10 @@ button,
|
|||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-button {
|
||||||
|
color: $info-color;
|
||||||
|
border: 1px solid $info-color;
|
||||||
|
}
|
||||||
.info {
|
.info {
|
||||||
color: $info-color;
|
color: $info-color;
|
||||||
padding-left: 35px;
|
padding-left: 35px;
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
<small>{{ site }}</small>
|
<small>{{ site }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="frames"
|
v-if="hosts"
|
||||||
class="tab"
|
class="tab"
|
||||||
:class="{'active': tab === 'embeddedSites'}"
|
:class="{'active': tab === 'embeddedSites'}"
|
||||||
@click="setTab(tab = 'embeddedSites')"
|
@click="setTab(tab = 'embeddedSites')"
|
||||||
>
|
>
|
||||||
Embedded content
|
Embedded content ({{hosts?.length}} {{hosts?.length === 1 ? 'site' : 'sites'}})
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="tab"
|
class="tab"
|
||||||
@ -38,10 +38,10 @@
|
|||||||
></SiteExtensionSettings>
|
></SiteExtensionSettings>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="frames && tab === 'embeddedSites' && globalSettings">
|
<template v-if="hosts && tab === 'embeddedSites' && globalSettings">
|
||||||
<FrameSiteSettings
|
<FrameSiteSettings
|
||||||
v-if="settings"
|
v-if="settings"
|
||||||
:frames="frames"
|
:hosts="hosts"
|
||||||
:settings="settings"
|
:settings="settings"
|
||||||
></FrameSiteSettings>
|
></FrameSiteSettings>
|
||||||
</template>
|
</template>
|
||||||
@ -178,7 +178,7 @@ export default {
|
|||||||
'settings',
|
'settings',
|
||||||
'site',
|
'site',
|
||||||
'enableSettingsEditor',
|
'enableSettingsEditor',
|
||||||
'frames',
|
'hosts',
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="frame of frames" :key="frame.host" @click="selectedSite = frame.host" class="flex flex-col container pointer hoverable" style="margin-top: 4px; padding: 0.5rem 1rem;">
|
<div v-for="host of hosts" :key="host" @click="selectedSite = host" class="flex flex-col container pointer hoverable" style="margin-top: 4px; padding: 0.5rem 1rem;">
|
||||||
<SiteListItem
|
<SiteListItem
|
||||||
:frame="frame"
|
:host="host"
|
||||||
:settings="settings"
|
:settings="settings"
|
||||||
></SiteListItem>
|
></SiteListItem>
|
||||||
</div>
|
</div>
|
||||||
@ -48,7 +48,7 @@ export default {
|
|||||||
},
|
},
|
||||||
props: [
|
props: [
|
||||||
'settings',
|
'settings',
|
||||||
'frames',
|
'hosts',
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -27,7 +27,9 @@
|
|||||||
<b>NOTE:</b> Sites not on this list use default extension settings.
|
<b>NOTE:</b> Sites not on this list use default extension settings.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<b>Other sites:</b>
|
<div class="w-full text-center" style="margin-bottom: -1.25rem">
|
||||||
|
<b>Other sites</b>
|
||||||
|
</div>
|
||||||
<div style="margin: 1rem 0rem" class="w-full">
|
<div style="margin: 1rem 0rem" class="w-full">
|
||||||
<div class="flex flex-row items-baseline">
|
<div class="flex flex-row items-baseline">
|
||||||
<div style="margin-right: 1rem">Search for site:</div>
|
<div style="margin-right: 1rem">Search for site:</div>
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<div class="flex-grow pointer">
|
<div class="flex-grow pointer">
|
||||||
<b>{{ frame.host ?? frame.key }}</b>
|
<b>{{ host }}</b>
|
||||||
<span :style="getSiteTypeColor(frame.type)">
|
<span :style="getSiteTypeColor(siteSettings?.data?.type)">
|
||||||
(config: {{frame.type ?? 'unknown'}})
|
(config: {{siteSettings?.data?.type ?? 'unknown'}})
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>Edit</div>
|
<div>Edit</div>
|
||||||
@ -15,10 +15,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<small>
|
<small>
|
||||||
Enabled: <span :style="getSiteEnabledColor(frame.host, 'enable')"><small>{{ getSiteEnabledModes(frame.host, 'enable') }}</small></span>;
|
Enabled: <span :style="getSiteEnabledColor(host, 'enable')"><small>{{ getSiteEnabledModes(host, 'enable') }}</small></span>;
|
||||||
Aard <span :style="getSiteEnabledColor(frame.host, 'enableAard')"><small>{{ getSiteEnabledModes(frame.host, 'enableAard') }}</small></span>;
|
Aard <span :style="getSiteEnabledColor(host, 'enableAard')"><small>{{ getSiteEnabledModes(host, 'enableAard') }}</small></span>;
|
||||||
kbd: <span :style="getSiteEnabledColor(frame.host, 'enableKeyboard')"><small>{{ getSiteEnabledModes(frame.host, 'enableKeyboard') }}</small></span>
|
kbd: <span :style="getSiteEnabledColor(host, 'enableKeyboard')"><small>{{ getSiteEnabledModes(host, 'enableKeyboard') }}</small></span>
|
||||||
UI: <span :style="getSiteEnabledColor(frame.host, 'enableUI')"><small>{{ getSiteEnabledModes(frame.host, 'enableUI') }}</small></span>
|
UI: <span :style="getSiteEnabledColor(host, 'enableUI')"><small>{{ getSiteEnabledModes(host, 'enableUI') }}</small></span>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -29,15 +29,16 @@ import ExtensionMode from '../../../../../common/enums/ExtensionMode.enum';
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
siteSettings: undefined
|
siteSettings: undefined,
|
||||||
|
supportType: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: [
|
props: [
|
||||||
'settings',
|
'settings',
|
||||||
'frame',
|
'host',
|
||||||
],
|
],
|
||||||
created() {
|
created() {
|
||||||
this.siteSettings = this.settings.getSiteSettings(this.frame.host ?? this.frame.key);
|
this.siteSettings = this.settings.getSiteSettings(this.host);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getSiteTypeColor(siteType) {
|
getSiteTypeColor(siteType) {
|
||||||
|
@ -1,21 +1,54 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col relative h-full" style="padding-bottom: 20px">
|
<div class="flex flex-col relative h-full" style="padding-bottom: 20px">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Extension is disabled for a given site when it's disabled in full screen, since
|
Extension is disabled for a given site when it's disabled in full screen, since
|
||||||
current settings do not allow the extension to only be disabled while in full screen
|
current settings do not allow the extension to only be disabled while in full screen
|
||||||
-->
|
-->
|
||||||
<template v-if="siteSettings.isEnabledForEnvironment(false, true) === ExtensionMode.Disabled">
|
<template v-if="siteSettings.isEnabledForEnvironment(false, true) === ExtensionMode.Disabled && !enabledHosts?.length">
|
||||||
<div class="h-full flex flex-col items-center justify-center">
|
<div class="h-full flex flex-col items-center justify-center" style="margin-top: 8rem">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
Extension is not enabled for this site.
|
Extension is not enabled for this site.
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Please enable extension for this site.
|
Please enable extension for this site.
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="flex flex-row items-center"
|
||||||
|
style="background-color: transparent; padding: 0.25rem 0.5rem; margin-top: 1rem;"
|
||||||
|
@click="openSettings()"
|
||||||
|
>
|
||||||
|
Open settings <mdicon style="margin-left: 0.5rem;" name="open-in-new" size="16"></mdicon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
<div
|
||||||
|
v-if="siteSettings.isEnabledForEnvironment(false, true) === ExtensionMode.Disabled"
|
||||||
|
class="warning-compact"
|
||||||
|
>
|
||||||
|
<div class="w-full flex flex-row">
|
||||||
|
<div class="grow">
|
||||||
|
<b>Extension is disabled for this site.</b>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="flex flex-row items-center"
|
||||||
|
style="border: 1px solid black; background-color: transparent; color: black; padding: 0.25rem 0.5rem; margin-top: -0.25rem; margin-right: -0.5rem;"
|
||||||
|
@click="openSettings()"
|
||||||
|
>
|
||||||
|
Open settings <mdicon style="margin-left: 0.5rem;" name="open-in-new" size="16"></mdicon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<small>Controls will only work on content embedded from the following sites:</small><br/>
|
||||||
|
<div class="w-full flex flex-row justify-center">
|
||||||
|
<span v-for="host of enabledHosts" :key="host" class="website-name">{{host}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<mdicon name="crop" :size="16" />
|
<mdicon name="crop" :size="16" />
|
||||||
<span>CROP</span>
|
<span>CROP</span>
|
||||||
@ -90,6 +123,7 @@ import StretchOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoS
|
|||||||
import ZoomOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoSettings/ZoomOptionsPanel.vue';
|
import ZoomOptionsPanel from '@csui/src/PlayerUiPanels/PanelComponents/VideoSettings/ZoomOptionsPanel.vue';
|
||||||
import ExtensionMode from '@src/common/enums/ExtensionMode.enum.ts';
|
import ExtensionMode from '@src/common/enums/ExtensionMode.enum.ts';
|
||||||
import AlignmentOptionsControlComponent from '@csui/src/PlayerUiPanels/AlignmentOptionsControlComponent.vue';
|
import AlignmentOptionsControlComponent from '@csui/src/PlayerUiPanels/AlignmentOptionsControlComponent.vue';
|
||||||
|
import { SiteSettings } from '../../../../ext/lib/settings/SiteSettings';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@ -102,16 +136,24 @@ export default {
|
|||||||
|
|
||||||
],
|
],
|
||||||
props: [
|
props: [
|
||||||
|
'site',
|
||||||
'settings',
|
'settings',
|
||||||
'siteSettings',
|
'siteSettings',
|
||||||
'eventBus',
|
'eventBus',
|
||||||
|
'hosts'
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
exec: null,
|
exec: null,
|
||||||
ExtensionMode: ExtensionMode,
|
ExtensionMode: ExtensionMode,
|
||||||
|
enabledHosts: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
hosts(val) {
|
||||||
|
this.filterActiveSites(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.eventBus.subscribe(
|
this.eventBus.subscribe(
|
||||||
'uw-config-broadcast',
|
'uw-config-broadcast',
|
||||||
@ -120,6 +162,7 @@ export default {
|
|||||||
function: (config) => this.handleConfigBroadcast(config)
|
function: (config) => this.handleConfigBroadcast(config)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
this.filterActiveSites(this.hosts);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.eventBus.sendToTunnel('get-ar');
|
this.eventBus.sendToTunnel('get-ar');
|
||||||
@ -128,8 +171,37 @@ export default {
|
|||||||
this.eventBus.unsubscribeAll(this);
|
this.eventBus.unsubscribeAll(this);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
filterActiveSites(val) {
|
||||||
|
this.enabledHosts = [];
|
||||||
|
|
||||||
|
for (const host of val) {
|
||||||
|
const siteSettings = new SiteSettings(this.settings, host);
|
||||||
|
|
||||||
|
if (siteSettings.isEnabledForEnvironment(false, true) === ExtensionMode.Enabled) {
|
||||||
|
this.enabledHosts.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openSettings() {
|
||||||
|
this.eventBus.send('open-popup-settings', {tab: 'extensionSettings'})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.warning-compact {
|
||||||
|
background-color: #d6ba4a;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
margin-top: -0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
.website-name {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
|
||||||
|
&:not(:last-of-type)::after {
|
||||||
|
content: ','
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -93,12 +93,16 @@ export default class UWServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async _promisifyTabsGet(browserObj, tabId){
|
async _promisifyTabsGet(browserObj, tabId){
|
||||||
return new Promise( (resolve, reject) => {
|
return new Promise( (resolve, reject) => {
|
||||||
browserObj.tabs.get(tabId, (tab) => resolve(tab));
|
browserObj.tabs.get(tabId, (tab) => resolve(tab));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region CSS managemeent
|
||||||
|
|
||||||
async injectCss(css, sender) {
|
async injectCss(css, sender) {
|
||||||
if (!css) {
|
if (!css) {
|
||||||
return;
|
return;
|
||||||
@ -167,6 +171,7 @@ export default class UWServer {
|
|||||||
this.injectCss(newCss, sender);
|
this.injectCss(newCss, sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
extractHostname(url){
|
extractHostname(url){
|
||||||
var hostname;
|
var hostname;
|
||||||
@ -214,7 +219,6 @@ export default class UWServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: change extension icon based on whether there's any videos on current page
|
//TODO: change extension icon based on whether there's any videos on current page
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerVideo(sender) {
|
registerVideo(sender) {
|
||||||
@ -288,7 +292,6 @@ export default class UWServer {
|
|||||||
const tabHostname = await this.getCurrentTabHostname();
|
const tabHostname = await this.getCurrentTabHostname();
|
||||||
this.logger.info('getCurrentSite', 'Returning data:', {site, tabHostname});
|
this.logger.info('getCurrentSite', 'Returning data:', {site, tabHostname});
|
||||||
|
|
||||||
|
|
||||||
this.eventBus.send(
|
this.eventBus.send(
|
||||||
'set-current-site',
|
'set-current-site',
|
||||||
{
|
{
|
||||||
@ -318,9 +321,12 @@ export default class UWServer {
|
|||||||
return {
|
return {
|
||||||
host: 'INVALID SITE',
|
host: 'INVALID SITE',
|
||||||
frames: [],
|
frames: [],
|
||||||
|
hostnames: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hostnames = await this.comms.listUniqueFrameHosts();
|
||||||
|
|
||||||
if (this.videoTabs[ctab.id]) {
|
if (this.videoTabs[ctab.id]) {
|
||||||
// if video is older than PageInfo's video rescan period (+ 4000ms of grace),
|
// if video is older than PageInfo's video rescan period (+ 4000ms of grace),
|
||||||
// we clean it up from videoTabs[tabId].frames array.
|
// we clean it up from videoTabs[tabId].frames array.
|
||||||
@ -343,6 +349,7 @@ export default class UWServer {
|
|||||||
return {
|
return {
|
||||||
...this.videoTabs[ctab.id],
|
...this.videoTabs[ctab.id],
|
||||||
host: this.extractHostname(ctab.url),
|
host: this.extractHostname(ctab.url),
|
||||||
|
hostnames,
|
||||||
selected: this.selectedSubitem
|
selected: this.selectedSubitem
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -352,7 +359,8 @@ export default class UWServer {
|
|||||||
return {
|
return {
|
||||||
host: this.extractHostname(ctab.url),
|
host: this.extractHostname(ctab.url),
|
||||||
frames: [],
|
frames: [],
|
||||||
selected: this.selectedSubitem
|
hostnames,
|
||||||
|
selected: this.selectedSubitem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,36 @@ class CommsServer {
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all unique hosts that are present in all the frames of a given tab.
|
||||||
|
* This includes both hostname of the tab, as well as of all iframes embedded in it.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async listUniqueFrameHosts() {
|
||||||
|
const aTab = await this.activeTab;
|
||||||
|
|
||||||
|
const tabPort = this.ports[aTab.id];
|
||||||
|
const hosts = [];
|
||||||
|
|
||||||
|
for (const frame in tabPort) {
|
||||||
|
for (const portName in tabPort[frame]) {
|
||||||
|
const port = tabPort[frame][portName];
|
||||||
|
|
||||||
|
const host = port.sender.origin.split('://')[1];
|
||||||
|
|
||||||
|
// if host is invalid or already exists in our list, skip adding it
|
||||||
|
if (!host || hosts.includes(host)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('uniq hosts:', hosts)
|
||||||
|
return hosts;
|
||||||
|
}
|
||||||
|
|
||||||
sendMessage(message, context?) {
|
sendMessage(message, context?) {
|
||||||
this.logger.debug('sendMessage', `preparing to send message ${message.command ?? ''} ...`, {message, context});
|
this.logger.debug('sendMessage', `preparing to send message ${message.command ?? ''} ...`, {message, context});
|
||||||
// stop messages from returning where they came from, and prevent
|
// stop messages from returning where they came from, and prevent
|
||||||
|
@ -69,6 +69,7 @@ class PageInfo {
|
|||||||
keyboardHandler: any;
|
keyboardHandler: any;
|
||||||
|
|
||||||
fsStatus = {fullscreen: true}; // fsStatus needs to be passed to VideoData, so fullScreen property is shared between videoData instances
|
fsStatus = {fullscreen: true}; // fsStatus needs to be passed to VideoData, so fullScreen property is shared between videoData instances
|
||||||
|
isIframe: boolean = false;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
fsEventListener = {
|
fsEventListener = {
|
||||||
@ -79,6 +80,8 @@ class PageInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constructor(eventBus: EventBus, siteSettings: SiteSettings, settings: Settings, logAggregator: LogAggregator, readOnly = false) {
|
constructor(eventBus: EventBus, siteSettings: SiteSettings, settings: Settings, logAggregator: LogAggregator, readOnly = false) {
|
||||||
|
this.isIframe = window.self !== window.top;
|
||||||
|
|
||||||
this.logAggregator = logAggregator;
|
this.logAggregator = logAggregator;
|
||||||
this.logger = new ComponentLogger(logAggregator, 'PageInfo', {});
|
this.logger = new ComponentLogger(logAggregator, 'PageInfo', {});
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
@ -112,10 +115,11 @@ class PageInfo {
|
|||||||
this.eventBus.subscribeMulti({
|
this.eventBus.subscribeMulti({
|
||||||
'probe-video': {
|
'probe-video': {
|
||||||
function: () => {
|
function: () => {
|
||||||
console.warn('[uw] probe-video event received..');
|
console.log(`[${window.location}] probe-video received.`)
|
||||||
|
this.rescan();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -186,7 +190,21 @@ class PageInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideos(): HTMLVideoElement[] {
|
/**
|
||||||
|
* Returns all videos on the page.
|
||||||
|
*
|
||||||
|
* If minSize is provided, it only returns <video> elements that are
|
||||||
|
* equal or bigger than desired size:
|
||||||
|
*
|
||||||
|
* * sm: 320 x 180
|
||||||
|
* * md: 720 x 400
|
||||||
|
* * lg: 1280 x 720
|
||||||
|
*
|
||||||
|
* If minSize is omitted, it returns all <video> elements.
|
||||||
|
* @param minSize
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getAllVideos(minSize?: 'sm' | 'md' | 'lg') {
|
||||||
const videoQs = this.siteSettings.getCustomDOMQuerySelector('video');
|
const videoQs = this.siteSettings.getCustomDOMQuerySelector('video');
|
||||||
let videos: HTMLVideoElement[] = [];
|
let videos: HTMLVideoElement[] = [];
|
||||||
|
|
||||||
@ -196,96 +214,38 @@ class PageInfo {
|
|||||||
videos = Array.from(document.getElementsByTagName('video') ?? []);
|
videos = Array.from(document.getElementsByTagName('video') ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter out videos that aren't big enough
|
if (!minSize) {
|
||||||
videos = videos.filter(
|
|
||||||
(v: HTMLVideoElement) => v.clientHeight > 720 && v.clientWidth > 1208
|
|
||||||
);
|
|
||||||
|
|
||||||
return videos;
|
return videos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.filterVideos(videos, minSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
filterVideos(videos: HTMLVideoElement[], minSize: 'sm' | 'md' | 'lg') {
|
||||||
|
// minimums are determined by vibes and shit.
|
||||||
|
// 'sm' is based on "slightly smaller than embeds on old.reddit"
|
||||||
|
const minX = { sm: 320, md: 720, lg: 1280 };
|
||||||
|
const minY = { sm: 180, md: 400, lg: 720 };
|
||||||
|
|
||||||
|
// filter out videos that aren't big enough
|
||||||
|
return videos.filter(
|
||||||
|
(v: HTMLVideoElement) => v.clientHeight >= minY[minSize] && v.clientWidth >= minX[minSize]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets videos on the page that are big enough for extension to trigger
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getVideos(): HTMLVideoElement[] {
|
||||||
|
return this.getAllVideos('lg');
|
||||||
|
}
|
||||||
|
|
||||||
hasVideo() {
|
hasVideo() {
|
||||||
return this.readOnly ? this.hasVideos : this.videos.length;
|
return this.readOnly ? this.hasVideos : this.videos.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private emitVideoStatus(videosDetected?: boolean) {
|
||||||
* Re-scans the page for videos. Removes any videos that no longer exist from our list
|
|
||||||
* of videos. Destroys all videoData objects for all the videos that don't have their
|
|
||||||
* own <video> html element on the page.
|
|
||||||
* @param rescanReason Why was the rescan triggered. Mostly used for logging.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
rescan(rescanReason?: RescanReason){
|
|
||||||
// is there any video data objects that had their HTML elements removed but not yet
|
|
||||||
// destroyed? We clean that up here.
|
|
||||||
const orphans = this.videos.filter(x => !document.body.contains(x.element));
|
|
||||||
|
|
||||||
for (const orphan of orphans) {
|
|
||||||
orphan.videoData.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove all destroyed videos.
|
|
||||||
this.videos = this.videos.filter(x => !x.videoData.destroyed);
|
|
||||||
|
|
||||||
// add new videos
|
|
||||||
try{
|
|
||||||
let vids = this.getVideos();
|
|
||||||
|
|
||||||
if(!vids || vids.length == 0){
|
|
||||||
this.hasVideos = false;
|
|
||||||
|
|
||||||
if(rescanReason == RescanReason.PERIODIC){
|
|
||||||
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "Scheduling normal rescan.")
|
|
||||||
this.scheduleRescan(RescanReason.PERIODIC);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new videos
|
|
||||||
this.hasVideos = false;
|
|
||||||
let videoExists = false;
|
|
||||||
|
|
||||||
for (const videoElement of vids) {
|
|
||||||
// do not re-add videos that we already track:
|
|
||||||
if (this.videos.find(x => x.element.isEqualNode(videoElement))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we find even a single video with width and height, that means the page has valid videos
|
|
||||||
// if video lacks either of the two properties, we skip all further checks cos pointless
|
|
||||||
if(!videoElement.offsetWidth || !videoElement.offsetHeight) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// at this point, we're certain that we found new videos. Let's update some properties:
|
|
||||||
this.hasVideos = true;
|
|
||||||
|
|
||||||
// if PageInfo is marked as "readOnly", we actually aren't adding any videos to anything because
|
|
||||||
// that's super haram. We're only interested in whether
|
|
||||||
if (this.readOnly) {
|
|
||||||
// in lite mode, we're done. This is all the info we want, but we want to actually start doing
|
|
||||||
// things that interfere with the website. We still want to be running a rescan, tho.
|
|
||||||
|
|
||||||
if(rescanReason == RescanReason.PERIODIC){
|
|
||||||
this.scheduleRescan(RescanReason.PERIODIC);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "found new video candidate:", videoElement, "NOTE:: Video initialization starts here:\n--------------------------------\n")
|
|
||||||
|
|
||||||
try {
|
|
||||||
const newVideo = new VideoData(videoElement, this.settings, this.siteSettings, this);
|
|
||||||
this.videos.push({videoData: newVideo, element: videoElement});
|
|
||||||
} catch (e) {
|
|
||||||
this.logger.error('rescan', "rescan error: failed to initialize videoData. Skipping this video.",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeDestroyed();
|
|
||||||
|
|
||||||
// if we're left without videos on the current page, we unregister the page.
|
// if we're left without videos on the current page, we unregister the page.
|
||||||
// if we have videos, we call register.
|
// if we have videos, we call register.
|
||||||
if (this.eventBus) {
|
if (this.eventBus) {
|
||||||
@ -303,19 +263,105 @@ class PageInfo {
|
|||||||
// things in the less-than-optimal. more-than-retarded way.
|
// things in the less-than-optimal. more-than-retarded way.
|
||||||
//
|
//
|
||||||
// no but honestly fuck Chrome.
|
// no but honestly fuck Chrome.
|
||||||
|
if (videosDetected || this.hasVideo()) {
|
||||||
// if (this.videos.length != oldVideoCount) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (this.videos.length > 0) {
|
|
||||||
// this.comms.registerVideo({host: window.location.hostname, location: window.location});
|
|
||||||
this.eventBus.send('has-video', null);
|
this.eventBus.send('has-video', null);
|
||||||
} else {
|
} else {
|
||||||
// this.comms.unregisterVideo({host: window.location.hostname, location: window.location});
|
|
||||||
this.eventBus.send('noVideo', null);
|
this.eventBus.send('noVideo', null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-scans the page for videos. Removes any videos that no longer exist from our list
|
||||||
|
* of videos. Destroys all videoData objects for all the videos that don't have their
|
||||||
|
* own <video> html element on the page.
|
||||||
|
* @param rescanReason Why was the rescan triggered. Mostly used for logging.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
rescan(rescanReason?: RescanReason){
|
||||||
|
let videosDetected = false;
|
||||||
|
|
||||||
|
// is there any video data objects that had their HTML elements removed but not yet
|
||||||
|
// destroyed? We clean that up here.
|
||||||
|
const orphans = this.videos.filter(x => !document.body.contains(x.element));
|
||||||
|
|
||||||
|
for (const orphan of orphans) {
|
||||||
|
orphan.videoData.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all destroyed videos.
|
||||||
|
this.videos = this.videos.filter(x => !x.videoData.destroyed);
|
||||||
|
|
||||||
|
|
||||||
|
// add new videos
|
||||||
|
try {
|
||||||
|
// in iframes, emit registerIframe even if video is smaller than required
|
||||||
|
let vids = this.getAllVideos('sm');
|
||||||
|
|
||||||
|
if (this.isIframe && this.eventBus) {
|
||||||
|
videosDetected ||= vids?.length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// for normal operations, use standard size limits
|
||||||
|
vids = this.filterVideos(vids, 'lg');
|
||||||
|
|
||||||
|
if(!vids || vids.length == 0){
|
||||||
|
this.hasVideos = false;
|
||||||
|
|
||||||
|
if(rescanReason == RescanReason.PERIODIC){
|
||||||
|
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "Scheduling normal rescan.")
|
||||||
|
this.scheduleRescan(RescanReason.PERIODIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emitVideoStatus(videosDetected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new videos
|
||||||
|
this.hasVideos = false;
|
||||||
|
for (const videoElement of vids) {
|
||||||
|
// do not re-add videos that we already track:
|
||||||
|
if (this.videos.find(x => x.element.isEqualNode(videoElement))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we find even a single video with width and height, that means the page has valid videos
|
||||||
|
// if video lacks either of the two properties, we skip all further checks cos pointless
|
||||||
|
if(!videoElement.offsetWidth || !videoElement.offsetHeight) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point, we're certain that we found new videos. Let's update some properties:
|
||||||
|
this.hasVideos = true;
|
||||||
|
videosDetected ||= true;
|
||||||
|
|
||||||
|
// if PageInfo is marked as "readOnly", we actually aren't adding any videos to anything because
|
||||||
|
// that's super haram. We're only interested in whether
|
||||||
|
if (this.readOnly) {
|
||||||
|
// in lite mode, we're done. This is all the info we want, but we want to actually start doing
|
||||||
|
// things that interfere with the website. We still want to be running a rescan, tho.
|
||||||
|
|
||||||
|
if(rescanReason == RescanReason.PERIODIC){
|
||||||
|
this.scheduleRescan(RescanReason.PERIODIC);
|
||||||
|
}
|
||||||
|
this.emitVideoStatus(videosDetected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "found new video candidate:", videoElement, "NOTE:: Video initialization starts here:\n--------------------------------\n")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newVideo = new VideoData(videoElement, this.settings, this.siteSettings, this);
|
||||||
|
this.videos.push({videoData: newVideo, element: videoElement});
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error('rescan', "rescan error: failed to initialize videoData. Skipping this video.",e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeDestroyed();
|
||||||
|
this.emitVideoStatus(videosDetected);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// if we encounter a fuckup, we can assume that no videos were found on the page. We destroy all videoData
|
// if we encounter a fuckup, we can assume that no videos were found on the page. We destroy all videoData
|
||||||
// objects to prevent multiple initialization (which happened, but I don't know why). No biggie if we destroyed
|
// objects to prevent multiple initialization (which happened, but I don't know why). No biggie if we destroyed
|
||||||
|
@ -5,17 +5,18 @@
|
|||||||
import UWContent from './UWContent';
|
import UWContent from './UWContent';
|
||||||
|
|
||||||
if(process.env.CHANNEL !== 'stable'){
|
if(process.env.CHANNEL !== 'stable'){
|
||||||
console.warn("\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n");
|
|
||||||
|
let isIframe;
|
||||||
try {
|
try {
|
||||||
if(window.self !== window.top){
|
isIframe = window.self !== window.top;
|
||||||
console.info("%cWe aren't in an iframe.", "color: #afc, background: #174");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
console.info("%cWe are in an iframe!", "color: #fea, background: #d31", window.self, window.top);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.info("%cWe are in an iframe!", "color: #fea, background: #d31");
|
isIframe = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
"\n\n\n\n\n\n ——— Sᴛλʀᴛɪɴɢ Uʟᴛʀᴀᴡɪᴅɪꜰʏ ———\n << ʟᴏᴀᴅɪɴɢ ᴍᴀɪɴ ꜰɪʟᴇ >>\n\n\n\n",
|
||||||
|
"\n - are we in iframe?", isIframe
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const main = new UWContent();
|
const main = new UWContent();
|
||||||
|
Loading…
Reference in New Issue
Block a user