Compare commits

...

3 Commits

Author SHA1 Message Date
60dd1193ab Detect embedded content 2025-06-18 01:04:42 +02:00
2bc95af73c Fix iframe detection 2025-06-17 22:49:16 +02:00
178bb65b4a Improve embedded frame detection 2025-06-17 20:12:44 +02:00
11 changed files with 261 additions and 86 deletions

View File

@ -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({

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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>

View File

@ -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>;&nbsp; Enabled: <span :style="getSiteEnabledColor(host, 'enable')"><small>{{ getSiteEnabledModes(host, 'enable') }}</small></span>;&nbsp;
Aard <span :style="getSiteEnabledColor(frame.host, 'enableAard')"><small>{{ getSiteEnabledModes(frame.host, 'enableAard') }}</small></span>;&nbsp; Aard <span :style="getSiteEnabledColor(host, 'enableAard')"><small>{{ getSiteEnabledModes(host, 'enableAard') }}</small></span>;&nbsp;
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) {

View File

@ -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" />&nbsp;&nbsp; <mdicon name="crop" :size="16" />&nbsp;&nbsp;
<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>

View File

@ -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,
} }
} }

View File

@ -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

View File

@ -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 = {
@ -78,7 +79,9 @@ 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,28 +190,87 @@ 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[] = [];
if (videoQs){ if (videoQs){
videos = Array.from(document.querySelectorAll(videoQs) as NodeListOf<HTMLVideoElement> ?? []); videos = Array.from(document.querySelectorAll(videoQs) as NodeListOf<HTMLVideoElement> ?? []);
} else{ } else {
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( return videos;
(v: HTMLVideoElement) => v.clientHeight > 720 && v.clientWidth > 1208 }
);
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) {
// if we're left without videos on the current page, we unregister the page.
// if we have videos, we call register.
if (this.eventBus) {
// We used to send "register video" requests only on the first load, or if the number of
// videos on the page has changed. However, since Chrome Web Store started to require every
// extension requiring "broad permissions" to undergo manual review
// ... and since Chrome Web Store is known for taking their sweet ass time reviewing extensions,
// with review times north of an entire fucking month
// ... and since the legacy way of checking whether our frames-with-videos cache in background
// script contains any frames that no longer exist required us to use webNavigation.getFrame()/
// webNavigation.getAllFrames(), which requires a permission that triggers a review.
//
// While the extension uses some other permissions that trigger manual review, it's said that
// less is better / has a positive effect on your manual review times ... So I guess we'll do
// things in the less-than-optimal. more-than-retarded way.
//
// no but honestly fuck Chrome.
if (videosDetected || this.hasVideo()) {
this.eventBus.send('has-video', null);
} else {
this.eventBus.send('noVideo', null);
}
}
}
/** /**
* Re-scans the page for videos. Removes any videos that no longer exist from our list * 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 * of videos. Destroys all videoData objects for all the videos that don't have their
@ -216,6 +279,8 @@ class PageInfo {
* @returns * @returns
*/ */
rescan(rescanReason?: RescanReason){ rescan(rescanReason?: RescanReason){
let videosDetected = false;
// is there any video data objects that had their HTML elements removed but not yet // is there any video data objects that had their HTML elements removed but not yet
// destroyed? We clean that up here. // destroyed? We clean that up here.
const orphans = this.videos.filter(x => !document.body.contains(x.element)); const orphans = this.videos.filter(x => !document.body.contains(x.element));
@ -227,9 +292,18 @@ class PageInfo {
// remove all destroyed videos. // remove all destroyed videos.
this.videos = this.videos.filter(x => !x.videoData.destroyed); this.videos = this.videos.filter(x => !x.videoData.destroyed);
// add new videos // add new videos
try{ try {
let vids = this.getVideos(); // 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){ if(!vids || vids.length == 0){
this.hasVideos = false; this.hasVideos = false;
@ -238,13 +312,13 @@ class PageInfo {
this.logger.info({src: 'rescan', origin: 'videoRescan'}, "Scheduling normal rescan.") this.logger.info({src: 'rescan', origin: 'videoRescan'}, "Scheduling normal rescan.")
this.scheduleRescan(RescanReason.PERIODIC); this.scheduleRescan(RescanReason.PERIODIC);
} }
this.emitVideoStatus(videosDetected);
return; return;
} }
// add new videos // add new videos
this.hasVideos = false; this.hasVideos = false;
let videoExists = false;
for (const videoElement of vids) { for (const videoElement of vids) {
// do not re-add videos that we already track: // do not re-add videos that we already track:
if (this.videos.find(x => x.element.isEqualNode(videoElement))) { if (this.videos.find(x => x.element.isEqualNode(videoElement))) {
@ -259,6 +333,7 @@ class PageInfo {
// at this point, we're certain that we found new videos. Let's update some properties: // at this point, we're certain that we found new videos. Let's update some properties:
this.hasVideos = true; this.hasVideos = true;
videosDetected ||= true;
// if PageInfo is marked as "readOnly", we actually aren't adding any videos to anything because // 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 // that's super haram. We're only interested in whether
@ -269,6 +344,7 @@ class PageInfo {
if(rescanReason == RescanReason.PERIODIC){ if(rescanReason == RescanReason.PERIODIC){
this.scheduleRescan(RescanReason.PERIODIC); this.scheduleRescan(RescanReason.PERIODIC);
} }
this.emitVideoStatus(videosDetected);
return; return;
} }
@ -285,37 +361,7 @@ class PageInfo {
} }
this.removeDestroyed(); this.removeDestroyed();
this.emitVideoStatus(videosDetected);
// if we're left without videos on the current page, we unregister the page.
// if we have videos, we call register.
if (this.eventBus) {
// We used to send "register video" requests only on the first load, or if the number of
// videos on the page has changed. However, since Chrome Web Store started to require every
// extension requiring "broad permissions" to undergo manual review
// ... and since Chrome Web Store is known for taking their sweet ass time reviewing extensions,
// with review times north of an entire fucking month
// ... and since the legacy way of checking whether our frames-with-videos cache in background
// script contains any frames that no longer exist required us to use webNavigation.getFrame()/
// webNavigation.getAllFrames(), which requires a permission that triggers a review.
//
// While the extension uses some other permissions that trigger manual review, it's said that
// less is better / has a positive effect on your manual review times ... So I guess we'll do
// things in the less-than-optimal. more-than-retarded way.
//
// no but honestly fuck Chrome.
// 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);
} else {
// this.comms.unregisterVideo({host: window.location.hostname, location: window.location});
this.eventBus.send('noVideo', null);
}
}
} 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

View File

@ -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();