#include utility.js #include watcher.js const MszAudioEmbedPlayerEvents = function() { return [ 'play', 'pause', 'stop', 'mute', 'volume', 'rate', 'duration', 'time', ]; }; const MszAudioEmbed = function(player) { const elem = $e({ attrs: { classList: ['aembed', 'aembed-' + player.getType()], }, child: player, }); return { getElement: function() { return elem; }, appendTo: function(target) { target.appendChild(elem); }, insertBefore: function(ref) { $ib(ref, elem); }, nuke: function() { $r(elem); }, replaceElement(target) { $ib(target, elem); $r(target); }, getPlayer: function() { return player; }, }; }; const MszAudioEmbedPlayer = function(metadata, options) { options = options || {}; const shouldAutoplay = options.autoplay === undefined || options.autoplay, haveNativeControls = options.nativeControls !== undefined && options.nativeControls; const playerAttrs = { src: metadata.url, style: {}, }; if(shouldAutoplay) playerAttrs.autoplay = 'autoplay'; if(haveNativeControls) playerAttrs.controls = 'controls'; const watchers = new MszWatcherCollection; watchers.define(MszAudioEmbedPlayerEvents()); const player = $e({ tag: 'audio', attrs: playerAttrs, }); const pub = { getElement: function() { return player; }, appendTo: function(target) { target.appendChild(player); }, insertBefore: function(ref) { $ib(ref, player); }, nuke: function() { $r(player); }, replaceElement(target) { $ib(target, player); $r(target); }, getType: function() { return 'external'; }, }; pub.watch = (name, handler) => watchers.watch(name, handler); pub.unwatch = (name, handler) => watchers.unwatch(name, handler); player.addEventListener('play', function() { watchers.call('play', pub); }); const pPlay = function() { player.play(); }; pub.play = pPlay; const pPause = function() { player.pause(); }; pub.pause = pPause; let stopCalled = false; player.addEventListener('pause', function() { watchers.call(stopCalled ? 'stop' : 'pause', pub); stopCalled = false; }); const pStop = function() { stopCalled = true; player.pause(); player.currentTime = 0; }; pub.stop = pStop; const pIsPlaying = function() { return !player.paused; }; pub.isPlaying = pIsPlaying; const pIsMuted = function() { return player.muted; }; pub.isMuted = pIsMuted; let lastMuteState = player.muted; player.addEventListener('volumechange', function() { if(lastMuteState !== player.muted) { lastMuteState = player.muted; watchers.call('mute', pub, [lastMuteState]); } else watchers.call('volume', pub, [player.volume]); }); const pSetMuted = function(state) { player.muted = state; }; pub.setMuted = pSetMuted; const pGetVolume = function() { return player.volume; }; pub.getVolume = pGetVolume; const pSetVolume = function(volume) { player.volume = volume; }; pub.setVolume = pSetVolume; const pGetPlaybackRate = function() { return player.playbackRate; }; pub.getPlaybackRate = pGetPlaybackRate; player.addEventListener('ratechange', function() { watchers.call('rate', pub, [player.playbackRate]); }); const pSetPlaybackRate = function(rate) { player.playbackRate = rate; }; pub.setPlaybackRate = pSetPlaybackRate; window.addEventListener('durationchange', function() { watchers.call('duration', pub, [player.duration]); }); const pGetDuration = function() { return player.duration; }; pub.getDuration = pGetDuration; window.addEventListener('timeupdate', function() { watchers.call('time', pub, [player.currentTime]); }); const pGetTime = function() { return player.currentTime; }; pub.getTime = pGetTime; const pSeek = function(time) { player.currentTime = time; }; pub.seek = pSeek; return pub; }; const MszAudioEmbedPlaceholder = function(metadata, options) { options = options || {}; if(typeof options.player !== 'function' && typeof options.onclick !== 'function') throw 'Neither a player nor an onclick handler were provided.'; let title = [], album = undefined; if(metadata.media !== undefined && metadata.media.tags !== undefined) { const tags = metadata.media.tags; if(tags.title !== undefined) { if(tags.artist !== undefined) { title.push({ tag: 'span', attrs: { className: 'aembedph-info-title-artist', }, child: tags.artist, }); title.push(' - '); } title.push({ tag: 'span', attrs: { className: 'aembedph-info-title-title', }, child: tags.title, }); } else { title.push({ tag: 'span', attrs: { className: 'aembedph-info-title-title', }, child: metadata.title, }); } if(tags.album !== undefined && tags.album !== tags.title) album = tags.album; } const infoChildren = []; infoChildren.push({ tag: 'h1', attrs: { className: 'aembedph-info-title', }, child: title, }); infoChildren.push({ tags: 'p', attrs: { className: 'aembedph-info-album', }, child: album, }); infoChildren.push({ tag: 'div', attrs: { className: 'aembedph-info-site', }, child: metadata.site_name, }); const style = []; if(typeof metadata.color !== 'undefined') style.push('--aembedph-colour: ' + metadata.color); const coverBackground = $e({ attrs: { className: 'aembedph-bg', }, child: { tag: 'img', attrs: { alt: '', src: metadata.image, onerror: function(ev) { coverBackground.classList.add('aembedph-bg-none'); }, }, }, }); const coverPreview = $e({ attrs: { className: 'aembedph-info-cover', }, child: { tag: 'img', attrs: { alt: '', src: metadata.image, onerror: function(ev) { coverPreview.classList.add('aembedph-info-cover-none'); }, }, }, }); const pub = {}; const elem = $e({ attrs: { className: ('aembedph aembedph-' + (options.type || 'external')), style: style.join(';'), title: metadata.title, }, child: [ coverBackground, { attrs: { className: 'aembedph-fg', }, child: [ { attrs: { className: 'aembedph-info', }, child: [ coverPreview, { attrs: { className: 'aembedph-info-body', }, child: infoChildren, } ], }, { attrs: { className: 'aembedph-play', onclick: function(ev) { if(ev.target.tagName.toLowerCase() === 'a') return; if(typeof options.onclick === 'function') { options.onclick(ev); return; } const player = new options.player(metadata, options); const embed = new MszAudioEmbed(player); if(options.autoembed === undefined || options.autoembed) embed.replaceElement(elem); if(typeof options.onembed === 'function') options.onembed(embed); }, }, child: [ { attrs: { className: 'aembedph-play-internal', }, child: { tag: 'i', attrs: { className: 'fas fa-play fa-3x fa-fw', }, }, }, { attrs: { className: 'aembedph-play-external', }, child: { tag: 'a', attrs: { className: 'aembedph-play-external-link', href: metadata.url, target: '_blank', rel: 'noopener', }, child: ('or listen on ' + metadata.site_name + '?') }, } ], } ], }, ], }); pub.getElement = function() { return elem; }; pub.appendTo = function(target) { target.appendChild(elem); }; pub.insertBefore = function(ref) { $ib(ref, elem); }; pub.nuke = function() { $r(elem); }; pub.replaceElement = function(target) { $ib(target, elem); $r(target); }; return pub; }