Compare commits

..

11 Commits

Author SHA1 Message Date
ed
54013d861b v0.11.23 2021-06-21 21:15:56 +02:00
ed
ec100210dc support showing album-cover on windows lockscreen 2021-06-21 19:15:22 +00:00
ed
3ab1acf32c v0.11.22 2021-06-21 20:30:29 +02:00
ed
8c28266418 subscribe to media-keys globally as a media player 2021-06-21 20:26:11 +02:00
ed
7f8b8dcb92 scandir is not withable before py3.6 2021-06-21 20:23:35 +02:00
ed
6dd39811d4 disable u2idx if sqlite3 is unavailable 2021-06-21 20:22:54 +02:00
ed
35e2138e3e doc: macos support 2021-06-21 18:42:15 +02:00
ed
239b4e9fe6 v0.11.21 2021-06-20 21:25:18 +02:00
ed
2fcd0e7e72 abandon listing tags in browser when db busy 2021-06-20 21:19:47 +02:00
ed
357347ce3a lower timeout on db reads 2021-06-20 21:03:35 +02:00
ed
36dc1107fb update dbtool desc 2021-06-20 20:05:43 +02:00
10 changed files with 172 additions and 46 deletions

View File

@@ -111,7 +111,7 @@ summary: all planned features work! now please enjoy the bloatening
* ☑ FUSE client (read-only)
* browser
* ☑ tree-view
* ☑ audio player
* ☑ audio player (with OS media controls)
* ☑ thumbnails
* ☑ images using Pillow
* ☑ videos using FFmpeg

View File

@@ -48,15 +48,16 @@ you could replace winfsp with [dokan](https://github.com/dokan-dev/dokany/releas
# [`dbtool.py`](dbtool.py)
upgrade utility which can show db info and help transfer data between databases, for example when a new version of copyparty recommends to wipe the DB and reindex because it now collects additional metadata during analysis, but you have some really expensive `-mtp` parsers and want to copy over the tags from the old db
upgrade utility which can show db info and help transfer data between databases, for example when a new version of copyparty is incompatible with the old DB and automatically rebuilds the DB from scratch, but you have some really expensive `-mtp` parsers and want to copy over the tags from the old db
for that example (upgrading to v0.11.0), first move the old db aside, launch copyparty, let it rebuild the db until the point where it starts running mtp (colored messages as it adds the mtp tags), then CTRL-C and patch in the old mtp tags from the old db instead
for that example (upgrading to v0.11.20), first launch the new version of copyparty like usual, let it make a backup of the old db and rebuild the new db until the point where it starts running mtp (colored messages as it adds the mtp tags), that's when you hit CTRL-C and patch in the old mtp tags from the old db instead
so assuming you have `-mtp` parsers to provide the tags `key` and `.bpm`:
```
~/bin/dbtool.py -ls up2k.db
~/bin/dbtool.py -src up2k.db.v0.10.22 up2k.db -cmp
~/bin/dbtool.py -src up2k.db.v0.10.22 up2k.db -rm-mtp-flag -copy key
~/bin/dbtool.py -src up2k.db.v0.10.22 up2k.db -rm-mtp-flag -copy .bpm -vac
cd /mnt/nas/music/.hist
~/src/copyparty/bin/dbtool.py -ls up2k.db
~/src/copyparty/bin/dbtool.py -src up2k.*.v3 up2k.db -cmp
~/src/copyparty/bin/dbtool.py -src up2k.*.v3 up2k.db -rm-mtp-flag -copy key
~/src/copyparty/bin/dbtool.py -src up2k.*.v3 up2k.db -rm-mtp-flag -copy .bpm -vac
```

View File

@@ -410,7 +410,7 @@ def main(argv=None):
+ " (if you crash with codec errors then that is why)"
)
if WINDOWS and sys.version_info < (3, 6):
if sys.version_info < (3, 6):
al.no_scandir = True
# signal.signal(signal.SIGINT, sighandler)

View File

@@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (0, 11, 20)
VERSION = (0, 11, 23)
CODENAME = "the grid"
BUILD_DT = (2021, 6, 20)
BUILD_DT = (2021, 6, 21)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -1765,16 +1765,27 @@ class HttpCli(object):
fn = f["name"]
rd = f["rd"]
del f["rd"]
if icur:
if not icur:
break
if vn != dbv:
_, rd = vn.get_dbv(rd)
q = "select w from up where rd = ? and fn = ?"
r = None
try:
r = icur.execute(q, (rd, fn)).fetchone()
except:
except Exception as ex:
if "database is locked" in str(ex):
break
try:
args = s3enc(idx.mem_cur, rd, fn)
r = icur.execute(q, args).fetchone()
except:
m = "tag list error, {}/{}\n{}"
self.log(m.format(rd, fn, min_ex()))
break
tags = {}
f["tags"] = tags
@@ -1784,9 +1795,14 @@ class HttpCli(object):
w = r[0][:16]
q = "select k, v from mt where w = ? and k != 'x'"
try:
for k, v in icur.execute(q, (w,)):
taglist[k] = True
tags[k] = v
except:
m = "tag read error, {}/{} [{}]:\n{}"
self.log(m.format(rd, fn, w, min_ex()))
break
if icur:
taglist = [k for k in vn.flags.get("mte", "").split(",") if k in taglist]

View File

@@ -26,7 +26,7 @@ class U2idx(object):
self.timeout = self.args.srch_time
if not HAVE_SQLITE3:
self.log("could not load sqlite3; searchign wqill be disabled")
self.log("your python does not have sqlite3; searching will be disabled")
return
self.cur = {}
@@ -57,6 +57,9 @@ class U2idx(object):
raise Pebkac(500, min_ex())
def get_cur(self, ptop):
if not HAVE_SQLITE3:
return None
cur = self.cur.get(ptop)
if cur:
return cur
@@ -66,7 +69,7 @@ class U2idx(object):
if not os.path.exists(db_path):
return None
cur = sqlite3.connect(db_path).cursor()
cur = sqlite3.connect(db_path, 2).cursor()
self.cur[ptop] = cur
return cur

View File

@@ -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 {

View File

@@ -222,10 +222,14 @@ var have_webp = null;
var mpl = (function () {
var have_mctl = 'mediaSession' in navigator && window.MediaMetadata;
ebi('op_player').innerHTML = (
'<div><h3>switches</h3><div>' +
'<a href="#" class="tgl btn" id="au_preload" tt="start loading the next song near the end for gapless playback">preload</a>' +
'<a href="#" class="tgl btn" id="au_npclip" tt="show buttons for clipboarding the currently playing song">/np clip</a>' +
'<a href="#" class="tgl btn" id="au_os_ctl" tt="os integration (media hotkeys / osd)">os-ctl</a>' +
'<a href="#" class="tgl btn" id="au_osd_cv" tt="show album cover in osd">osd-cv</a>' +
'</div></div>' +
'<div><h3>playback mode</h3><div id="pb_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,55 @@ 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';
var pwd = get_pwd();
if (pwd)
cover += '&pw=' + uricom_enc(pwd);
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 +434,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 +502,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 +720,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 +775,9 @@ function playpause(e) {
}
else
play(0);
if (navigator.mediaSession)
navigator.mediaSession.playbackState = mp.au.paused ? "paused" : "playing";
};
@@ -1124,6 +1217,7 @@ function play(tid, seek, call_depth) {
mpui.progress_updater();
pbar.drawbuf();
mpl.announce();
return true;
}
catch (ex) {
@@ -1206,6 +1300,8 @@ function autoplay_blocked(seek) {
seek_au_sec(seek);
else
mpui.progress_updater();
mpl.announce();
};
na.onclick = unblocked;
}
@@ -1515,18 +1611,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 +1632,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')

View File

@@ -359,6 +359,15 @@ function get_vpath() {
}
function get_pwd() {
var pwd = ('; ' + document.cookie).split('; cppwd=');
if (pwd.length < 2)
return null;
return pwd[1].split(';')[0];
}
function unix2iso(ts) {
return new Date(ts * 1000).toISOString().replace("T", " ").slice(0, -5);
}

View File

@@ -157,7 +157,7 @@ dbg.asyncStore.pendingBreakpoints = {}
about:config >> devtools.debugger.prefs-schema-version = -1
# determine server version
git reset --hard origin/HEAD && git log --format=format:"%H %ai %d" --decorate=full > /dev/shm/revs && cat /dev/shm/revs | while read -r rev extra; do (git reset --hard $rev >/dev/null 2>/dev/null && dsz=$(cat copyparty/web/{util,browser,up2k}.js 2>/dev/null | diff -wNarU0 - <(cat /mnt/Users/ed/Downloads/ref/{util,browser,up2k}.js) | wc -c) && printf '%s %6s %s\n' "$rev" $dsz "$extra") </dev/null; done
git pull; git reset --hard origin/HEAD && git log --format=format:"%H %ai %d" --decorate=full > ../revs && cat ../{util,browser}.js >../vr && cat ../revs | while read -r rev extra; do (git reset --hard $rev >/dev/null 2>/dev/null && dsz=$(cat copyparty/web/{util,browser}.js >../vg 2>/dev/null && diff -wNarU0 ../{vg,vr} | wc -c) && printf '%s %6s %s\n' "$rev" $dsz "$extra") </dev/null; done
##