124 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python
 | |
| 
 | |
| import re
 | |
| import os
 | |
| import sys
 | |
| import tempfile
 | |
| import subprocess as sp
 | |
| 
 | |
| import keyfinder
 | |
| 
 | |
| from copyparty.util import fsenc
 | |
| 
 | |
| """
 | |
| dep: github/mixxxdj/libkeyfinder
 | |
| dep: pypi/keyfinder
 | |
| dep: ffmpeg
 | |
| 
 | |
| note: this is a janky edition of the regular audio-key.py,
 | |
|   slicing the files at 20sec intervals and keeping 5sec from each,
 | |
|   surprisingly accurate but still garbage (446 ok, 69 bad, 13% miss)
 | |
| 
 | |
|   it is fast tho
 | |
| """
 | |
| 
 | |
| 
 | |
| def get_duration():
 | |
|     # TODO provide ffprobe tags to mtp as json
 | |
| 
 | |
|     # fmt: off
 | |
|     dur = sp.check_output([
 | |
|         "ffprobe",
 | |
|         "-hide_banner",
 | |
|         "-v", "fatal",
 | |
|         "-show_streams",
 | |
|         "-show_format",
 | |
|         fsenc(sys.argv[1])
 | |
|     ])
 | |
|     # fmt: on
 | |
| 
 | |
|     dur = dur.decode("ascii", "replace").split("\n")
 | |
|     dur = [x.split("=")[1] for x in dur if x.startswith("duration=")]
 | |
|     dur = [float(x) for x in dur if re.match(r"^[0-9\.,]+$", x)]
 | |
|     return list(sorted(dur))[-1] if dur else None
 | |
| 
 | |
| 
 | |
| def get_segs(dur):
 | |
|     # keep first 5s of each 20s,
 | |
|     # keep entire last segment
 | |
|     ofs = 0
 | |
|     segs = []
 | |
|     while True:
 | |
|         seg = [ofs, 5]
 | |
|         segs.append(seg)
 | |
|         if dur - ofs < 20:
 | |
|             seg[-1] = int(dur - seg[0])
 | |
|             break
 | |
| 
 | |
|         ofs += 20
 | |
| 
 | |
|     return segs
 | |
| 
 | |
| 
 | |
| def slice(tf):
 | |
|     dur = get_duration()
 | |
|     dur = min(dur, 600)  # max 10min
 | |
|     segs = get_segs(dur)
 | |
| 
 | |
|     # fmt: off
 | |
|     cmd = [
 | |
|         "ffmpeg",
 | |
|         "-nostdin",
 | |
|         "-hide_banner",
 | |
|         "-v", "fatal",
 | |
|         "-y"
 | |
|     ]
 | |
| 
 | |
|     for seg in segs:
 | |
|         cmd.extend([
 | |
|             "-ss", str(seg[0]),
 | |
|             "-i", fsenc(sys.argv[1])
 | |
|         ])
 | |
|     
 | |
|     filt = ""
 | |
|     for n, seg in enumerate(segs):
 | |
|         filt += "[{}:a:0]atrim=duration={}[a{}]; ".format(n, seg[1], n)
 | |
|     
 | |
|     prev = "a0"
 | |
|     for n in range(1, len(segs)):
 | |
|         nxt = "b{}".format(n)
 | |
|         filt += "[{}][a{}]acrossfade=d=0.5[{}]; ".format(prev, n, nxt)
 | |
|         prev = nxt
 | |
| 
 | |
|     cmd.extend([
 | |
|         "-filter_complex", filt[:-2],
 | |
|         "-map", "[{}]".format(nxt),
 | |
|         "-sample_fmt", "s16",
 | |
|         tf
 | |
|     ])
 | |
|     # fmt: on
 | |
| 
 | |
|     # print(cmd)
 | |
|     sp.check_call(cmd)
 | |
| 
 | |
| 
 | |
| def det(tf):
 | |
|     slice(tf)
 | |
|     print(keyfinder.key(tf).camelot())
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     with tempfile.NamedTemporaryFile(suffix=".flac", delete=False) as f:
 | |
|         f.write(b"h")
 | |
|         tf = f.name
 | |
| 
 | |
|     try:
 | |
|         det(tf)
 | |
|     finally:
 | |
|         os.unlink(tf)
 | |
|         pass
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 | 
