Skip to content

Instantly share code, notes, and snippets.

@jackpmorgan
Created April 10, 2023 15:45
Show Gist options
  • Save jackpmorgan/2b34532cc0e4bd94ea44595659d5eb60 to your computer and use it in GitHub Desktop.
Save jackpmorgan/2b34532cc0e4bd94ea44595659d5eb60 to your computer and use it in GitHub Desktop.
function(instance, context) {
class HowlerPlayer {
constructor(audioUrl, title, artist, album, artworkSrc) {
const _audioUrl = audioUrl;
const _title = title;
const _artist = artist;
const _album = album;
const _artworkSrc = artworkSrc;
this.createdTimestamp = Date.now();
this.formatDuration = (durationInSeconds) => {
const minutes = Math.floor(durationInSeconds / 60);
const seconds = Math.floor(durationInSeconds % 60).toString().padStart(2, '0');
return `${minutes}:${seconds}`;
};
this.audio = new Howl({
src: [_audioUrl],
html5: true,
volume: 1,
autoplay: false,
autoUnlock: true,
onload: () => {
const duration = this.duration();
const formattedDuration = this.formatDuration(duration);
instance.publishState('duration', duration);
instance.publishState('durationstring', `${formattedDuration}`);
instance.publishState('isloaded', true);
this.updateMediaSession(_title, _artist, _album, _artworkSrc);
},
});
this.audio.on('end', () => {
instance.publishState('isplaying', false);
this.audio.stop(instance.data.playID);
instance.triggerEvent('onEnd');
navigator.mediaSession.playbackState = 'paused';
});
this.audio.on('playerror', () => {
if (!instance.data.player) {
return;
}
this.audio.once('unlock', () => {
instance.publishState('isplaying', false);
console.log('Device is locked, unable to play the next song');
this.audio.play(instance.data.playID);
navigator.mediaSession.playbackState = 'playing';
instance.triggerEvent('onPlay');
});
});
}
//Class methods
play() {
this.audio.play();
instance.triggerEvent('onPlay');
this.onSeekUpdate((seekPosition) => {
const formattedPosition = this.formatDuration(seekPosition);
this.updateMediaSessionPositionState();
});
}
onSeekUpdate(callback) {
const createdTimestamp = this.createdTimestamp;
const update = () => {
if (createdTimestamp !== instance.data.player.createdTimestamp) return;
callback(this.seek());
requestAnimationFrame(update);
};
update();
}
updateMediaSessionPositionState() {
if ('mediaSession' in navigator) {
navigator.mediaSession.setPositionState({
duration: this.duration(),
playbackRate: 1,
position: this.seek(),
});
}
}
pause() {
this.audio.pause(instance.data.playID);
instance.triggerEvent('onPause');
}
seek(position) {
if (typeof position !== 'undefined') {
this.audio.seek(position);
} else {
return this.audio.seek();
}
instance.triggerEvent('onSeek');
}
stop() {
this.audio.stop(instance.data.playID);
instance.triggerEvent('onStop');
}
duration() {
return this.audio.duration();
}
updateMediaSession(_title, _artist, _album, _artworkSrc) {
const getArtworkData = (src) => {
if (!src) {
return null;
}
if (!src.startsWith('http')) {
src = `https:${src}`;
}
const extension = src.match(/\.(png|jpg|jpeg|gif|bmp|webp|svg)$/i);
if (!extension) {
return null;
}
const typeMap = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
bmp: 'image/bmp',
webp: 'image/webp',
svg: 'image/svg+xml',
};
const type = typeMap[extension[1].toLowerCase()];
return [{
src,
type
}];
};
if ('mediaSession' in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: _title,
artist: _artist,
album: _album,
artwork: getArtworkData(_artworkSrc),
});
console.log(navigator.mediaSession.metadata)
navigator.mediaSession.setActionHandler('play', () => {
this.play();
});
navigator.mediaSession.setActionHandler('pause', () => {
this.pause();
});
navigator.mediaSession.setActionHandler('seekbackward', () => {
this.seek(this.seek() - 10);
});
navigator.mediaSession.setActionHandler('seekforward', () => {
this.seek(this.seek() + 10);
});
navigator.mediaSession.setActionHandler('stop', () => {
this.stop();
});
navigator.mediaSession.setActionHandler('seekto', (details) => {
if (details.fastSeek && 'fastSeek' in this.audio) {
this.audio.fastSeek(details.seekTime);
} else {
this.seek(details.seekTime);
}
});
}
}
}
window.HowlerPlayer = HowlerPlayer;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment