Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature #300: Reduce quality when window loses focus (from pull request #2162) #2212

Merged
merged 2 commits into from
Apr 27, 2024

Conversation

Alpaczyk
Copy link
Contributor

This commit is adding a feature described in #300. Users can choose the quality to which the player will lower when the window is unfocused. When the window is focused again, the quality is coming back to the desired one.
By mistake I closed previous pull request

@raszpl
Copy link
Contributor

raszpl commented Apr 27, 2024

should probably just be else here?

if (available_quality_levels.includes(quality) === false) {

assumes storage.player_quality is always enabled. ImprovedTube.playerQuality actually tests this, but its in the middle of function and easy to miss :(

if (quality && quality !== 'auto') {

this.focus === false case should save current playback quality, and try to restore saved value

hmm, something like this? :

ImprovedTube.playerQualityWithoutFocus = function () {
	function closest (num, arr) {
		let curr = arr[0];
		let diff = Math.abs (num - curr);
		for (let val = 0; val < arr.length; val++) {
			let newdiff = Math.abs (num - arr[val]);
			if (newdiff < diff) {
				diff = newdiff;
				curr = arr[val];
			}
		}
		return curr;
	};

	let player = this.elements.player,
		qualityWithoutFocus = this.storage.player_quality_without_focus,
		available_quality_levels = player.getAvailableQualityLevels();

	if(qualityWithoutFocus && qualityWithoutFocus != 'disabled' && player){
		if(this.focus === false) {
			ImprovedTube.qualityWithoutFocus = player.getPlaybackQuality();
			if (available_quality_levels.includes(qualityWithoutFocus) === false) {
				let label = ['tiny', 'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'hd2160', 'hd2880', 'highres'];
				let resolution = ['144', '240', '360', '480', '720', '1080', '1440', '2160', '2880', '4320'];
				let availableresolutions = available_quality_levels.reduce(function (array, elem) {
					array.push(resolution[label.indexOf(elem)]); return array;
				}, []);

				qualityWithoutFocus = closest(resolution[label.indexOf(qualityWithoutFocus)], availableresolutions);
				qualityWithoutFocus = label[resolution.indexOf(qualityWithoutFocus)];
			}

			player.setPlaybackQualityRange(qualityWithoutFocus);
			player.setPlaybackQuality(qualityWithoutFocus);

		} else if (ImprovedTube.qualityWithoutFocus) {
			player.setPlaybackQualityRange(ImprovedTube.qualityWithoutFocus);
			player.setPlaybackQuality(ImprovedTube.qualityWithoutFocus);
		}
	}

};

BUT! no idea if player.getPlaybackQuality() is guaranteed to always return something valid and sane. There is also danger of playerQualityWithoutFocus being called very early when player was just created and YT is slowly ramping up video download while setting initial video quality to very low, then we set qualityWithoutFocus, then user switches to the tab and we force set this saved (qualityWithoutFocus) very low quality :o Its not as easy peasy as I first thought :(
hmm maybe just returning to 'auto' is safest? That will only leave annoyed those users users who
-set specific quality manually in the player
-minimize
-come back and see it restored to 'auto' :]

for the future: Ideally ImprovedTube should have a facility to monitor for user manually changing quality thru player interface during playback.

So the above, but with

		} else {
			player.setPlaybackQualityRange('auto');
			player.setPlaybackQuality('auto');
		}

should be fine?

ps: Seeing as both playerQuality and playerQualityWithoutFocus have to perform this stupid 'find closest quality available' dance and thus share almost half the functions code, maybe it would be prudent to combining both at some point later in time when its debugged/ironed out and battle tested.

@ImprovedTube
Copy link
Member

ImprovedTube commented Apr 27, 2024

started combining here #2162 (comment)

@ImprovedTube ImprovedTube merged commit 3b0bc3d into code-charity:master Apr 27, 2024
@raszpl
Copy link
Contributor

raszpl commented Apr 27, 2024

merged before it was fixed

assumes storage.player_quality is always enabled

@ImprovedTube
Copy link
Member

for the credits

ImprovedTube added a commit that referenced this pull request Apr 27, 2024
ImprovedTube added a commit that referenced this pull request Apr 27, 2024
ImprovedTube added a commit that referenced this pull request Apr 27, 2024
@ImprovedTube
Copy link
Member

@Alpaczyk @raszpl

/*------------------------------------------------------------------------------
QUALITY
------------------------------------------------------------------------------*/
ImprovedTube.playerQuality = function (quality) {
    if (!quality) quality = this.storage.player_quality;
    if (quality && quality !== 'auto') {
        var player = this.elements.player;
        if (player && player.getAvailableQualityLevels && !player.dataset.defaultQuality) {
            var available_quality_levels = player.getAvailableQualityLevels();
            function closest(num, arr) {
                let curr = arr[0];
                let diff = Math.abs(num - curr);
                for (let val = 0; val < arr.length; val++) {
                    let newdiff = Math.abs(num - arr[val]);
                    if (newdiff < diff) {
                        diff = newdiff;
                        curr = arr[val];
                    }
                }
                return curr;
            }
            if (!available_quality_levels.includes(quality)) {
                let label = ['tiny', 'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'hd2160', 'hd2880', 'highres'];
                let resolution = ['144', '240', '360', '480', '720', '1080', '1440', '2160', '2880', '4320'];
                let availableresolutions = available_quality_levels.map(q => resolution[label.indexOf(q)]);
                quality = closest(resolution[label.indexOf(quality)], availableresolutions);
                quality = label[resolution.indexOf(quality)];
            }
            player.setPlaybackQualityRange(quality);
            player.setPlaybackQuality(quality);
            player.dataset.defaultQuality = quality;
        }
    }
};
/*------------------------------------------------------------------------------
QUALITY WITHOUT FOCUS
------------------------------------------------------------------------------*/
ImprovedTube.playerQualityWithoutFocus = function () {
    var qualityWithoutFocus = this.storage.player_quality_without_focus;
    if (qualityWithoutFocus && qualityWithoutFocus !== 'disabled') {
        if (this.focus === true) {
            if (ImprovedTube.qualityBeforeBlur) {
                ImprovedTube.playerQuality(ImprovedTube.qualityBeforeBlur);
            } else {
                ImprovedTube.playerQuality();
            }
        } else if (this.focus === false) {
            ImprovedTube.qualityBeforeBlur = this.elements.player.getPlaybackQuality();
            if (ImprovedTube.played_time > 0 && ImprovedTube.formatSecond(player.getDuration() * 0.997 - player.getCurrentTime()) > 11) {
                setTimeout(function () {
                    if (this.focus === false) {
                        ImprovedTube.playerQuality(qualityWithoutFocus);
                    }
                }, Math.max(321, 3210 - ImprovedTube.played_time));
            }
        }
    }
};

@ImprovedTube
Copy link
Member

also, does this make sense? @raszpl c2e2e1a
(just making sure these dont run uncessarily:
ImprovedTube.alwaysShowProgressBar();
ImprovedTube.playerRemainingDuration();
)

@raszpl
Copy link
Contributor

raszpl commented Apr 28, 2024

crashes (player.getDuration)
doesnt work after crash fix because playerQuality is written in a way to only work once (!player.dataset.defaultQuality)
doesn do anything because ImprovedTube.formatSecond returns ISO 8601
doesn do anything because this inside settimeout is not ImprovedTube
what was the intend for checking time?
Why settimeout in the first place, and why such weird delay?
finally:

There is also danger of playerQualityWithoutFocus being called very early when player was just created and YT is slowly ramping up video download while setting initial video quality to very low, then we set qualityWithoutFocus, then user switches to the tab and we force set this saved (qualityWithoutFocus) very low quality

are you using Cunningham's Law on me ? :]

@raszpl
Copy link
Contributor

raszpl commented Apr 28, 2024

also would be nice to throw checking iv video is paused in there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants