No edit summary |
No edit summary |
||
| Line 31: | Line 31: | ||
}); | }); | ||
}); | }); | ||
import lottieWeb from 'https://cdn.skypack.dev/lottie-web'; | |||
class AudioPlayer extends HTMLElement { | |||
constructor() { | |||
super(); | |||
const template = document.querySelector('template'); | |||
const templateContent = template.content; | |||
const shadow = this.attachShadow({mode: 'open'}); | |||
shadow.appendChild(templateContent.cloneNode(true)); | |||
} | |||
connectedCallback() { | |||
everything(this); | |||
} | |||
} | |||
const everything = function(element) { | |||
const shadow = element.shadowRoot; | |||
const audioPlayerContainer = shadow.getElementById('audio-player-container'); | |||
const playIconContainer = shadow.getElementById('play-icon'); | |||
const seekSlider = shadow.getElementById('seek-slider'); | |||
const volumeSlider = shadow.getElementById('volume-slider'); | |||
const muteIconContainer = shadow.getElementById('mute-icon'); | |||
const audio = shadow.querySelector('audio'); | |||
const durationContainer = shadow.getElementById('duration'); | |||
const currentTimeContainer = shadow.getElementById('current-time'); | |||
const outputContainer = shadow.getElementById('volume-output'); | |||
let playState = 'play'; | |||
let muteState = 'unmute'; | |||
let raf = null; | |||
audio.src = element.getAttribute('data-src'); | |||
const playAnimation = lottieWeb.loadAnimation({ | |||
container: playIconContainer, | |||
path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/pause/pause.json', | |||
renderer: 'svg', | |||
loop: false, | |||
autoplay: false, | |||
name: "Play Animation", | |||
}); | |||
const muteAnimation = lottieWeb.loadAnimation({ | |||
container: muteIconContainer, | |||
path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/mute/mute.json', | |||
renderer: 'svg', | |||
loop: false, | |||
autoplay: false, | |||
name: "Mute Animation", | |||
}); | |||
playAnimation.goToAndStop(14, true); | |||
const whilePlaying = () => { | |||
seekSlider.value = Math.floor(audio.currentTime); | |||
currentTimeContainer.textContent = calculateTime(seekSlider.value); | |||
audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`); | |||
raf = requestAnimationFrame(whilePlaying); | |||
} | |||
const showRangeProgress = (rangeInput) => { | |||
if(rangeInput === seekSlider) audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%'); | |||
else audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%'); | |||
} | |||
const calculateTime = (secs) => { | |||
const minutes = Math.floor(secs / 60); | |||
const seconds = Math.floor(secs % 60); | |||
const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; | |||
return `${minutes}:${returnedSeconds}`; | |||
} | |||
const displayDuration = () => { | |||
durationContainer.textContent = calculateTime(audio.duration); | |||
} | |||
const setSliderMax = () => { | |||
seekSlider.max = Math.floor(audio.duration); | |||
} | |||
const displayBufferedAmount = () => { | |||
const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1)); | |||
audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`); | |||
} | |||
if (audio.readyState > 0) { | |||
displayDuration(); | |||
setSliderMax(); | |||
displayBufferedAmount(); | |||
} else { | |||
audio.addEventListener('loadedmetadata', () => { | |||
displayDuration(); | |||
setSliderMax(); | |||
displayBufferedAmount(); | |||
}); | |||
} | |||
playIconContainer.addEventListener('click', () => { | |||
if(playState === 'play') { | |||
audio.play(); | |||
playAnimation.playSegments([14, 27], true); | |||
requestAnimationFrame(whilePlaying); | |||
playState = 'pause'; | |||
} else { | |||
audio.pause(); | |||
playAnimation.playSegments([0, 14], true); | |||
cancelAnimationFrame(raf); | |||
playState = 'play'; | |||
} | |||
}); | |||
muteIconContainer.addEventListener('click', () => { | |||
if(muteState === 'unmute') { | |||
muteAnimation.playSegments([0, 15], true); | |||
audio.muted = true; | |||
muteState = 'mute'; | |||
} else { | |||
muteAnimation.playSegments([15, 25], true); | |||
audio.muted = false; | |||
muteState = 'unmute'; | |||
} | |||
}); | |||
audio.addEventListener('progress', displayBufferedAmount); | |||
seekSlider.addEventListener('input', (e) => { | |||
showRangeProgress(e.target); | |||
currentTimeContainer.textContent = calculateTime(seekSlider.value); | |||
if(!audio.paused) { | |||
cancelAnimationFrame(raf); | |||
} | |||
}); | |||
seekSlider.addEventListener('change', () => { | |||
audio.currentTime = seekSlider.value; | |||
if(!audio.paused) { | |||
requestAnimationFrame(whilePlaying); | |||
} | |||
}); | |||
volumeSlider.addEventListener('input', (e) => { | |||
const value = e.target.value; | |||
showRangeProgress(e.target); | |||
outputContainer.textContent = value; | |||
audio.volume = value / 100; | |||
}); | |||
if('mediaSession' in navigator) { | |||
navigator.mediaSession.metadata = new MediaMetadata({ | |||
title: 'Komorebi', | |||
artist: 'Anitek', | |||
album: 'MainStay', | |||
artwork: [ | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '96x96', type: 'image/png' }, | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '128x128', type: 'image/png' }, | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '192x192', type: 'image/png' }, | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '256x256', type: 'image/png' }, | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '384x384', type: 'image/png' }, | |||
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '512x512', type: 'image/png' } | |||
] | |||
}); | |||
navigator.mediaSession.setActionHandler('play', () => { | |||
if(playState === 'play') { | |||
audio.play(); | |||
playAnimation.playSegments([14, 27], true); | |||
requestAnimationFrame(whilePlaying); | |||
playState = 'pause'; | |||
} else { | |||
audio.pause(); | |||
playAnimation.playSegments([0, 14], true); | |||
cancelAnimationFrame(raf); | |||
playState = 'play'; | |||
} | |||
}); | |||
navigator.mediaSession.setActionHandler('pause', () => { | |||
if(playState === 'play') { | |||
audio.play(); | |||
playAnimation.playSegments([14, 27], true); | |||
requestAnimationFrame(whilePlaying); | |||
playState = 'pause'; | |||
} else { | |||
audio.pause(); | |||
playAnimation.playSegments([0, 14], true); | |||
cancelAnimationFrame(raf); | |||
playState = 'play'; | |||
} | |||
}); | |||
navigator.mediaSession.setActionHandler('seekbackward', (details) => { | |||
audio.currentTime = audio.currentTime - (details.seekOffset || 10); | |||
}); | |||
navigator.mediaSession.setActionHandler('seekforward', (details) => { | |||
audio.currentTime = audio.currentTime + (details.seekOffset || 10); | |||
}); | |||
navigator.mediaSession.setActionHandler('seekto', (details) => { | |||
if (details.fastSeek && 'fastSeek' in audio) { | |||
audio.fastSeek(details.seekTime); | |||
return; | |||
} | |||
audio.currentTime = details.seekTime; | |||
}); | |||
navigator.mediaSession.setActionHandler('stop', () => { | |||
audio.currentTime = 0; | |||
seekSlider.value = 0; | |||
audioPlayerContainer.style.setProperty('--seek-before-width', '0%'); | |||
currentTimeContainer.textContent = '0:00'; | |||
if(playState === 'pause') { | |||
playAnimation.playSegments([0, 14], true); | |||
cancelAnimationFrame(raf); | |||
playState = 'play'; | |||
} | |||
}); | |||
} | |||
} | |||
customElements.define('audio-player', AudioPlayer); | |||
/* GreenAudioPlayer.init({*/ | /* GreenAudioPlayer.init({*/ | ||
/* selector: '.player', // inits Green Audio Player on each audio container that has class "player"*/ | /* selector: '.player', // inits Green Audio Player on each audio container that has class "player"*/ | ||
/* stopOthersOnPlay: true*/ | /* stopOthersOnPlay: true*/ | ||
/* });*/ | /* });*/ | ||
Revision as of 21:50, 12 June 2023
/* Any JavaScript here will be loaded for all users on every page load. */
mw.hook('wikipage.content').add(function($content) {
var $bandcamp = $content.find( '.bandcamp:not(.loaded)' );
if ( !$bandcamp.length ) return;
$bandcamp.each( function() {
var elem = $( this );
var width = elem.attr( 'data-width' ),
height = elem.attr( 'data-height' ),
data_src = elem.attr( 'data-src' );
if ( !/^https?:\/\/bandcamp\.com\//.test( data_src ) ) return;
elem.empty();
var is_px = [ true, true ]; // width, height
if ( /%/.test( width ) || !/\d+/.test( width ) ) is_px[ 0 ] = false;
if ( /%/.test( height ) ) is_px[ 1 ] = false;
var frame_width = parseFloat( width, 10 ) || 100;
frame_height = height ? ( parseFloat( height, 10 ) || 'auto' ) : '';
$( '<iframe />', {
style: 'border: 0',
width: frame_width + ( is_px[ 0 ] ? 'px' : '%' ),
height: frame_height + ( frame_height ? ( is_px[ 1 ] ? 'px': '%' ) : '' ),
src: data_src
}).appendTo( elem );
elem.addClass( 'loaded' );
});
});
import lottieWeb from 'https://cdn.skypack.dev/lottie-web';
class AudioPlayer extends HTMLElement {
constructor() {
super();
const template = document.querySelector('template');
const templateContent = template.content;
const shadow = this.attachShadow({mode: 'open'});
shadow.appendChild(templateContent.cloneNode(true));
}
connectedCallback() {
everything(this);
}
}
const everything = function(element) {
const shadow = element.shadowRoot;
const audioPlayerContainer = shadow.getElementById('audio-player-container');
const playIconContainer = shadow.getElementById('play-icon');
const seekSlider = shadow.getElementById('seek-slider');
const volumeSlider = shadow.getElementById('volume-slider');
const muteIconContainer = shadow.getElementById('mute-icon');
const audio = shadow.querySelector('audio');
const durationContainer = shadow.getElementById('duration');
const currentTimeContainer = shadow.getElementById('current-time');
const outputContainer = shadow.getElementById('volume-output');
let playState = 'play';
let muteState = 'unmute';
let raf = null;
audio.src = element.getAttribute('data-src');
const playAnimation = lottieWeb.loadAnimation({
container: playIconContainer,
path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/pause/pause.json',
renderer: 'svg',
loop: false,
autoplay: false,
name: "Play Animation",
});
const muteAnimation = lottieWeb.loadAnimation({
container: muteIconContainer,
path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/mute/mute.json',
renderer: 'svg',
loop: false,
autoplay: false,
name: "Mute Animation",
});
playAnimation.goToAndStop(14, true);
const whilePlaying = () => {
seekSlider.value = Math.floor(audio.currentTime);
currentTimeContainer.textContent = calculateTime(seekSlider.value);
audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`);
raf = requestAnimationFrame(whilePlaying);
}
const showRangeProgress = (rangeInput) => {
if(rangeInput === seekSlider) audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%');
else audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%');
}
const calculateTime = (secs) => {
const minutes = Math.floor(secs / 60);
const seconds = Math.floor(secs % 60);
const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
return `${minutes}:${returnedSeconds}`;
}
const displayDuration = () => {
durationContainer.textContent = calculateTime(audio.duration);
}
const setSliderMax = () => {
seekSlider.max = Math.floor(audio.duration);
}
const displayBufferedAmount = () => {
const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1));
audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`);
}
if (audio.readyState > 0) {
displayDuration();
setSliderMax();
displayBufferedAmount();
} else {
audio.addEventListener('loadedmetadata', () => {
displayDuration();
setSliderMax();
displayBufferedAmount();
});
}
playIconContainer.addEventListener('click', () => {
if(playState === 'play') {
audio.play();
playAnimation.playSegments([14, 27], true);
requestAnimationFrame(whilePlaying);
playState = 'pause';
} else {
audio.pause();
playAnimation.playSegments([0, 14], true);
cancelAnimationFrame(raf);
playState = 'play';
}
});
muteIconContainer.addEventListener('click', () => {
if(muteState === 'unmute') {
muteAnimation.playSegments([0, 15], true);
audio.muted = true;
muteState = 'mute';
} else {
muteAnimation.playSegments([15, 25], true);
audio.muted = false;
muteState = 'unmute';
}
});
audio.addEventListener('progress', displayBufferedAmount);
seekSlider.addEventListener('input', (e) => {
showRangeProgress(e.target);
currentTimeContainer.textContent = calculateTime(seekSlider.value);
if(!audio.paused) {
cancelAnimationFrame(raf);
}
});
seekSlider.addEventListener('change', () => {
audio.currentTime = seekSlider.value;
if(!audio.paused) {
requestAnimationFrame(whilePlaying);
}
});
volumeSlider.addEventListener('input', (e) => {
const value = e.target.value;
showRangeProgress(e.target);
outputContainer.textContent = value;
audio.volume = value / 100;
});
if('mediaSession' in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: 'Komorebi',
artist: 'Anitek',
album: 'MainStay',
artwork: [
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '96x96', type: 'image/png' },
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '128x128', type: 'image/png' },
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '192x192', type: 'image/png' },
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '256x256', type: 'image/png' },
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '384x384', type: 'image/png' },
{ src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '512x512', type: 'image/png' }
]
});
navigator.mediaSession.setActionHandler('play', () => {
if(playState === 'play') {
audio.play();
playAnimation.playSegments([14, 27], true);
requestAnimationFrame(whilePlaying);
playState = 'pause';
} else {
audio.pause();
playAnimation.playSegments([0, 14], true);
cancelAnimationFrame(raf);
playState = 'play';
}
});
navigator.mediaSession.setActionHandler('pause', () => {
if(playState === 'play') {
audio.play();
playAnimation.playSegments([14, 27], true);
requestAnimationFrame(whilePlaying);
playState = 'pause';
} else {
audio.pause();
playAnimation.playSegments([0, 14], true);
cancelAnimationFrame(raf);
playState = 'play';
}
});
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
audio.currentTime = audio.currentTime - (details.seekOffset || 10);
});
navigator.mediaSession.setActionHandler('seekforward', (details) => {
audio.currentTime = audio.currentTime + (details.seekOffset || 10);
});
navigator.mediaSession.setActionHandler('seekto', (details) => {
if (details.fastSeek && 'fastSeek' in audio) {
audio.fastSeek(details.seekTime);
return;
}
audio.currentTime = details.seekTime;
});
navigator.mediaSession.setActionHandler('stop', () => {
audio.currentTime = 0;
seekSlider.value = 0;
audioPlayerContainer.style.setProperty('--seek-before-width', '0%');
currentTimeContainer.textContent = '0:00';
if(playState === 'pause') {
playAnimation.playSegments([0, 14], true);
cancelAnimationFrame(raf);
playState = 'play';
}
});
}
}
customElements.define('audio-player', AudioPlayer);
/* GreenAudioPlayer.init({*/
/* selector: '.player', // inits Green Audio Player on each audio container that has class "player"*/
/* stopOthersOnPlay: true*/
/* });*/