mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
new xau hook: podcast-normalizer.py
This commit is contained in:
parent
c9cdc3e1c1
commit
a06c5eb048
|
@ -14,6 +14,8 @@ run copyparty with `--help-hooks` for usage details / hook type explanations (xm
|
||||||
* [discord-announce.py](discord-announce.py) announces new uploads on discord using webhooks ([example](https://user-images.githubusercontent.com/241032/215304439-1c1cb3c8-ec6f-4c17-9f27-81f969b1811a.png))
|
* [discord-announce.py](discord-announce.py) announces new uploads on discord using webhooks ([example](https://user-images.githubusercontent.com/241032/215304439-1c1cb3c8-ec6f-4c17-9f27-81f969b1811a.png))
|
||||||
* [reject-mimetype.py](reject-mimetype.py) rejects uploads unless the mimetype is acceptable
|
* [reject-mimetype.py](reject-mimetype.py) rejects uploads unless the mimetype is acceptable
|
||||||
* [into-the-cache-it-goes.py](into-the-cache-it-goes.py) avoids bugs in caching proxies by immediately downloading each file that is uploaded
|
* [into-the-cache-it-goes.py](into-the-cache-it-goes.py) avoids bugs in caching proxies by immediately downloading each file that is uploaded
|
||||||
|
* [podcast-normalizer.py](podcast-normalizer.py) creates a second file with dynamic-range-compression whenever an audio file is uploaded
|
||||||
|
* good example of the `idx` [hook effect](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#hook-effects) to tell copyparty about additional files to scan/index
|
||||||
|
|
||||||
|
|
||||||
# upload batches
|
# upload batches
|
||||||
|
@ -25,6 +27,7 @@ these are `--xiu` hooks; unlike `xbu` and `xau` (which get executed on every sin
|
||||||
# before upload
|
# before upload
|
||||||
* [reject-extension.py](reject-extension.py) rejects uploads if they match a list of file extensions
|
* [reject-extension.py](reject-extension.py) rejects uploads if they match a list of file extensions
|
||||||
* [reloc-by-ext.py](reloc-by-ext.py) redirects an upload to another destination based on the file extension
|
* [reloc-by-ext.py](reloc-by-ext.py) redirects an upload to another destination based on the file extension
|
||||||
|
* good example of the `reloc` [hook effect](https://github.com/9001/copyparty/blob/hovudstraum/docs/devnotes.md#hook-effects)
|
||||||
|
|
||||||
|
|
||||||
# on message
|
# on message
|
||||||
|
|
121
bin/hooks/podcast-normalizer.py
Executable file
121
bin/hooks/podcast-normalizer.py
Executable file
|
@ -0,0 +1,121 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess as sp
|
||||||
|
|
||||||
|
|
||||||
|
_ = r"""
|
||||||
|
sends all uploaded audio files through an aggressive
|
||||||
|
dynamic-range-compressor to even out the volume levels
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
ffmpeg
|
||||||
|
|
||||||
|
being an xau hook, this gets eXecuted After Upload completion
|
||||||
|
but before copyparty has started hashing/indexing the file, so
|
||||||
|
we'll create a second normalized copy in a subfolder and tell
|
||||||
|
copyparty to hash/index that additional file as well
|
||||||
|
|
||||||
|
example usage as global config:
|
||||||
|
-e2d -e2t --xau j,c1,bin/hooks/podcast-normalizer.py
|
||||||
|
|
||||||
|
parameters explained,
|
||||||
|
e2d/e2t = enable database and metadata indexing
|
||||||
|
xau = execute after upload
|
||||||
|
j = this hook needs upload information as json (not just the filename)
|
||||||
|
c1 = this hook returns json on stdout, so tell copyparty to read that
|
||||||
|
|
||||||
|
example usage as a volflag (per-volume config):
|
||||||
|
-v srv/inc/pods:inc/pods:r:rw,ed:c,xau=j,c1,bin/hooks/podcast-normalizer.py
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
(share fs-path srv/inc/pods at URL /inc/pods,
|
||||||
|
readable by all, read-write for user ed,
|
||||||
|
running this xau (exec-after-upload) plugin for all uploaded files)
|
||||||
|
|
||||||
|
example usage as a volflag in a copyparty config file:
|
||||||
|
[/inc/pods]
|
||||||
|
srv/inc/pods
|
||||||
|
accs:
|
||||||
|
r: *
|
||||||
|
rw: ed
|
||||||
|
flags:
|
||||||
|
e2d # enables file indexing
|
||||||
|
e2t # metadata tags too
|
||||||
|
xau: j,c1,bin/hooks/podcast-normalizer.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
### CONFIG
|
||||||
|
|
||||||
|
# filetypes to process; ignores everything else
|
||||||
|
EXTS = "mp3 flac ogg opus m4a aac wav wma"
|
||||||
|
|
||||||
|
# the name of the subdir to put the normalized files in
|
||||||
|
SUBDIR = "normalized"
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
|
||||||
|
# try to enable support for crazy filenames
|
||||||
|
try:
|
||||||
|
from copyparty.util import fsenc
|
||||||
|
except:
|
||||||
|
|
||||||
|
def fsenc(p):
|
||||||
|
return p.encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# read info from copyparty
|
||||||
|
inf = json.loads(sys.argv[1])
|
||||||
|
vpath = inf["vp"]
|
||||||
|
abspath = inf["ap"]
|
||||||
|
|
||||||
|
# check if the file-extension is on the to-be-processed list
|
||||||
|
ext = abspath.lower().split(".")[-1]
|
||||||
|
if ext not in EXTS.split():
|
||||||
|
return
|
||||||
|
|
||||||
|
# jump into the folder where the file was uploaded
|
||||||
|
# and create the subfolder to place the normalized copy inside
|
||||||
|
dirpath, filename = os.path.split(abspath)
|
||||||
|
os.chdir(fsenc(dirpath))
|
||||||
|
os.makedirs(SUBDIR, exist_ok=True)
|
||||||
|
|
||||||
|
# the input and output filenames to give ffmpeg
|
||||||
|
fname_in = fsenc(f"./{filename}")
|
||||||
|
fname_out = fsenc(f"{SUBDIR}/{filename}.opus")
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
# create and run the ffmpeg command
|
||||||
|
cmd = [
|
||||||
|
b"ffmpeg",
|
||||||
|
b"-nostdin",
|
||||||
|
b"-hide_banner",
|
||||||
|
b"-i", fname_in,
|
||||||
|
b"-af", b"dynaudnorm=f=100:g=9", # the normalizer config
|
||||||
|
b"-c:a", b"libopus",
|
||||||
|
b"-b:a", b"128k",
|
||||||
|
fname_out,
|
||||||
|
]
|
||||||
|
# fmt: on
|
||||||
|
sp.check_output(cmd)
|
||||||
|
|
||||||
|
# and finally, tell copyparty about the new file
|
||||||
|
# so it appears in the database and rss-feed:
|
||||||
|
vpath = f"{SUBDIR}/{filename}.opus"
|
||||||
|
print(json.dumps({"idx": {"vp": [vpath]}}))
|
||||||
|
|
||||||
|
# (it's fine to give it a relative path like that; it gets
|
||||||
|
# resolved relative to the folder the file was uploaded into)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as ex:
|
||||||
|
print("podcast-normalizer failed; %r" % (ex,))
|
|
@ -281,8 +281,11 @@ on writing your own [hooks](../README.md#event-hooks)
|
||||||
hooks can cause intentional side-effects, such as redirecting an upload into another location, or creating+indexing additional files, or deleting existing files, by returning json on stdout
|
hooks can cause intentional side-effects, such as redirecting an upload into another location, or creating+indexing additional files, or deleting existing files, by returning json on stdout
|
||||||
|
|
||||||
* `reloc` can redirect uploads before/after uploading has finished, based on filename, extension, file contents, uploader ip/name etc.
|
* `reloc` can redirect uploads before/after uploading has finished, based on filename, extension, file contents, uploader ip/name etc.
|
||||||
|
* example: [reloc-by-ext](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/reloc-by-ext.py)
|
||||||
* `idx` informs copyparty about a new file to index as a consequence of this upload
|
* `idx` informs copyparty about a new file to index as a consequence of this upload
|
||||||
|
* example: [podcast-normalizer.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/podcast-normalizer.py)
|
||||||
* `del` tells copyparty to delete an unrelated file by vpath
|
* `del` tells copyparty to delete an unrelated file by vpath
|
||||||
|
* example: ( ´・ω・) nyoro~n
|
||||||
|
|
||||||
for these to take effect, the hook must be defined with the `c1` flag; see example [reloc-by-ext](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/reloc-by-ext.py)
|
for these to take effect, the hook must be defined with the `c1` flag; see example [reloc-by-ext](https://github.com/9001/copyparty/blob/hovudstraum/bin/hooks/reloc-by-ext.py)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue