UNPKG

solid-panes

Version:

Solid-compatible Panes: applets and views for the mashlib and databrowser

181 lines (177 loc) • 7.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var UI = _interopRequireWildcard(require("solid-ui")); var $rdf = _interopRequireWildcard(require("rdflib")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /* Single audio play Pane ** */ const ns = UI.ns; var _default = exports.default = { icon: UI.icons.iconBase + 'noun_534313.svg', name: 'audio', // Does the subject deserve an audio play pane? label: function (subject, context) { const kb = context.session.store; const typeURIs = kb.findTypeURIs(subject); const prefix = $rdf.Util.mediaTypeClass('audio/*').uri.split('*')[0]; for (const t in typeURIs) { if (t.startsWith(prefix)) return 'Play audio'; } return null; }, render: function (subject, context) { const kb = context.session.store; const dom = context.dom; const options = { autoplay: false, chain: true, chainAlbums: true, loop: false }; const removeExtension = function (str) { const dot = str.lastIndexOf('.'); if (dot < 0) return str; // if any const slash = str.lastIndexOf('/'); if (dot < slash) return str; return str.slice(0, dot); }; // True if there is another file like song.mp3 when this is "song 1.mp3" // or this is song.m4a // const looksRedundant = function (x) { const folder = kb.any(undefined, ns.ldp('contains'), x); if (!folder) return false; const contents = kb.each(folder, ns.ldp('contains')); if (contents.length < 2) return false; const thisName = x.uri; for (let k = 0; k < contents.length; k++) { const otherName = contents[k].uri; if (thisName.length > otherName.length && thisName.startsWith(removeExtension(otherName))) { return true; } if (thisName.endsWith('.m4a') && otherName.endsWith('.mp3') && removeExtension(thisName) === removeExtension(otherName)) { return true; } } return false; }; // Alternative methods could include: // Accesing metadata in the audio contol, or paring the audio file const guessNames = function (x) { const a = x.uri.split('/').slice(-3); // Hope artist, album, track const decode = function (str) { try { return decodeURIComponent(str); } catch (e) { return str; } }; artistRow.textContent = decode(a[0]); albumRow.textContent = decode(a[1]); trackRow.textContent = decode(removeExtension(a[2])); }; const moveOn = function (current, level) { return new Promise(function (resolve) { level = level || 0; if (!options.chain) return resolve(null); // Ideally navigate graph else cheat with URI munging: const folder = kb.any(undefined, ns.ldp('contains'), current) || current.dir(); if (!folder) return resolve(null); kb.fetcher.load(folder).then(function (_xhr) { const contents = kb.each(folder, ns.ldp('contains')); // @@ load if not loaded // if (contents.length < 2) return resolve(null) NO might move on from 1-track album let j; contents.sort(); // sort by URI which hopefully will get tracks in order for (let i = 0; i < contents.length; i++) { if (current.uri === contents[i].uri) { j = (i + 1) % contents.length; if (j === 0) { if (!options.chainAlbums) { if (options.loop) { return resolve(contents[j]); } return resolve(null); // No more music needed } else { // chain albums if (level === 1 || !options.chainAlbums) return resolve(null); // limit of navigating treee moveOn(folder, level + 1).then(function (folder2) { if (folder2) { kb.fetcher.load(folder2).then(function (_xhr) { const contents = kb.each(folder2, ns.ldp('contains')); if (contents.length === 0) return resolve(null); contents.sort(); console.log('New Album: ' + folder2); return resolve(contents[0]); // Start off new album }); } }); } } else { return resolve(contents[j]); } } } // for }); }); }; const endedListener = function (event) { const current = kb.sym(event.target.getAttribute('src')); if (!options.chain) return; const tryNext = function (cur) { const current = cur; moveOn(current).then(function (next) { if (!next) { console.log('No successor to ' + current); return; } if (!looksRedundant(next)) { console.log('Moving on to ' + next); guessNames(next); controlRow.appendChild(audioControl(next, true)); // Force autoplay controlRow.removeChild(event.target); } else { console.log('Ignoring redundant ' + next); tryNext(next); } }); }; tryNext(current); }; const audioControl = function (song, autoplay) { const audio = dom.createElement('audio'); audio.setAttribute('controls', 'yes'); // get audio with authenticated fetch kb.fetcher._fetch(song.uri).then(function (response) { return response.blob(); }).then(function (myBlob) { const objectURL = URL.createObjectURL(myBlob); audio.setAttribute('src', objectURL); // w640 h480 // }); if (autoplay) { audio.setAttribute('autoplay', 'autoplay'); // Make this a personal preference } audio.addEventListener('ended', endedListener, false); return audio; }; const div = dom.createElement('div'); const table = div.appendChild(dom.createElement('table')); const labelStyle = 'padding: 0.3em; color:white; background-color: black;'; const artistRow = table.appendChild(dom.createElement('tr')); artistRow.style.cssText = labelStyle; const albumRow = table.appendChild(dom.createElement('tr')); albumRow.style.cssText = labelStyle; const trackRow = table.appendChild(dom.createElement('tr')); trackRow.style.cssText = labelStyle; const controlRow = table.appendChild(dom.createElement('tr')); guessNames(subject); controlRow.appendChild(audioControl(subject, options.autoplay)); if (!kb.holds(undefined, ns.ldp('contains'), subject) && subject.dir()) { kb.fetcher.load(subject.dir()); // Prefetch enclosing @@ or playlist } return div; } }; // ends