mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-03 21:43:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/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,))
 |