Last active
July 24, 2019 05:51
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
naughty.im | |
Copyright (c) 2012 to 2020 by | |
Jeffrey Carpenter <[email protected]> | |
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