diff --git a/README.md b/README.md index 07fc4add..c264f30b 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,8 @@ the browser has the following hotkeys * `I/K` prev/next folder * `P` parent folder +you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&1:20` after the `.../#af-c8960dab` + ## zip downloads @@ -339,7 +341,6 @@ in the `scripts` folder: roughly sorted by priority -* audio link with timestamp * separate sqlite table per tag * audio fingerprinting * readme.md as epilogue diff --git a/copyparty/web/browser.css b/copyparty/web/browser.css index dff3abad..1e70ec02 100644 --- a/copyparty/web/browser.css +++ b/copyparty/web/browser.css @@ -284,7 +284,7 @@ a, #files tbody div a:last-child { line-height: 1em; } #wtoggle.sel { - width: 6em; + width: 6.4em; } #wtoggle.sel #wzip { display: inline-block; @@ -779,10 +779,10 @@ html.light #files tr:hover td { html.light #files tbody a.play { color: #c0f; } -html.light #files tr.play td { +html.light tr.play td { background: #fc5; } -html.light #files tr.play a { +html.light tr.play a { color: #406; } html.light #files > thead > tr > th.min span { @@ -802,17 +802,20 @@ html.light #widget a { html.light #files tr.sel:hover td { background: #c37; } +html.light #files tr.sel td { + color: #fff; +} html.light #files tr.sel a { color: #fff; } html.light input[type="checkbox"] + label { color: #333; } -.opview input[type="text"] { +html.light .opview input[type="text"] { background: #fff; color: #333; box-shadow: 0 0 2px #888; - border-color: #d38; + border-color: #38d; } html.light #ops:hover #opdesc { background: #fff; @@ -826,10 +829,6 @@ html.light #u2tab a>span, html.light #files td div span { color: #000; } -html.light #files a:hover { - color: #000; - background: #fff; -} html.light #path { background: #f7f7f7; text-shadow: none; @@ -850,4 +849,9 @@ html.light #path a:hover { } html.light #files tbody div a { color: #d38; +} +html.light #files a:hover, +html.light #files tr.sel a:hover { + color: #000; + background: #fff; } \ No newline at end of file diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index ace69031..0345664d 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -314,8 +314,8 @@ function seek_au_sec(seek) { mp.au.currentTime = seek; + // ogv.js breaks on .play() during playback if (mp.au === mp.au_native) - // hack: ogv.js breaks on .play() during playback mp.au.play(); } @@ -427,7 +427,7 @@ catch (ex) { } // plays the tid'th audio file on the page -function play(tid, call_depth) { +function play(tid, seek, call_depth) { if (mp.order.length == 0) return alert('no audio found wait what'); @@ -449,7 +449,7 @@ function play(tid, call_depth) { } // ogv.js breaks on .play() unless directly user-triggered - var hack_attempt_play = true; + var attempt_play = true; var url = mp.tracks[tid]; if (need_ogv && /\.(ogg|opus)$/i.test(url)) { @@ -458,7 +458,7 @@ function play(tid, call_depth) { } else if (window['OGVPlayer']) { mp.au = mp.au_ogvjs = new OGVPlayer(); - hack_attempt_play = false; + attempt_play = false; mp.au.addEventListener('error', evau_error, true); mp.au.addEventListener('progress', pbar.drawpos, false); widget.open(); @@ -470,7 +470,7 @@ function play(tid, call_depth) { show_modal('

loading ogv.js

thanks apple

'); import_js('/.cpr/deps/ogv.js', function () { - play(tid, 1); + play(tid, seek, 1); }); return; @@ -498,21 +498,26 @@ function play(tid, call_depth) { ebi(oid).parentElement.parentElement.className += ' play'; try { - if (hack_attempt_play) + if (attempt_play) mp.au.play(); if (mp.au.paused) - autoplay_blocked(); + autoplay_blocked(seek); + else if (seek) { + seek_au_sec(seek); + } - var o = ebi(oid); - o.setAttribute('id', 'thx_js'); - if (window.history && history.replaceState) { - hist_replace(document.location.pathname + '#' + oid); + if (!seek) { + var o = ebi(oid); + o.setAttribute('id', 'thx_js'); + if (window.history && history.replaceState) { + hist_replace(document.location.pathname + '#' + oid); + } + else { + document.location.hash = oid; + } + o.setAttribute('id', oid); } - else { - document.location.hash = oid; - } - o.setAttribute('id', oid); pbar.drawbuf(); return true; @@ -576,7 +581,7 @@ function unblocked() { // show ui to manually start playback of a linked song -function autoplay_blocked() { +function autoplay_blocked(seek) { show_modal( '
' + '
Cancel
(show file list)
'); @@ -592,6 +597,8 @@ function autoplay_blocked() { if (e) e.preventDefault(); unblocked(); mp.au.play(); + if (seek) + seek_au_sec(seek); }; na.onclick = unblocked; } @@ -600,8 +607,20 @@ function autoplay_blocked() { // autoplay linked track (function () { var v = location.hash; - if (v && v.length == 12 && v.indexOf('#af-') === 0) - play(v.slice(2)); + if (v && v.indexOf('#af-') === 0) { + var id = v.slice(2).split('&'); + if (id[0].length != 10) + return; + + if (id.length == 1) + return play(id[0]); + + var m = /^[Tt=0]*([0-9]+[Mm:])?0*([0-9]+)[Ss]?$/.exec(id[1]); + if (!m) + return play(id[0]); + + return play(id[0], parseInt(m[1] || 0) * 60 + parseInt(m[2] || 0)); + } })(); @@ -1549,8 +1568,11 @@ function addcrc() { ebi('unsearch') ? 'div>a:last-child' : 'a')); for (var a = 0, aa = links.length; a < aa; a++) - if (!links[a].getAttribute('id')) - links[a].setAttribute('id', 'f-' + crc32(links[a].textContent || links[a].innerText)); + if (!links[a].getAttribute('id')) { + var crc = crc32(links[a].textContent || links[a].innerText); + crc = ('00000000' + crc).slice(-8); + links[a].setAttribute('id', 'f-' + crc); + } }