Whitespace

This commit is contained in:
Tamius Han 2021-10-25 23:11:34 +02:00
parent 746a78577e
commit a4948d3eef
5 changed files with 146 additions and 134 deletions

View File

@ -14,7 +14,7 @@ interface ActionScopeInterface {
code?: string, code?: string,
ctrlKey?: boolean, ctrlKey?: boolean,
metaKey?: boolean, metaKey?: boolean,
altKey?: boolean, altKey?: boolean,
shiftKey?: boolean, shiftKey?: boolean,
onKeyUp?: boolean, onKeyUp?: boolean,
onKeyDown?: boolean, onKeyDown?: boolean,
@ -22,10 +22,17 @@ interface ActionScopeInterface {
}[], }[],
} }
interface RestrictionsSettings {
disableOnSmallPlayers?: boolean; // Whether ultrawidify should disable itself when the player is small
minAllowedWidth?: number; // if player is less than this many px wide, ultrawidify will disable itself
minAllowedHeight?: number; // if player is less than this many px tall, ultrawidify will disable itself
onlyAllowInFullscreen?: boolean; // if enabled, ultrawidify will be disabled when not in full screen regardless of what previous two options say
}
interface SettingsInterface { interface SettingsInterface {
arDetect: { arDetect: {
disabledReason: string, // if automatic aspect ratio has been disabled, show reason disabledReason: string, // if automatic aspect ratio has been disabled, show reason
allowedMisaligned: number, // top and bottom letterbox thickness can differ by this much. allowedMisaligned: number, // top and bottom letterbox thickness can differ by this much.
// Any more and we don't adjust ar. // Any more and we don't adjust ar.
allowedArVariance: number, // amount by which old ar can differ from the new (1 = 100%) allowedArVariance: number, // amount by which old ar can differ from the new (1 = 100%)
timers: { // autodetection frequency timers: { // autodetection frequency
@ -56,14 +63,14 @@ interface SettingsInterface {
}, },
}, },
// samplingInterval: 10, // we sample at columns at (width/this) * [ 1 .. this - 1] // samplingInterval: 10, // we sample at columns at (width/this) * [ 1 .. this - 1]
blackframe: { blackframe: {
sufficientColorVariance: number, // calculate difference between average intensity and pixel, for every pixel for every color sufficientColorVariance: number, // calculate difference between average intensity and pixel, for every pixel for every color
// component. Average intensity is normalized to where 0 is black and 1 is biggest value for // component. Average intensity is normalized to where 0 is black and 1 is biggest value for
// that component. If sum of differences between normalized average intensity and normalized // that component. If sum of differences between normalized average intensity and normalized
// component varies more than this % between color components, we can afford to use less strict // component varies more than this % between color components, we can afford to use less strict
// cumulative threshold. // cumulative threshold.
cumulativeThresholdLax: number, cumulativeThresholdLax: number,
cumulativeThresholdStrict: number,// if we add values of all pixels together and get more than this, the frame is bright enough. cumulativeThresholdStrict: number,// if we add values of all pixels together and get more than this, the frame is bright enough.
// (note: blackframe is 16x9 px -> 144px total. cumulative threshold can be reached fast) // (note: blackframe is 16x9 px -> 144px total. cumulative threshold can be reached fast)
blackPixelsCondition: number, // How much pixels must be black (1 all, 0 none) before we consider frame as black. Takes blackPixelsCondition: number, // How much pixels must be black (1 all, 0 none) before we consider frame as black. Takes
@ -103,7 +110,7 @@ interface SettingsInterface {
randomCols: number, // we add this many randomly selected columns to the static columns randomCols: number, // we add this many randomly selected columns to the static columns
staticRows: number, // forms grid with staticSampleCols. Determined in the same way. For black frame checks staticRows: number, // forms grid with staticSampleCols. Determined in the same way. For black frame checks
}, },
guardLine: { // all pixels on the guardline need to be black, or else we trigger AR recalculation guardLine: { // all pixels on the guardline need to be black, or else we trigger AR recalculation
// (if AR fails to be recalculated, we reset AR) // (if AR fails to be recalculated, we reset AR)
enabled: boolean, enabled: boolean,
ignoreEdgeMargin: number, // we ignore anything that pokes over the black line this close to the edge ignoreEdgeMargin: number, // we ignore anything that pokes over the black line this close to the edge
@ -117,14 +124,14 @@ interface SettingsInterface {
safetyBorderPx: number, // determines the thickness of safety border in fallback mode safetyBorderPx: number, // determines the thickness of safety border in fallback mode
noTriggerZonePx: number // if we detect edge less than this many pixels thick, we don't correct. noTriggerZonePx: number // if we detect edge less than this many pixels thick, we don't correct.
}, },
arSwitchLimiter: { // to be implemented arSwitchLimiter: { // to be implemented
switches: number, // we can switch this many times switches: number, // we can switch this many times
period: number // per this period period: number // per this period
}, },
edgeDetection: { edgeDetection: {
sampleWidth: number, // we take a sample this wide for edge detection sampleWidth: number, // we take a sample this wide for edge detection
detectionThreshold: number, // sample needs to have this many non-black pixels to be a valid edge detectionThreshold: number, // sample needs to have this many non-black pixels to be a valid edge
confirmationThreshold: number, // confirmationThreshold: number, //
singleSideConfirmationThreshold: number, // we need this much edges (out of all samples, not just edges) in order singleSideConfirmationThreshold: number, // we need this much edges (out of all samples, not just edges) in order
// to confirm an edge in case there's no edges on top or bottom (other // to confirm an edge in case there's no edges on top or bottom (other
// than logo, of course) // than logo, of course)
@ -138,11 +145,11 @@ interface SettingsInterface {
// are now. (NOTE: keep this less than 1 in case we implement logo detection) // are now. (NOTE: keep this less than 1 in case we implement logo detection)
}, },
pillarTest: { pillarTest: {
ignoreThinPillarsPx: number, // ignore pillars that are less than this many pixels thick. ignoreThinPillarsPx: number, // ignore pillars that are less than this many pixels thick.
allowMisaligned: number // left and right edge can vary this much (%) allowMisaligned: number // left and right edge can vary this much (%)
}, },
textLineTest: { textLineTest: {
nonTextPulse: number, // if a single continuous pulse has this many non-black pixels, we aren't dealing nonTextPulse: number, // if a single continuous pulse has this many non-black pixels, we aren't dealing
// with text. This value is relative to canvas width (%) // with text. This value is relative to canvas width (%)
pulsesToConfirm: number, // this is a threshold to confirm we're seeing text. pulsesToConfirm: number, // this is a threshold to confirm we're seeing text.
pulsesToConfirmIfHalfBlack: number, // this is the threshold to confirm we're seeing text if longest black pulse pulsesToConfirmIfHalfBlack: number, // this is the threshold to confirm we're seeing text if longest black pulse
@ -150,11 +157,15 @@ interface SettingsInterface {
testRowOffset: number // we test this % of height from detected edge testRowOffset: number // we test this % of height from detected edge
} }
}, },
restrictions?: RestrictionsSettings;
zoom: { zoom: {
minLogZoom: number, minLogZoom: number,
maxLogZoom: number, maxLogZoom: number,
announceDebounce: number // we wait this long before announcing new zoom announceDebounce: number // we wait this long before announcing new zoom
}, },
miscSettings: { miscSettings: {
mousePan: { mousePan: {
enabled: boolean enabled: boolean
@ -197,8 +208,8 @@ interface SettingsInterface {
// ::: ACTIONS ::: // ::: ACTIONS :::
// ----------------------------------------- // -----------------------------------------
// Nastavitve za ukaze. Zamenja stare nastavitve za bližnične tipke. // Nastavitve za ukaze. Zamenja stare nastavitve za bližnične tipke.
// //
// Polje 'shortcut' je tabela, če se slučajno lotimo kdaj delati choordov. // Polje 'shortcut' je tabela, če se slučajno lotimo kdaj delati choordov.
actions: { actions: {
name?: string, // name displayed in settings name?: string, // name displayed in settings
label?: string, // name displayed in ui (can be overridden in scope/playerUi) label?: string, // name displayed in ui (can be overridden in scope/playerUi)
@ -226,31 +237,31 @@ interface SettingsInterface {
// ----------------------------------------- // -----------------------------------------
// Nastavitve za posamezno stran // Nastavitve za posamezno stran
// Config for a given page: // Config for a given page:
// //
// <hostname> : { // <hostname> : {
// status: <option> // should extension work on this site? // status: <option> // should extension work on this site?
// arStatus: <option> // should we do autodetection on this site? // arStatus: <option> // should we do autodetection on this site?
// //
// defaultAr?: <ratio> // automatically apply this aspect ratio on this side. Use extension defaults if undefined. // defaultAr?: <ratio> // automatically apply this aspect ratio on this side. Use extension defaults if undefined.
// stretch? <stretch mode> // automatically stretch video on this site in this manner // stretch? <stretch mode> // automatically stretch video on this site in this manner
// videoAlignment? <left|center|right> // videoAlignment? <left|center|right>
// //
// type: <official|community|user> // 'official' — blessed by Tam. // type: <official|community|user> // 'official' — blessed by Tam.
// // 'community' — blessed by reddit. // // 'community' — blessed by reddit.
// // 'user' — user-defined (not here) // // 'user' — user-defined (not here)
// override: <true|false> // override user settings for this site on update // override: <true|false> // override user settings for this site on update
// } // }
// //
// Veljavne vrednosti za možnosti // Veljavne vrednosti za možnosti
// Valid values for options: // Valid values for options:
// //
// status, arStatus, statusEmbedded: // status, arStatus, statusEmbedded:
// //
// * enabled — always allow, full // * enabled — always allow, full
// * basic — allow, but only the basic version without playerData // * basic — allow, but only the basic version without playerData
// * default — allow if default is to allow, block if default is to block // * default — allow if default is to allow, block if default is to block
// * disabled — never allow // * disabled — never allow
// //
sites: { sites: {
[x: string]: { [x: string]: {
mode?: ExtensionMode, mode?: ExtensionMode,
@ -286,8 +297,10 @@ interface SettingsInterface {
}, },
css?: string; css?: string;
usePlayerArInFullscreen?: boolean; usePlayerArInFullscreen?: boolean;
restrictions?: RestrictionsSettings;
} }
} }
} }
export default SettingsInterface; export default SettingsInterface;

View File

@ -39,7 +39,7 @@ class PageInfo {
currentCrop: any; currentCrop: any;
actionHandlerInitQueue: any[] = []; actionHandlerInitQueue: any[] = [];
currentZoomScale: number = 1; currentZoomScale: number = 1;
actionHandler: any; actionHandler: any;
//#endregion //#endregion
@ -51,7 +51,7 @@ class PageInfo {
this.extensionMode = extensionMode; this.extensionMode = extensionMode;
this.readOnly = readOnly; this.readOnly = readOnly;
if (comms){ if (comms){
this.comms = comms; this.comms = comms;
} }
@ -179,10 +179,10 @@ class PageInfo {
* 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
* own <video> html element on the page. * own <video> html element on the page.
* @param rescanReason Why was the rescan triggered. Mostly used for logging. * @param rescanReason Why was the rescan triggered. Mostly used for logging.
* @returns * @returns
*/ */
rescan(rescanReason?: RescanReason){ rescan(rescanReason?: RescanReason){
// 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));
for (const orphan of orphans) { for (const orphan of orphans) {
@ -198,7 +198,7 @@ class PageInfo {
if(!vids || vids.length == 0){ if(!vids || vids.length == 0){
this.hasVideos = false; this.hasVideos = false;
if(rescanReason == RescanReason.PERIODIC){ if(rescanReason == RescanReason.PERIODIC){
this.logger.log('info', 'videoRescan', "[PageInfo::rescan] Scheduling normal rescan.") this.logger.log('info', 'videoRescan', "[PageInfo::rescan] Scheduling normal rescan.")
this.scheduleRescan(RescanReason.PERIODIC); this.scheduleRescan(RescanReason.PERIODIC);
@ -221,14 +221,14 @@ class PageInfo {
if(!videoElement.offsetWidth || !videoElement.offsetHeight) { if(!videoElement.offsetWidth || !videoElement.offsetHeight) {
continue; continue;
} }
// 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;
// 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
if (this.readOnly) { if (this.readOnly) {
// in lite mode, we're done. This is all the info we want, but we want to actually start doing // 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. // things that interfere with the website. We still want to be running a rescan, tho.
if(rescanReason == RescanReason.PERIODIC){ if(rescanReason == RescanReason.PERIODIC){
@ -241,11 +241,11 @@ class PageInfo {
try { try {
const newVideo = new VideoData(videoElement, this.settings, this); const newVideo = new VideoData(videoElement, this.settings, this);
this.videos.push({videoData: newVideo, element: videoElement}); this.videos.push({videoData: newVideo, element: videoElement});
} catch (e) { } catch (e) {
this.logger.log('error', 'debug', "rescan error: failed to initialize videoData. Skipping this video.",e); this.logger.log('error', 'debug', "rescan error: failed to initialize videoData. Skipping this video.",e);
} }
this.logger.log('info', 'videoRescan', "END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n") this.logger.log('info', 'videoRescan', "END VIDEO INITIALIZATION\n\n\n-------------------------------------\nvideos[] is now this:", this.videos,"\n\n\n\n\n\n\n\n")
} }
@ -254,24 +254,24 @@ class PageInfo {
// 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.comms) { if (this.comms) {
// We used to send "register video" requests only on the first load, or if the number of // 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 // videos on the page has changed. However, since Chrome Web Store started to require every
// extension requiring "broad permissions" to undergo manual review // extension requiring "broad permissions" to undergo manual review
// ... and since Chrome Web Store is known for taking their sweet ass time reviewing extensions, // ... and since Chrome Web Store is known for taking their sweet ass time reviewing extensions,
// with review times north of an entire fucking month // with review times north of an entire fucking month
// ... and since the legacy way of checking whether our frames-with-videos cache in background // ... 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()/ // script contains any frames that no longer exist required us to use webNavigation.getFrame()/
// webNavigation.getAllFrames(), which requires a permission that triggers a review. // 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 // 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 // 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. // things in the less-than-optimal. more-than-retarded way.
// //
// no but honestly fuck Chrome. // no but honestly fuck Chrome.
// if (this.videos.length != oldVideoCount) { // if (this.videos.length != oldVideoCount) {
// } // }
if (this.videos.length > 0) { if (this.videos.length > 0) {
// this.comms.registerVideo({host: window.location.hostname, location: window.location}); // this.comms.registerVideo({host: window.location.hostname, location: window.location});
this.comms.registerVideo(); this.comms.registerVideo();
@ -313,7 +313,7 @@ class PageInfo {
} }
let ths = this; let ths = this;
this.rescanTimer = setTimeout(function(rescanReason){ this.rescanTimer = setTimeout(function(rescanReason){
ths.rescanTimer = null; ths.rescanTimer = null;
ths.rescan(rescanReason); ths.rescan(rescanReason);
@ -331,7 +331,7 @@ class PageInfo {
} }
let ths = this; let ths = this;
this.urlCheckTimer = setTimeout(function(){ this.urlCheckTimer = setTimeout(function(){
ths.urlCheckTimer = null; ths.urlCheckTimer = null;
ths.ghettoUrlCheck(); ths.ghettoUrlCheck();
@ -345,7 +345,7 @@ class PageInfo {
ghettoUrlCheck() { ghettoUrlCheck() {
if (this.lastUrl != window.location.href){ if (this.lastUrl != window.location.href){
this.logger.log('error', 'videoRescan', "[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!"); this.logger.log('error', 'videoRescan', "[PageInfo::ghettoUrlCheck] URL has changed. Triggering a rescan!");
this.rescan(RescanReason.URL_CHANGE); this.rescan(RescanReason.URL_CHANGE);
this.lastUrl = window.location.href; this.lastUrl = window.location.href;
} }
@ -377,7 +377,7 @@ class PageInfo {
if (vd.videoData.isPlaying()) { if (vd.videoData.isPlaying()) {
vd.videoData.pause(); vd.videoData.pause();
} }
} }
} else { } else {
for(let vd of this.videos){ for(let vd of this.videos){
vd.videoData.pause(); vd.videoData.pause();
@ -426,7 +426,7 @@ class PageInfo {
stopArDetection(playingOnly){ stopArDetection(playingOnly){
if (playingOnly) { if (playingOnly) {
for(let vd of this.videos){ for(let vd of this.videos){
if (vd.videoData.isPlaying()) { if (vd.videoData.isPlaying()) {
vd.videoData.stopArDetection(); vd.videoData.stopArDetection();
} }
} }
@ -474,11 +474,11 @@ class PageInfo {
} }
} }
} }
setVideoAlignment(videoAlignment, playingOnly) { setVideoAlignment(videoAlignment, playingOnly) {
if (playingOnly) { if (playingOnly) {
for(let vd of this.videos) { for(let vd of this.videos) {
if (vd.videoData.isPlaying()) { if (vd.videoData.isPlaying()) {
vd.videoData.setVideoAlignment(videoAlignment) vd.videoData.setVideoAlignment(videoAlignment)
} }
} }
@ -555,7 +555,7 @@ class PageInfo {
} }
} }
markPlayer(name, color) { markPlayer(name, color) {
for (let vd of this.videos) { for (let vd of this.videos) {
vd.videoData.markPlayer(name,color); vd.videoData.markPlayer(name,color);
} }
@ -604,7 +604,7 @@ class PageInfo {
setArPersistence(persistenceMode) { setArPersistence(persistenceMode) {
// name of this function is mildly misleading — we don't really _set_ ar persistence. (Ar persistence // name of this function is mildly misleading — we don't really _set_ ar persistence. (Ar persistence
// mode is set and saved via popup or keyboard shortcuts, if user defined them) We just save the current // mode is set and saved via popup or keyboard shortcuts, if user defined them) We just save the current
// aspect ratio whenever aspect ratio persistence mode changes. // aspect ratio whenever aspect ratio persistence mode changes.
if (persistenceMode === CropModePersistence.CurrentSession) { if (persistenceMode === CropModePersistence.CurrentSession) {
sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(this.currentCrop)); sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(this.currentCrop));
} else if (persistenceMode === CropModePersistence.Forever) { } else if (persistenceMode === CropModePersistence.Forever) {
@ -615,7 +615,7 @@ class PageInfo {
this.settings.active.sites[window.location.hostname] = this.settings.getDefaultOption(); this.settings.active.sites[window.location.hostname] = this.settings.getDefaultOption();
this.settings.active.sites[window.location.hostname]['defaultAr'] = this.currentCrop; this.settings.active.sites[window.location.hostname]['defaultAr'] = this.currentCrop;
} }
this.settings.saveWithoutReload(); this.settings.saveWithoutReload();
} }
} }
@ -632,7 +632,7 @@ class PageInfo {
} }
this.defaultCrop = ar; this.defaultCrop = ar;
if (cropModePersistence === CropModePersistence.CurrentSession) { if (cropModePersistence === CropModePersistence.CurrentSession) {
sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(ar)); sessionStorage.setItem('uw-crop-mode-session-persistence', JSON.stringify(ar));
} else if (cropModePersistence === CropModePersistence.Forever) { } else if (cropModePersistence === CropModePersistence.Forever) {
@ -643,7 +643,7 @@ class PageInfo {
this.settings.active.sites[window.location.hostname] = this.settings.getDefaultOption(); this.settings.active.sites[window.location.hostname] = this.settings.getDefaultOption();
this.settings.active.sites[window.location.hostname]['defaultAr'] = ar; this.settings.active.sites[window.location.hostname]['defaultAr'] = ar;
} }
this.settings.saveWithoutReload(); this.settings.saveWithoutReload();
} }
} }

View File

@ -202,7 +202,7 @@ class PlayerData {
// attributeFilter: ['style', 'class'], // attributeFilter: ['style', 'class'],
attributeOldValue: true, attributeOldValue: true,
}; };
this.observer.observe(this.element); this.observer.observe(this.element);
} catch (e) { } catch (e) {
console.error("failed to set observer",e ) console.error("failed to set observer",e )
@ -361,7 +361,6 @@ class PlayerData {
element = element.parentNode; element = element.parentNode;
} }
if (element) { if (element) {
this.updatePlayerDimensions(element);
return element; return element;
} }
} else if (this.settings.active.sites[host]?.DOM?.player?.querySelectors) { } else if (this.settings.active.sites[host]?.DOM?.player?.querySelectors) {
@ -372,7 +371,7 @@ class PlayerData {
// Let's see how this works // Let's see how this works
if (this.collectionHas(allSelectors, element)) { if (this.collectionHas(allSelectors, element)) {
score = 100; // every matching element gets a baseline 100 points score = 100; // every matching element gets a baseline 100 points
// elements that match the size get a hefty bonus // elements that match the size get a hefty bonus
if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2)) if ( (element.offsetWidth >= videoWidth && this.equalish(element.offsetHeight, videoHeight, 2))
|| (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) { || (element.offsetHeight >= videoHeight && this.equalish(element.offsetWidth, videoHeight, 2))) {
@ -414,12 +413,12 @@ class PlayerData {
element = element.parentNode; element = element.parentNode;
continue; continue;
} }
// element is player, if at least one of the sides is as long as the video // element is player, if at least one of the sides is as long as the video
// note that we can't make any additional assumptions with regards to player // note that we can't make any additional assumptions with regards to player
// size, since there are both cases where the other side is bigger _and_ cases // size, since there are both cases where the other side is bigger _and_ cases
// where other side is smaller than the video. // where other side is smaller than the video.
// //
// Don't bother thinking about this too much, as any "thinking" was quickly // Don't bother thinking about this too much, as any "thinking" was quickly
// corrected by bugs caused by various edge cases. // corrected by bugs caused by various edge cases.
if ( if (
@ -439,7 +438,7 @@ class PlayerData {
score -= scorePenalty * penaltyMultiplier++; score -= scorePenalty * penaltyMultiplier++;
// the bigger the size difference between the video and the player, // the bigger the size difference between the video and the player,
// the more penalty we'll incur. Since we did some grace ith // the more penalty we'll incur. Since we did some grace ith
let playerSizePenalty = 1; let playerSizePenalty = 1;
if ( element.offsetHeight > (videoHeight + 5)) { if ( element.offsetHeight > (videoHeight + 5)) {
playerSizePenalty = (element.offsetWidth - videoHeight) * sizePenaltyMultiplier; playerSizePenalty = (element.offsetWidth - videoHeight) * sizePenaltyMultiplier;
@ -455,7 +454,7 @@ class PlayerData {
score: score, score: score,
}); });
} }
element = element.parentNode; element = element.parentNode;
} }
@ -465,7 +464,7 @@ class PlayerData {
if (elementQ.length) { if (elementQ.length) {
// return element with biggest score // return element with biggest score
const playerElement = elementQ.sort( (a,b) => b.score - a.score)[0].element; const playerElement = elementQ.sort( (a,b) => b.score - a.score)[0].element;
this.updatePlayerDimensions(playerElement); this.updatePlayerDimensions(playerElement);
return playerElement; return playerElement;
} }
@ -487,7 +486,7 @@ class PlayerData {
forceDetectPlayerElementChange() { forceDetectPlayerElementChange() {
// Player dimension changes get calculated every time updatePlayerDimensions is called (which happens // Player dimension changes get calculated every time updatePlayerDimensions is called (which happens
// every time getPlayer() detects an element). If updatePlayerDimension detects dimensions were changed, // every time getPlayer() detects an element). If updatePlayerDimension detects dimensions were changed,
// it will always re-apply current crop, rendering this function little more than a fancy alias for // it will always re-apply current crop, rendering this function little more than a fancy alias for
// getPlayer(). // getPlayer().
this.getPlayer(); this.getPlayer();
} }

View File

@ -57,10 +57,10 @@ class VideoData {
return 1; return 1;
} }
} }
constructor(video, settings, pageInfo){ constructor(video, settings, pageInfo){
(window as any).ultrawidify.addVideo(this); (window as any).ultrawidify.addVideo(this);
this.logger = pageInfo.logger; this.logger = pageInfo.logger;
this.arSetupComplete = false; this.arSetupComplete = false;
this.video = video; this.video = video;
@ -87,15 +87,15 @@ class VideoData {
async onVideoLoaded() { async onVideoLoaded() {
if (!this.videoLoaded) { if (!this.videoLoaded) {
/** /**
* video.readyState 101: * video.readyState 101:
* 0 no info. Can't play. * 0 no info. Can't play.
* 1 we have metadata but nothing else * 1 we have metadata but nothing else
* 2 we have data for current playback position, but not future <--- meaning current frame, meaning Aard can work here or higher * 2 we have data for current playback position, but not future <--- meaning current frame, meaning Aard can work here or higher
* 3 we have a lil bit for the future * 3 we have a lil bit for the future
* 4 we'll survive to the end * 4 we'll survive to the end
*/ */
if (!this.video?.videoWidth || !this.video?.videoHeight || this.video.readyState < 2) { if (!this.video?.videoWidth || !this.video?.videoHeight || this.video.readyState < 2) {
return; // onVideoLoaded is a lie in this case return; // onVideoLoaded is a lie in this case
} }
@ -199,7 +199,7 @@ class VideoData {
// INIT OBSERVERS // INIT OBSERVERS
try { try {
if (BrowserDetect.firefox) { if (BrowserDetect.firefox) {
this.observer = new ResizeObserver( this.observer = new ResizeObserver(
_.debounce( _.debounce(
this.onVideoDimensionsChanged, this.onVideoDimensionsChanged,
250, 250,
@ -212,11 +212,11 @@ class VideoData {
} else { } else {
// Chrome for some reason insists that this.onPlayerDimensionsChanged is not a function // Chrome for some reason insists that this.onPlayerDimensionsChanged is not a function
// when it's not wrapped into an anonymous function // when it's not wrapped into an anonymous function
this.observer = new ResizeObserver( this.observer = new ResizeObserver(
_.debounce( _.debounce(
(m, o) => { (m, o) => {
this.onVideoDimensionsChanged(m, o) this.onVideoDimensionsChanged(m, o)
}, },
250, 250,
{ {
leading: true, leading: true,
@ -252,7 +252,7 @@ class VideoData {
// start fallback video/player size detection // start fallback video/player size detection
this.fallbackChangeDetection(); this.fallbackChangeDetection();
// force reload last aspect ratio (if default crop ratio exists), but only after the video is // force reload last aspect ratio (if default crop ratio exists), but only after the video is
if (this.pageInfo.defaultCrop) { if (this.pageInfo.defaultCrop) {
this.resizer.setAr(this.pageInfo.defaultCrop); this.resizer.setAr(this.pageInfo.defaultCrop);
} }
@ -315,7 +315,7 @@ class VideoData {
if (this.video) { if (this.video) {
this.video.classList.remove(this.userCssClassName); this.video.classList.remove(this.userCssClassName);
this.video.classList.remove('uw-ultrawidify-base-wide-screen'); this.video.classList.remove('uw-ultrawidify-base-wide-screen');
this.video.removeEventListener('onloadeddata', this.onLoadedData); this.video.removeEventListener('onloadeddata', this.onLoadedData);
this.video.removeEventListener('onloadedmetadata', this.onLoadedMetadata); this.video.removeEventListener('onloadedmetadata', this.onLoadedMetadata);
@ -354,14 +354,14 @@ class VideoData {
} }
//#endregion //#endregion
restoreCrop() { restoreCrop() {
this.logger.log('info', 'debug', '[VideoData::restoreCrop] Attempting to reset aspect ratio.') this.logger.log('info', 'debug', '[VideoData::restoreCrop] Attempting to reset aspect ratio.')
// if we have default crop set for this page, apply this. // if we have default crop set for this page, apply this.
// otherwise, reset crop // otherwise, reset crop
if (this.pageInfo.defaultCrop) { if (this.pageInfo.defaultCrop) {
this.resizer.setAr(this.pageInfo.defaultCrop); this.resizer.setAr(this.pageInfo.defaultCrop);
} else { } else {
this.resizer.reset(); this.resizer.reset();
try { try {
this.stopArDetection(); this.stopArDetection();
@ -500,7 +500,7 @@ class VideoData {
this.player.forceDetectPlayerElementChange(); this.player.forceDetectPlayerElementChange();
this.restoreAr(); this.restoreAr();
} }
} catch(e) { } catch(e) {
console.error('Validating video offsets failed:', e) console.error('Validating video offsets failed:', e)
} }
@ -518,7 +518,7 @@ class VideoData {
// This will _always_ give us an array. Empty string gives an array // This will _always_ give us an array. Empty string gives an array
// that contains one element. That element is an empty string. // that contains one element. That element is an empty string.
const styleArray = (this.video.getAttribute('style') || '').split(';'); const styleArray = (this.video.getAttribute('style') || '').split(';');
const styleObject = {}; const styleObject = {};
for (const style of styleArray) { for (const style of styleArray) {
@ -537,10 +537,10 @@ class VideoData {
} }
/** /**
* Some sites try to accomodate ultrawide users by "cropping" videos * Some sites try to accommodate ultrawide users by "cropping" videos
* by setting 'style' attribute of the video element to 'height: X%', * by setting 'style' attribute of the video element to 'height: X%',
* where 'X' is something greater than 100. * where 'X' is something greater than 100.
* *
* This function gets that percentage and converts it into a factor. * This function gets that percentage and converts it into a factor.
*/ */
getHeightCompensationFactor() { getHeightCompensationFactor() {
@ -579,7 +579,7 @@ class VideoData {
this.arDetector.init(); this.arDetector.init();
} }
} }
startArDetection() { startArDetection() {
this.logger.log('info', 'debug', "[VideoData::startArDetection] starting AR detection") this.logger.log('info', 'debug', "[VideoData::startArDetection] starting AR detection")
if(this.destroyed || this.invalid) { if(this.destroyed || this.invalid) {
@ -670,7 +670,7 @@ class VideoData {
if (this.invalid) { if (this.invalid) {
return; return;
} }
if (ar.type === AspectRatioType.Fixed || ar.type === AspectRatioType.FitHeight || ar.type === AspectRatioType.FitHeight) { if (ar.type === AspectRatioType.Fixed || ar.type === AspectRatioType.FitHeight || ar.type === AspectRatioType.FitHeight) {
this.player.forceRefreshPlayerElement(); this.player.forceRefreshPlayerElement();
} }
@ -788,7 +788,7 @@ class VideoData {
this.logger.log('info', 'debug', "[VideoDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions.width, this.dimensions.height, "new dimensions:", this.video.offsetWidth, this.video.offsetHeight); this.logger.log('info', 'debug', "[VideoDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions.width, this.dimensions.height, "new dimensions:", this.video.offsetWidth, this.video.offsetHeight);
} }
} }
// if size doesn't match, update & return true // if size doesn't match, update & return true
if (this.dimensions?.width != videoWidth if (this.dimensions?.width != videoWidth
|| this.dimensions?.height != videoHeight ){ || this.dimensions?.height != videoHeight ){

View File

@ -59,7 +59,7 @@ class Resizer {
this.settings = videoData.settings; this.settings = videoData.settings;
this.scaler = new Scaler(this.conf); this.scaler = new Scaler(this.conf);
this.stretcher = new Stretcher(this.conf); this.stretcher = new Stretcher(this.conf);
this.zoom = new Zoom(this.conf); this.zoom = new Zoom(this.conf);
this.videoAlignment = this.settings.getDefaultVideoAlignment(window.location.hostname); // this is initial video alignment this.videoAlignment = this.settings.getDefaultVideoAlignment(window.location.hostname); // this is initial video alignment
@ -72,17 +72,17 @@ class Resizer {
this.canPan = false; this.canPan = false;
} }
this.userCssClassName = videoData.userCssClassName; this.userCssClassName = videoData.userCssClassName;
} }
injectCss(css) { injectCss(css) {
this.conf.pageInfo.injectCss(css); this.conf.pageInfo.injectCss(css);
} }
ejectCss(css) { ejectCss(css) {
this.conf.pageInfo.ejectCss(css); this.conf.pageInfo.ejectCss(css);
} }
replaceCss(oldCss, newCss) { replaceCss(oldCss, newCss) {
this.conf.pageInfo.replaceCss(oldCss, newCss); this.conf.pageInfo.replaceCss(oldCss, newCss);
} }
@ -101,7 +101,7 @@ class Resizer {
if (ar.type !== AspectRatioType.FitWidth && ar.type !== AspectRatioType.FitHeight && ar.ratio) { if (ar.type !== AspectRatioType.FitWidth && ar.type !== AspectRatioType.FitHeight && ar.ratio) {
return ar; return ar;
} }
// Skrbi za "stare" možnosti, kot na primer "na širino zaslona", "na višino zaslona" in "ponastavi". // Skrbi za "stare" možnosti, kot na primer "na širino zaslona", "na višino zaslona" in "ponastavi".
// Približevanje opuščeno. // Približevanje opuščeno.
// handles "legacy" options, such as 'fit to widht', 'fit to height' and AspectRatioType.Reset. No zoom tho // handles "legacy" options, such as 'fit to widht', 'fit to height' and AspectRatioType.Reset. No zoom tho
let ratioOut; let ratioOut;
@ -112,22 +112,22 @@ class Resizer {
return null; return null;
} }
if (! this.conf.player.dimensions) { if (! this.conf.player.dimensions) {
ratioOut = screen.width / screen.height; ratioOut = screen.width / screen.height;
} else { } else {
this.logger.log('info', 'debug', `[Resizer::calculateRatioForLegacyOptions] <rid:${this.resizerId}> Player dimensions:`, this.conf.player.dimensions.width ,'x', this.conf.player.dimensions.height,'aspect ratio:', this.conf.player.dimensions.width / this.conf.player.dimensions.height) this.logger.log('info', 'debug', `[Resizer::calculateRatioForLegacyOptions] <rid:${this.resizerId}> Player dimensions:`, this.conf.player.dimensions.width ,'x', this.conf.player.dimensions.height,'aspect ratio:', this.conf.player.dimensions.width / this.conf.player.dimensions.height)
ratioOut = this.conf.player.dimensions.width / this.conf.player.dimensions.height; ratioOut = this.conf.player.dimensions.width / this.conf.player.dimensions.height;
} }
// POMEMBNO: lastAr je potrebno nastaviti šele po tem, ko kličemo _res_setAr(). _res_setAr() predvideva, // POMEMBNO: lastAr je potrebno nastaviti šele po tem, ko kličemo _res_setAr(). _res_setAr() predvideva,
// da želimo nastaviti statično (type: 'static') razmerje stranic — tudi, če funkcijo kličemo tu oz. v ArDetect. // da želimo nastaviti statično (type: 'static') razmerje stranic — tudi, če funkcijo kličemo tu oz. v ArDetect.
// //
// IMPORTANT NOTE: lastAr needs to be set after _res_setAr() is called, as _res_setAr() assumes we're // IMPORTANT NOTE: lastAr needs to be set after _res_setAr() is called, as _res_setAr() assumes we're
// setting a static aspect ratio (even if the function is called from here or ArDetect). // setting a static aspect ratio (even if the function is called from here or ArDetect).
let fileAr = this.conf.video.videoWidth / this.conf.video.videoHeight; let fileAr = this.conf.video.videoWidth / this.conf.video.videoHeight;
if (ar.type === AspectRatioType.FitWidth){ if (ar.type === AspectRatioType.FitWidth){
ar.ratio = ratioOut > fileAr ? ratioOut : fileAr; ar.ratio = ratioOut > fileAr ? ratioOut : fileAr;
} }
@ -168,12 +168,12 @@ class Resizer {
if (this.destroyed) { if (this.destroyed) {
return; return;
} }
if (!this.video.videoWidth || !this.video.videoHeight) { if (!this.video.videoWidth || !this.video.videoHeight) {
this.logger.log('warning', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> Video has no width or no height. This is not allowed. Aspect ratio will not be set, and videoData will be uninitialized.'); this.logger.log('warning', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> Video has no width or no height. This is not allowed. Aspect ratio will not be set, and videoData will be uninitialized.');
this.conf.videoUnloaded(); this.conf.videoUnloaded();
} }
this.logger.log('info', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar); this.logger.log('info', 'debug', '[Resizer::setAr] <rid:'+this.resizerId+'> trying to set ar. New ar:', ar);
if (ar == null) { if (ar == null) {
@ -198,10 +198,10 @@ class Resizer {
// this means here's the optimal place to set or forget aspect ratio. Saving of current crop ratio // this means here's the optimal place to set or forget aspect ratio. Saving of current crop ratio
// is handled in pageInfo.updateCurrentCrop(), which also makes sure to persist aspect ratio if ar // is handled in pageInfo.updateCurrentCrop(), which also makes sure to persist aspect ratio if ar
// is set to persist between videos / through current session / until manual reset. // is set to persist between videos / through current session / until manual reset.
if (ar.type === AspectRatioType.Automatic || if (ar.type === AspectRatioType.Automatic ||
ar.type === AspectRatioType.Reset || ar.type === AspectRatioType.Reset ||
ar.type === AspectRatioType.Initial ) { ar.type === AspectRatioType.Initial ) {
// reset/undo default // reset/undo default
this.conf.pageInfo.updateCurrentCrop(undefined); this.conf.pageInfo.updateCurrentCrop(undefined);
} else { } else {
this.conf.pageInfo.updateCurrentCrop(ar); this.conf.pageInfo.updateCurrentCrop(ar);
@ -224,7 +224,7 @@ class Resizer {
// if (this.extensionMode === ExtensionMode.Basic && !PlayerData.isFullScreen() && ar.type !== AspectRatioType.Reset) { // if (this.extensionMode === ExtensionMode.Basic && !PlayerData.isFullScreen() && ar.type !== AspectRatioType.Reset) {
// // don't actually apply or calculate css when using basic mode if not in fullscreen // // don't actually apply or calculate css when using basic mode if not in fullscreen
// // ... unless we're resetting the aspect ratio to original // // ... unless we're resetting the aspect ratio to original
// return; // return;
// } // }
if (! this.video) { if (! this.video) {
@ -234,7 +234,7 @@ class Resizer {
// pause AR on: // pause AR on:
// * ar.type NOT automatic // * ar.type NOT automatic
// * ar.type is auto, but stretch is set to basic basic stretch // * ar.type is auto, but stretch is set to basic basic stretch
// //
// unpause when using other modes // unpause when using other modes
if (ar.type !== AspectRatioType.Automatic || this.stretcher.mode === StretchType.Basic) { if (ar.type !== AspectRatioType.Automatic || this.stretcher.mode === StretchType.Basic) {
this.conf?.arDetector?.pause(); this.conf?.arDetector?.pause();
@ -245,10 +245,10 @@ class Resizer {
} }
// do stretch thingy // do stretch thingy
if (this.stretcher.mode === StretchType.NoStretch if (this.stretcher.mode === StretchType.NoStretch
|| this.stretcher.mode === StretchType.Conditional || this.stretcher.mode === StretchType.Conditional
|| this.stretcher.mode === StretchType.FixedSource){ || this.stretcher.mode === StretchType.FixedSource){
stretchFactors = this.scaler.calculateCrop(ar); stretchFactors = this.scaler.calculateCrop(ar);
if(! stretchFactors || stretchFactors.error){ if(! stretchFactors || stretchFactors.error){
@ -274,7 +274,7 @@ class Resizer {
this.stretcher.applyStretchFixedSource(stretchFactors); this.stretcher.applyStretchFixedSource(stretchFactors);
} }
this.logger.log('info', 'debug', "[Resizer::setAr] Processed stretch factors for ", this.logger.log('info', 'debug', "[Resizer::setAr] Processed stretch factors for ",
this.stretcher.mode === StretchType.NoStretch ? 'stretch-free crop.' : this.stretcher.mode === StretchType.NoStretch ? 'stretch-free crop.' :
this.stretcher.mode === StretchType.Conditional ? 'crop with conditional StretchType.' : 'crop with fixed stretch', this.stretcher.mode === StretchType.Conditional ? 'crop with conditional StretchType.' : 'crop with fixed stretch',
'Stretch factors are:', stretchFactors 'Stretch factors are:', stretchFactors
); );
@ -343,7 +343,7 @@ class Resizer {
const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth; const relativeX = (event.pageX - player.offsetLeft) / player.offsetWidth;
const relativeY = (event.pageY - player.offsetTop) / player.offsetHeight; const relativeY = (event.pageY - player.offsetTop) / player.offsetHeight;
this.logger.log('info', 'mousemove', "[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY, "\nrelativeX/Y:", relativeX, relativeY) this.logger.log('info', 'mousemove', "[Resizer::panHandler] mousemove.pageX, pageY:", event.pageX, event.pageY, "\nrelativeX/Y:", relativeX, relativeY)
this.setPan(relativeX, relativeY); this.setPan(relativeX, relativeY);
@ -356,7 +356,7 @@ class Resizer {
} }
setPan(relativeMousePosX, relativeMousePosY){ setPan(relativeMousePosX, relativeMousePosY){
// relativeMousePos[X|Y] - on scale from 0 to 1, how close is the mouse to player edges. // relativeMousePos[X|Y] - on scale from 0 to 1, how close is the mouse to player edges.
// use these values: top, left: 0, bottom, right: 1 // use these values: top, left: 0, bottom, right: 1
if(! this.pan){ if(! this.pan){
this.pan = {x: 0, y: 0}; this.pan = {x: 0, y: 0};
@ -379,7 +379,7 @@ class Resizer {
restore() { restore() {
this.logger.log('info', 'debug', "[Resizer::restore] <rid:"+this.resizerId+"> attempting to restore aspect ratio", {'lastAr': this.lastAr} ); this.logger.log('info', 'debug', "[Resizer::restore] <rid:"+this.resizerId+"> attempting to restore aspect ratio", {'lastAr': this.lastAr} );
// this is true until we verify that css has actually been applied // this is true until we verify that css has actually been applied
if(this.lastAr.type === AspectRatioType.Initial){ if(this.lastAr.type === AspectRatioType.Initial){
this.setAr({type: AspectRatioType.Reset}); this.setAr({type: AspectRatioType.Reset});
@ -414,7 +414,7 @@ class Resizer {
setZoom(zoomLevel, no_announce) { setZoom(zoomLevel, no_announce) {
this.zoom.setZoom(zoomLevel, no_announce); this.zoom.setZoom(zoomLevel, no_announce);
} }
zoomStep(step){ zoomStep(step){
this.zoom.zoomStep(step); this.zoom.zoomStep(step);
} }
@ -439,23 +439,23 @@ class Resizer {
/** /**
* Returns the size of the video file _as displayed_ on the screen. * Returns the size of the video file _as displayed_ on the screen.
* Consider the following example: * Consider the following example:
* *
* * player dimensions are 2560x1080 * * player dimensions are 2560x1080
* * <video> is child of player * * <video> is child of player
* * <video> has the following css: {width: 100%, height: 100%} * * <video> has the following css: {width: 100%, height: 100%}
* * video file dimensions are 1280x720 * * video file dimensions are 1280x720
* *
* CSS will ensure that the dimensions of <video> tag are equal to the dimension of the * CSS will ensure that the dimensions of <video> tag are equal to the dimension of the
* player element that is, 2560x1080px. This is no bueno, because the browser will upscale * player element that is, 2560x1080px. This is no bueno, because the browser will upscale
* the video file to take up as much space as it can (without stretching it). This means * the video file to take up as much space as it can (without stretching it). This means
* we'll get a 1920x1080 video (as displayed) and a letterbox. * we'll get a 1920x1080 video (as displayed) and a letterbox.
* *
* We can't get that number out of anywhere: video.videoWidth will return 1280 (video file * We can't get that number out of anywhere: video.videoWidth will return 1280 (video file
* dimensions) and .offsetWidth (and the likes) will return the <video> tag dimension. Neither * dimensions) and .offsetWidth (and the likes) will return the <video> tag dimension. Neither
* will return the actual size of video as displayed, which we need in order to calculate the * will return the actual size of video as displayed, which we need in order to calculate the
* extra space to the left and right of the video. * extra space to the left and right of the video.
* *
* We make the assumption of the * We make the assumption of the
*/ */
computeVideoDisplayedDimensions() { computeVideoDisplayedDimensions() {
const offsetWidth = this.conf.video.offsetWidth; const offsetWidth = this.conf.video.offsetWidth;
@ -464,7 +464,7 @@ class Resizer {
const scaleX = offsetWidth / this.conf.video.videoWidth; const scaleX = offsetWidth / this.conf.video.videoWidth;
const scaleY = offsetHeight / this.conf.video.videoHeight; const scaleY = offsetHeight / this.conf.video.videoHeight;
// if differences between the scale factors are minimal, we presume offsetWidth and // if differences between the scale factors are minimal, we presume offsetWidth and
// offsetHeight are the accurate enough for our needs // offsetHeight are the accurate enough for our needs
if (Math.abs(scaleX - scaleY) < 0.02) { if (Math.abs(scaleX - scaleY) < 0.02) {
return { return {
@ -505,19 +505,19 @@ class Resizer {
* and let the browser figure out the height through the magic of height:auto. This is bad, * and let the browser figure out the height through the magic of height:auto. This is bad,
* because our addon generally relies of videos always being 100% of the height of the * because our addon generally relies of videos always being 100% of the height of the
* container. * container.
* *
* This sometimes leads to a situation where realVideoHeight and realVideoWidth at least * This sometimes leads to a situation where realVideoHeight and realVideoWidth at least
* one of which should be roughly equal to the player width or hight with the other one being * one of which should be roughly equal to the player width or hight with the other one being
* either smaller or equal are both smaller than player width or height; and sometimes * either smaller or equal are both smaller than player width or height; and sometimes
* rather substantially. Fortunately for us, realVideo[Width|Height] and player dimensions * rather substantially. Fortunately for us, realVideo[Width|Height] and player dimensions
* never lie, which allows us to calculate the extra scale factor we need. * never lie, which allows us to calculate the extra scale factor we need.
* *
* Returned factor for this function should do fit:contain, not fit:cover. * Returned factor for this function should do fit:contain, not fit:cover.
* @param realVideoWidth real video width * @param realVideoWidth real video width
* @param realVideoHeight real video height * @param realVideoHeight real video height
* @param playerWidth player width * @param playerWidth player width
* @param playerHeight player height * @param playerHeight player height
* @param mode whether to * @param mode whether to
*/ */
computeAutoHeightCompensationFactor(realVideoWidth: number, realVideoHeight: number, playerWidth: number, playerHeight: number, mode: 'height' | 'width'): number { computeAutoHeightCompensationFactor(realVideoWidth: number, realVideoHeight: number, playerWidth: number, playerHeight: number, mode: 'height' | 'width'): number {
const widthFactor = playerWidth / realVideoWidth; const widthFactor = playerWidth / realVideoWidth;
@ -538,7 +538,7 @@ class Resizer {
// We also don't compensate for height:auto if height is provided via element style // We also don't compensate for height:auto if height is provided via element style
let autoHeightCompensationFactor; let autoHeightCompensationFactor;
if ( if (
stretchFactors.cropStrategy === CropStrategy.CropLetterbox stretchFactors.cropStrategy === CropStrategy.CropLetterbox
&& (!stretchFactors.styleHeightCompensationFactor || stretchFactors.styleHeightCompensationFactor === 1) && (!stretchFactors.styleHeightCompensationFactor || stretchFactors.styleHeightCompensationFactor === 1)
) { ) {
autoHeightCompensationFactor = this.computeAutoHeightCompensationFactor(realVideoWidth, realVideoHeight, this.conf.player.dimensions.width, this.conf.player.dimensions.height, 'height'); autoHeightCompensationFactor = this.computeAutoHeightCompensationFactor(realVideoWidth, realVideoHeight, this.conf.player.dimensions.width, this.conf.player.dimensions.height, 'height');
@ -551,14 +551,14 @@ class Resizer {
const wdiffAfterZoom = realVideoWidth * stretchFactors.xFactor - this.conf.player.dimensions.width; const wdiffAfterZoom = realVideoWidth * stretchFactors.xFactor - this.conf.player.dimensions.width;
const hdiffAfterZoom = realVideoHeight * stretchFactors.yFactor - this.conf.player.dimensions.height; const hdiffAfterZoom = realVideoHeight * stretchFactors.yFactor - this.conf.player.dimensions.height;
const translate = { const translate = {
x: wdiff * 0.5, x: wdiff * 0.5,
y: hdiff * 0.5, y: hdiff * 0.5,
}; };
if (this.pan.relativeOffsetX || this.pan.relativeOffsetY) { if (this.pan.relativeOffsetX || this.pan.relativeOffsetY) {
// don't offset when video is smaller than player // don't offset when video is smaller than player
@ -574,7 +574,7 @@ class Resizer {
translate.x -= wdiffAfterZoom * 0.5; translate.x -= wdiffAfterZoom * 0.5;
} }
} }
this.logger.log( this.logger.log(
'info', ['debug', 'resizer'], "[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:", 'info', ['debug', 'resizer'], "[Resizer::_res_computeOffsets] <rid:"+this.resizerId+"> calculated offsets:",
'\n\n---- elements ----', '\n\n---- elements ----',
@ -588,21 +588,21 @@ class Resizer {
'\nstretch factors: ', stretchFactors, '\nstretch factors: ', stretchFactors,
'\npan & zoom: ', this.pan, this.zoom.scale, '\npan & zoom: ', this.pan, this.zoom.scale,
'\nwdiff, hdiff: ', wdiff, 'x', hdiff, '\nwdiff, hdiff: ', wdiff, 'x', hdiff,
'\nwdiff, hdiffAfterZoom:', wdiffAfterZoom, 'x', hdiffAfterZoom, '\nwdiff, hdiffAfterZoom:', wdiffAfterZoom, 'x', hdiffAfterZoom,
'\n\n---- data out ----\n', '\n\n---- data out ----\n',
'translate:', translate 'translate:', translate
); );
// by the way, let's do a quick sanity check whether video player is doing any fuckies wuckies // by the way, let's do a quick sanity check whether video player is doing any fuckies wuckies
// fucky wucky examples: // fucky wucky examples:
// //
// * video width is bigger than player width AND video height is bigger than player height // * video width is bigger than player width AND video height is bigger than player height
// * video width is smaller than player width AND video height is smaller than player height // * video width is smaller than player width AND video height is smaller than player height
// //
// In both examples, at most one of the two conditions can be true at the same time. If both // In both examples, at most one of the two conditions can be true at the same time. If both
// conditions are true at the same time, we need to go 'chiny reckon' and recheck our player // conditions are true at the same time, we need to go 'chiny reckon' and recheck our player
// element. Chances are our video is not getting aligned correctly // element. Chances are our video is not getting aligned correctly
if ( if (
(this.conf.video.offsetWidth > this.conf.player.dimensions.width && this.conf.video.offsetHeight > this.conf.player.dimensions.height) || (this.conf.video.offsetWidth > this.conf.player.dimensions.width && this.conf.video.offsetHeight > this.conf.player.dimensions.height) ||
(this.conf.video.offsetWidth < this.conf.player.dimensions.width && this.conf.video.offsetHeight < this.conf.player.dimensions.height) (this.conf.video.offsetWidth < this.conf.player.dimensions.width && this.conf.video.offsetHeight < this.conf.player.dimensions.height)
) { ) {
@ -622,9 +622,9 @@ class Resizer {
} }
} }
return translate; return translate;
} }
//#region css handling //#region css handling
buildStyleArray(existingStyleString, extraStyleString) { buildStyleArray(existingStyleString, extraStyleString) {
if (existingStyleString) { if (existingStyleString) {
@ -648,15 +648,15 @@ class Resizer {
} }
} }
} }
for (let i in styleArray) { for (let i in styleArray) {
styleArray[i] = styleArray[i].trim(); styleArray[i] = styleArray[i].trim();
// some sites do 'top: 50%; left: 50%; transform: <transform>' to center videos. // some sites do 'top: 50%; left: 50%; transform: <transform>' to center videos.
// we dont wanna, because we already center videos on our own // we dont wanna, because we already center videos on our own
if (styleArray[i].startsWith("transform:") if (styleArray[i].startsWith("transform:")
|| styleArray[i].startsWith("top:") || styleArray[i].startsWith("top:")
|| styleArray[i].startsWith("left:") || styleArray[i].startsWith("left:")
|| styleArray[i].startsWith("right:") || styleArray[i].startsWith("right:")
|| styleArray[i].startsWith("bottom:") || styleArray[i].startsWith("bottom:")
|| styleArray[i].startsWith("margin") || styleArray[i].startsWith("margin")
){ ){
@ -682,7 +682,7 @@ class Resizer {
} }
applyCss(stretchFactors, translate){ applyCss(stretchFactors, translate){
// apply extra CSS here. In case of duplicated properties, extraCss overrides // apply extra CSS here. In case of duplicated properties, extraCss overrides
// default styleString // default styleString
if (! this.video) { if (! this.video) {
this.logger.log('warn', 'debug', "[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing."); this.logger.log('warn', 'debug', "[Resizer::applyCss] <rid:"+this.resizerId+"> Video went missing, doing nothing.");
@ -692,7 +692,7 @@ class Resizer {
} }
this.logger.log('info', ['debug', 'resizer'], "[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate}); this.logger.log('info', ['debug', 'resizer'], "[Resizer::applyCss] <rid:"+this.resizerId+"> will apply css.", {stretchFactors, translate});
// save stuff for quick tests (before we turn numbers into css values): // save stuff for quick tests (before we turn numbers into css values):
this.currentVideoSettings = { this.currentVideoSettings = {
validFor: this.conf.player.dimensions, validFor: this.conf.player.dimensions,
@ -716,7 +716,7 @@ class Resizer {
// important — guarantees video will be properly aligned // important — guarantees video will be properly aligned
// Note that position:absolute cannot be put here, otherwise old.reddit /w RES breaks — videos embedded // Note that position:absolute cannot be put here, otherwise old.reddit /w RES breaks — videos embedded
// from certain hosts will get a height: 0px. This is bad. // from certain hosts will get a height: 0px. This is bad.
styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px;"); styleArray.push("top: 0px !important; left: 0px !important; bottom: 0px !important; right: 0px;");
// important — some websites (cough reddit redesign cough) may impose some dumb max-width and max-height // important — some websites (cough reddit redesign cough) may impose some dumb max-width and max-height
// restrictions. If site has dumb shit like 'max-width: 100%' and 'max-height: 100vh' in their CSS, that // restrictions. If site has dumb shit like 'max-width: 100%' and 'max-height: 100vh' in their CSS, that