Skip to content

Instantly share code, notes, and snippets.

@i8degrees
Last active July 24, 2019 05:51
Show Gist options
  • Save i8degrees/60be41bc42beae08b54a74d5b0641ad4 to your computer and use it in GitHub Desktop.
Save i8degrees/60be41bc42beae08b54a74d5b0641ad4 to your computer and use it in GitHub Desktop.
A snippet from my nom-video module from Naughty Girl to demonstrate the "Page Visibility" API (browser implement)
<!DOCTYPE html>
<html>
<head>
<title>nom-video: demo</title>
</head>
<body>
<!-- hero video cover -->
<!-- ...and so on and so forth and what have you! -->
<!-- Album page with 25 video thumbnails -->
<!-- Wait for it! -->
<!-- ... -->
<!-- Damn girl! Your data stream blow job has nearly got two of my very expensive CPU cores to melt! -->
<!-- Okay, now that we are at the very bottom of the page, it is a generally safe assumption that the critical bits
of the page will have completed or be well upon its way to completion by this point! -->
<script src="/nom-video/src/hooks/vis.js">
// NOTE(jeff): Need not bother with this when empty; I am only showing it for sake of the API...
const p = {
videos: [],
};
// IMPORTANT(jeff): The only requirement here for calling this guy is that the HTML DOM has finalized its parsing,
// AKA the video tags have parsed in (as far as the browser sees it!)
setupPageVisibilityAPI(p);
</script>
<!-- Do **not** waste everybody's time parsing in the whole module here; you ass, I broke this feature into its own
standalone unit for the same very reason that has me creating this demo for you here no! Future teller I am. -->
<script src="/nom-video/index.js"></script>
</body>
</html>
/******************************************************************************
naughty.im
Copyright (c) 2012 to 2020 by
Jeffrey Carpenter <jeff@naughty.im>
ALL RIGHTS RESERVED
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
'use strict';
function ready(target = document, callback = noop, options = {}) {
const readyState =
(document.readyState === `complete` || document.readyState !== `loading`);
if(readyState) {
if(isFunction(callback) == true) {
return callback(target);
}
}
target.removeEventListener(`DOMContentLoaded`, callback, options);
return target.addEventListener(`DOMContentLoaded`, callback, options);
}
// FIXME(jeff): I have fucked up somewhere with the timer resume; I have found that it does not always resume the video
// playback as intended. You will be okay, I promise!
function freezeVideoPlayback(videos, delta = 60) {
const dt = delta || 60; // 1min
if(stopTimer >= 0) {
utils.clearThrottle(stopTimer);
}
stopTimer = utils.throttle(dt, function() {
videos.forEach(function(source) {
if(source && utils.isFunction(source.pause) == true) {
source.pause();
}
});
}, this);
}
const DEFAULT_OPTIONS = {
videos: [],
};
// IMPORTANT(jeff): Use the Page Visibility API [1] to pause video playback
// upon window activity.
//
// NOTE(jeff): This is an performance optimization; prevent playback of
// media when the page is outside of user focus, such as when it is hidden
// from the end-user.
//
// 1. https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API/Timing_element_visibility
export function setupPageVisibilityAPI(params = {}) {
let target;
const options = utils.extend(DEFAULT_OPTIONS, params);
// IMPORTANT(jeff): You pass in an array of video URL strings for this function, OR ELSE!
//
// ...or, or I am going to say fuck it, and just select every single video tag on this page and call it good. Right? Right.
//
// The default logic I chose here is that one tends to not have "special needs" when calling upon this API.
// Special needs would be like choosing to only terminate the advertisement banners from ticking past... which I
// have found to be an actual use case, but what the fuck ever! Move the fuck on...
const el = options.videos || document.querySelectorAll(`video`);
if(!el) {
return;
}
el.forEach(function(source) {
if(source) {
// NOTE(jeff): Yes, I am looking at each video source tag here and peeking to see if the "data-flags" attribute
// has been set. If so, a particular string alerts the script to go ahead and opt-in to the use of this performance
// optimization.
// <video id="boobs1">
// <source src="sd.mp4" data-flags="omnipotent">
// <source src="hd.mp4"></source>
// </video>
const flags = utils.toString(source.getAttribute(`data-flags`));
if(flags.includes(`omnipotent`) == false) {
options.videos.push(source);
}
}
});
// NOTE(jeff): Refer to the MDN docs regarding the "DOMContentLoaded" event [1] for
//
// 1. https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event
ready(function(evt) {
freezeVideoPlayback(options.videos);
return window.addEventListener('visibilitychange', function() {
const hiddenPage = document.hidden;
if(hiddenPage == true) {
// if(stopTimer >= 0) {
// utils.clearThrottle(stopTimer);
// }
options.videos.forEach(function(video) {
if(video) {
video.pause();
}
});
} else if(hiddenPage == false) {
options.videos.forEach(function(video) {
if(video && video.paused) {
video.play();
}
});
// freezeVideoPlayback(options.videos);
}
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment