mirror of
https://github.com/9001/copyparty.git
synced 2025-10-27 10:03:36 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3e0afad2 | ||
|
|
d8d1f94a86 | ||
|
|
00dfd8cfd1 | ||
|
|
273de6db31 | ||
|
|
c6c0eeb0ff | ||
|
|
e70c74a3b5 | ||
|
|
f7d939eeab | ||
|
|
e815c091b9 | ||
|
|
963529b7cf | ||
|
|
638a52374d | ||
|
|
d9d42b7aa2 | ||
|
|
ec7e5f36a2 | ||
|
|
56110883ea |
@@ -25,6 +25,7 @@ turn your phone or raspi into a portable file server with resumable uploads/down
|
|||||||
* [search configuration](#search-configuration)
|
* [search configuration](#search-configuration)
|
||||||
* [metadata from audio files](#metadata-from-audio-files)
|
* [metadata from audio files](#metadata-from-audio-files)
|
||||||
* [file parser plugins](#file-parser-plugins)
|
* [file parser plugins](#file-parser-plugins)
|
||||||
|
* [complete examples](#complete-examples)
|
||||||
* [client examples](#client-examples)
|
* [client examples](#client-examples)
|
||||||
* [dependencies](#dependencies)
|
* [dependencies](#dependencies)
|
||||||
* [optional gpl stuff](#optional-gpl-stuff)
|
* [optional gpl stuff](#optional-gpl-stuff)
|
||||||
@@ -171,8 +172,8 @@ copyparty can invoke external programs to collect additional metadata for files
|
|||||||
|
|
||||||
## complete examples
|
## complete examples
|
||||||
|
|
||||||
* read-only music server with bpm and key scanning
|
* read-only music server with bpm and key scanning
|
||||||
* `python copyparty-sfx.py -v /mnt/nas/music:/music:r -e2dsa -e2ts -mtp .bpm=f,~/bin/audio-bpm.py -mtp key=f,~/bin/audio-key.py`
|
`python copyparty-sfx.py -v /mnt/nas/music:/music:r -e2dsa -e2ts -mtp .bpm=f,audio-bpm.py -mtp key=f,audio-key.py`
|
||||||
|
|
||||||
|
|
||||||
# client examples
|
# client examples
|
||||||
|
|||||||
@@ -5,4 +5,30 @@ some of these rely on libraries which are not MIT-compatible
|
|||||||
* [audio-bpm.py](./audio-bpm.py) detects the BPM of music using the BeatRoot Vamp Plugin; imports GPL2
|
* [audio-bpm.py](./audio-bpm.py) detects the BPM of music using the BeatRoot Vamp Plugin; imports GPL2
|
||||||
* [audio-key.py](./audio-key.py) detects the melodic key of music using the Mixxx fork of keyfinder; imports GPL3
|
* [audio-key.py](./audio-key.py) detects the melodic key of music using the Mixxx fork of keyfinder; imports GPL3
|
||||||
|
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
|
||||||
run [`install-deps.sh`](install-deps.sh) to build/install most dependencies required by these programs (supports windows/linux/macos)
|
run [`install-deps.sh`](install-deps.sh) to build/install most dependencies required by these programs (supports windows/linux/macos)
|
||||||
|
|
||||||
|
*alternatively* (or preferably) use packages from your distro instead, then you'll need at least these:
|
||||||
|
|
||||||
|
* from distro: `numpy vamp-plugin-sdk beatroot-vamp mixxx-keyfinder ffmpeg`
|
||||||
|
* from pypy: `keyfinder vamp`
|
||||||
|
|
||||||
|
|
||||||
|
# usage from copyparty
|
||||||
|
|
||||||
|
`copyparty -e2dsa -e2ts -mtp key=f,audio-key.py -mtp .bpm=f,audio-bpm.py`
|
||||||
|
|
||||||
|
* `f,` makes the detected value replace any existing values
|
||||||
|
* the `.` in `.bpm` indicates numeric value
|
||||||
|
* assumes the python files are in the folder you're launching copyparty from, replace the filename with a relative/absolute path if that's not the case
|
||||||
|
* `mtp` modules will not run if a file has existing tags in the db, so clear out the tags with `-e2tsr` the first time you launch with new `mtp` options
|
||||||
|
|
||||||
|
|
||||||
|
## usage with volume-flags
|
||||||
|
|
||||||
|
instead of affecting all volumes, you can set the options for just one volume like so:
|
||||||
|
```
|
||||||
|
copyparty -v /mnt/nas/music:/music:r:cmtp=key=f,audio-key.py:cmtp=.bpm=f,audio-bpm.py:ce2dsa:ce2ts
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (0, 9, 9)
|
VERSION = (0, 9, 13)
|
||||||
CODENAME = "the strongest music server"
|
CODENAME = "the strongest music server"
|
||||||
BUILD_DT = (2021, 3, 21)
|
BUILD_DT = (2021, 3, 23)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ class VFS(object):
|
|||||||
self.nodes = {} # child nodes
|
self.nodes = {} # child nodes
|
||||||
self.all_vols = {vpath: self} # flattened recursive
|
self.all_vols = {vpath: self} # flattened recursive
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "VFS({})".format(
|
||||||
|
", ".join(
|
||||||
|
"{}={!r}".format(k, self.__dict__[k])
|
||||||
|
for k in "realpath vpath uread uwrite flags".split()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def _trk(self, vol):
|
def _trk(self, vol):
|
||||||
self.all_vols[vol.vpath] = vol
|
self.all_vols[vol.vpath] = vol
|
||||||
return vol
|
return vol
|
||||||
@@ -343,6 +351,21 @@ class AuthSrv(object):
|
|||||||
# append parsers from argv to volume-flags
|
# append parsers from argv to volume-flags
|
||||||
self._read_volflag(vol.flags, "mtp", self.args.mtp, True)
|
self._read_volflag(vol.flags, "mtp", self.args.mtp, True)
|
||||||
|
|
||||||
|
# d2d drops all database features for a volume
|
||||||
|
for grp, rm in [["d2d", "e2d"], ["d2t", "e2t"]]:
|
||||||
|
if not vol.flags.get(grp, False):
|
||||||
|
continue
|
||||||
|
|
||||||
|
vol.flags["d2t"] = True
|
||||||
|
vol.flags = {k: v for k, v in vol.flags.items() if not k.startswith(rm)}
|
||||||
|
|
||||||
|
# mt* needs e2t so drop those too
|
||||||
|
for grp, rm in [["e2t", "mt"]]:
|
||||||
|
if vol.flags.get(grp, False):
|
||||||
|
continue
|
||||||
|
|
||||||
|
vol.flags = {k: v for k, v in vol.flags.items() if not k.startswith(rm)}
|
||||||
|
|
||||||
# verify tags mentioned by -mt[mp] are used by -mte
|
# verify tags mentioned by -mt[mp] are used by -mte
|
||||||
local_mtp = {}
|
local_mtp = {}
|
||||||
local_only_mtp = {}
|
local_only_mtp = {}
|
||||||
|
|||||||
@@ -1295,7 +1295,7 @@ class HttpCli(object):
|
|||||||
|
|
||||||
tags = {}
|
tags = {}
|
||||||
f["tags"] = tags
|
f["tags"] = tags
|
||||||
|
|
||||||
if not r:
|
if not r:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -1306,7 +1306,7 @@ class HttpCli(object):
|
|||||||
tags[k] = v
|
tags[k] = v
|
||||||
|
|
||||||
if icur:
|
if icur:
|
||||||
taglist = [k for k in vn.flags["mte"].split(",") if k in taglist]
|
taglist = [k for k in vn.flags.get("mte", "").split(",") if k in taglist]
|
||||||
for f in dirs:
|
for f in dirs:
|
||||||
f["tags"] = {}
|
f["tags"] = {}
|
||||||
|
|
||||||
@@ -1379,7 +1379,9 @@ class HttpCli(object):
|
|||||||
ts=ts,
|
ts=ts,
|
||||||
perms=json.dumps(perms),
|
perms=json.dumps(perms),
|
||||||
taglist=taglist,
|
taglist=taglist,
|
||||||
tag_order=json.dumps(vn.flags["mte"].split(",")),
|
tag_order=json.dumps(
|
||||||
|
vn.flags["mte"].split(",") if "mte" in vn.flags else []
|
||||||
|
),
|
||||||
have_up2k_idx=("e2d" in vn.flags),
|
have_up2k_idx=("e2d" in vn.flags),
|
||||||
have_tags_idx=("e2t" in vn.flags),
|
have_tags_idx=("e2t" in vn.flags),
|
||||||
logues=logues,
|
logues=logues,
|
||||||
|
|||||||
@@ -225,9 +225,14 @@ class Up2k(object):
|
|||||||
|
|
||||||
_, flags = self._expr_idx_filter(flags)
|
_, flags = self._expr_idx_filter(flags)
|
||||||
|
|
||||||
a = "\033[0;36m{}:\033[1;30m{}"
|
ft = "\033[0;32m{}{:.0}"
|
||||||
a = [a.format(k, v) for k, v in sorted(flags.items())]
|
ff = "\033[0;35m{}{:.0}"
|
||||||
self.log(" ".join(a) + "\033[0m")
|
fv = "\033[0;36m{}:\033[1;30m{}"
|
||||||
|
a = [
|
||||||
|
(ft if v is True else ff if v is False else fv).format(k, str(v))
|
||||||
|
for k, v in flags.items()
|
||||||
|
]
|
||||||
|
self.log(" ".join(sorted(a)) + "\033[0m")
|
||||||
|
|
||||||
reg = {}
|
reg = {}
|
||||||
path = os.path.join(ptop, ".hist", "up2k.snap")
|
path = os.path.join(ptop, ".hist", "up2k.snap")
|
||||||
@@ -282,9 +287,12 @@ class Up2k(object):
|
|||||||
dbw = [reg[0], 0, time.time()]
|
dbw = [reg[0], 0, time.time()]
|
||||||
self.pp.n = next(dbw[0].execute("select count(w) from up"))[0]
|
self.pp.n = next(dbw[0].execute("select count(w) from up"))[0]
|
||||||
|
|
||||||
# can be symlink so don't `and d.startswith(top)``
|
excl = [
|
||||||
excl = set([d.realpath for d in all_vols if d != vol])
|
vol.realpath + "/" + d.vpath[len(vol.vpath) :].lstrip("/")
|
||||||
n_add = self._build_dir(dbw, top, excl, top)
|
for d in all_vols
|
||||||
|
if d != vol and (d.vpath.startswith(vol.vpath + "/") or not vol.vpath)
|
||||||
|
]
|
||||||
|
n_add = self._build_dir(dbw, top, set(excl), top)
|
||||||
n_rm = self._drop_lost(dbw[0], top)
|
n_rm = self._drop_lost(dbw[0], top)
|
||||||
if dbw[1]:
|
if dbw[1]:
|
||||||
self.log("commit {} new files".format(dbw[1]))
|
self.log("commit {} new files".format(dbw[1]))
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ function MPlayer() {
|
|||||||
var links = document.querySelectorAll('#files>tbody>tr>td:nth-child(1)>a');
|
var links = document.querySelectorAll('#files>tbody>tr>td:nth-child(1)>a');
|
||||||
for (var a = 0, aa = links.length; a < aa; a++) {
|
for (var a = 0, aa = links.length; a < aa; a++) {
|
||||||
var tid = links[a].getAttribute('id');
|
var tid = links[a].getAttribute('id');
|
||||||
if (tid.indexOf('af-') !== 0)
|
if (!tid || tid.indexOf('af-') !== 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
order.push(tid.slice(1));
|
order.push(tid.slice(1));
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ gtar=$(command -v gtar || command -v gnutar) || true
|
|||||||
unexpand() { gunexpand "$@"; }
|
unexpand() { gunexpand "$@"; }
|
||||||
command -v grealpath >/dev/null &&
|
command -v grealpath >/dev/null &&
|
||||||
realpath() { grealpath "$@"; }
|
realpath() { grealpath "$@"; }
|
||||||
|
|
||||||
|
[ -e /opt/local/bin/bzip2 ] &&
|
||||||
|
bzip2() { /opt/local/bin/bzip2 "$@"; }
|
||||||
|
}
|
||||||
|
pybin=$(command -v python3 || command -v python) || {
|
||||||
|
echo need python
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -e copyparty/__main__.py ] || cd ..
|
[ -e copyparty/__main__.py ] || cd ..
|
||||||
@@ -38,11 +45,15 @@ gtar=$(command -v gtar || command -v gnutar) || true
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_sh=1
|
||||||
|
do_py=1
|
||||||
while [ ! -z "$1" ]; do
|
while [ ! -z "$1" ]; do
|
||||||
[ "$1" = clean ] && clean=1 && shift && continue
|
[ "$1" = clean ] && clean=1 && shift && continue
|
||||||
[ "$1" = re ] && repack=1 && shift && continue
|
[ "$1" = re ] && repack=1 && shift && continue
|
||||||
[ "$1" = no-ogv ] && no_ogv=1 && shift && continue
|
[ "$1" = no-ogv ] && no_ogv=1 && shift && continue
|
||||||
[ "$1" = no-cm ] && no_cm=1 && shift && continue
|
[ "$1" = no-cm ] && no_cm=1 && shift && continue
|
||||||
|
[ "$1" = no-sh ] && do_sh= && shift && continue
|
||||||
|
[ "$1" = no-py ] && do_py= && shift && continue
|
||||||
break
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -173,7 +184,7 @@ done
|
|||||||
find | grep -E '\.py$' |
|
find | grep -E '\.py$' |
|
||||||
grep -vE '__version__' |
|
grep -vE '__version__' |
|
||||||
tr '\n' '\0' |
|
tr '\n' '\0' |
|
||||||
xargs -0 python ../scripts/uncomment.py
|
xargs -0 $pybin ../scripts/uncomment.py
|
||||||
|
|
||||||
f=dep-j2/jinja2/constants.py
|
f=dep-j2/jinja2/constants.py
|
||||||
awk '/^LOREM_IPSUM_WORDS/{o=1;print "LOREM_IPSUM_WORDS = u\"a\"";next} !o; /"""/{o=0}' <$f >t
|
awk '/^LOREM_IPSUM_WORDS/{o=1;print "LOREM_IPSUM_WORDS = u\"a\"";next} !o; /"""/{o=0}' <$f >t
|
||||||
@@ -195,24 +206,36 @@ tar -cf tar "${args[@]}" --numeric-owner copyparty dep-j2
|
|||||||
|
|
||||||
echo compressing tar
|
echo compressing tar
|
||||||
# detect best level; bzip2 -7 is usually better than -9
|
# detect best level; bzip2 -7 is usually better than -9
|
||||||
for n in {2..9}; do cp tar t.$n; bzip2 -$n t.$n & done; wait; mv -v $(ls -1S t.*.bz2 | tail -n 1) tar.bz2
|
[ $do_py ] && { for n in {2..9}; do cp tar t.$n; bzip2 -$n t.$n & done; wait; mv -v $(ls -1S t.*.bz2 | tail -n 1) tar.bz2; }
|
||||||
for n in {2..9}; do cp tar t.$n; xz -ze$n t.$n & done; wait; mv -v $(ls -1S t.*.xz | tail -n 1) tar.xz
|
[ $do_sh ] && { for n in {2..9}; do cp tar t.$n; xz -ze$n t.$n & done; wait; mv -v $(ls -1S t.*.xz | tail -n 1) tar.xz; }
|
||||||
rm t.*
|
rm t.* || true
|
||||||
|
exts=()
|
||||||
|
|
||||||
|
|
||||||
|
[ $do_sh ] && {
|
||||||
|
exts+=(sh)
|
||||||
echo creating unix sfx
|
echo creating unix sfx
|
||||||
(
|
(
|
||||||
sed "s/PACK_TS/$ts/; s/PACK_HTS/$hts/; s/CPP_VER/$ver/" <../scripts/sfx.sh |
|
sed "s/PACK_TS/$ts/; s/PACK_HTS/$hts/; s/CPP_VER/$ver/" <../scripts/sfx.sh |
|
||||||
grep -E '^sfx_eof$' -B 9001;
|
grep -E '^sfx_eof$' -B 9001;
|
||||||
cat tar.xz
|
cat tar.xz
|
||||||
) >$sfx_out.sh
|
) >$sfx_out.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ $do_py ] && {
|
||||||
|
exts+=(py)
|
||||||
echo creating generic sfx
|
echo creating generic sfx
|
||||||
python ../scripts/sfx.py --sfx-make tar.bz2 $ver $ts
|
$pybin ../scripts/sfx.py --sfx-make tar.bz2 $ver $ts
|
||||||
mv sfx.out $sfx_out.py
|
mv sfx.out $sfx_out.py
|
||||||
chmod 755 $sfx_out.*
|
chmod 755 $sfx_out.*
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
printf "done:\n"
|
printf "done:\n"
|
||||||
printf " %s\n" "$(realpath $sfx_out)."{sh,py}
|
for ext in ${exts[@]}; do
|
||||||
# rm -rf *
|
printf " %s\n" "$(realpath $sfx_out)."$ext
|
||||||
|
done
|
||||||
|
|
||||||
|
# apk add bash python3 tar xz bzip2
|
||||||
# while true; do ./make-sfx.sh; for f in ..//dist/copyparty-sfx.{sh,py}; do mv $f $f.$(wc -c <$f | awk '{print$1}'); done; done
|
# while true; do ./make-sfx.sh; for f in ..//dist/copyparty-sfx.{sh,py}; do mv $f $f.$(wc -c <$f | awk '{print$1}'); done; done
|
||||||
|
|||||||
Reference in New Issue
Block a user