Created
November 4, 2016 12:24
-
-
Save Dan-Q/1ea1e663d28d84be4a159ad65675b38a to your computer and use it in GitHub Desktop.
Simple one-file tool for the Bodleian Libraries' Heritage Window (5x3 HD video wall). Shows thumbnails for a YouTube playlist, then picks one video and plays it, then repeats.
This file contains hidden or 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> | |
<meta charset="utf-8" /> | |
<title>YouTube Video Wall</title> | |
<style type="text/css"> | |
body { | |
margin: 0; | |
background: black; | |
color: white; | |
} | |
main { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 3200px; | |
height: 1080px; | |
display: flex; | |
flex-wrap: wrap; | |
justify-content: center; | |
align-items: center; | |
} | |
img { | |
opacity: 0; | |
transition: opacity 0.5s; | |
} | |
img.visible { | |
opacity: 1; | |
} | |
</style> | |
</head> | |
<body> | |
<main> | |
</main> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> | |
<script> | |
'use strict'; | |
// Constants | |
const API_KEY ='PUT-YOUR-API-KEY-HERE'; | |
const PLAYLIST_ID = 'PLjw-j0hh81Ic1Cj43I3HpMLvFZzg6E8CH'; | |
const VIDEO_COUNT = 18; // number of videos to request from the playlist | |
const IMAGE_APPEAR_TIME = 250; // time (ms) between each thumbnail appearing | |
const VIDEO_APPEAR_TIME = 3000; // time (ms) after all thumbnails appear before video chosen | |
const THUMB_REMAIN_TIME = 1000; // time (ms) after all-but-chosen thumbnails disappear before video begins | |
const PANIC_TIME = 1000 * 60 * 15; // time (15 minutes) after which player will assume something went wrong (e.g. connection dropped) and will restart from scratch | |
const main = $('main'); | |
// In case of any kind of failure, auto-restart after a while | |
setTimeout(window.location.reload, PANIC_TIME); | |
// Fisher-Yates shuffle | |
function shuffle(array) { | |
let m = array.length, t, i; | |
while (m) { | |
let i = Math.floor(Math.random() * m--); | |
let t = array[m]; | |
array[m] = array[i]; | |
array[i] = t; | |
} | |
return array; | |
} | |
// Draw thumbnail wall, pick video, show video | |
function run(){ | |
main.html(''); | |
$.get(`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=${VIDEO_COUNT}&playlistId=${PLAYLIST_ID}&key=${API_KEY}`, function(data) { | |
for(let item of shuffle(data.items)){ | |
let snippet = item.snippet; | |
let thumb = snippet.thumbnails.high; | |
main.append(`<img src="${thumb.url}" height="${thumb.height}" width="${thumb.width}" alt="${snippet.title}" data-video-id="${snippet.resourceId.videoId}" />`); | |
} | |
let imageAppearify = setInterval(function(){ | |
let hiddenImages = $('img:not(.visible)'); | |
if(hiddenImages.length == 0) { | |
clearInterval(imageAppearify); | |
setTimeout(function(){ | |
let imgs = $('img'); | |
let randomImg = $(imgs[Math.floor(Math.random() * imgs.length)]); | |
imgs.not(randomImg).removeClass('visible'); | |
setTimeout(function(){ | |
randomImg.removeClass('visible'); | |
setTimeout(function(){ | |
let videoId = randomImg.data('video-id'); | |
$('main').html(`<iframe width="1920" height="1080" src="https://www.youtube-nocookie.com/embed/${videoId}?autoplay=1&rel=0&controls=0&showinfo=0" frameborder="0" allowfullscreen></iframe>`); | |
$.get(`https://www.googleapis.com/youtube/v3/videos?id=${videoId}&part=contentDetails&key=${API_KEY}`, function(videoData){ | |
let duration = videoData.items[0].contentDetails.duration.match(/((\d+)M)?(\d+)S/); | |
let mins = parseInt(duration[2]) || 0; | |
let secs = parseInt(duration[3]) || 0; | |
let time = (mins * 60) + secs; | |
setTimeout(function(){ run(); }, time * 1000); // start over when video finishes | |
}); | |
}, 300); // just longer than fade-out time for images, defined by CSS | |
}, THUMB_REMAIN_TIME); | |
}, VIDEO_APPEAR_TIME); | |
return; | |
} | |
$(hiddenImages[Math.floor(Math.random() * hiddenImages.length)]).addClass('visible'); | |
}, IMAGE_APPEAR_TIME); | |
}); | |
} | |
// When page finished loading, start! | |
$(run); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment