-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
00a32f3
commit 1c4487f
Showing
2 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
# ytscreensaver | ||
Simple wrapper to play YouTube videos as a screensaver with the clock | ||
|
||
Simply open "screensaver.html" in the browser. | ||
|
||
I wrote this as a simple video screensaver for my Shield TV Android with https://play.google.com/store/apps/details?id=chyzinr.webpagescreensaver |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,324 @@ | ||
<html> | ||
<head> | ||
<title>Testing</title> | ||
<link rel="preconnect" href="https://fonts.googleapis.com"> | ||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet"> | ||
<style> | ||
.roboto-thin { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 100; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-light { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 300; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-regular { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 400; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-medium { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 500; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-bold { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 700; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-black { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 900; | ||
font-style: normal; | ||
} | ||
|
||
.roboto-thin-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 100; | ||
font-style: italic; | ||
} | ||
|
||
.roboto-light-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 300; | ||
font-style: italic; | ||
} | ||
|
||
.roboto-regular-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 400; | ||
font-style: italic; | ||
} | ||
|
||
.roboto-medium-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 500; | ||
font-style: italic; | ||
} | ||
|
||
.roboto-bold-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 700; | ||
font-style: italic; | ||
} | ||
|
||
.roboto-black-italic { | ||
font-family: "Roboto", sans-serif; | ||
font-weight: 900; | ||
font-style: italic; | ||
} | ||
|
||
body { | ||
margin: 0 auto; | ||
overflow: hidden; | ||
} | ||
.player { | ||
overflow: hidden; | ||
display: block; | ||
position: absolute; | ||
width: 100%; | ||
height: 100%; | ||
border: 0; | ||
} | ||
.hidden { | ||
opacity: 0; | ||
display: none !important; | ||
} | ||
.fadeInPlayer { | ||
animation: fadeIn 5s; | ||
} | ||
.fadeOutPlayer { | ||
animation: fadeOut 5s; | ||
} | ||
@keyframes fadeIn { | ||
0% { opacity: 0; } | ||
100% { opacity: 1; } | ||
} | ||
@keyframes faceOut { | ||
0% { opacity: 1; } | ||
100% { opacity: 0; } | ||
} | ||
#clock { | ||
position: absolute; | ||
color: white; | ||
text-shadow: 1px 1px 2px black; | ||
} | ||
#date { | ||
font-size: 24px; | ||
} | ||
#time { | ||
font-size: 36px; | ||
} | ||
.topLeft { | ||
left: 50px; | ||
top: 25px; | ||
} | ||
.topRight { | ||
right: 50px; | ||
top: 25px; | ||
} | ||
.bottomLeft { | ||
left: 50px; | ||
bottom: 25px; | ||
} | ||
.bottomRight { | ||
right: 50px; | ||
bottom: 25px; | ||
} | ||
.top { | ||
top: 0; | ||
} | ||
.bottom { | ||
bottom: 0; | ||
} | ||
#progressContainer { | ||
position: absolute; | ||
left: 0; | ||
width: 100%; | ||
background-color: black; | ||
opacity: 0.6; | ||
} | ||
#progressBar { | ||
position: relative; | ||
height: 3px; | ||
background-color: gray; | ||
left: 0; | ||
width: 100%; | ||
} | ||
#progressAmount { | ||
position: relative; | ||
width: 5%; | ||
height: 5px; | ||
background-color: white; | ||
} | ||
</style> | ||
</head> | ||
<body onload="init();"> | ||
<iframe id="player1" class="player" src="about:blank"></iframe> | ||
<iframe id="player2" class="player hidden" src="about:blank"></iframe> | ||
<div id="clock" class="roboto-regular topLeft"> | ||
<div id="date"></div> | ||
<div id="time"></div> | ||
</div> | ||
<div id="progressContainer" class="top"> | ||
<div id="progressBar"> | ||
<div id="progressAmount"></div> | ||
</div> | ||
</div> | ||
<script> | ||
const Minute = 60; | ||
const Hour = 60 * Minute; | ||
const Months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; | ||
const Days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; | ||
|
||
// Configuration | ||
|
||
// If false, shows the progress across the entire screen. If true, shows only the progress within the video | ||
const RelativeProgress = false; | ||
// Duration of each video segment to play in seconds | ||
const duration = 20 * Minute; | ||
// Videos to go through | ||
const videos = [ | ||
{"id": "z4swrq4ucfQ", "hours": 2, "minutes": 1, "seconds": 43, "skip": 0}, | ||
{"id": "WZFIo4yj17c", "hours": 6, "minutes": 10, "seconds": 10, "skip": 10}, | ||
{"id": "uYJQIKAVBw8", "hours": 2, "minutes": 0, "seconds": 0, "skip": 10} | ||
] | ||
|
||
let current = document.getElementById('player1'); | ||
let next = document.getElementById('player2'); | ||
const clock = document.getElementById('clock'); | ||
const date = document.getElementById('date'); | ||
const time = document.getElementById('time'); | ||
const progressContainer = document.getElementById('progressContainer'); | ||
const progressBar = document.getElementById('progressBar'); | ||
const progressAmount = document.getElementById('progressAmount'); | ||
|
||
let lastVideo = -1; | ||
let switching = -1; | ||
|
||
function init() { | ||
updateTime(); | ||
} | ||
|
||
function nextVideo(doSwitch) { | ||
const v = videos[Math.floor(Math.random() * videos.length)]; | ||
const durationSeconds = duration - v['skip']; | ||
const totalSeconds = (v['hours'] * Hour) + (v['minutes'] * Minute) + (v['seconds']); | ||
const blocks = totalSeconds / durationSeconds; | ||
let start = Math.floor((Math.random() * blocks) * durationSeconds) + v['skip']; | ||
if (start >= totalSeconds - duration - 30) { | ||
start = totalSeconds - duration - 30 | ||
} | ||
const player = doSwitch ? next : current; | ||
player.src = `https://www.youtube.com/embed/${v['id']}?autoplay=1&mute=1&controls=0&start=${start}`; | ||
if (doSwitch) switching = 0; | ||
|
||
// Update progress | ||
if (RelativeProgress) { | ||
const startPercentage = (start / totalSeconds) * 100; | ||
const durationPercentage = (duration / totalSeconds) * 100; | ||
progressBar.style.left = `${startPercentage}%`; | ||
progressBar.style.width = `${durationPercentage}%`; | ||
} | ||
progressAmount.style.width = '0'; | ||
if (progressContainer.classList.contains('top')) { | ||
progressContainer.classList.add('bottom'); | ||
progressContainer.classList.remove('top'); | ||
} else { | ||
progressContainer.classList.add('top'); | ||
progressContainer.classList.remove('bottom'); | ||
} | ||
} | ||
|
||
function updateTime() { | ||
const now = new Date(); | ||
|
||
// Update progress | ||
const progress = now.getTime() - lastVideo; | ||
const progressPercentage = (progress / (duration * 1000)) * 100; | ||
progressAmount.style.width = `${progressPercentage}%`; | ||
|
||
if (switching === 5) { | ||
// Start transitioning | ||
current.classList.add('fadeOutPlayer'); | ||
next.classList.add('fadeInPlayer'); | ||
next.classList.remove('hidden'); | ||
} else if (switching === 11) { | ||
// Finish transitioning | ||
current.src = 'about:blank'; | ||
current.classList.add('hidden'); | ||
current.classList.remove('fadeOutPlayer'); | ||
next.classList.remove('fadeInPlayer'); | ||
|
||
let p = next; | ||
next = current; | ||
current = p; | ||
switching = -1; | ||
} | ||
if (switching !== -1) { | ||
switching += 1; | ||
} | ||
|
||
if (lastVideo === -1) { | ||
nextVideo(false); | ||
lastVideo = now.getTime(); | ||
} else if (now.getTime() - lastVideo > duration * 1000) { | ||
// Change video | ||
nextVideo(true); | ||
lastVideo = now.getTime(); | ||
|
||
if (clock.classList.contains("topLeft")) { | ||
clock.classList.remove("topLeft"); | ||
clock.classList.add("topRight"); | ||
} else if (clock.classList.contains("topRight")) { | ||
clock.classList.remove("topRight"); | ||
clock.classList.add("bottomLeft"); | ||
} else if (clock.classList.contains("bottomLeft")) { | ||
clock.classList.remove("bottomLeft"); | ||
clock.classList.add("bottomRight"); | ||
} else if (clock.classList.contains("bottomRight")) { | ||
clock.classList.remove("bottomRight"); | ||
clock.classList.add("topLeft"); | ||
} | ||
} | ||
|
||
now.getDay() | ||
|
||
const day = Days[now.getDay()]; | ||
const month = Months[now.getMonth()]; | ||
const dayInMonth = now.getDate(); | ||
const year = now.getFullYear(); | ||
|
||
let h = now.getHours(); | ||
let m = now.getMinutes(); | ||
let s = now.getSeconds(); | ||
let amPm = 'am'; | ||
if (h > 12) { | ||
h -= 12; | ||
amPm = 'pm'; | ||
} else if (h === 0) { | ||
h = 12; | ||
} | ||
m = checkTime(m); | ||
s = checkTime(s); | ||
date.innerHTML = `${day}, ${month} ${dayInMonth}, ${year}`; | ||
time.innerHTML = h + ":" + m + ":" + s + ' ' + amPm; | ||
setTimeout(updateTime, 1000); | ||
} | ||
|
||
function checkTime(i) { | ||
if (i < 10) {i = "0" + i} // add zero in front of numbers < 10 | ||
return i; | ||
} | ||
</script> | ||
</body> | ||
</html> |