Simplify player data dimension change tracking a bit
This commit is contained in:
parent
a4948d3eef
commit
e9b882376c
@ -12,6 +12,28 @@ if (process.env.CHANNEL !== 'stable'){
|
|||||||
console.info("Loading PageInfo");
|
console.info("Loading PageInfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* The classes kinda go like this:
|
||||||
|
*
|
||||||
|
* PageInfo — one per page/frame.
|
||||||
|
* |
|
||||||
|
* +——— VideoData — child of PageInfo. There may be more than one of those
|
||||||
|
* | +—— PlayerData — VideoData has exactly ONE (1) PlayerData
|
||||||
|
* | +—— AspectRatioDetector — VideoData has 0-1 AARD things
|
||||||
|
* | +—— Resizer
|
||||||
|
* | +—— Scaler
|
||||||
|
* | +—— Stretcher
|
||||||
|
* | +—— Zoom
|
||||||
|
* +——— VideoData
|
||||||
|
* | +—— PlayerData
|
||||||
|
* | :
|
||||||
|
* :
|
||||||
|
*
|
||||||
|
* There is as many VideoData objects as there are videos.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
class PageInfo {
|
class PageInfo {
|
||||||
//#region flags
|
//#region flags
|
||||||
readOnly: boolean = false;
|
readOnly: boolean = false;
|
||||||
@ -375,12 +397,12 @@ class PageInfo {
|
|||||||
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.pause();
|
vd.videoData.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(let vd of this.videos){
|
for(let vd of this.videos){
|
||||||
vd.videoData.pause();
|
vd.videoData.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,7 +411,7 @@ class PageInfo {
|
|||||||
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.resume();
|
vd.videoData.enable();
|
||||||
if(resumeAutoar){
|
if(resumeAutoar){
|
||||||
vd.videoData.resumeAutoAr();
|
vd.videoData.resumeAutoAr();
|
||||||
}
|
}
|
||||||
@ -397,7 +419,7 @@ class PageInfo {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(let vd of this.videos){
|
for(let vd of this.videos){
|
||||||
vd.videoData.resume();
|
vd.videoData.enable();
|
||||||
if(resumeAutoar){
|
if(resumeAutoar){
|
||||||
vd.videoData.resumeAutoAr();
|
vd.videoData.resumeAutoAr();
|
||||||
}
|
}
|
||||||
@ -575,18 +597,6 @@ class PageInfo {
|
|||||||
this.announceZoomTimeout = setTimeout(() => ths.comms.announceZoom(scale), this.settings.active.zoom.announceDebounce);
|
this.announceZoomTimeout = setTimeout(() => ths.comms.announceZoom(scale), this.settings.active.zoom.announceDebounce);
|
||||||
}
|
}
|
||||||
|
|
||||||
setManualTick(manualTick) {
|
|
||||||
for(let vd of this.videos) {
|
|
||||||
vd.videoData.setManualTick(manualTick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tick() {
|
|
||||||
for(let vd of this.videos) {
|
|
||||||
vd.videoData.tick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendPerformanceUpdate(performanceUpdate) {
|
sendPerformanceUpdate(performanceUpdate) {
|
||||||
if(this.comms) {
|
if(this.comms) {
|
||||||
this.comms.sendPerformanceUpdate(performanceUpdate);
|
this.comms.sendPerformanceUpdate(performanceUpdate);
|
||||||
|
@ -14,35 +14,29 @@ if (process.env.CHANNEL !== 'stable'){
|
|||||||
console.info("Loading: PlayerData.js");
|
console.info("Loading: PlayerData.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sprejme <video> tag (element) in seznam imen, ki se lahko pojavijo v razredih oz. id staršev.
|
interface PlayerDimensions {
|
||||||
// vrne dimenzije predvajalnika (širina, višina)
|
width?: number;
|
||||||
//
|
height?: number;
|
||||||
// Na youtube v theater mode je razširitev rahlo pokvarjena. Video tag ostane večji od predvajalnika, ko se zapusti
|
fullscreen?: boolean;
|
||||||
// celozaslonski način. Ta funkcija skuša to težavo rešiti tako, da poišče element predvajalnika, ki je zavit okoli videa.
|
}
|
||||||
//
|
|
||||||
// Funkcija izkorišča lastnost, da bi načeloma moral biti vsak zunanji element večji od notranjega. Najmanjši element od
|
/**
|
||||||
// <video> značke pa do korena drevesa bi tako moral biti predvajalnik.
|
* accepts <video> tag (element) and list of names that can appear in id or class
|
||||||
//
|
* returns player dimensions (width, height)
|
||||||
// Če je podan seznam imen, potem funkcija vrne dimenzije prvega elementa, ki v id oz. razredu vsebuje katerokoli ime iz seznama
|
* Theater mode is mildly broken on youtube. <video> tag remains bigger than the player after leaving the fullscreen mode, and
|
||||||
//
|
* there's nothing we can do about that. This function aims to solve the problem by finding the player element that's wrapped around
|
||||||
// | EN |
|
* the <video> tag.
|
||||||
//
|
|
||||||
// accepts <video> tag (element) and list of names that can appear in id or class
|
* In general, an outer tag should be bigger than the inner tag. Therefore the smallest element between <video> tag and the document
|
||||||
// returns player dimensions (width, height)
|
* root should be the player.
|
||||||
//
|
|
||||||
// Theater mode is mildly broken on youtube. <video> tag remains bigger than the player after leaving the fullscreen mode, and
|
* If list of names is provided, the function returns dimensions of the first element that contains any name from the list in either
|
||||||
// there's nothing we can do about that. This function aims to solve the problem by finding the player element that's wrapped around
|
* id or class.
|
||||||
// the <video> tag.
|
*/
|
||||||
//
|
|
||||||
// In general, an outer tag should be bigger than the inner tag. Therefore the smallest element between <video> tag and the document
|
|
||||||
// root should be the player.
|
|
||||||
//
|
|
||||||
// If list of names is provided, the function returns dimensions of the first element that contains any name from the list in either
|
|
||||||
// id or class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class PlayerData {
|
class PlayerData {
|
||||||
|
private playerCssClass = 'uw-ultrawidify-player-css';
|
||||||
|
|
||||||
//#region helper objects
|
//#region helper objects
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
videoData: VideoData;
|
videoData: VideoData;
|
||||||
@ -57,13 +51,14 @@ class PlayerData {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region flags
|
//#region flags
|
||||||
|
enabled: boolean;
|
||||||
invalid: boolean = false;
|
invalid: boolean = false;
|
||||||
private periodicallyRefreshPlayerElement: boolean = false;
|
private periodicallyRefreshPlayerElement: boolean = false;
|
||||||
halted: boolean = true;
|
halted: boolean = true;
|
||||||
|
|
||||||
//#region misc stuff
|
//#region misc stuff
|
||||||
extensionMode: any;
|
extensionMode: any;
|
||||||
dimensions: {width?: number, height?: number, fullscreen?: boolean};
|
dimensions: PlayerDimensions;
|
||||||
private playerIdElement: any;
|
private playerIdElement: any;
|
||||||
private observer: ResizeObserver;
|
private observer: ResizeObserver;
|
||||||
|
|
||||||
@ -117,7 +112,7 @@ class PlayerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.extensionMode === ExtensionMode.Enabled) {
|
if (this.extensionMode === ExtensionMode.Enabled) {
|
||||||
this.checkPlayerSizeChange();
|
this.trackDimensionChanges();
|
||||||
}
|
}
|
||||||
this.startChangeDetection();
|
this.startChangeDetection();
|
||||||
|
|
||||||
@ -142,21 +137,138 @@ class PlayerData {
|
|||||||
return ( ihdiff < 5 && iwdiff < 5 );
|
return ( ihdiff < 5 && iwdiff < 5 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onPlayerDimensionsChanged(mutationList?, observer?) {
|
/**
|
||||||
if (this?.checkPlayerSizeChange()) {
|
*
|
||||||
this.videoData.resizer.restore();
|
*/
|
||||||
|
trackDimensionChanges() {
|
||||||
|
|
||||||
|
// get player dimensions _once_
|
||||||
|
let currentPlayerDimensions;
|
||||||
|
const isFullScreen = PlayerData.isFullScreen();
|
||||||
|
|
||||||
|
if (isFullScreen) {
|
||||||
|
currentPlayerDimensions = {
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight,
|
||||||
|
fullscreen: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
currentPlayerDimensions = {
|
||||||
|
width: this.element.offsetWidth,
|
||||||
|
height: this.element.offsetHeight,
|
||||||
|
fullscreen: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if dimensions of the player box are the same as the last known
|
||||||
|
// dimensions, we don't have to do anything
|
||||||
|
if (
|
||||||
|
this.dimensions
|
||||||
|
&& this.dimensions.width == currentPlayerDimensions.width
|
||||||
|
&& this.dimensions.height == currentPlayerDimensions.height
|
||||||
|
) {
|
||||||
|
this.dimensions = currentPlayerDimensions;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in every other case, we need to check if the player is still
|
||||||
|
// big enough to warrant our extension running.
|
||||||
|
|
||||||
|
this.handleSizeConstraints(currentPlayerDimensions);
|
||||||
|
this.handleDimensionChanges(currentPlayerDimensions, this.dimensions);
|
||||||
|
|
||||||
|
// Save current dimensions to avoid triggering this function pointlessly
|
||||||
|
this.dimensions = currentPlayerDimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles size restrictions (if any)
|
||||||
|
* @param currentPlayerDimensions
|
||||||
|
*/
|
||||||
|
private handleSizeConstraints(currentPlayerDimensions: PlayerDimensions) {
|
||||||
|
|
||||||
|
// never disable ultrawidify in full screen
|
||||||
|
if (currentPlayerDimensions.fullscreen) {
|
||||||
|
this.enable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const restrictions = this.settings.getSettingsForSite()?.restrictions ?? this.settings.active?.restrictions;
|
||||||
|
|
||||||
|
// if 'disable on small players' option is not enabled, the extension will run in any case
|
||||||
|
if (!restrictions?.disableOnSmallPlayers) {
|
||||||
|
this.enable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we only allow ultrawidify in full screen, we disable it when not in full screen
|
||||||
|
if (restrictions.onlyAllowInFullscreen && !currentPlayerDimensions.fullscreen) {
|
||||||
|
this.disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if current width or height are smaller than the minimum, the extension will not run
|
||||||
|
if (restrictions.minAllowedHeight > currentPlayerDimensions?.height || restrictions.minAllowedWidth > currentPlayerDimensions?.width) {
|
||||||
|
this.disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in this case, the player is big enough to warrant enabling Ultrawidify
|
||||||
|
this.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private handleDimensionChanges(newDimensions: PlayerDimensions, oldDimensions: PlayerDimensions) {
|
||||||
|
if (!this.enabled) {
|
||||||
|
this.logger.log('info', 'debug', "[PlayerDetect] player size changed, but PlayerDetect is in disabled state. The player element is probably too small.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this 'if' is just here for debugging — real code starts later. It's safe to collapse and
|
||||||
|
// ignore the contents of this if (unless we need to change how logging works)
|
||||||
|
this.logger.log('info', 'debug', "[PlayerDetect] player size potentially changed.\n\nold dimensions:", oldDimensions, '\nnew dimensions:', newDimensions);
|
||||||
|
|
||||||
|
// if size doesn't match, trigger onPlayerDimensionChange
|
||||||
|
if (
|
||||||
|
newDimensions?.width != oldDimensions?.width
|
||||||
|
|| newDimensions?.height != oldDimensions?.height
|
||||||
|
|| newDimensions?.fullscreen != oldDimensions?.fullscreen
|
||||||
|
){
|
||||||
|
// If player size changes, we restore aspect ratio
|
||||||
|
this.videoData.resizer?.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
start(){
|
* Enables ultrawidify for this video by adding the relevant classes
|
||||||
|
* to the video and player element.
|
||||||
|
*/
|
||||||
|
enable() {
|
||||||
|
this.enabled = true;
|
||||||
|
this.element.classList.add(this.playerCssClass);
|
||||||
this.startChangeDetection();
|
this.startChangeDetection();
|
||||||
|
this.videoData.enable({fromPlayer: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(){
|
/**
|
||||||
this.halted = true;
|
* Disables ultrawidify for this video by removing the relevant classes
|
||||||
this.stopChangeDetection();
|
* from the video and player elements.
|
||||||
|
*
|
||||||
|
* NOTE: it is very important to keep change detection active while disabled,
|
||||||
|
* because otherwise ultrawidify will otherwise remain inactive after
|
||||||
|
* switching (back to) full screen.
|
||||||
|
*/
|
||||||
|
disable() {
|
||||||
|
this.enabled = false;
|
||||||
|
this.element.classList.remove(this.playerCssClass);
|
||||||
|
this.videoData.disable({fromPlayer: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onPlayerDimensionsChanged(mutationList?, observer?) {
|
||||||
|
this.trackDimensionChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -165,6 +277,7 @@ class PlayerData {
|
|||||||
this.notificationService?.destroy();
|
this.notificationService?.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region player element change detection
|
||||||
startChangeDetection(){
|
startChangeDetection(){
|
||||||
if (this.invalid) {
|
if (this.invalid) {
|
||||||
return;
|
return;
|
||||||
@ -216,7 +329,7 @@ class PlayerData {
|
|||||||
while (!this.halted) {
|
while (!this.halted) {
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
try {
|
try {
|
||||||
this.doPeriodicPlayerElementChangeCheck();
|
this.forceRefreshPlayerElement();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[PlayerData::legacycd] this message is pretty high on the list of messages you shouldn\'t see', e);
|
console.error('[PlayerData::legacycd] this message is pretty high on the list of messages you shouldn\'t see', e);
|
||||||
}
|
}
|
||||||
@ -225,7 +338,7 @@ class PlayerData {
|
|||||||
|
|
||||||
doPeriodicPlayerElementChangeCheck() {
|
doPeriodicPlayerElementChangeCheck() {
|
||||||
if (this.periodicallyRefreshPlayerElement) {
|
if (this.periodicallyRefreshPlayerElement) {
|
||||||
this.forceDetectPlayerElementChange();
|
this.forceRefreshPlayerElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,6 +346,7 @@ class PlayerData {
|
|||||||
this.observer.disconnect();
|
this.observer.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region interface
|
||||||
makeOverlay() {
|
makeOverlay() {
|
||||||
if (!this.overlayNode) {
|
if (!this.overlayNode) {
|
||||||
this.destroyOverlay();
|
this.destroyOverlay();
|
||||||
@ -283,7 +397,10 @@ class PlayerData {
|
|||||||
}
|
}
|
||||||
this.playerIdElement = undefined;
|
this.playerIdElement = undefined;
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//#region helper functions
|
||||||
collectionHas(collection, element) {
|
collectionHas(collection, element) {
|
||||||
for (let i = 0, len = collection.length; i < len; i++) {
|
for (let i = 0, len = collection.length; i < len; i++) {
|
||||||
if (collection[i] == element) {
|
if (collection[i] == element) {
|
||||||
@ -292,31 +409,7 @@ class PlayerData {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
updatePlayerDimensions(element) {
|
|
||||||
const isFullScreen = PlayerData.isFullScreen();
|
|
||||||
|
|
||||||
if (element.offsetWidth !== this.dimensions?.width
|
|
||||||
|| element.offsetHeight !== this.dimensions?.height
|
|
||||||
|| isFullScreen !== this.dimensions?.fullscreen) {
|
|
||||||
|
|
||||||
// update dimensions only if they've changed, _before_ we do a restore (not after)
|
|
||||||
this.dimensions = {
|
|
||||||
width: element.offsetWidth,
|
|
||||||
height: element.offsetHeight,
|
|
||||||
fullscreen: isFullScreen
|
|
||||||
};
|
|
||||||
|
|
||||||
// actually re-calculate zoom when player size changes, but only if videoData.resizer
|
|
||||||
// is defined. Since resizer needs a PlayerData object to exist, videoData.resizer will
|
|
||||||
// be undefined the first time this function will run.
|
|
||||||
this.videoData.resizer?.restore();
|
|
||||||
|
|
||||||
// NOTE: it's possible that notificationService hasn't been initialized yet at this point.
|
|
||||||
// no biggie if it wasn't, we just won't replace the notification UI
|
|
||||||
this.notificationService?.replace(this.element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlayer() {
|
getPlayer() {
|
||||||
const host = window.location.hostname;
|
const host = window.location.hostname;
|
||||||
@ -398,7 +491,6 @@ class PlayerData {
|
|||||||
// return element with biggest score
|
// return element with biggest score
|
||||||
// if video player has not been found, proceed to automatic detection
|
// if video player has not been found, proceed to automatic detection
|
||||||
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);
|
|
||||||
return playerElement;
|
return playerElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,7 +499,6 @@ class PlayerData {
|
|||||||
// try to find element the old fashioned way
|
// try to find element the old fashioned way
|
||||||
|
|
||||||
while (element){
|
while (element){
|
||||||
// odstranimo čudne elemente, ti bi pokvarili zadeve
|
|
||||||
// remove weird elements, those would break our stuff
|
// remove weird elements, those would break our stuff
|
||||||
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
|
if ( element.offsetWidth == 0 || element.offsetHeight == 0){
|
||||||
element = element.parentNode;
|
element = element.parentNode;
|
||||||
@ -465,7 +556,6 @@ class PlayerData {
|
|||||||
// 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);
|
|
||||||
return playerElement;
|
return playerElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,87 +573,10 @@ class PlayerData {
|
|||||||
return a > b - tolerance && a < b + tolerance;
|
return a > b - tolerance && a < b + tolerance;
|
||||||
}
|
}
|
||||||
|
|
||||||
forceDetectPlayerElementChange() {
|
|
||||||
// Player dimension changes get calculated every time updatePlayerDimensions is called (which happens
|
|
||||||
// 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
|
|
||||||
// getPlayer().
|
|
||||||
this.getPlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
forceRefreshPlayerElement() {
|
forceRefreshPlayerElement() {
|
||||||
this.getPlayer();
|
this.element = this.getPlayer();
|
||||||
}
|
this.notificationService?.replace(this.element);
|
||||||
|
this.trackDimensionChanges();
|
||||||
checkPlayerSizeChange() {
|
|
||||||
// this 'if' is just here for debugging — real code starts later. It's safe to collapse and
|
|
||||||
// ignore the contents of this if (unless we need to change how logging works)
|
|
||||||
if (this.logger.canLog('debug')){
|
|
||||||
if (this.dimensions?.fullscreen){
|
|
||||||
if(! PlayerData.isFullScreen()){
|
|
||||||
this.logger.log('info', 'debug', "[PlayerDetect] player size changed. reason: exited fullscreen");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(! this.element) {
|
|
||||||
this.logger.log('info', 'playerDetect', "[PlayerDetect] player element isn't defined");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.element &&
|
|
||||||
( +this.dimensions?.width != +this.element?.offsetWidth ||
|
|
||||||
+this.dimensions?.height != +this.element?.offsetHeight )
|
|
||||||
) {
|
|
||||||
this.logger.log('info', 'debug', "[PlayerDetect] player size changed. reason: dimension change. Old dimensions?", this.dimensions?.width, this.dimensions?.height, "new dimensions:", this.element?.offsetWidth, this.element?.offsetHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if size doesn't match, update & return true
|
|
||||||
if (this.dimensions?.width != this.element.offsetWidth
|
|
||||||
|| this.dimensions?.height != this.element.offsetHeight ){
|
|
||||||
|
|
||||||
const isFullScreen = PlayerData.isFullScreen();
|
|
||||||
|
|
||||||
if (isFullScreen) {
|
|
||||||
this.dimensions = {
|
|
||||||
width: window.innerWidth,
|
|
||||||
height: window.innerHeight,
|
|
||||||
fullscreen: true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.dimensions = {
|
|
||||||
width: this.element.offsetWidth,
|
|
||||||
height: this.element.offsetHeight,
|
|
||||||
fullscreen: isFullScreen
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkFullscreenChange() {
|
|
||||||
const isFs = PlayerData.isFullScreen();
|
|
||||||
|
|
||||||
if (this.dimensions) {
|
|
||||||
if (this.dimensions.fullscreen != isFs) {
|
|
||||||
this.dimensions = {
|
|
||||||
fullscreen: isFs,
|
|
||||||
width: isFs ? screen.width : this.video.offsetWidth,
|
|
||||||
height: isFs ? screen.height : this.video.offsetHeight
|
|
||||||
};
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.log('info', 'debug', "[PlayerData::checkFullscreenChange] this.dimensions is not defined. Assuming fs change happened and setting default values.")
|
|
||||||
|
|
||||||
this.dimensions = {
|
|
||||||
fullscreen: isFs,
|
|
||||||
width: isFs ? screen.width : this.video.offsetWidth,
|
|
||||||
height: isFs ? screen.height : this.video.offsetHeight
|
|
||||||
};
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showNotification(notificationId) {
|
showNotification(notificationId) {
|
||||||
|
@ -12,8 +12,11 @@ import { sleep } from '../../../common/js/utils';
|
|||||||
import { hasDrm } from '../ar-detect/DrmDetecor';
|
import { hasDrm } from '../ar-detect/DrmDetecor';
|
||||||
|
|
||||||
class VideoData {
|
class VideoData {
|
||||||
|
private baseCssName: string = 'uw-ultrawidify-base-wide-screen';
|
||||||
|
|
||||||
//#region flags
|
//#region flags
|
||||||
arSetupComplete: boolean = false;
|
arSetupComplete: boolean = false;
|
||||||
|
enabled: boolean;
|
||||||
destroyed: boolean = false;
|
destroyed: boolean = false;
|
||||||
invalid: boolean = false;
|
invalid: boolean = false;
|
||||||
videoStatusOk: boolean = false;
|
videoStatusOk: boolean = false;
|
||||||
@ -186,7 +189,6 @@ class VideoData {
|
|||||||
* for our standards)
|
* for our standards)
|
||||||
*/
|
*/
|
||||||
async setupStageTwo() {
|
async setupStageTwo() {
|
||||||
// POZOR: VRSTNI RED JE POMEMBEN (arDetect mora bit zadnji)
|
|
||||||
// NOTE: ORDERING OF OBJ INITIALIZATIONS IS IMPORTANT (arDetect needs to go last)
|
// NOTE: ORDERING OF OBJ INITIALIZATIONS IS IMPORTANT (arDetect needs to go last)
|
||||||
this.player = new PlayerData(this);
|
this.player = new PlayerData(this);
|
||||||
if (this.player.invalid) {
|
if (this.player.invalid) {
|
||||||
@ -242,12 +244,10 @@ class VideoData {
|
|||||||
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
|
this.logger.log('info', ['debug', 'init'], '[VideoData::ctor] Created videoData with vdid', this.vdid, '\nextension mode:', this.extensionMode)
|
||||||
|
|
||||||
this.pageInfo.initMouseActionHandler(this);
|
this.pageInfo.initMouseActionHandler(this);
|
||||||
|
|
||||||
// NOTE — since base class for our <video> element depends on player aspect ratio,
|
|
||||||
// we handle it in PlayerData class.
|
|
||||||
this.video.classList.add('uw-ultrawidify-base-wide-screen');
|
|
||||||
this.video.classList.add(this.userCssClassName); // this also needs to be applied BEFORE we initialize resizer!
|
|
||||||
|
|
||||||
|
// aspect ratio autodetection cannot be properly initialized at this time,
|
||||||
|
// so we'll avoid doing that
|
||||||
|
this.enable({withoutAard: true});
|
||||||
|
|
||||||
// start fallback video/player size detection
|
// start fallback video/player size detection
|
||||||
this.fallbackChangeDetection();
|
this.fallbackChangeDetection();
|
||||||
@ -322,7 +322,7 @@ class VideoData {
|
|||||||
this.video.removeEventListener('ontimeupdate', this.onTimeUpdate);
|
this.video.removeEventListener('ontimeupdate', this.onTimeUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pause();
|
this.disable();
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
try {
|
try {
|
||||||
this.arDetector.halt();
|
this.arDetector.halt();
|
||||||
@ -344,6 +344,46 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables ultrawidify in general.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
enable(options?: {fromPlayer?: boolean, withoutAard?: boolean}) {
|
||||||
|
this.enabled = true;
|
||||||
|
|
||||||
|
// NOTE — since base class for our <video> element depends on player aspect ratio,
|
||||||
|
// we handle it in PlayerData class.
|
||||||
|
this.video.classList.add(this.baseCssName);
|
||||||
|
this.video.classList.add(this.userCssClassName); // this also needs to be applied BEFORE we initialize resizer! — O RLY? NEEDS TO BE CHECKED
|
||||||
|
|
||||||
|
if (!options?.withoutAard) {
|
||||||
|
this.startArDetection();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options?.fromPlayer) {
|
||||||
|
this.player?.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.restoreCrop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables ultrawidify in general.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
disable(options?: {fromPlayer?: boolean}) {
|
||||||
|
this.enabled = false;
|
||||||
|
|
||||||
|
this.stopArDetection();
|
||||||
|
|
||||||
|
this.video.classList.remove(this.baseCssName);
|
||||||
|
this.video.classList.remove(this.userCssClassName);
|
||||||
|
|
||||||
|
if (!options.fromPlayer) {
|
||||||
|
this.player?.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//#region video status
|
//#region video status
|
||||||
isVideoPlaying() {
|
isVideoPlaying() {
|
||||||
return this.video && !!(this.video.currentTime > 0 && !this.video.paused && !this.video.ended && this.video.readyState > 2);
|
return this.video && !!(this.video.currentTime > 0 && !this.video.paused && !this.video.ended && this.video.readyState > 2);
|
||||||
@ -355,6 +395,10 @@ class VideoData {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
restoreCrop() {
|
restoreCrop() {
|
||||||
|
if (!this.resizer) {
|
||||||
|
this.logger.log('warn', 'debug', '[VideoData::restoreCrop] Resizer has not been initialized yet. Crop will not be restored.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
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
|
||||||
@ -399,11 +443,16 @@ class VideoData {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.enabled) {
|
||||||
|
this.logger.log('info', 'info', '[VideoData::onVideoMutation] mutation was triggered, but the extension is disabled. Is the player window too small?');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(const mutation of mutationList) {
|
for(const mutation of mutationList) {
|
||||||
if (mutation.type === 'attributes') {
|
if (mutation.type === 'attributes') {
|
||||||
if( mutation.attributeName === 'class'
|
if( mutation.attributeName === 'class'
|
||||||
&& mutation.oldValue.indexOf('uw-ultrawidify-base-wide-screen') !== -1
|
&& mutation.oldValue.indexOf(this.baseCssName) !== -1
|
||||||
&& !this.video.classList.contains('uw-ultrawidify-base-wide-screen')
|
&& !this.video.classList.contains(this.baseCssName)
|
||||||
) {
|
) {
|
||||||
// force the page to include our class in classlist, if the classlist has been removed
|
// force the page to include our class in classlist, if the classlist has been removed
|
||||||
// while classList.add() doesn't duplicate classes (does nothing if class is already added),
|
// while classList.add() doesn't duplicate classes (does nothing if class is already added),
|
||||||
@ -413,7 +462,7 @@ class VideoData {
|
|||||||
|
|
||||||
confirmAspectRatioRestore = true;
|
confirmAspectRatioRestore = true;
|
||||||
this.video.classList.add(this.userCssClassName);
|
this.video.classList.add(this.userCssClassName);
|
||||||
this.video.classList.add('uw-ultrawidify-base-wide-screen');
|
this.video.classList.add(this.baseCssName);
|
||||||
} else if (mutation.attributeName === 'style') {
|
} else if (mutation.attributeName === 'style') {
|
||||||
confirmAspectRatioRestore = true;
|
confirmAspectRatioRestore = true;
|
||||||
}
|
}
|
||||||
@ -426,6 +475,13 @@ class VideoData {
|
|||||||
onVideoDimensionsChanged(mutationList, observer) {
|
onVideoDimensionsChanged(mutationList, observer) {
|
||||||
if (!mutationList || this.video === undefined) { // something's wrong
|
if (!mutationList || this.video === undefined) { // something's wrong
|
||||||
if (observer && this.video) {
|
if (observer && this.video) {
|
||||||
|
this.logger.log(
|
||||||
|
'warn', 'debug',
|
||||||
|
'onVideoDimensionChanged encountered a weird state. video and observer exist, but mutationlist does not.\n\nmutationList:', mutationList,
|
||||||
|
'\nobserver:', observer,
|
||||||
|
'\nvideo:', this.video,
|
||||||
|
'\n\nObserver will be disconnected.'
|
||||||
|
);
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -440,7 +496,8 @@ class VideoData {
|
|||||||
*/
|
*/
|
||||||
private _processDimensionsChanged() {
|
private _processDimensionsChanged() {
|
||||||
if (!this.player) {
|
if (!this.player) {
|
||||||
this.logger.log('warn', 'debug', `[VideoData::_processDimensionsChanged] Player is not defined. This is super haram.`, this.player)
|
this.logger.log('warn', 'debug', `[VideoData::_processDimensionsChanged] Player is not defined. This is super haram.`, this.player);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// adding player observer taught us that if element size gets triggered by a class, then
|
// adding player observer taught us that if element size gets triggered by a class, then
|
||||||
// the 'style' attributes don't necessarily trigger. This means we also need to trigger
|
// the 'style' attributes don't necessarily trigger. This means we also need to trigger
|
||||||
@ -497,7 +554,7 @@ class VideoData {
|
|||||||
&& this.isWithin(vh, (ph - (translateY * 2)), 2)
|
&& this.isWithin(vh, (ph - (translateY * 2)), 2)
|
||||||
&& this.isWithin(vw, (pw - (translateX * 2)), 2)) {
|
&& this.isWithin(vw, (pw - (translateX * 2)), 2)) {
|
||||||
} else {
|
} else {
|
||||||
this.player.forceDetectPlayerElementChange();
|
this.player.forceRefreshPlayerElement();
|
||||||
this.restoreAr();
|
this.restoreAr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,16 +613,8 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
return heightCompensationFactor;
|
return heightCompensationFactor;
|
||||||
}
|
}
|
||||||
firstTimeArdInit(){
|
|
||||||
if(this.destroyed || this.invalid) {
|
|
||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(! this.arSetupComplete){
|
|
||||||
this.arDetector = new ArDetector(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//#region AARD handlers
|
||||||
initArDetection() {
|
initArDetection() {
|
||||||
if(this.destroyed || this.invalid) {
|
if(this.destroyed || this.invalid) {
|
||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
||||||
@ -587,57 +636,20 @@ class VideoData {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasDrm(this.video)) {
|
|
||||||
this.player.showNotification('AARD_DRM');
|
|
||||||
this.hasDrm = true;
|
|
||||||
} else {
|
|
||||||
this.hasDrm = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.arDetector) {
|
|
||||||
this.initArDetection();
|
|
||||||
}
|
|
||||||
this.arDetector.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
rebootArDetection() {
|
|
||||||
if(this.destroyed || this.invalid) {
|
|
||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.arDetector.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
stopArDetection() {
|
|
||||||
if (this.arDetector) {
|
|
||||||
this.arDetector.halt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pause(){
|
|
||||||
this.paused = true;
|
|
||||||
if(this.arDetector){
|
|
||||||
this.arDetector.halt();
|
|
||||||
}
|
|
||||||
if(this.player){
|
|
||||||
this.player.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resume(){
|
|
||||||
if(this.destroyed || this.invalid) {
|
|
||||||
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.paused = false;
|
|
||||||
try {
|
try {
|
||||||
// this.resizer.start();
|
if (hasDrm(this.video)) {
|
||||||
if (this.player) {
|
this.player.showNotification('AARD_DRM');
|
||||||
this.player.start();
|
this.hasDrm = true;
|
||||||
|
} else {
|
||||||
|
this.hasDrm = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.arDetector) {
|
||||||
|
this.initArDetection();
|
||||||
|
}
|
||||||
|
this.arDetector.start();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.log('error', 'debug', "[VideoData.js::resume] cannot resume for reasons. Will destroy videoData. Error here:", e);
|
this.logger.log('warn', 'debug', '[VideoData::startArDetection()] Could not start aard for some reason. Was the function was called too early?', e);
|
||||||
this.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,18 +659,14 @@ class VideoData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setManualTick(manualTick) {
|
stopArDetection() {
|
||||||
if(this.arDetector){
|
if (this.arDetector) {
|
||||||
this.arDetector.setManualTick(manualTick);
|
this.arDetector.halt();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tick() {
|
|
||||||
if(this.arDetector){
|
|
||||||
this.arDetector.tick();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region shit that gets propagated to resizer and should be removed. Implement an event bus instead
|
||||||
setLastAr(lastAr){
|
setLastAr(lastAr){
|
||||||
if (this.invalid) {
|
if (this.invalid) {
|
||||||
return;
|
return;
|
||||||
@ -771,6 +779,7 @@ class VideoData {
|
|||||||
isPlaying() {
|
isPlaying() {
|
||||||
return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended;
|
return this.video && this.video.currentTime > 0 && !this.video.paused && !this.video.ended;
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
checkVideoSizeChange(){
|
checkVideoSizeChange(){
|
||||||
const videoWidth = this.video.offsetWidth;
|
const videoWidth = this.video.offsetWidth;
|
||||||
|
@ -615,9 +615,7 @@ class Resizer {
|
|||||||
// There seems to be no way to reproduce it.
|
// There seems to be no way to reproduce it.
|
||||||
if (! this._computeOffsetsRecursionGuard) {
|
if (! this._computeOffsetsRecursionGuard) {
|
||||||
this._computeOffsetsRecursionGuard = true;
|
this._computeOffsetsRecursionGuard = true;
|
||||||
if (this.conf.player.checkPlayerSizeChange()) {
|
this.conf.player.trackDimensionChanges();
|
||||||
this.conf.player.onPlayerDimensionsChanged();
|
|
||||||
}
|
|
||||||
this._computeOffsetsRecursionGuard = false;
|
this._computeOffsetsRecursionGuard = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user