import Debug from '../../conf/Debug'; import PlayerData from './PlayerData'; import Resizer from '../video-transform/Resizer'; import ArDetector from '../ar-detect/ArDetector'; import AspectRatioType from '../../../common/enums/AspectRatioType.enum'; import CropModePersistence from '../../../common/enums/CropModePersistence.enum'; import * as _ from 'lodash'; import BrowserDetect from '../../conf/BrowserDetect'; import Logger from '../Logger'; import Settings from '../Settings'; import PageInfo from './PageInfo'; import { sleep } from '../../../common/js/utils'; import { hasDrm } from '../ar-detect/DrmDetecor'; import EventBus from '../EventBus'; import { SiteSettings } from '../settings/SiteSettings'; /** * VideoData — handles CSS for the video element. * * To quickly disable or revert all modifications extension has made to the * video element, you can call disable() function. Calling disable() also * toggles autodetection off. */ class VideoData { private baseCssName: string = 'uw-ultrawidify-base-wide-screen'; //#region flags arSetupComplete: boolean = false; enabled: boolean; destroyed: boolean = false; invalid: boolean = false; videoStatusOk: boolean = false; videoLoaded: boolean = false; videoDimensionsLoaded: boolean = false; paused: boolean = false; //#endregion //#region misc stuff vdid: string; video: any; observer: ResizeObserver; mutationObserver: MutationObserver; mutationObserverConf: MutationObserverInit = { attributes: true, attributeFilter: ['class', 'style'], attributeOldValue: true, }; extensionMode: any; userCssClassName: string; validationId: number; dimensions: any; hasDrm: boolean; //#endregion //#region helper objects logger: Logger; siteSettings: SiteSettings; pageInfo: PageInfo; player: PlayerData; resizer: Resizer; arDetector: ArDetector; eventBus: EventBus; //#endregion get aspectRatio() { try { return this.video.videoWidth / this.video.videoHeight; } catch (e) { console.error('cannot determine stream aspect ratio!', e); return 1; } } constructor(video, siteSettings: SiteSettings, pageInfo){ this.logger = pageInfo.logger; this.arSetupComplete = false; this.video = video; this.destroyed = false; this.siteSettings = siteSettings; this.pageInfo = pageInfo; this.extensionMode = pageInfo.extensionMode; this.videoStatusOk = false; this.userCssClassName = `uw-fuck-you-and-do-what-i-tell-you_${this.vdid}`; this.videoLoaded = false; this.videoDimensionsLoaded = true; this.validationId = null; this.dimensions = { width: this.video.offsetWidth, height: this.video.offsetHeight, }; this.eventBus = new EventBus(); if (pageInfo.eventBus) { this.eventBus.setUpstreamBus(pageInfo.eventBus); this.eventBus.subscribe('get-drm-status', {function: () => { this.hasDrm = hasDrm(this.video); this.eventBus.send('uw-config-broadcast', {type: 'drm-status', hasDrm: this.hasDrm}); }}); } this.setupEventListeners(); } async onVideoLoaded() { if (!this.videoLoaded) { /** * video.readyState 101: * 0 — no info. Can't play. * 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 * 3 — we have a lil bit for the future * 4 — we'll survive to the end */ if (!this.video?.videoWidth || !this.video?.videoHeight || this.video.readyState < 2) { return; // onVideoLoaded is a lie in this case } this.logger.log('info', 'init', '%c[VideoData::onVideoLoaded] ——————————— Initiating phase two of videoData setup ———————————', 'color: #0f9'); this.videoLoaded = true; this.videoDimensionsLoaded = true; try { await this.setupStageTwo(); this.logger.log('info', 'init', '%c[VideoData::onVideoLoaded] ——————————— videoData setup stage two complete ———————————', 'color: #0f9'); } catch (e) { this.logger.log('error', 'init', '%c[VideoData::onVideoLoaded] ——————————— Setup stage two failed. ———————————\n', 'color: #f00', e); } } else if (!this.videoDimensionsLoaded) { this.logger.log('info', 'debug', "%c[VideoData::restoreCrop] Recovering from illegal video dimensions. Resetting aspect ratio.", "background: #afd, color: #132"); this.restoreCrop(); this.videoDimensionsLoaded = true; } } videoUnloaded() { this.videoLoaded = false; } async injectBaseCss() { try { if (!this.mutationObserver) { this.setupMutationObserver(); } this.eventBus.send( 'inject-css', ` .uw-ultrawidify-base-wide-screen { margin: 0px 0px 0px 0px !important; width: initial !important; align-self: start !important; justify-self: start !important; max-height: initial !important; max-width: initial !important; } ` ); } catch (e) { console.error('Failed to inject base css!', e); } } unsetBaseClass() { this.mutationObserver.disconnect(); this.mutationObserver = undefined; this.video.classList.remove('uw-ultrawidify-base-wide-screen'); } //#region