diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css index 57bc310e..702b9b58 100644 --- a/copyparty/web/browser.css +++ b/copyparty/web/browser.css @@ -811,10 +811,12 @@ input.eq_gain { padding: 0; border-bottom: 1px solid #555; } -#thumbs { +#thumbs, +#au_osd_cv { opacity: .3; } -#griden.on+#thumbs { +#griden.on+#thumbs, +#au_os_ctl.on+#au_osd_cv { opacity: 1; } #ghead { diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index d876d47c..a2c0b56b 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -222,10 +222,14 @@ var have_webp = null; var mpl = (function () { + var have_mctl = 'mediaSession' in navigator && window.MediaMetadata; + ebi('op_player').innerHTML = ( '

switches

' + 'preload' + '/np clip' + + 'os-ctl' + + 'osd-cv' + '
' + '

playback mode

' + @@ -238,7 +242,9 @@ var mpl = (function () { var r = { "pb_mode": sread('pb_mode') || 'loop-folder', "preload": bcfg_get('au_preload', true), - "clip": bcfg_get('au_npclip', false) + "clip": bcfg_get('au_npclip', false), + "os_ctl": bcfg_get('au_os_ctl', false) && have_mctl, + "osd_cv": bcfg_get('au_osd_cv', true), }; ebi('au_preload').onclick = function (e) { @@ -254,6 +260,20 @@ var mpl = (function () { clmod(ebi('wtoggle'), 'np', r.clip && mp.au); }; + ebi('au_os_ctl').onclick = function (e) { + ev(e); + r.os_ctl = !r.os_ctl && have_mctl; + bcfg_set('au_os_ctl', r.os_ctl); + if (!have_mctl) + alert('need firefox 82+ or chrome 73+'); + }; + + ebi('au_osd_cv').onclick = function (e) { + ev(e); + r.osd_cv = !r.osd_cv; + bcfg_set('au_osd_cv', r.osd_cv); + }; + function draw_pb_mode() { var btns = QSA('#pb_mode>a'); for (var a = 0, aa = btns.length; a < aa; a++) { @@ -270,6 +290,50 @@ var mpl = (function () { draw_pb_mode(); } + r.announce = function () { + if (!r.os_ctl) + return; + + var np = get_np()[0], + fns = np.file.split(' - '), + artist = (np.circle ? np.circle + ' // ' : '') + (np.artist || (fns.length > 1 ? fns[0] : '')), + tags = { + title: np.title || fns.slice(-1)[0] + }; + + if (artist) + tags.artist = artist; + + if (np.album) + tags.album = np.album; + + if (r.osd_cv) { + var files = QSA("#files tr>td:nth-child(2)>a[id]"), + cover = null; + + for (var a = 0, aa = files.length; a < aa; a++) { + if (/^(cover|folder)\.(jpe?g|png|gif)$/.test(files[a].textContent)) { + cover = files[a].getAttribute('href'); + break; + } + } + + if (cover) { + cover += (cover.indexOf('?') === -1 ? '?' : '&') + 'th=j'; + tags.artwork = [{ "src": cover, type: "image/jpeg" }]; + } + } + + navigator.mediaSession.metadata = new MediaMetadata(tags); + navigator.mediaSession.playbackState = mp.au.paused ? "paused" : "playing"; + navigator.mediaSession.setActionHandler('play', playpause); + navigator.mediaSession.setActionHandler('pause', playpause); + navigator.mediaSession.setActionHandler('seekbackward', function () { seek_au_rel(-10); }); + navigator.mediaSession.setActionHandler('seekforward', function () { seek_au_rel(10); }); + navigator.mediaSession.setActionHandler('previoustrack', prev_song); + navigator.mediaSession.setActionHandler('nexttrack', next_song); + }; + return r; })(); @@ -365,6 +429,28 @@ var mp = new MPlayer(); makeSortable(ebi('files'), mp.read_order.bind(mp)); +function get_np() { + var th = ebi('files').tHead.rows[0].cells, + tr = QS('#files tr.play').cells, + rv = [], + ra = [], + rt = {}; + + for (var a = 1, aa = th.length; a < aa; a++) { + var tv = tr[a].textContent, + tk = a == 1 ? 'file' : th[a].getAttribute('name').split('/').slice(-1)[0], + vis = th[a].className.indexOf('min') === -1; + + if (!tv) + continue; + + (vis ? rv : ra).push(tk); + rt[tk] = tv; + } + return [rt, rv, ra]; +}; + + // toggle player widget var widget = (function () { var ret = {}, @@ -411,22 +497,16 @@ var widget = (function () { }; npirc.onclick = nptxt.onclick = function (e) { ev(e); - var th = ebi('files').tHead.rows[0].cells, - tr = QS('#files tr.play').cells, - irc = this.getAttribute('id') == 'npirc', + var irc = this.getAttribute('id') == 'npirc', ck = irc ? '06' : '', cv = irc ? '07' : '', - m = ck + 'np: '; + m = ck + 'np: ', + npr = get_np(), + npk = npr[1], + np = npr[0]; - for (var a = 1, aa = th.length; a < aa; a++) { - if (th[a].className.indexOf('min') !== -1) - continue; - - var tv = tr[a].textContent, - tk = a == 1 ? '' : th[a].getAttribute('name').split('/').slice(-1)[0]; - - m += tk + '(' + cv + tv + ck + ') // '; - } + for (var a = 0; a < npk.length; a++) + m += (npk[a] == 'file' ? '' : npk[a]) + '(' + cv + np[npk[a]] + ck + ') // '; m += '[' + cv + s2ms(mp.au.currentTime) + ck + '/' + cv + s2ms(mp.au.duration) + ck + ']'; @@ -635,6 +715,11 @@ function seek_au_mul(mul) { seek_au_sec(mp.au.duration * mul); } +function seek_au_rel(sec) { + if (mp.au) + seek_au_sec(mp.au.currentTime + sec); +} + function seek_au_sec(seek) { if (!mp.au) return; @@ -685,6 +770,9 @@ function playpause(e) { } else play(0); + + if (navigator.mediaSession) + navigator.mediaSession.playbackState = mp.au.paused ? "paused" : "playing"; }; @@ -1124,6 +1212,7 @@ function play(tid, seek, call_depth) { mpui.progress_updater(); pbar.drawbuf(); + mpl.announce(); return true; } catch (ex) { @@ -1206,6 +1295,8 @@ function autoplay_blocked(seek) { seek_au_sec(seek); else mpui.progress_updater(); + + mpl.announce(); }; na.onclick = unblocked; } @@ -1515,18 +1606,18 @@ document.onkeydown = function (e) { pos = parseInt(k.slice(-1)) * 0.1; if (pos !== -1) - return seek_au_mul(pos); + return seek_au_mul(pos) || true; var n = k == 'KeyJ' ? -1 : k == 'KeyL' ? 1 : 0; if (n !== 0) - return song_skip(n); + return song_skip(n) || true; if (k == 'KeyP') - return playpause(); + return playpause() || true; n = k == 'KeyU' ? -10 : k == 'KeyO' ? 10 : 0; if (n !== 0) - return mp.au ? seek_au_sec(mp.au.currentTime + n) : true; + return seek_au_rel(n) || true; n = k == 'KeyI' ? -1 : k == 'KeyK' ? 1 : 0; if (n !== 0) @@ -1536,7 +1627,6 @@ document.onkeydown = function (e) { return tree_up(); if (k == 'KeyB') - //return treectl.hidden ? treectl.show() : treectl.hide(); return treectl.hidden ? treectl.entree() : treectl.detree(); if (k == 'KeyG')