mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-04 05:43:17 +00:00 
			
		
		
		
	audio-key: truncate at 5min + mojibake support
This commit is contained in:
		@@ -59,8 +59,6 @@ def main():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        det(tf)
 | 
					        det(tf)
 | 
				
			||||||
    except:
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
    finally:
 | 
					    finally:
 | 
				
			||||||
        os.unlink(tf)
 | 
					        os.unlink(tf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										123
									
								
								bin/mtag/audio-key-slicing.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										123
									
								
								bin/mtag/audio-key-slicing.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					#!/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()
 | 
				
			||||||
@@ -1,18 +1,52 @@
 | 
				
			|||||||
#!/usr/bin/env python
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					import tempfile
 | 
				
			||||||
 | 
					import subprocess as sp
 | 
				
			||||||
import keyfinder
 | 
					import keyfinder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from copyparty.util import fsenc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
dep: github/mixxxdj/libkeyfinder
 | 
					dep: github/mixxxdj/libkeyfinder
 | 
				
			||||||
dep: pypi/keyfinder
 | 
					dep: pypi/keyfinder
 | 
				
			||||||
dep: ffmpeg
 | 
					dep: ffmpeg
 | 
				
			||||||
 | 
					 | 
				
			||||||
note: cannot fsenc
 | 
					 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					# tried trimming the first/last 5th, bad idea,
 | 
				
			||||||
    print(keyfinder.key(sys.argv[1]).camelot())
 | 
					# misdetects 9a law field (Sphere Caliber) as 10b,
 | 
				
			||||||
except:
 | 
					# obvious when mixing 9a ghostly parapara ship
 | 
				
			||||||
    pass
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def det(tf):
 | 
				
			||||||
 | 
					    # fmt: off
 | 
				
			||||||
 | 
					    sp.check_call([
 | 
				
			||||||
 | 
					        "ffmpeg",
 | 
				
			||||||
 | 
					        "-nostdin",
 | 
				
			||||||
 | 
					        "-hide_banner",
 | 
				
			||||||
 | 
					        "-v", "fatal",
 | 
				
			||||||
 | 
					        "-y", "-i", fsenc(sys.argv[1]),
 | 
				
			||||||
 | 
					        "-t", "300",
 | 
				
			||||||
 | 
					        "-sample_fmt", "s16",
 | 
				
			||||||
 | 
					        tf
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
 | 
					    # fmt: on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,6 +106,12 @@ find -iname up2k.db | while IFS= read -r x; do sqlite3 "$x" 'select substr(w,1,1
 | 
				
			|||||||
# unschedule mtp scan for all files somewhere under "enc/"
 | 
					# unschedule mtp scan for all files somewhere under "enc/"
 | 
				
			||||||
sqlite3 -readonly up2k.db 'select substr(up.w,1,16) from up inner join mt on mt.w = substr(up.w,1,16) where rd like "enc/%" and +mt.k = "t:mtp"' > keys; awk '{printf "delete from mt where w = \"%s\" and +k = \"t:mtp\";\n", $0}' <keys | tee /dev/stderr | sqlite3 up2k.db
 | 
					sqlite3 -readonly up2k.db 'select substr(up.w,1,16) from up inner join mt on mt.w = substr(up.w,1,16) where rd like "enc/%" and +mt.k = "t:mtp"' > keys; awk '{printf "delete from mt where w = \"%s\" and +k = \"t:mtp\";\n", $0}' <keys | tee /dev/stderr | sqlite3 up2k.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# compare metadata key "key" between two databases
 | 
				
			||||||
 | 
					sqlite3 -readonly up2k.db.key-full 'select w, v from mt where k = "key" order by w' > k1; sqlite3 -readonly up2k.db 'select w, v from mt where k = "key" order by w' > k2; ok=0; ng=0; while IFS='|' read w k2; do k1="$(grep -E "^$w" k1 | sed -r 's/.*\|//')"; [ "$k1" = "$k2" ] && ok=$((ok+1)) || { ng=$((ng+1)); printf '%3s %3s  %s\n' "$k1" "$k2" "$(sqlite3 -readonly up2k.db.key-full "select * from up where substr(w,1,16) = '$w'" | sed -r 's/\|/ | /g')"; }; done < <(cat k2); echo "match $ok   diff $ng"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# actually this is much better
 | 
				
			||||||
 | 
					sqlite3 -readonly up2k.db.key-full 'select w, v from mt where k = "key" order by w' > k1; sqlite3 -readonly up2k.db 'select mt.w, mt.v, up.rd, up.fn from mt inner join up on mt.w = substr(up.w,1,16) where mt.k = "key" order by up.rd, up.fn' > k2; ok=0; ng=0; while IFS='|' read w k2 path; do k1="$(grep -E "^$w" k1 | sed -r 's/.*\|//')"; [ "$k1" = "$k2" ] && ok=$((ok+1)) || { ng=$((ng+1)); printf '%3s %3s  %s\n' "$k1" "$k2" "$path"; }; done < <(cat k2); echo "match $ok   diff $ng"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##
 | 
					##
 | 
				
			||||||
## media
 | 
					## media
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user