I have a date counter with play/pause button that works great, however, during pause the counter continues to run in the background.
To see what I mean, press pause, wait 10 seconds, press play and you will see the date has advanced 1 or 2 months, not to the next day. I am grateful for any help. My code is below.
var virtualOrigin = Date.parse("2020-01-01"),
realOrigin = Date.now(),
factor = 862350;
function getVirtual(time) {
return new Date(virtualOrigin + (time - realOrigin) * factor);
}
function format(time) {
var month = time.getMonth() + 1;
var day = time.getDate();
if (month < 10) {
month = '0' + month;
}
if (day < 10) {
day = '0' + day;
}
return (month) +
"-" + day +
"-" + time.getFullYear();
}
var output = document.getElementById("txt");
var t = 0;
var flagTimer = 'startTime()';
function pause() {
if (flagTimer == 'startTime()') {
clearTimeout(t);
document.getElementById('Pause').value = "Play";
flagTimer = 'pause';
} else {
flagTimer = 'startTime()';
document.getElementById('Pause').value = "Pause";
startTime();
}
}
function startTime() {
var now = new Date();
var display = getVirtual(now);
output.innerText = format(display);
t = setTimeout(startTime, 1000 / factor - (now.getMilliseconds() %
(1000 / factor)));
}
function clickEvent() {
pause();
}
.txt {
color: orange;
margin-left: 46%;
margin-top: 10%;
position: absolute;
z-index: 300;
}
#Pause {
margin-left: 47.6%;
margin-top: 10%;
border: 2px solid orange;
color: blue;
display: block;
width: 55px;
text-align: center;
}
#Pause:hover {
background-color: orange;
color: white;
border: 2px solid lightblue;
}
#toggle-animation {
margin-left: 45.5%;
margin-top: 10%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>timer8</title>
<meta charset=UTF-8>
</head>
<body onload="startTime()">
<input type="button" id="Pause" class="toggle-animation" value="Pause" onclick="clickEvent();" />
<div id="txt" class="txt"></div>
</body>
</html>
Your function to calculate the virtual date:
function getVirtual(time) {
return new Date( virtualOrigin + (time - realOrigin) * factor );
}
... calculates it based on the difference between the current time and page load time, regardless of whether you have paused or not.
You could fix this by:
when pausing, updating virtualOrigin to the current virtual datetime
in your getVirtual(time) function, only adding the difference when your timer is unpaused
when unpausing, updating realOrigin to the current real datetime.
I'm trying to build a chat based on AJAX that receives data every second by settimeout.
I wrote a basic code where there is a number that increases each second of the number obtained from the php page2.
I checked it from my computer by opening the file in 3 different browsers and saw that it takes a lot of virtual memory from the server. My fear is what will happen if I build a real chat in this format and 50 people simultaneously enter?
I know that setTimeout takes a lot of memory, is there any other way to build chat? Or can I improve what I did?
I would be very happy to answer!
that's what i did:
<body>
<h1 id='number'>0</h1>
<script>
function ajax() {
if (window.XMLHttpRequest) {
var a = new XMLHttpRequest()
} else {
var a = new ActivXObject('Microsoft.XMLHTTP')
}
return a
}
var settime = 1000;
var myTime;
ajaxMain();
function ajaxMain() {
xmlhttp = ajax();
xmlhttp.onreadystatechange = function() {
if (((xmlhttp.readyState == 4) || (xmlhttp.readyState == 0)) && (xmlhttp.status == 200)) {
if (xmlhttp.responseText) {
id('mmm').innerHTML = (xmlhttp.responseText) * 1 + (id('number').innerHTML) * 1;
myTime = setTimeout('ajaxMain()', settime)
}
} else {
if (xmlhttp.responseText.match(/^\<\!/)) {
clearTimeout(myTime);
myTime = setTimeout('ajaxMain()', settime)
}
}
}
xmlhttp.open('GET', 'page2.php', true)
xmlhttp.send()
}
</script>
</body>
</html>
page2.php:
<?php
echo 1
?>
Thier is a full guide how to create an AJAX based chat system in PHP by Ashraf Gheith,
I'll quote:
CREATE TABLE `chat` (
`id` INT(9) NOT NULL AUTO_INCREMENT ,
`usrname` VARCHAR(255) NOT NULL ,
`color` VARCHAR(6) NOT NULL ,
`chattext` TEXT NOT NULL ,
`chattime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
PRIMARY KEY (`id`)
) ENGINE = MyISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci;
var lastTimeID = 0;
$(document).ready(function() {
$('#btnSend').click( function() {
sendChatText();
$('#chatInput').val("");
});
startChat();
});
function startChat(){
setInterval( function() { getChatText(); }, 2000);
}
function getChatText() {
$.ajax({
type: "GET",
url: "/refresh.php?lastTimeID=" + lastTimeID
}).done( function( data )
{
var jsonData = JSON.parse(data);
var jsonLength = jsonData.results.length;
var html = "";
for (var i = 0; i < jsonLength; i++) {
var result = jsonData.results[i];
html += '<div style="color:#' + result.color + '">(' + result.chattime + ') <b>' + result.usrname +'</b>: ' + result.chattext + '</div>';
lastTimeID = result.id;
}
$('#view_ajax').append(html);
});
}
function sendChatText(){
var chatInput = $('#chatInput').val();
if(chatInput != ""){
$.ajax({
type: "GET",
url: "/submit.php?chattext=" + encodeURIComponent( chatInput )
});
}
}
body{
margin: 0;
padding: 0;
}
#view_ajax {
display: block;
overflow: auto;
width: 500px;
height: 300px;
border: 1px solid #333;
margin: 0 auto;
margin-top: 20px;
}
#ajaxForm{
display: block;
margin: 0 auto;
width: 500px;
height: 50px;
margin-top: 10px;
}
#chatInput{
width: 454px;
}
<html>
<head>
<title>Chat Room Example</title>
<script src="js/jquery.min.js"></script>
<script src="js/main.js"></script>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<div id="view_ajax"></div>
<div id="ajaxForm">
<input type="text" id="chatInput" /><input type="button" value="Send" id="btnSend" />
</div>
</body>
</html>
The full guide will be on this link
I'm trying to learn Java Script Animations and I found really good examples on this site: http://javascript.info/tutorial/animation#maths-the-function-of-progress-delta
But the problem is, as a beginner, I don't understand how the functions and objects work with each other.
Question 01
I copied the example "Let’s create a movement animation on it’s base:" But my version does not work.
<!DOCTYPE HTML>
<html>
<head>
<style>
.example_path{
position: relative;
width: 600px;
height: 100px;
border-style: solid;
border-width: 5px;
}
.example_block{
position: absolute;
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
</head>
<body>
<div onclick="move(this.children[0])" class="example_path">
<div class="example_block"></div>
</div>
<script>
function move(element, delta, duration) {
var to = 500
animate({
delay: 10,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
}
})
}
</script>
</body>
</html>
output console: ReferenceError: animate is not defined
Does anyone know what the problem is?
Question 02
My second wish is, to integrate the easeInOut function
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
bounceEaseInOut = makeEaseInOut(bounce)
How can I link both code snippets? The code is also from this page: http://javascript.info/tutorial/animation#maths-the-function-of-progress-delta
Add animate and makeEaseInOut into your script tag then you can use them. You may want to include the functions in a separate JavaScript file eventually.
<script>
function animate(opts) {
var start = new Date
var id = setInterval(function() {
var timePassed = new Date - start
var progress = timePassed / opts.duration
if (progress > 1) progress = 1
var delta = opts.delta(progress)
opts.step(delta)
if (progress == 1) {
clearInterval(id)
}
}, opts.delay || 10)
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2
else
return (2 - delta(2*(1-progress))) / 2
}
}
bounceEaseInOut = makeEaseInOut(bounce)
</script>
that's what I tried.
I still have problems.
output console: delta is not a function. bounce is not a function.
I know I have to learn more about creating functions. But right now I'm not that good to solve the problem.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
.example_path{
position: relative;
width: 600px;
height: 100px;
border-style: solid;
border-width: 5px;
}
.example_block{
position: absolute;
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
<script>
function move(element, delta, duration) {
var to = 500;
animate({
delay: 10,
duration: duration || 1000, // 1 sec by default
delta: delta,
step: function(delta) {
element.style.left = to*delta + "px"
}
});
}
function animate(opts) {
var start = new Date;
var id = setInterval(function() {
var timePassed = new Date - start;
var progress = timePassed / opts.duration;
if (progress > 1) progress = 1
var delta = opts.delta(progress);
opts.step(delta);
if (progress == 1) {
clearInterval(id);
}
}, opts.delay || 10);
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress)/2;
else
return (2 - delta(2*(1-progress)))/2;
};
}
varbounceEaseInOut = makeEaseInOut(bounce);
</script>
</head>
<body>
<div onclick="move(this.children[0], makeEaseInOut(bounce), 3000)" class="example_path">
<div class="example_block"></div>
</div>
</body>
</html>
I've made a very simple animation using javascript, hope it helps, try to "Run code snippet" for better understanding.
/*JavaScript*/
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function Back() {
var elem1 = document.getElementById("animate");
var id1 = setInterval(frame2, 5);
var pos1 = 350;
function frame2() {
if (pos1 == 0) {
clearInterval(id1);
} else {
pos1--;
elem1.style.top = pos1 + 'px';
elem1.style.left = pos1 + 'px';
}
}
}
/*CSS*/
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
/*HTML*/
<button onclick="myMove()">Click Me</button>
<button onclick="Back()"> roll back</button>
<div id ="container">
<div id ="animate"></div>
</div>
I have articles to display in an application of smart TV (coding JavaScript) but unfortunately, it shows only the first few onces while all the rest of them stay down hidden. Is there any way how to scroll in Samsung Smart TV ?
if you are using divs or list to display data than you can easily hide a list or Div using jquery on key press.
scrollBy and scrollTo work fine on samsung smart tv (not on lg). You did not describe your problem well enough, but I guess all you need to bind up/down keys to one of the scroll APIs.
I recommend using isscrolljs instead of using scrollBy and scrollTo, as it works well on both samsung and lg. smarttvjs also uses it.
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
var InitH = 440 -10;
var InitTop = 50;
var MaxTop;
var interT = null, interD = null;
var d;
var t;
var prevT = null;
var Main =
{
};
Main.onLoad = function()
{
// Enable key event processing
this.enableKeys();
widgetAPI.sendReadyEvent();
MaxTop = $("#Content").position().top - (parseInt($("#Content").css("height"))- InitH);
alert($("#Content").position().top);
alert(MaxTop);
};
Main.onUnload = function()
{
};
Main.enableKeys = function()
{
document.getElementById("anchor").focus();
};
Main.keyDown = function()
{
var keyCode = event.keyCode;
alert("Key pressed: " + keyCode);
switch(keyCode)
{
case tvKey.KEY_RETURN:
case tvKey.KEY_PANEL_RETURN:
alert("RETURN");
widgetAPI.sendReturnEvent();
break;
case tvKey.KEY_LEFT:
alert("LEFT");
break;
case tvKey.KEY_RIGHT:
alert("RIGHT");
break;
case tvKey.KEY_UP:
alert("UP");
interTop();
d = new Date();
t =parseInt((d.getTime()%10000)/1000);
alert(t+" ---------" );
//alert(scroll);
//Math.abs(t-prevT)>=3 && Math.abs(t-prevT)<=7
if(($("#Content").position().top<InitTop && t!=prevT) || prevT == null){
$("#Content").css("top",$("#Content").position().top+50+"px");
prevT = t;
}else if($("#Content").position().top>InitTop){
$("#Content").css("top",InitTop+"px");
}
break;
case tvKey.KEY_DOWN:
alert("DOWN");
interDown();
d = new Date();
t =parseInt((d.getTime()%10000)/1000);
alert(t+" ---------" );
//alert(scroll);
//Math.abs(t-prevT)>=3 && Math.abs(t-prevT)<=7
if(($("#Content").position().top>MaxTop && t!=prevT) || prevT == null){
$("#Content").css("top",$("#Content").position().top-50+"px");
prevT = t;
}else if($("#Content").position().top<MaxTop){
$("#Content").css("top",MaxTop+"px");
}
break;
case tvKey.KEY_ENTER:
case tvKey.KEY_PANEL_ENTER:
alert("ENTER");
alert($("#Content").css("height"));
alert($("#Content").position().top);
break;
default:
alert("Unhandled key");
break;
}
};
function interTop(){
clearInterval(interD);
interD = null;
if(interT == null){
interT = setInterval(function(){if($("#Content").position().top>InitTop){
$("#Content").css("top",InitTop+"px");
}
},500);
}
}
function interDown(){
clearInterval(interT);
interT = null;
if(interD == null){
interD = setInterval(function(){if($("#Content").position().top<MaxTop){
$("#Content").css("top",MaxTop+"px");
}
},500);
}
}
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
var total_item = 3, current_item = 0;
//var variable = Document.getElementById("Content");
var Main =
{
};
Main.onLoad = function()
{
// Enable key event processing
this.enableKeys();
widgetAPI.sendReadyEvent();
navigation("DOWN");
fetchNews();
///////////////////////////////////
/* L'appel du Parser à compléter */
/* L'appel du Parser à compléter */
/* L'appel du Parser à compléter */
///////////////////////////////////
};
Main.onUnload = function()
{
};
Main.enableKeys = function()
{
document.getElementById("anchor").focus();
};
Main.keyDown = function()
{
var keyCode = event.keyCode;
alert("Key pressed: " + keyCode);
switch(keyCode)
{
case tvKey.KEY_RETURN:
case tvKey.KEY_PANEL_RETURN:
alert("RETURN");
widgetAPI.blockNavigation(event);
parent.location = "index.html";
break;
case tvKey.KEY_LEFT:
alert("LEFT");
break;
case tvKey.KEY_RIGHT:
alert("RIGHT");
break;
case tvKey.KEY_UP:
alert("UP");
//navigation("UP");
break;
case tvKey.KEY_DOWN:
alert("DOWN");
//navigation("DOWN");
break;
case tvKey.KEY_ENTER:
case tvKey.KEY_PANEL_ENTER:
alert("ENTER");
//gotoPage();
break;
default:
alert("Unhandled key");
break;
}
};
function navigation(direction){
$("#btn_"+current_item).removeClass("selected_btn");
if(direction == "UP"){
if(current_item == 1)
current_item = total_item;
else
current_item--;
}else if(direction == "DOWN"){
if(current_item == total_item)
current_item = 1;
else
current_item++;
}
$("#btn_"+current_item).addClass("selected_btn");
}
function gotoPage(){
switch(current_item){
//case 1: parent.location = "gallery.html"; break;
case 2: parent.location = "news.html"; break;
case 3: parent.location = "about.html"; break;
}
}
function fetchNews(){
if ( ParserNews.init()) {
ParserNews.dataReceivedCallback = function() {
prepareNewsList();
};
ParserNews.fetchDatas();
}
};
function prepareNewsList(){
var i;
for(i=0; i<DataNews.getCount(); i++){
$("<div/>").addClass("newsItem").html('<div class="title">'+DataNews.getTitle(i)+'</div></br><div><img src ="'+DataNews.getDate(i)+'"></div>').appendTo($("body"));
}
alert(DataNews.getTitle(3)) ;
alert(DataNews.getMiservices(3)) ;
alert(DataNews.getCount());
}
// This is the CSS file
* {
padding: 0;
margin: 0;
border: 0;
}
/* Layout */
body {
width: 1280px;
height: 720px;
background-image: url("../img/backk.jpg");
position: fixed;
}
.newsItem {
padding: 10px;
color: #fff;
width: 1250px;
height: 100px;
margin-bottom: 10px;
margin-left: 80px;
background-color: #388e8e;
}
.title {
color: #87d2ef;
font-size: 20px;
}
.description {
color: #fff;
font-size: 15px;
}
.img {
width: 50px;
height: 60px;
position: absolute;
left: 50px;
top: 50px;
}
.text {
position: absolute;
width: 500px;
height: 400px;
left: 400px;
top: 50px;
font-size: 25px;
color: #fff;
}
#Content {
-webkit-transition: top 1s ease-in-out;
}
.transitions .top {
top: 0;
}
.transitions .bottom {
top: -70px;
}
// Finally HTML file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Tunisie</title>
<!-- TODO : Common API -->
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"></script>
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"></script>
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/jquery.js"></script>
<!-- TODO : Javascript code -->
<script type="text/javascript" src="app/javascript/Parser_News.js"></script>
<script type="text/javascript" src="app/javascript/Data_News.js"></script>
<script language="javascript" type="text/javascript" src="app/javascript/News.js"></script>
<script language="javascript" type="text/javascript" src="app/javascript/testScroll.js"></script>
<!-- TODO : Style sheets code -->
<link rel="stylesheet" href="app/stylesheets/testScroll.css" type="text/css">
<!-- TODO: Plugins -->
</head>
<body onload="Main.onLoad();" onunload="Main.onUnload();">
<!-- Dummy anchor as focus for key events -->
<div class="newsItem" id="Content" style="width:100%; top:50px; left:100px; border:solid 1px #000000; position:fixed;">
</div>
</body>
</html>
Is it possible to play only the audio from a YouTube video using HTML 5 and Javascript?
UPDATE 2022
webm formats added for demo. You can always check for console log and add all formats needed.
UPDATE 2021
You can parse Youtube HTML page for all streams available for this particular video and extract audio only streams.
Here is an example with public Google Image proxy (but you can use any free or your own CORS proxy):
var vid = "3r_Z5AYJJd4",
audio_streams = {},
audio_tag = document.getElementById('youtube');
fetch("https://images" + ~~(Math.random() * 33) + "-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURIComponent("https://www.youtube.com/watch?hl=en&v=" + vid)).then(response => {
if (response.ok) {
response.text().then(data => {
var regex = /(?:ytplayer\.config\s*=\s*|ytInitialPlayerResponse\s?=\s?)(.+?)(?:;var|;\(function|\)?;\s*if|;\s*if|;\s*ytplayer\.|;\s*<\/script)/gmsu;
data = data.split('window.getPageData')[0];
data = data.replace('ytInitialPlayerResponse = null', '');
data = data.replace('ytInitialPlayerResponse=window.ytInitialPlayerResponse', '');
data = data.replace('ytplayer.config={args:{raw_player_response:ytInitialPlayerResponse}};', '');
var matches = regex.exec(data);
var data = matches && matches.length > 1 ? JSON.parse(matches[1]) : false;
console.log(data);
var streams = [],
result = {};
if (data.streamingData) {
if (data.streamingData.adaptiveFormats) {
streams = streams.concat(data.streamingData.adaptiveFormats);
}
if (data.streamingData.formats) {
streams = streams.concat(data.streamingData.formats);
}
} else {
return false;
}
streams.forEach(function(stream, n) {
var itag = stream.itag * 1,
quality = false;
console.log(stream);
switch (itag) {
case 139:
quality = "48kbps";
break;
case 140:
quality = "128kbps";
break;
case 141:
quality = "256kbps";
break;
case 249:
quality = "webm_l";
break;
case 250:
quality = "webm_m";
break;
case 251:
quality = "webm_h";
break;
}
if (quality) audio_streams[quality] = stream.url;
});
console.log(audio_streams);
audio_tag.src = audio_streams['256kbps'] || audio_streams['128kbps'] || audio_streams['48kbps'];
audio_tag.play();
})
}
});
<audio id="youtube" autoplay controls loop></audio>
Doesn't work for all videos, very depends on monetization settings or something like that.
Embed the video player and use CSS to hide the video. If you do it properly you may even be able to hide only the video and not the controls below it.
However, I'd recommend against it, because it will be a violation of YouTube TOS. Use your own server instead if you really want to play only audio.
UPDATED FOR 2020
It seems in Septeber 2019, YouTube updated the values that are returned by get_video_info.
Rather than data.url_encoded_fmt_stream_map and data.adaptive_fmts (as used in the other older examples) now we are looking for for data.formats and data.adaptiveFormats.
Anyways here is what you are all here for some code that loads a YouTube video into an <audio> element. Try it on CodePen
// YouTube video ID
var videoID = "CMNry4PE93Y";
// Fetch video info (using a proxy to avoid CORS errors)
fetch('https://cors-anywhere.herokuapp.com/' + "https://www.youtube.com/get_video_info?video_id=" + videoID).then(response => {
if (response.ok) {
response.text().then(ytData => {
// parse response to find audio info
var ytData = parse_str(ytData);
var getAdaptiveFormats = JSON.parse(ytData.player_response).streamingData.adaptiveFormats;
var findAudioInfo = getAdaptiveFormats.findIndex(obj => obj.audioQuality);
// get the URL for the audio file
var audioURL = getAdaptiveFormats[findAudioInfo].url;
// update the <audio> element src
var youtubeAudio = document.getElementById('youtube');
youtubeAudio.src = audioURL;
});
}
});
function parse_str(str) {
return str.split('&').reduce(function(params, param) {
var paramSplit = param.split('=').map(function(value) {
return decodeURIComponent(value.replace('+', ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}
<audio id="youtube" controls></audio>
This may be an old post but people could still be searching for this so here you go:
<div style="position:relative;width:267px;height:25px;overflow:hidden;">
<div style="position:absolute;top:-276px;left:-5px">
<iframe width="300" height="300"
src="https://www.youtube.com/embed/youtubeID?rel=0">
</iframe>
</div>
</div>
You can make a fake audio player to toggle the Youtube iframe through Youtube Iframe API,
and also use the API to get informations that you want to display on your audio player.
Here is my example.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="player.css">
<script src="https://www.youtube.com/iframe_api"></script>
<script src="player.js"></script>
<script>
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
</script>
</head>
<body>
<!--Youtube-->
<div id="player" style="display: none; visibility: hidden;"></div>
<!--Player-->
<div class="audio-player">
<div class="player-controls">
<div id="radioIcon"></div>
<button id="playAudio"></button>
<div id="seekObjContainer">
<div id="seekObj">
<div id="percentage"></div>
</div>
</div>
<p><small id="currentTime">00:00</small></p>
</div>
</div>
</body>
</html>
player.js
var player;
function onPlayerReady(event) {
document.getElementById(ui.play).addEventListener('click', togglePlay);
timeupdater = setInterval(initProgressBar, 100);
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
document.getElementById(ui.play).classList.remove('pause');
document.getElementById(ui.percentage).style.width = 0;
document.getElementById(ui.currentTime).innerHTML = '00:00';
player.seekTo(0, true);
}
}
let ui = {
play: 'playAudio',
audio: 'audio',
percentage: 'percentage',
seekObj: 'seekObj',
currentTime: 'currentTime'
};
function togglePlay() {
if (player.getPlayerState() === 1) {
player.pauseVideo();
document.getElementById(ui.play).classList.remove('pause');
} else {
player.playVideo();
document.getElementById(ui.play).classList.add('pause');
}
}
function calculatePercentPlayed() {
let percentage = (player.getCurrentTime() / player.getDuration()).toFixed(2) * 100;
document.getElementById(ui.percentage).style.width = `${percentage}%`;
}
function calculateCurrentValue(currentTime) {
const currentMinute = parseInt(currentTime / 60) % 60;
const currentSecondsLong = currentTime % 60;
const currentSeconds = currentSecondsLong.toFixed();
const currentTimeFormatted = `${currentMinute < 10 ? `0${currentMinute}` : currentMinute}:${
currentSeconds < 10 ? `0${currentSeconds}` : currentSeconds
}`;
return currentTimeFormatted;
}
function initProgressBar() {
const currentTime = calculateCurrentValue(player.getCurrentTime());
document.getElementById(ui.currentTime).innerHTML = currentTime;
document.getElementById(ui.seekObj).addEventListener('click', seek);
function seek(e) {
const percent = e.offsetX / this.offsetWidth;
player.seekTo(percent * player.getDuration());
}
calculatePercentPlayed();
}
player.css
* {
box-sizing: border-box;
}
body {
background-size: 6px 6px !important;
background-image: linear-gradient(-45deg, rgba(0, 0, 0, 0) 46%, coral 49%, coral 51%, rgba(0, 0, 0, 0) 55%);
background-color: white;
padding-top: 60px;
}
.audio-player {
width: 470px;
padding: 35px 20px;
margin: auto;
background-color: white;
border: 1px solid black;
}
.audio-player .player-controls {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
}
.audio-player #radioIcon {
width: 30px;
height: 30px;
background: url("https://img.icons8.com/ios/50/000000/microphone.png") no-repeat center;
background-size: contain;
}
.audio-player #playAudio {
-webkit-appearance: none;
outline: none;
cursor: pointer;
border: none;
width: 30px;
height: 30px;
background: url("https://img.icons8.com/play") no-repeat center;
background-size: contain;
}
.audio-player #playAudio.pause {
background: url("https://img.icons8.com/pause") no-repeat center;
background-size: contain;
}
.audio-player p {
margin: 0 0 0 5px;
line-height: 1;
display: inline-flex;
}
.audio-player p small {
font-size: 10px;
}
.audio-player #seekObjContainer {
position: relative;
width: 300px;
margin: 0 5px;
height: 5px;
}
.audio-player #seekObjContainer #seekObj {
position: relative;
width: 100%;
height: 100%;
background-color: #e3e3e3;
border: 1px solid black;
}
.audio-player #seekObjContainer #seekObj #percentage {
position: absolute;
left: 0;
top: 0;
height: 100%;
background-color: coral;
}
The audio player came from here.
Hope this could help you guys!!
VIDEO_ID with actual ID of your YouTube video.
<div data-video="VIDEO_ID"
data-autoplay="0"
data-loop="1"
id="youtube-audio">
</div>
<script src="https://www.youtube.com/iframe_api"></script>
<script src="https://cdn.rawgit.com/labnol/files/master/yt.js"></script>
The answer is simple:
Use a 3rd party product like jwplayer or similar,
then set it to the minimal player size which is the audio player size (only shows player controls).
Voila.
Been using this for over 8 years.
I agree with Tom van der Woerdt. You could use CSS to hide the video (visibility:hidden or overflow:hidden in a div wrapper constrained by height), but that may violate Youtube's policies. Additionally, how could you control the audio (pause, stop, volume, etc.)?
You could instead turn to resources such as http://www.houndbite.com/ to manage audio.
Adding to the mentions of jwplayer and possible TOS violations, I would like to to link to the following repository on github: YouTube Audio Player Generation Library, that allows to generate the following output:
Library has the support for the playlists and PHP autorendering given the video URL and the configuration options.
var vid = "bpt84ceWAY0",
audio_streams = {},
audio_tag = document.getElementById('youtube');
fetch("https://"+vid+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=https%3A%2F%2Fwww.youtube.com%2Fget_video_info%3Fvideo_id%3D" + vid).then(response => {
if (response.ok) {
response.text().then(data => {
var data = parse_str(data),
streams = (data.url_encoded_fmt_stream_map + ',' + data.adaptive_fmts).split(',');
streams.forEach(function(s, n) {
var stream = parse_str(s),
itag = stream.itag * 1,
quality = false;
console.log(stream);
switch (itag) {
case 139:
quality = "48kbps";
break;
case 140:
quality = "128kbps";
break;
case 141:
quality = "256kbps";
break;
}
if (quality) audio_streams[quality] = stream.url;
});
console.log(audio_streams);
audio_tag.src = audio_streams['128kbps'];
audio_tag.play();
})
}
});
function parse_str(str) {
return str.split('&').reduce(function(params, param) {
var paramSplit = param.split('=').map(function(value) {
return decodeURIComponent(value.replace('+', ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}
<audio id="youtube" autoplay controls loop></audio>
As an alternative answer, you can set the video's brightness to zero and the video area will go all black while the controls remain visible...
Via CSS...
filter: brightness(0%);
Via JS...
V.style.filter='brightness(0%)';
NB: Normal default value for brightness is 100%.
// YouTube video ID
var videoID = "CMNry4PE93Y";
// Fetch video info (using a proxy to avoid CORS errors)
fetch('https://cors-anywhere.herokuapp.com/' + "https://www.youtube.com/get_video_info?video_id=" + videoID).then(response => {
if (response.ok) {
response.text().then(ytData => {
// parse response to find audio info
var ytData = parse_str(ytData);
var getAdaptiveFormats = JSON.parse(ytData.player_response).streamingData.adaptiveFormats;
var findAudioInfo = getAdaptiveFormats.findIndex(obj => obj.audioQuality);
// get the URL for the audio file
var audioURL = getAdaptiveFormats[findAudioInfo].url;
// update the <audio> element src
var youtubeAudio = document.getElementById('youtube');
youtubeAudio.src = audioURL;
});
}
});
function parse_str(str) {
return str.split('&').reduce(function(params, param) {
var paramSplit = param.split('=').map(function(value) {
return decodeURIComponent(value.replace('+', ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}
<audio id="youtube" controls></audio>