Compare commits

..

12 Commits

10 changed files with 392 additions and 80 deletions

View File

@ -332,6 +332,7 @@ export interface SiteSettingsInterface {
override?: boolean; // whether settings for this site will be overwritten by extension upgrade script override?: boolean; // whether settings for this site will be overwritten by extension upgrade script
workarounds?: { workarounds?: {
iframeTransparencyWarningDismissed?: boolean;
disableColorSchemeAwareness?: boolean; disableColorSchemeAwareness?: boolean;
forceColorScheme?: 'normal' | 'light' | 'dark', forceColorScheme?: 'normal' | 'light' | 'dark',
lastColorSchemeAwarenessCheck?: Date; lastColorSchemeAwarenessCheck?: Date;

View File

@ -36,6 +36,17 @@
</div> </div>
Ultrawidify Ultrawidify
<div
v-if="!siteSettings?.data.workarounds?.iframeTransparencyWarningDismissed"
class="absolute ui-warning small uw-clickable">
If all you see is white or black screen,<br/>disable UI and report your GPU to github.<br/>Open.<br/>
<br />
<br /> You can also <a href="" @click="iframeAutofix()">click here to attempt a fix</a>.
<br />
<br /> If you experience no issues, <a href="" @click="iframeDismiss()">click here to hide this warning.</a>
</div>
</div> </div>
</template> </template>
@ -452,6 +463,7 @@ export default {
this.sendToParentLowLevel('uw-bus-tunnel', { this.sendToParentLowLevel('uw-bus-tunnel', {
action: 'get-player-dimensions' action: 'get-player-dimensions'
}); });
this.sendToParentLowLevel('uw-get-page-stats', null);
}, },
destroyed() { destroyed() {
@ -585,6 +597,22 @@ export default {
handleBusTunnelIn(payload) { handleBusTunnelIn(payload) {
this.eventBus.send(payload.action, payload.config, payload.routingData); this.eventBus.send(payload.action, payload.config, payload.routingData);
},
async iframeAutofix() {
console.log('site:', this.site, this.siteSettings);
if (this.siteSettings?.data.workarounds?.disableColorSchemeAwareness === false) {
await this.settings.setProp(['sites', this.site, 'workarounds', 'disableColorSchemeAwareness'], true);
} else {
await this.settings.setProp(['sites', this.site, 'workarounds', 'disableColorSchemeAwareness'], false);
}
await this.settings.saveWithoutReload();
this.eventBus.sendToTunnel('uw-reload-window');
},
async iframeDismiss() {
await this.settings.setProp(['sites', this.site, 'workarounds', 'iframeTransparencyWarningDismissed'], true);
await this.settings.save();
this.eventBus.sendToTunnel('uw-reload-window');
} }
} }
} }
@ -656,10 +684,14 @@ export default {
.ui-warning { .ui-warning {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0;
transform: translateY(-100%); transform: translateY(-100%);
max-width: 16rem; max-width: 20rem;
width: 16rem; width: 20rem;
padding: 1rem;
box-sizing: border-box;
overflow: hidden; overflow: hidden;
overflow-wrap: break-word; overflow-wrap: break-word;
@ -667,6 +699,17 @@ export default {
white-space: normal; white-space: normal;
word-break: break-word; word-break: break-word;
word-wrap: break-word; word-wrap: break-word;
&.small {
font-size: 0.85rem;
color: #888;
background-color: rgba(0,0,0,0.69);
a {
color: #fa6;
opacity: 0.69;
}
}
} }

View File

@ -16,6 +16,27 @@
<li> <a target="_blank" href="https://github.com/tamius-han/ultrawidify/issues"><b>Github (preferred)</b></a><br/></li> <li> <a target="_blank" href="https://github.com/tamius-han/ultrawidify/issues"><b>Github (preferred)</b></a><br/></li>
<li>Email: <a target="_blank" :href="mailtoLink">tamius.han@gmail.com</a></li> <li>Email: <a target="_blank" :href="mailtoLink">tamius.han@gmail.com</a></li>
</ul> </ul>
<hr />
<b>Is your screen entirely white or entirely black?</b>
<p>This appears to be a rare issue that happens to some people. If you're experiencing this issue, please consider contacting me and sharing the following data:</p>
<ul>
<li>Which sites this problem appears on and whether it happens on youtube. If you use youtube premium, please try signing out of youtube (or use a new profile in Google Chrome) in order to see whether youtube premium is required.</li>
<li>your browser (get full version from <code>chrome://settings/help</code>). if using browsers other than Chrome, please try to reproduce this issue in Chrome</li>
<li>your operating system</li>
<li>your graphics card</li>
<li>whether you're using dark theme in your OS, and whether you're using website's built-in dark/light theme.</li>
</ul>
<p>Please post this info to <a href="https://github.com/tamius-han/ultrawidify/issues/262" target="_blank">this thread</a>, or message me via e-mail.</p>
<p>Then, disable the in-player UI.</p>
<hr />
<p> <p>
When reporting bugs, please include the following information: When reporting bugs, please include the following information:
</p> </p>
@ -67,6 +88,7 @@ export default {
mailtoLink: '', mailtoLink: '',
redditLink: '', redditLink: '',
showEasterEgg: false, showEasterEgg: false,
pageData: {}
} }
}, },
async created() { async created() {

View File

@ -32,7 +32,7 @@
<li>Half-fixed in-player UI on sites where player is not detected correctly</li> <li>Half-fixed in-player UI on sites where player is not detected correctly</li>
</ul> </ul>
<h3>6.2.3</h3> <h3>6.2.3 (current)</h3>
<ul> <ul>
<li>Fixed default persistent mode</li> <li>Fixed default persistent mode</li>
</ul> </ul>

View File

@ -111,7 +111,7 @@ export default class UWContent {
this.logger.log('info', 'debug', "[uw.js::setup] KeyboardHandler initiated."); this.logger.log('info', 'debug', "[uw.js::setup] KeyboardHandler initiated.");
this.globalUi = new UI('ultrawidify-global-ui', {eventBus: this.eventBus, isGlobal: true}); this.globalUi = new UI('ultrawidify-global-ui', {eventBus: this.eventBus, isGlobal: true, siteSettings: this.siteSettings});
this.globalUi.enable(); this.globalUi.enable();
this.globalUi.setUiVisibility(false); this.globalUi.setUiVisibility(false);

View File

@ -379,7 +379,7 @@ export default class UWServer {
} }
async verifyUiTransparency(verificationData: IframeVerificationPlayerData, sender: MessageSender, telemetryData?: any) { async verifyUiTransparency(verificationData: IframeVerificationPlayerData, sender: MessageSender, telemetryData?: any) {
const hasTransparency = this.IframeTransparencyVerifier.verifyUiTransparency( const transparencyVerificationResult = await this.IframeTransparencyVerifier.verifyUiTransparency(
sender.tab.windowId, sender.tab.windowId,
{ {
player: verificationData, player: verificationData,
@ -390,8 +390,13 @@ export default class UWServer {
} }
); );
console.log('Transparency confirmed.');
this.eventBus.send( this.eventBus.send(
'iframe-transparency-results', 'iframe-transparency-results',
{
transparencyVerificationResult
},
{ {
comms: { comms: {
forwardTo: 'active' forwardTo: 'active'
@ -399,12 +404,12 @@ export default class UWServer {
} }
); );
axios.post( // axios.post(
'https://uw-telemetry.tamius.net/iframe-transparency', // 'https://uw-telemetry.tamius.net/iframe-transparency',
{ // {
...telemetryData, // ...telemetryData,
transparencyCheckResult: hasTransparency, // transparencyCheckResult: hasTransparency,
} // }
); // );
} }
} }

View File

@ -34,41 +34,53 @@ interface IframeCheckPosition {
export class IframeTransparencyVerifier { export class IframeTransparencyVerifier {
async verifyUiTransparency(windowId: number, tabDimensions: IframeVerificationData): Promise<TransparencyVerificationResult> { async verifyUiTransparency(windowId: number, tabDimensions: IframeVerificationData): Promise<{result: TransparencyVerificationResult, dataUrl?: string}> { console.info('Verifying UI transparency:', tabDimensions);
const {visibleX, visibleY} = this.getVisibleMarkers(tabDimensions);
if (!visibleX.length || visibleY.length) {
return TransparencyVerificationResult.NoVisibleElements;
}
const checkPositions = this.processMarkers(visibleX, visibleY); // const {visibleX, visibleY} = this.getVisibleMarkers(tabDimensions);
// if (!visibleX.length || !visibleY.length) {
// console.warn('[transparency check] No visible elements.');
return {result: TransparencyVerificationResult.NoVisibleElements};
// }
const dataUrl = await chrome.tabs.captureVisibleTab( // const checkPositions = this.processMarkers(visibleX, visibleY);
windowId,
{
format: "png"
}
);
try { // const dataUrl = await chrome.tabs.captureVisibleTab(
const canvas = new OffscreenCanvas(tabDimensions.tab.width, tabDimensions.tab.height); // undefined, // windowId,
const ctx = canvas.getContext('2d')!; // {
// format: "png"
// }
// );
const image = new Image(); // try {
const imageLoadPromise = new Promise(r => image.onload = r); // const canvas = new OffscreenCanvas(tabDimensions.tab.width, tabDimensions.tab.height);
image.src = dataUrl; // const ctx = canvas.getContext('2d')!;
await imageLoadPromise;
(ctx as any).drawImage(image, 0, 0);
const imageData = (ctx as any).getImageData(0, 0, tabDimensions.tab.width, tabDimensions.tab.height).data; // const res = await fetch(dataUrl);
// const blob = await res.blob();
if (this.detectMarkers(checkPositions, tabDimensions.tab.width, imageData)) { // const bitmap = createImageBitmap(blob);
return TransparencyVerificationResult.Ok;
} else { // (ctx as any).drawImage(bitmap, 0, 0);
return TransparencyVerificationResult.Fail;
} // const imageData = (ctx as any).getImageData(0, 0, tabDimensions.tab.width, tabDimensions.tab.height).data;
} catch (e) {
return TransparencyVerificationResult.Error; // if (this.detectMarkers(checkPositions, tabDimensions.tab.width, imageData)) {
} // console.info('Verified transparency');
// return {
// result: TransparencyVerificationResult.Ok,
// dataUrl: dataUrl
// };
// } else {
// console.info('Transparency checks came back negative');
// return {
// result: TransparencyVerificationResult.Fail,
// dataUrl: dataUrl
// };
// }
// } catch (e) {
// console.error('[transparency check] Error while checking for transparency:', e);
// return {result: TransparencyVerificationResult.Error};
// }
} }
private getVisibleMarkers({tab, player}: IframeVerificationData) { private getVisibleMarkers({tab, player}: IframeVerificationData) {
@ -78,6 +90,8 @@ export class IframeTransparencyVerifier {
// Determine which markers should be visible. // Determine which markers should be visible.
// Visibility: TOP ROW // Visibility: TOP ROW
console.log('player:', player.y, tab.height);
if (player.y >= 0 && player.y < tab.height) { if (player.y >= 0 && player.y < tab.height) {
visibleY.push({ visibleY.push({
position: 'top', position: 'top',
@ -87,7 +101,7 @@ export class IframeTransparencyVerifier {
// Visibility: CENTER // Visibility: CENTER
const yHalfPosition = Math.floor(player.y + player.height / 2); const yHalfPosition = Math.floor(player.y + player.height / 2);
if (player.y + yHalfPosition - 2 > 0 || player.y + yHalfPosition + 2 < tab.height) { if (player.y + yHalfPosition - 2 > 0 && player.y + yHalfPosition + 2 < tab.height) {
visibleY.push({ visibleY.push({
position: 'center', position: 'center',
offset: player.y + yHalfPosition, offset: player.y + yHalfPosition,
@ -95,7 +109,7 @@ export class IframeTransparencyVerifier {
} }
// Visibility: BOTTOM ROW // Visibility: BOTTOM ROW
if (player.y + player.height - 1 > 0 || player.y + player.height + 1 < tab.height) { if (player.y + player.height - 1 > 0 && player.y + player.height + 1 < tab.height) {
visibleY.push({ visibleY.push({
position: 'bottom', position: 'bottom',
offset: player.y + player.height - 1, offset: player.y + player.height - 1,
@ -112,21 +126,23 @@ export class IframeTransparencyVerifier {
// Visibility: X CENTER // Visibility: X CENTER
const xHalfPosition = Math.floor(player.x + player.width / 2); const xHalfPosition = Math.floor(player.x + player.width / 2);
if (player.x + xHalfPosition - 2 > 0 || player.x + xHalfPosition + 2 < tab.width) { if (player.x + xHalfPosition - 2 > 0 && player.x + xHalfPosition + 2 < tab.width) {
visibleY.push({ visibleX.push({
position: 'center', position: 'center',
offset: player.x + xHalfPosition, offset: player.x + xHalfPosition,
}); });
} }
// Visibility: RIGHT SIDE // Visibility: RIGHT SIDE
if (player.x + player.width - 1 > 0 || player.x + player.width + 1 < tab.width) { if (player.x + player.width - 1 > 0 && player.x + player.width + 1 < tab.width) {
visibleX.push({ visibleX.push({
position: 'right', position: 'right',
offset: player.x + player.width - 1, offset: player.x + player.width - 1,
}); });
} }
console.log('visible candidates', visibleX, visibleY);
return { return {
visibleX, visibleX,
visibleY, visibleY,

View File

@ -323,8 +323,38 @@ class Settings {
this.active = activeSettings; this.active = activeSettings;
} }
async setProp(prop, value) { /**
this.active[prop] = value; * Sets value of a prop at given path.
* @param propPath path to property we want to set. If prop path does not exist,
* this function will recursively create it. It is assumed that uninitialized properties
* are objects.
* @param value
*/
async setProp(propPath: string | string[], value: any, options?: {forceReload?: boolean}, currentPath?: any) {
if (!Array.isArray(propPath)) {
propPath = propPath.split('.');
}
if (!currentPath) {
currentPath = this.active;
}
const currentProp = propPath.shift();
if (propPath.length) {
if (!currentPath[currentProp]) {
currentPath[currentProp] = {};
}
return this.setProp(propPath, value, options, currentPath[currentProp]);
} else {
currentPath[currentProp] = value;
if (options?.forceReload) {
return this.save();
} else {
return this.saveWithoutReload();
}
}
} }
async save(options?) { async save(options?) {

View File

@ -15,8 +15,8 @@ if (process.env.CHANNEL !== 'stable'){
// As of 1. 1. 2025, 'light' and 'dark' are commented out in order to force 'csui-overlay-normal' everywhere. // As of 1. 1. 2025, 'light' and 'dark' are commented out in order to force 'csui-overlay-normal' everywhere.
const csuiVersions = { const csuiVersions = {
'normal': 'csui', // csui-overlay-normal.html, maps to csui.html 'normal': 'csui', // csui-overlay-normal.html, maps to csui.html
// 'light': 'csui-light', // csui-overlay-light.html, maps to csui-light.html 'light': 'csui-light', // csui-overlay-light.html, maps to csui-light.html
// 'dark': 'csui-dark' // csui-overlay-dark.html, maps to csui-dark.html 'dark': 'csui-dark' // csui-overlay-dark.html, maps to csui-dark.html
}; };
const MAX_IFRAME_ERROR_COUNT = 5; const MAX_IFRAME_ERROR_COUNT = 5;
@ -29,14 +29,10 @@ class UI {
this.interfaceId = interfaceId; this.interfaceId = interfaceId;
this.uiConfig = uiConfig; this.uiConfig = uiConfig;
this.lastProbeResponseTs = null; this.lastProbeResponseTs = null;
this.isVisible = false;
this.isOpaque = false;
this.isGlobal = uiConfig.isGlobal ?? false; this.isGlobal = uiConfig.isGlobal ?? false;
// TODO: at some point, UI should be different for global popup and in-player UI
const preferredScheme = window.getComputedStyle( document.body ,null).getPropertyValue('color-scheme');
const csuiVersion = csuiVersions[preferredScheme] ?? csuiVersions.normal;
this.uiURI = chrome.runtime.getURL(`/csui/${csuiVersion}.html`);
this.extensionBase = chrome.runtime.getURL('').replace(/\/$/, "");
this.eventBus = uiConfig.eventBus; this.eventBus = uiConfig.eventBus;
this.disablePointerEvents = false; this.disablePointerEvents = false;
@ -44,15 +40,44 @@ class UI {
this.saveState = undefined; this.saveState = undefined;
this.playerData = uiConfig.playerData; this.playerData = uiConfig.playerData;
this.uiSettings = uiConfig.uiSettings; this.uiSettings = uiConfig.uiSettings;
this.siteSettings = uiConfig.siteSettings;
this.settings = uiConfig.settings;
this.iframeErrorCount = 0; this.iframeErrorCount = 0;
this.iframeConfirmed = false; this.iframeConfirmed = false;
this.iframeRejected = false; this.iframeRejected = false;
this.preventHiding = false;
this.wantsToHide = false;
this.wantsToTransparent = false;
this.performedTransparencyCheck = false;
// TODO: at some point, UI should be different for global popup and in-player UI
const csuiVersion = this.getCsuiVersion();
this.uiURI = chrome.runtime.getURL(`/csui/${csuiVersion}.html`);
this.extensionBase = chrome.runtime.getURL('').replace(/\/$/, "");
} }
async init() { async init() {
try {
this.initIframes(); this.initIframes();
this.initMessaging(); this.initMessaging();
} catch (e) {
console.error('failed to init ui:', e)
}
}
getCsuiVersion() {
if (this.siteSettings?.workarounds?.forceColorScheme) {
return csuiVersions[this.siteSettings.workarounds.forceColorScheme];
}
if (this.siteSettings?.data?.workarounds?.disableColorSchemeAwareness !== false) {
return csuiVersions.normal;
}
const preferredScheme = window.getComputedStyle( document.body ,null).getPropertyValue('color-scheme');
return csuiVersions[preferredScheme] ?? csuiVersions.normal;
} }
initIframes() { initIframes() {
@ -94,8 +119,8 @@ class UI {
iframe.style.position = "absolute"; iframe.style.position = "absolute";
iframe.style.zIndex = this.isGlobal ? '90009' : '90000'; iframe.style.zIndex = this.isGlobal ? '90009' : '90000';
iframe.style.border = 0; iframe.style.border = 0;
iframe.style.pointerEvents = 'none';
iframe.style.opacity = 0; iframe.style.opacity = 0;
iframe.style.pointerEvents = 'none';
iframe.style.backgroundColor = 'transparent !important'; iframe.style.backgroundColor = 'transparent !important';
/* so we have a problem: we want iframe to be clickthrough everywhere except /* so we have a problem: we want iframe to be clickthrough everywhere except
@ -158,6 +183,18 @@ class UI {
document.addEventListener('mousemove', fn, true); document.addEventListener('mousemove', fn, true);
} }
// Add some squares to the page.
// Sets up checks for conditions that cause these two mutually exclusive issues:
// * https://github.com/tamius-han/ultrawidify/issues/262
// * https://github.com/tamius-han/ultrawidify/issues/259
for (const x of ['left', 'center', 'right']) {
for (const y of ['top', 'center', 'bottom']) {
if (x !== y) {
rootDiv.appendChild(this.generateDebugMarker(x, y));
}
}
}
rootDiv.appendChild(iframe); rootDiv.appendChild(iframe);
} }
@ -173,6 +210,11 @@ class UI {
this.eventBus.subscribeMulti( this.eventBus.subscribeMulti(
{ {
'uw-reload-window': {
function: () => {
window.location.reload();
}
},
'uw-config-broadcast': { 'uw-config-broadcast': {
function: (config, routingData) => { function: (config, routingData) => {
this.sendToIframe('uw-config-broadcast', config, routingData); this.sendToIframe('uw-config-broadcast', config, routingData);
@ -190,24 +232,6 @@ class UI {
this.sendToIframe('uw-set-ui-state', {...config, isGlobal: this.isGlobal}, routingData); this.sendToIframe('uw-set-ui-state', {...config, isGlobal: this.isGlobal}, routingData);
} }
}, },
'uw-get-page-stats': {
function: (config, routingData) => {
console.log('got get page stats!');
this.eventBus.send(
'uw-page-stats',
{
pcsDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
pcsLight: window.matchMedia('(prefers-color-scheme: light)').matches,
colorScheme: window.getComputedStyle( document.body ,null).getPropertyValue('color-scheme')
},
{
comms: {
forwardTo: 'popup'
}
}
);
}
},
'uw-restore-ui-state': { 'uw-restore-ui-state': {
function: (config, routingData) => { function: (config, routingData) => {
if (!this.isGlobal) { if (!this.isGlobal) {
@ -215,8 +239,26 @@ class UI {
this.sendToIframe('uw-restore-ui-state', config, routingData); this.sendToIframe('uw-restore-ui-state', config, routingData);
} }
} }
},
'iframe-transparency-results': {
function: (data, routingData) => {
console.log('——————————— iframe transparency results are back!', data);
} }
}, },
'uw-get-page-stats': {
function: (config, routingData) => {
console.log('uw:Č Got page stats request')
this.sendToIframeLowLevel(
'uw-page-stats',
{
pcsDark: window.matchMedia('(prefers-color-scheme: dark)').matches,
pcsLight: window.matchMedia('(prefers-color-scheme: light)').matches,
colorScheme: window.getComputedStyle( document.body ,null).getPropertyValue('color-scheme')
},
);
}
},
},
this this
); );
} }
@ -229,7 +271,151 @@ class UI {
this.handleMessage(message); this.handleMessage(message);
} }
verifyIframeTransparency() {
if (this.isGlobal) {
return;
}
if (!this.siteSettings || !this.settings) {
console.warn('settings not provided, not verifying transparency');
return;
}
if (this.performedTransparencyCheck || !this.isOpaque || !this.uiConfig?.parentElement) {
// console.warn('transparency was already checked, opacity is zero, or parent element isnt a thing:', this.performedTransparencyCheck, 'is opaque:', this.isOpaque, this.uiConfig?.parentElement);
return;
}
let reportTelemetry = true;
// if (this.siteSettings.data.workarounds?.disableSchemeAwareness) {
// if (this.settings.active.telemetry?.iframeTransparency?.[window.location.hostname]?.reportedWithColorSchemeDisabled) {
// reportTelemetry = false;
// } else {
// this.settings.setProp(['telemetry', window.location.hostname, 'reportedWithColorSchemaDisabled'], true)
// }
// } else {
// if (this.settings.active.telemetry?.iframeTransparency?.[window.location.hostname]?.reportedWithColorSchemeAllowed) {
// reportTelemetry = false;
// } else {
// this.settings.setProp(['telemetry', window.location.hostname, 'reportedWithColorSchemeAllowed'], true)
// }
// }
const rect = this.uiConfig.parentElement.getBoundingClientRect();
this.preventHiding = true;
setTimeout( () => {
this.eventBus.send(
'verify-iframe-transparency',
{
playerData: {
y: rect.top,
x: rect.left,
width: rect.width,
height: rect.height,
},
telemetryData: {
reportTelemetry,
}
}
);
}, 50);
this.performedTransparencyCheck = true;
setTimeout(() => {
this.preventHiding = false;
if (this.wantsToHide) {
this.setUiVisibility(false);
}
if (this.wantsToTransparent) {
this.setUiOpacity(false);
}
this.wantsToHide = false;
this.wantsToTransparent = false;
});
}
/**
* Generates marker positions for bug mitigations
*/
generateDebugMarker(x, y) {
const [parentMainDimension, parentCrossDimension] = y === 'center' ? ['height', 'width'] : ['width', 'height'];
let anchorStyle;
if (x === 'center' && x === y) {
anchorStyle = 'left: 50%; top: 50%; transform: translate(-50%, -50%);';
} else {
switch (x) {
case 'left':
anchorStyle = 'left: 0px;';
break;
case 'center':
anchorStyle = 'left: 50%; transform: translateX(-50%);';
break;
case 'right':
anchorStyle = 'right: 0px;';
break;
}
switch (y) {
case 'top':
anchorStyle = `${anchorStyle} top: 0px;`;
break;
case 'center':
anchorStyle = `${anchorStyle} top: 50%; transform: translateY(-50%);`;
break;
case 'bottom':
anchorStyle = `${anchorStyle} bottom: 0px;`;
break;
}
}
let [mainAxis, crossAxis] = y === 'center' ? ['left', 'top'] : ['top', 'left'];
const template = document.createElement('template');
template.innerHTML = `
<div style="position: absolute; ${anchorStyle} ${parentMainDimension}: 4px; ${parentCrossDimension}: 1px; pointer-events: none;">
<div style="position: relative; width: 100%; height: 100%">
<div style="position: absolute; ${mainAxis}: 0px; ${crossAxis}: 0px; width: 1px; height: 1px; background-color: #000102"></div>
<div style="position: absolute; ${mainAxis}: 1px; ${crossAxis}: 0px; width: 1px; height: 1px; background-color: #030405"></div>
<div style="position: absolute; ${mainAxis}: 2px; ${crossAxis}: 0px; width: 1px; height: 1px; background-color: #050403"></div>
<div style="position: absolute; ${mainAxis}: 3px; ${crossAxis}: 0px; width: 1px; height: 1px; background-color: #020100"></div>
</div>
<div style="top: 5px; left: 5px; opacity: 0">
This marker is Chrome Shitiness Mitigation mechanism for Ultrawidify. It turns out that as of 2025-01, Chrome does not correctly respect
allowTransparency property on certain iframes, and will force white or black background across the entire element. It is unclear what's
causing the issue so far, it seems to appear randomly.
</div>
</div>
`.replace(/\s+/g, ' ').trim();
return template.content.firstChild;
}
setUiOpacity(visible) {
if (!visible && this.isVisible && this.preventHiding) {
this.wantsToTransparent = true;
return;
}
this.uiIframe.style.opacity = visible ? '100' : '0';
this.isOpaque = visible;
if (visible) {
this.verifyIframeTransparency();
}
}
setUiVisibility(visible) { setUiVisibility(visible) {
if (!visible && this.isVisible && this.preventHiding) {
this.wantsToHide = true;
return;
}
this.isVisible = visible;
if (visible) { if (visible) {
this.element.style.width = '100%'; this.element.style.width = '100%';
this.element.style.height = '100%'; this.element.style.height = '100%';
@ -241,6 +427,7 @@ class UI {
this.uiIframe.style.width = '0px'; this.uiIframe.style.width = '0px';
this.uiIframe.style.height = '0px'; this.uiIframe.style.height = '0px';
} }
} }
async enable() { async enable() {
@ -342,7 +529,8 @@ class UI {
} }
this.uiIframe.style.pointerEvents = event.data.clickable ? 'auto' : 'none'; this.uiIframe.style.pointerEvents = event.data.clickable ? 'auto' : 'none';
this.uiIframe.style.opacity = event.data.opacity || this.isGlobal ? '100' : '0'; this.setUiOpacity(event.data.opacity || this.isGlobal);
// this.setUiVisibility( event.data.opacity || this.isGlobal );
break; break;
case 'uw-bus-tunnel': case 'uw-bus-tunnel':
const busCommand = event.data.payload; const busCommand = event.data.payload;
@ -355,7 +543,8 @@ class UI {
this.setUiVisibility(!this.isGlobal); this.setUiVisibility(!this.isGlobal);
break; break;
case 'uwui-hidden': case 'uwui-hidden':
this.uiIframe.style.opacity = event.data.opacity || this.isGlobal ? '100' : '0'; this.setUiOpacity(event.data.opacity || this.isGlobal);
// this.setUiVisibility(event.data.opacity || this.isGlobal);
break; break;
case 'uwui-global-window-hidden': case 'uwui-global-window-hidden':
if (!this.isGlobal) { if (!this.isGlobal) {

View File

@ -248,7 +248,11 @@ class PlayerData {
//#endregion //#endregion
deferredUiInitialization(playerDimensions) { deferredUiInitialization(playerDimensions) {
if (this.ui || ! this.videoData.settings.active.ui?.inPlayer?.enabled) { if (
this.ui
|| ! this.videoData.settings.active.ui?.inPlayer?.enabled
|| (this.siteSettings.data.ui && !this.siteSettings.data.ui.enabled)
) {
return; return;
} }
@ -265,7 +269,9 @@ class PlayerData {
parentElement: this.element, parentElement: this.element,
eventBus: this.eventBus, eventBus: this.eventBus,
playerData: this, playerData: this,
uiSettings: this.videoData.settings.active.ui uiSettings: this.videoData.settings.active.ui,
settings: this.videoData.settings,
siteSettings: this.siteSettings
} }
); );