Skip to content

Instantly share code, notes, and snippets.

@vajradog
Created February 17, 2023 11:34
Show Gist options
  • Save vajradog/38df2ec057e4e9b2a23d9b0bf67ab3e3 to your computer and use it in GitHub Desktop.
Save vajradog/38df2ec057e4e9b2a23d9b0bf67ab3e3 to your computer and use it in GitHub Desktop.
xxaGYGj
<!--
Audio player courtesy of Ivan
https://codepen.io/k-ivan/pen/pJMLmJ
-->
<div class="audio-player">
<div class="player-head">
<div class="player-image">
<img src="https://images.unsplash.com/photo-1542438408-abb260104ef3?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1935&q=80" alt="" />
</div>
<div class="player-close-icon">
<i class="ion-ios-close"></i>
</div>
<div class="player-description">
<h2>Start</h2>
<p>An introduction a really great audio experience</p>
</div>
</div>
<div class="player-controls">
<div class="ap" id="ap">
<div class="ap__inner">
<div class="ap__item ap__item--playback">
<button class="ap__controls ap__controls--prev">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M9.516 12l8.484-6v12zM6 6h2.016v12h-2.016v-12z"></path>
</svg>
</button>
<button class="ap__controls ap__controls--toggle">
<svg class="icon-play" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="36" height="36" viewBox="0 0 36 36" data-play="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" data-pause="M 12,26 16.33,26 16.33,10 12,10 z M 20.66,26 25,26 25,10 20.66,10 z">
<path d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z"></path>
</svg>
</button>
<button class="ap__controls ap__controls--next">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M15.984 6h2.016v12h-2.016v-12zM6 18v-12l8.484 6z"></path>
</svg>
</button>
<div class="ap__controls volume-container">
<button class="volume-btn">
<svg class="icon-volume-on" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M14.016 3.234q3.047 0.656 5.016 3.117t1.969 5.648-1.969 5.648-5.016 3.117v-2.063q2.203-0.656 3.586-2.484t1.383-4.219-1.383-4.219-3.586-2.484v-2.063zM16.5 12q0 2.813-2.484 4.031v-8.063q2.484 1.219 2.484 4.031zM3 9h3.984l5.016-5.016v16.031l-5.016-5.016h-3.984v-6z"></path>
</svg>
<svg class="icon-volume-off" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 3.984v4.219l-2.109-2.109zM4.266 3l16.734 16.734-1.266 1.266-2.063-2.063q-1.734 1.359-3.656 1.828v-2.063q1.172-0.328 2.25-1.172l-4.266-4.266v6.75l-5.016-5.016h-3.984v-6h4.734l-4.734-4.734zM18.984 12q0-2.391-1.383-4.219t-3.586-2.484v-2.063q3.047 0.656 5.016 3.117t1.969 5.648q0 2.25-1.031 4.172l-1.5-1.547q0.516-1.266 0.516-2.625zM16.5 12q0 0.422-0.047 0.609l-2.438-2.438v-2.203q2.484 1.219 2.484 4.031z"></path>
</svg>
</button>
<div class="volume">
<div class="volume__track">
<div class="volume__bar"></div>
</div>
</div>
</div>
</div>
<div class="ap__item ap__item--track">
<div class="track">
<div class="track__title">Queue is empty</div>
<div class="track__time">
<span class="track__time--current">--</span>
<span> / </span>
<span class="track__time--duration">--</span>
</div>
<div class="progress-container">
<div class="progress">
<div class="progress__bar"></div>
<div class="progress__preload"></div>
</div>
</div>
</div>
</div>
<div class="ap__item ap__item--settings">
<button class="ap__controls ap__controls--repeat">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031h-1.969v-6h12v-3l3.984 3.984-3.984 3.984v-3h-10.031z"></path>
</svg>
</button>
<button class="ap__controls ap__controls--playlist">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
<path d="M17.016 12.984l4.969 3-4.969 3v-6zM2.016 15v-2.016h12.984v2.016h-12.984zM18.984 5.016v1.969h-16.969v-1.969h16.969zM18.984 9v2.016h-16.969v-2.016h16.969z"></path>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
(function(window, undefined) {
'use strict';
var AudioPlayer = (function() {
// Player vars!
var
docTitle = document.title,
player = document.getElementById('ap'),
playBtn,
playSvg,
playSvgPath,
prevBtn,
nextBtn,
plBtn,
repeatBtn,
volumeBtn,
progressBar,
preloadBar,
curTime,
durTime,
trackTitle,
audio,
index = 0,
playList,
volumeBar,
wheelVolumeValue = 0,
volumeLength,
repeating = false,
seeking = false,
rightClick = false,
apActive = false,
// playlist vars
pl,
plUl,
plLi,
tplList =
'<li class="pl-list" data-track="{count}">'+
'<div class="pl-list__track">'+
'<div class="pl-list__icon"></div>'+
'<div class="pl-list__eq">'+
'<div class="eq">'+
'<div class="eq__bar"></div>'+
'<div class="eq__bar"></div>'+
'<div class="eq__bar"></div>'+
'<div class="eq__bar"></div>'+
'</div>'+
'</div>'+
'</div>'+
'<div class="pl-list__title">{title}</div>'+
'<button class="pl-list__download">'+
'<svg xmlns="http://www.w3.org/2000/svg"fill="#000000" height="20" viewBox="0 0 448 420" >'+
'<polygon points="216.1,389 161.4,335.2 149.7,346.6 224.2,420 298.7,346.6 286.9,335.2 232.1,389 232.1,282 216.1,282 "/>'+
'<path d="M367.3,118.4c0-1.2,0.2-2.3,0.2-3.5C367.5,51.4,314.6,0,250.7,0c-46.1,0-85.8,26.8-104.4,65.4c-8.1-4-17.1-6.3-26.8-6.3 c-29.6,0-54.1,23.3-58.9,51.3C25.4,122.4,0,153.8,0,192.8C0,241.9,40.1,282,89.6,282h70.5h21h35V147h16v135h134 c45,0,81.9-37.2,81.9-82.1S412.6,118.5,367.3,118.4z"/>'+
'</svg>'+
'</button>'+
'</li>',
// settings
settings = {
volume : 0.7,
changeDocTitle: true,
confirmClose : true,
autoPlay : false,
buffered : true,
notification : true,
playList : []
};
function init(options) {
if(!('classList' in document.documentElement)) {
return false;
}
if(apActive || player === null) {
return 'Player already init';
}
settings = extend(settings, options);
// get player elements
playBtn = player.querySelector('.ap__controls--toggle');
playSvg = playBtn.querySelector('.icon-play');
playSvgPath = playSvg.querySelector('path');
prevBtn = player.querySelector('.ap__controls--prev');
nextBtn = player.querySelector('.ap__controls--next');
repeatBtn = player.querySelector('.ap__controls--repeat');
volumeBtn = player.querySelector('.volume-btn');
plBtn = player.querySelector('.ap__controls--playlist');
curTime = player.querySelector('.track__time--current');
durTime = player.querySelector('.track__time--duration');
trackTitle = player.querySelector('.track__title');
progressBar = player.querySelector('.progress__bar');
preloadBar = player.querySelector('.progress__preload');
volumeBar = player.querySelector('.volume__bar');
playList = settings.playList;
playBtn.addEventListener('click', playToggle, false);
volumeBtn.addEventListener('click', volumeToggle, false);
repeatBtn.addEventListener('click', repeatToggle, false);
progressBar.closest('.progress-container').addEventListener('mousedown', handlerBar, false);
progressBar.closest('.progress-container').addEventListener('mousemove', seek, false);
document.documentElement.addEventListener('mouseup', seekingFalse, false);
volumeBar.closest('.volume').addEventListener('mousedown', handlerVol, false);
volumeBar.closest('.volume').addEventListener('mousemove', setVolume);
volumeBar.closest('.volume').addEventListener(wheel(), setVolume, false);
document.documentElement.addEventListener('mouseup', seekingFalse, false);
prevBtn.addEventListener('click', prev, false);
nextBtn.addEventListener('click', next, false);
apActive = true;
// Create playlist
renderPL();
plBtn.addEventListener('click', plToggle, false);
// Create audio object
audio = new Audio();
audio.volume = settings.volume;
audio.preload = 'auto';
audio.addEventListener('error', errorHandler, false);
audio.addEventListener('timeupdate', timeUpdate, false);
audio.addEventListener('ended', doEnd, false);
volumeBar.style.height = audio.volume * 100 + '%';
volumeLength = volumeBar.css('height');
if(settings.confirmClose) {
window.addEventListener("beforeunload", beforeUnload, false);
}
if(isEmptyList()) {
return false;
}
audio.src = playList[index].file;
trackTitle.innerHTML = playList[index].title;
if(settings.autoPlay) {
audio.play();
playBtn.classList.add('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
plLi[index].classList.add('pl-list--current');
notify(playList[index].title, {
icon: playList[index].icon,
body: 'Now playing'
});
}
}
function changeDocumentTitle(title) {
if(settings.changeDocTitle) {
if(title) {
document.title = title;
}
else {
document.title = docTitle;
}
}
}
function beforeUnload(evt) {
if(!audio.paused) {
var message = 'Music still playing';
evt.returnValue = message;
return message;
}
}
function errorHandler(evt) {
if(isEmptyList()) {
return;
}
var mediaError = {
'1': 'MEDIA_ERR_ABORTED',
'2': 'MEDIA_ERR_NETWORK',
'3': 'MEDIA_ERR_DECODE',
'4': 'MEDIA_ERR_SRC_NOT_SUPPORTED'
};
audio.pause();
curTime.innerHTML = '--';
durTime.innerHTML = '--';
progressBar.style.width = 0;
preloadBar.style.width = 0;
playBtn.classList.remove('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
plLi[index] && plLi[index].classList.remove('pl-list--current');
changeDocumentTitle();
throw new Error('Houston we have a problem: ' + mediaError[evt.target.error.code]);
}
/**
* UPDATE PL
*/
function updatePL(addList) {
if(!apActive) {
return 'Player is not yet initialized';
}
if(!Array.isArray(addList)) {
return;
}
if(addList.length === 0) {
return;
}
var count = playList.length;
var html = [];
playList.push.apply(playList, addList);
addList.forEach(function(item) {
html.push(
tplList.replace('{count}', count++).replace('{title}', item.title)
);
});
// If exist empty message
if(plUl.querySelector('.pl-list--empty')) {
plUl.removeChild( pl.querySelector('.pl-list--empty') );
audio.src = playList[index].file;
trackTitle.innerHTML = playList[index].title;
}
// Add song into playlist
plUl.insertAdjacentHTML('beforeEnd', html.join(''));
plLi = pl.querySelectorAll('li');
}
/**
* PlayList methods
*/
function renderPL() {
var html = [];
playList.forEach(function(item, i) {
html.push(
tplList.replace('{count}', i).replace('{title}', item.title)
);
});
pl = create('div', {
'className': 'pl-container',
'id': 'pl',
'innerHTML': '<ul class="pl-ul">' + (!isEmptyList() ? html.join('') : '<li class="pl-list--empty">PlayList is empty</li>') + '</ul>'
});
player.parentNode.insertBefore(pl, player.nextSibling);
plUl = pl.querySelector('.pl-ul');
plLi = plUl.querySelectorAll('li');
pl.addEventListener('click', listHandler, false);
}
function listHandler(evt) {
evt.preventDefault();
if(evt.target.matches('.pl-list__title') || evt.target.matches('.pl-list__track') || evt.target.matches('.pl-list__icon') || evt.target.matches('.pl-list__eq') || evt.target.matches('.eq')) {
var current = parseInt(evt.target.closest('.pl-list').getAttribute('data-track'), 10);
if(index !== current) {
index = current;
play(current);
}
else {
playToggle();
}
} else {
if(!!evt.target.closest('.pl-list__remove')) {
var parentEl = evt.target.closest('.pl-list');
var isDel = parseInt(parentEl.getAttribute('data-track'), 10);
playList.splice(isDel, 1);
parentEl.closest('.pl-ul').removeChild(parentEl);
plLi = pl.querySelectorAll('li');
[].forEach.call(plLi, function(el, i) {
el.setAttribute('data-track', i);
});
if(!audio.paused) {
if(isDel === index) {
play(index);
}
}
else {
if(isEmptyList()) {
clearAll();
}
else {
if(isDel === index) {
if(isDel > playList.length - 1) {
index -= 1;
}
audio.src = playList[index].file;
trackTitle.innerHTML = playList[index].title;
progressBar.style.width = 0;
}
}
}
if(isDel < index) {
index--;
}
}
}
}
function plActive() {
if(audio.paused) {
plLi[index].classList.remove('pl-list--current');
return;
}
var current = index;
for(var i = 0, len = plLi.length; len > i; i++) {
plLi[i].classList.remove('pl-list--current');
}
plLi[current].classList.add('pl-list--current');
}
/**
* Player methods
*/
function play(currentIndex) {
if(isEmptyList()) {
return clearAll();
}
index = (currentIndex + playList.length) % playList.length;
audio.src = playList[index].file;
trackTitle.innerHTML = playList[index].title;
// Change document title
changeDocumentTitle(playList[index].title);
// Audio play
audio.play();
// Show notification
notify(playList[index].title, {
icon: playList[index].icon,
body: 'Now playing',
tag: 'music-player'
});
// Toggle play button
playBtn.classList.add('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
// Set active song playlist
plActive();
}
function prev() {
play(index - 1);
}
function next() {
play(index + 1);
}
function isEmptyList() {
return playList.length === 0;
}
function clearAll() {
audio.pause();
audio.src = '';
trackTitle.innerHTML = 'queue is empty';
curTime.innerHTML = '--';
durTime.innerHTML = '--';
progressBar.style.width = 0;
preloadBar.style.width = 0;
playBtn.classList.remove('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
if(!plUl.querySelector('.pl-list--empty')) {
plUl.innerHTML = '<li class="pl-list--empty">PlayList is empty</li>';
}
changeDocumentTitle();
}
function playToggle() {
if(isEmptyList()) {
return;
}
if(audio.paused) {
if(audio.currentTime === 0) {
notify(playList[index].title, {
icon: playList[index].icon,
body: 'Now playing'
});
}
changeDocumentTitle(playList[index].title);
audio.play();
playBtn.classList.add('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
}
else {
changeDocumentTitle();
audio.pause();
playBtn.classList.remove('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
}
plActive();
}
function volumeToggle() {
if(audio.muted) {
if(parseInt(volumeLength, 10) === 0) {
volumeBar.style.height = settings.volume * 100 + '%';
audio.volume = settings.volume;
}
else {
volumeBar.style.height = volumeLength;
}
audio.muted = false;
volumeBtn.classList.remove('has-muted');
}
else {
audio.muted = true;
volumeBar.style.height = 0;
volumeBtn.classList.add('has-muted');
}
}
function repeatToggle() {
if(repeatBtn.classList.contains('is-active')) {
repeating = false;
repeatBtn.classList.remove('is-active');
}
else {
repeating = true;
repeatBtn.classList.add('is-active');
}
}
function plToggle() {
plBtn.classList.toggle('is-active');
pl.classList.toggle('h-show');
}
function timeUpdate() {
if(audio.readyState === 0) return;
var barlength = Math.round(audio.currentTime * (100 / audio.duration));
progressBar.style.width = barlength + '%';
var
curMins = Math.floor(audio.currentTime / 60),
curSecs = Math.floor(audio.currentTime - curMins * 60),
mins = Math.floor(audio.duration / 60),
secs = Math.floor(audio.duration - mins * 60);
(curSecs < 10) && (curSecs = '0' + curSecs);
(secs < 10) && (secs = '0' + secs);
curTime.innerHTML = curMins + ':' + curSecs;
durTime.innerHTML = mins + ':' + secs;
if(settings.buffered) {
var buffered = audio.buffered;
if(buffered.length) {
var loaded = Math.round(100 * buffered.end(0) / audio.duration);
preloadBar.style.width = loaded + '%';
}
}
}
/**
* TODO shuffle
*/
function shuffle() {
if(shuffle) {
index = Math.round(Math.random() * playList.length);
}
}
function doEnd() {
if(index === playList.length - 1) {
if(!repeating) {
audio.pause();
plActive();
playBtn.classList.remove('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
return;
}
else {
play(0);
}
}
else {
play(index + 1);
}
}
function moveBar(evt, el, dir) {
var value;
if(dir === 'horizontal') {
value = Math.round( ((evt.clientX - el.offset().left) + window.pageXOffset) * 100 / el.parentNode.offsetWidth);
el.style.width = value + '%';
return value;
}
else {
if(evt.type === wheel()) {
value = parseInt(volumeLength, 10);
var delta = evt.deltaY || evt.detail || -evt.wheelDelta;
value = (delta > 0) ? value - 10 : value + 10;
}
else {
var offset = (el.offset().top + el.offsetHeight) - window.pageYOffset;
value = Math.round((offset - evt.clientY));
}
if(value > 100) value = wheelVolumeValue = 100;
if(value < 0) value = wheelVolumeValue = 0;
volumeBar.style.height = value + '%';
return value;
}
}
function handlerBar(evt) {
rightClick = (evt.which === 3) ? true : false;
seeking = true;
seek(evt);
}
function handlerVol(evt) {
rightClick = (evt.which === 3) ? true : false;
seeking = true;
setVolume(evt);
}
function seek(evt) {
if(seeking && rightClick === false && audio.readyState !== 0) {
var value = moveBar(evt, progressBar, 'horizontal');
audio.currentTime = audio.duration * (value / 100);
}
}
function seekingFalse() {
seeking = false;
}
function setVolume(evt) {
evt.preventDefault();
volumeLength = volumeBar.css('height');
if(seeking && rightClick === false || evt.type === wheel()) {
var value = moveBar(evt, volumeBar.parentNode, 'vertical') / 100;
if(value <= 0) {
audio.volume = 0;
audio.muted = true;
volumeBtn.classList.add('has-muted');
}
else {
if(audio.muted) audio.muted = false;
audio.volume = value;
volumeBtn.classList.remove('has-muted');
}
}
}
function notify(title, attr) {
if(!settings.notification) {
return;
}
if(window.Notification === undefined) {
return;
}
attr.tag = 'AP music player';
window.Notification.requestPermission(function(access) {
if(access === 'granted') {
var notice = new Notification(title.substr(0, 110), attr);
setTimeout(notice.close.bind(notice), 5000);
}
});
}
/* Destroy method. Clear All */
function destroy() {
if(!apActive) return;
if(settings.confirmClose) {
window.removeEventListener('beforeunload', beforeUnload, false);
}
playBtn.removeEventListener('click', playToggle, false);
volumeBtn.removeEventListener('click', volumeToggle, false);
repeatBtn.removeEventListener('click', repeatToggle, false);
plBtn.removeEventListener('click', plToggle, false);
progressBar.closest('.progress-container').removeEventListener('mousedown', handlerBar, false);
progressBar.closest('.progress-container').removeEventListener('mousemove', seek, false);
document.documentElement.removeEventListener('mouseup', seekingFalse, false);
volumeBar.closest('.volume').removeEventListener('mousedown', handlerVol, false);
volumeBar.closest('.volume').removeEventListener('mousemove', setVolume);
volumeBar.closest('.volume').removeEventListener(wheel(), setVolume);
document.documentElement.removeEventListener('mouseup', seekingFalse, false);
prevBtn.removeEventListener('click', prev, false);
nextBtn.removeEventListener('click', next, false);
audio.removeEventListener('error', errorHandler, false);
audio.removeEventListener('timeupdate', timeUpdate, false);
audio.removeEventListener('ended', doEnd, false);
// Playlist
pl.removeEventListener('click', listHandler, false);
pl.parentNode.removeChild(pl);
audio.pause();
apActive = false;
index = 0;
playBtn.classList.remove('is-playing');
playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
volumeBtn.classList.remove('has-muted');
plBtn.classList.remove('is-active');
repeatBtn.classList.remove('is-active');
// Remove player from the DOM if necessary
// player.parentNode.removeChild(player);
}
/**
* Helpers
*/
function wheel() {
var wheel;
if ('onwheel' in document) {
wheel = 'wheel';
} else if ('onmousewheel' in document) {
wheel = 'mousewheel';
} else {
wheel = 'MozMousePixelScroll';
}
return wheel;
}
function extend(defaults, options) {
for(var name in options) {
if(defaults.hasOwnProperty(name)) {
defaults[name] = options[name];
}
}
return defaults;
}
function create(el, attr) {
var element = document.createElement(el);
if(attr) {
for(var name in attr) {
if(element[name] !== undefined) {
element[name] = attr[name];
}
}
}
return element;
}
function getTrack(index) {
return playList[index];
}
Element.prototype.offset = function() {
var el = this.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return {
top: el.top + scrollTop,
left: el.left + scrollLeft
};
};
Element.prototype.css = function(attr) {
if(typeof attr === 'string') {
return getComputedStyle(this, '')[attr];
}
else if(typeof attr === 'object') {
for(var name in attr) {
if(this.style[name] !== undefined) {
this.style[name] = attr[name];
}
}
}
};
// matches polyfill
window.Element && function(ElementPrototype) {
ElementPrototype.matches = ElementPrototype.matches ||
ElementPrototype.matchesSelector ||
ElementPrototype.webkitMatchesSelector ||
ElementPrototype.msMatchesSelector ||
function(selector) {
var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
while (nodes[++i] && nodes[i] != node);
return !!nodes[i];
};
}(Element.prototype);
// closest polyfill
window.Element && function(ElementPrototype) {
ElementPrototype.closest = ElementPrototype.closest ||
function(selector) {
var el = this;
while (el.matches && !el.matches(selector)) el = el.parentNode;
return el.matches ? el : null;
};
}(Element.prototype);
/**
* Public methods
*/
return {
init: init,
update: updatePL,
destroy: destroy,
getTrack: getTrack
};
})();
window.AP = AudioPlayer;
})(window);
// TEST: image for web notifications
var iconImage = 'http://funkyimg.com/i/21pX5.png';
AP.init({
playList: [
{'icon': iconImage, 'title': 'Hitman', 'file': 'http://incompetech.com/music/royalty-free/mp3-royaltyfree/Hitman.mp3'},
{'icon': iconImage, 'title': 'Forever Believe', 'file': 'https://a.clyp.it/zbh0qeyo.mp3'},
{'icon': iconImage, 'title': 'Drifting', 'file': 'https://a.clyp.it/bthbgqcs.mp3'},
{'icon': iconImage, 'title': 'Clap Along (Lorem ipsum dolor sit amet, consectetur adipisicing.)', 'file': 'https://a.clyp.it/lygki3hx.mp3'},
{'icon': iconImage, 'title': 'Pop Tune', 'file': 'https://a.clyp.it/enddsv44.mp3'}
]
});
// TEST: update playlist
// document.getElementById('addSongs').addEventListener('click', function(e) {
// e.preventDefault();
// AP.update([
// {'icon': iconImage, 'title': 'Drifting', 'file': 'https://a.clyp.it/bthbgqcs.mp3'},
// {'icon': iconImage, 'title': 'Clap Along (Lorem ipsum dolor sit amet, consectetur adipisicing.)', 'file': 'https://a.clyp.it/lygki3hx.mp3'},
// {'icon': iconImage, 'title': 'Pop Tune', 'file': 'https://a.clyp.it/enddsv44.mp3'}
// ]);
// })
$(document).ready(function(){
$(".pl-list__download").on("click", function(){
var trackPlaying = $(this).closest(".pl-list");
console.log(AP.getTrack(trackPlaying.attr("data-track")));
});
});
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
// $primaryColor: steelblue;
$primaryColor: #1ec279;
$apBG: #f2f2f2;
$plBG: #fff;
$plCurrentBG: $primaryColor;
$plColorIcon: $primaryColor;
$plCurrentColor: #fff;
$plHoverColor: #f6f6f6;
$iconColor: #777;
$iconColorActive: $primaryColor;
$iconBGActive: $primaryColor;
$barBG: #ddd;
$progressBG: $primaryColor;
$font-family: inherit;
$font-size: 16px;
$apHeight: 50px;
$apMaxWidth: 1440px;
$barSize: 3px;
$apZ: 99999;
$volZ: 88888;
$plZ: 77777;
*,
*::before,
*::after {
box-sizing: border-box
}
.audio-player {
display: flex;
flex-direction: column;
width: 95%;
max-width: 450px;
max-height: 95vh;
margin: 10px auto 0 auto;
overflow: hidden;
border-radius: 5px;
box-shadow: 0 0 40px rgba(0,0,0,0.2);
.player-head {
position: relative;
max-width: 100%;
max-height: 12rem;
min-height: 12rem;
overflow: hidden;
.player-image {
max-width: 100%;
z-index: 10;
img {
position: relative;
width: 110%;
left: -5%;
margin-top: -10%;
display: block;
filter: blur(15px);
filter:progid:DXImageTransform.Microsoft.Blur(PixelRadius='15');
}
}
.player-close-icon {
position: absolute;
top: 0.4rem;
right: 0.6rem;
transition: all 0.8s ease;
z-index: 25;
i {
color: white;
font-size: 2.3rem;
cursor: pointer;
}
.ion-ios-play {
margin-left: 0.2rem;
}
}
.player-description {
position: absolute;
top: 0;
left: 0;
padding: 1rem;
width: 100%;
z-index: 20;
h2 {
color: white;
padding: 0;
margin: 0;
font-weight: bold;
}
p {
color: white;
padding: 0;
margin: 0.5rem 0;
font-weight: 100;
}
}
}
.player-controls {
display: flex;
flex-direction: column;
.ap {
position: relative;
left: 0;
right: 0;
bottom: 0;
width: 100%;
min-width: 250px;
font-family: $font-family;
font-size: $font-size;
user-select: none;
border-top: 1px solid #ccc;
background: $apBG;
box-shadow: 0 -1px 10px rgba(0,0,0,.1);
z-index: $apZ;
}
.ap__inner {
display: flex;
max-width: $apMaxWidth;
margin: auto;
height: auto;
flex-wrap: wrap;
}
.ap__item {
display: flex;
flex: 1;
justify-content: center;
align-items: center;
}
.ap__item--playback, .ap__item--settings {
flex: 1 1 50%;
order: 1;
}
.ap__item--playback > .ap__controls,
.ap__item--settings > .ap__controls {
flex: 1;
}
.ap__item--settings {
display: none;
}
@keyframes fs {
0% {
opacity: 0;
transform: scale(.5);
}
100% {
opacity: 1;
transform: scale(1);
}
}
// track bar
.ap__item--track {
flex: 1 1 100%;
margin-bottom: 10px;
padding: 0 20px;
order: 1;
}
.track {
position: relative;
width: 100%;
align-self: flex-start;
padding: 5px 0 0;
}
.track__title {
position: absolute;
width: 100%;
overflow: hidden;
padding-right: 80px;
text-align: left;
white-space: nowrap;
text-overflow: ellipsis;
}
.track__time {
position: absolute;
top: 5px;
right: 0;
}
.progress-container {
position: relative;
padding: 7px 0;
margin-top: 15px;
overflow: hidden;
cursor: pointer;
&:hover .progress__bar:after {
opacity: 1;
}
}
.progress {
height: $barSize;
border-radius: $barSize;
background: $barBG;
}
.progress__bar,
.progress__preload {
position: absolute;
width: 0;
height: $barSize;
border-radius: $barSize 0 0 $barSize;
}
.progress__bar {
background: $progressBG;
z-index: 1;
&:after {
position: absolute;
top: 0;
right: -10px;
width: 10px;
height: 10px;
margin-top: -3px;
content: '';
border-radius: 6px;
background: $primaryColor;
opacity: 0;
transition: opacity .3s ease;
}
}
.progress__preload {
background: darken($barBG, 10%);
z-index: 0;
}
// Controls
.ap__controls,
.ap button {
margin: 0;
padding: 0;
border: 0;
outline: 0;
background: transparent;
position: relative;
display: block;
height: $apHeight;
text-align: center;
cursor: pointer;
transition: background .3s ease;
&:active {
background: rgba(0,0,0,.1);
}
&:hover {
opacity: 1;
}
}
.icon-play > path {
transition: all .3s ease;
}
.is-playing {
.icon-play {
fill: $iconColorActive;
}
}
// Volume
.volume-btn {
display: block;
text-align: center;
width: 100%;
}
.volume {
position: absolute;
left: 50%;
bottom: (#{$apHeight - 5px});
width: 40px;
margin-left: -20px;
height: 120px;
opacity: 0;
visibility: hidden;
transform: translateY(10px);
transition: all .3s cubic-bezier(0.17, 0.72, 0.26, 1.23);
background: $apBG;
border: 1px solid #ccc;
border-radius: 1px;
z-index: $volZ;
&::before,
&::after {
content: '';
position: absolute;
bottom: -12px;
border: 7px solid transparent;
border-top: 7px solid $apBG;
left: 50%;
margin-left: -7px;
}
&::after {
bottom: -14px;
z-index: -1;
border-top: 7px solid #ccc;
}
}
.volume-container:hover .volume {
opacity: 1;
transform: translateY(0);
visibility: visible;
}
.volume__track {
position: relative;
display: block;
width: $barSize;
height: 100px;
margin: 10px auto;
background: $barBG;
border-radius: $barSize;
overflow: hidden;
}
.volume__bar {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: $progressBG;
height: 50%;
}
.icon-volume-off {
display: none;
}
.has-muted {
.icon-volume-on {
display: none;
}
.icon-volume-off {
display: inline;
opacity: .7;
}
}
.ap__controls.is-active {
> svg {
fill: $iconColorActive;
filter: drop-shadow(0 0 3px rgba($iconColorActive, .4));
}
}
/*-----------------------
Playlist Player - PL
------------------------*/
.pl-container {
display: block;
position: relative;
top: 0;
right: 0;
bottom: $apHeight;
left: 0;
overflow: auto;
border-radius: 0px 0px 5px 5px;
font-family: $font-family;
font-size: $font-size;
background: $plBG;
z-index: $plZ;
}
.pl-ul {
width: 100%;
margin: 0 auto;
padding: 0 0 0 0;
}
.pl-list {
display: flex;
align-items: center;
// transition: background .2s ease;
height: 60px;
line-height: 60px;
overflow: hidden;
svg {
fill: #555;
}
}
.pl-list + .pl-list {
border-top: 1px solid #eee;
}
.pl-list:not(.pl-list--current):hover {
background: $plHoverColor;
}
.pl-list__track,
.pl-list__download {
flex: 0 50px;
text-align: center;
}
.pl-list__track {
cursor: pointer;
display: flex;
align-content: center;
justify-content: center;
}
.pl-list__icon {
display: inline-block;
align-self: center center;
width: 0;
height: 0;
border-top: 7px solid transparent;
border-bottom: 7px solid transparent;
border-left: 11px solid #555;
}
.pl-list__title {
overflow: hidden;
padding-right: 10px;
cursor: pointer;
text-align: left;
white-space: nowrap;
text-overflow: ellipsis;
flex: 1;
}
.pl-list__download {
height: 100%;
background: transparent;
border: 0;
outline: 0;
cursor: pointer;
transition: opacity .2s ease;
display: flex;
justify-content: center;
}
.pl-list__download > svg {
width: 20px;
height: 20px;
align-self: center;
}
.pl-list__eq {
display: none;
}
.pl-list--current {
background: $plCurrentBG;
color: $plCurrentColor;
}
.pl-list--current {
svg {
fill: $plCurrentColor;
}
.pl-list__eq {
display: block;
}
.pl-list__icon {
display: none;
}
}
.pl-list:hover .pl-list__download,
.pl-list--current .pl-list__download {
opacity: 1;
}
.pl-list--current .pl-list__download:hover {
background: darken($plCurrentBG, 5%);
}
.pl-list--empty {
position: absolute;
top: 50%;
left: 50%;
font-size: 2rem;
transform: translate(-50%, -50%);
letter-spacing: 2px;
color: #ccc;
}
@keyframes eq {
0% { height: 3px; }
50% { height: 15px; }
100% { height: 3px; }
}
.eq {
display: flex;
width: 20px;
height: 15px;
margin: 0 auto;
justify-content: space-between;
align-items: flex-end;
}
.eq__bar {
width: 4px;
background: $plCurrentColor;
filter: drop-shadow(0 0 5px $plCurrentColor);
}
.eq__bar:nth-child(2) {
animation: eq 1.2s ease-in-out infinite 0s;
}
.eq__bar:nth-child(4) {
animation: eq 1.2s ease-in-out infinite .2s;
}
.eq__bar:nth-child(1) {
animation: eq 1.2s ease-in-out infinite .4s;
}
.eq__bar:nth-child(3) {
animation: eq 1.2s ease-in-out infinite .6s;
}
.h-hide {
display: none;
}
.h-show {
display: block;
}
}
}
<link href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment