Skip to content

Instantly share code, notes, and snippets.

@donnaken15
Last active July 26, 2026 19:14
Show Gist options
  • Select an option

  • Save donnaken15/98e665de860e95521f81c1fdb3907a8c to your computer and use it in GitHub Desktop.

Select an option

Save donnaken15/98e665de860e95521f81c1fdb3907a8c to your computer and use it in GitHub Desktop.
speed up videos slightly and cut silence audacity-style for skimming commentary slop
#!/bin/zsh
#diff: curl -L https://gist.githubusercontent.com/donnaken15/98e665de860e95521f81c1fdb3907a8c/raw/slopper_skimmer.zsh | git diff --no-index - slopper_skimmer.zsh
#set -e # exits early without pressing anything, POS
# DON'T RUN THIS ON AV1 VIDEO
(($# == 0)) && { # LOL # $((?)) also works, amazing # NOT IN NORMAL SHELL
echo "No files entered"; exit 1
}
chcp.com 65001
function timefmt() {
local h m s ms time="$(($1))"
(( h = ((m = (s = (ms = ${time#-})) / 60) / 60) % 60, m %= 60, s %= 60, ms %= 1000, time < 0 )) && sign=-
# wish i could cram this in one statement
printf '%s%s%02d:%02d:%02d.%03d' "$2" "$sign" $h $m $s $ms
#FIX!!:
##(( h = ((m = (s = ${time#-} / 1000) / 60) / 60) % 60, m %= 60, s %= 60, ms %= 1000, time < 0 )) && sign=-
##printf '%s%s%02d:%02d:%06.3f' "$2" "$sign" $h $m $s
}
function get_seconds() {
valuefb="${(P)1:-${2:-00:00:00}}"
if [[ "$valuefb" =~ ^((([0-9]+):)?([0-9]{1,2}):)?([0-9]{1,2}(\.[0-9]+)?)$ ]]; then
(( $1 = ((match[3]*3600)+(match[4]*60)+match[5]) ))
else
(( $1 = "$valuefb" ))
fi
echo "Set $1 = `timefmt ${(P)1}`"
}
get_seconds start # KEEP START FOR TESTING SPECIFIC SEGMENT
function userval() { export "$1"="${(P)1:-${2:-0}}"; }
# figure this out like audacity duration and truncate to
userval sthres '-16.8dB'
userval sdur 0.13
userval srem 0.13
userval nick 0
userval speed 1.5
export speed
(( chunk > 0 )) && (( start += 4600.8 * speed * chunk ))
whywhy=(-hide_banner -hwaccel none)
#fargs=( # tfw draft preset
# -stats -stats_period 0.01 -pix_fmt yuv422p -g 900 # try asp
# -c:v libx264 -crf 29 -preset placebo -tune ssim -threads 15 -refs 2 -bf 8 -sc_threshold 40
# -c:a libopus -ar 24k -ab 56k -frame_duration 120 -flags:a +bitexact -compression_level:a 10
# -application voip -flush_packets 1 -max_muxing_queue_size 1 -blocksize 2048 -vbr:a on
# #-crf 43 -qmin 28 -qmax 45 -vb 1100k -minrate 40k -maxrate 2500k -c:v libvpx-vp9 -bf 64 -refs 8
# #-tile-columns 6 -tile-rows 2 -row-mt 1 -speed 6 -cpu-used 3 -deadline realtime
# #-tune ssim -tune-content screen -corpus-complexity 10000 -enable-tpl 1 -rc_lookahead 25
# #-frame-parallel 1 -aq-mode 2 -arnr-strength 0.4 -arnr-maxframes 7 -arnr-type 3 -sharpness 2
# #-static-thresh 0 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -auto-alt-ref 1
# #-color_range pc -bufsize 512M -lag-in-frames 25 -fflags +genpts+bitexact+nobuffer
# #-flags +qpel+mv4+aic+global_header -map_metadata -1
#)
cr=$'\r'; lf=$'\n'; imark='\[(silencedetect|Parsed_blackframe_[0-9]+) @ [0-9a-f]{16}\]'
kv='( ([A-Za-z0-9_]+): ?([^ ]+))?'$cr?; god="( \|)?$kv"; timecode='([0-9]{2}):([0-9]{2}):([0-9]{2}\.[0-9]+)'
comp='dynaudnorm=f=500:g=7' #comp='acompressor=threshold=0.07:ratio=4.2:attack=100:release=1000:makeup=1' # broken (clips hardcore): acompressor=threshold=-9dB:ratio=5.1:attack=0.2:release=1.0:makeup=1
((m_notice = 10.0)) # heads up warning (not using yet)
((m_lead = 0.3)) # seconds before/after detected frames
((m_trail = 1.9)) # minimal time skip (from last frame) because fatty has to get in that stupid word
((m_dist = 4.0)) # allowable distance between seconds before creating new cut, this should be a little more than reasonable
((cut_res = 30.0)) # trying hard to avoid video drifting, unironically doing more damage with more "bandaids" # bandages on my legs and my arms for you bandages bandages bandages
# ive never had such strong contempt in my life for something as (ironically) insignificant as a freaking adjective
# and its all because of you zoomer ******s, im on team flam now, oreo should neck
afix='pan=mono|c0=c0+c1,aresample=36k:async=0'
bthres='blend=difference,blackframe=94:38' # trailing 200ms visibility left with this
# cut processing literally zooms when video is disabled, like a zoomer.........
#echo "\x1b[91mKILL FFMPEG IF IT GETS STUCK, BECAUSE IT'S BAD SOFTWARE!!!!!!\x1b[0m"
alias readinto="read -r -d ''"
cut_fmt='silence \x1b[92m%9.3f\x1b[97m ==> \x1b[92m%9.3f\x1b[0m, \x1b[97mcut \x1b[96m%6.3fs\x1b[0m, \x1b[97mtotal\x1b[0m: \x1b[95m%8.3f\x1b[0m, \x1b[97mcuts\x1b[0m: \x1b[93m%4d\x1b[0m\n'
trap 'wait; exit 1;' TERM # don't have cuts print past termination # still happening i think...
((nick!=0)) && block=",drawbox=x=iw-w:y=ih-h+2:w=(iw*(1-0.66)):h=(ih*(1-0.5))+2:t=fill:c=red"
vd2='c:/program files (x86)/virtualdub/2/virtualdub64.exe'
for a in "$@"; do
[ ! -f "$a" ] && {
echo "Invalid or non-existent file: $a"
continue
}
date +'%F_%H-%M-%S.%3N' | readinto salt; salt="${salt//$cr/}"
salt="${salt//:/:}"
base="`ffprobe -hide_banner -i "$a" -show_streams -print_format json | jq -c --arg "fname" "$a" '{ sil: [], mas: [], str: .streams, fname: \$fname }'`"
jq -nr --argjson base "$base" 'first($base.str.[] | select(.codec_type == "video" and .disposition.attached_pic == 0)).index' | readinto v; v="${v//$cr/}"
jq -ne --argjson base "$base" --argjson i "$v" '$base.str[$i].codec_type != "video"' >/dev/null && {
echo 'This file does not have a video stream'
jq -n --indent 4 --argjson base "$base" '$base.str'
continue
}
cut_res="$(jq -bnr --argjson base "$base" --argjson i "$v" '$base.str[$i].r_frame_rate')" && \
echo "FPS eval: $cut_res" && cut_res=$(($cut_res)) || {
echo 'Something went wrong when parsing frame rate'
jq -n --indent 4 --argjson base "$base" '$base.str'
continue
}
scr="[0:a]$afix,$comp,silencedetect=n=$sthres:d=$sdur;"; sil=(); mas=(); tc=0.0 # total time cut
# disable if not skimming nick's vods
# 999999iq amogus: regex check to determine whose title is who's
# now that i think about it, graph time shouldnt be noticeable if printing is
# nonblocking, so it'll keep going while the read loop takes its sweet @$$ time....maybe...
# ...just going off the fact that processing doesn't pause when marking
if ((nick!=0)); then
scr+="[1][0:v]scale2ref[why1][trash1];[trash1][why1]$bthres"
why=( -i "$a" -stream_loop -1 -i 'A:/dummy_target.jpg')
else
#scr+="[1]nullsink"
why=(-vn -i "$a")
fi
((hate=cut_res*1000,cuts=0))
ffmpeg "${whywhy[@]}" -v info -nostats -ss $start "${why[@]}" -lavfi "$scr" \
-threads 13 -t $((4600.8 * speed)) -f null nul 2>&1 | while read -r i; do
# old: 96:32
if [[ "${i//$cr/}" =~ ${imark}${kv}${god}${god}${god}${god}${god} ]]; then
filt="${match[1]}"
#echo "--- $filt ---"
case "$filt" in
Parsed_blackframe_[0-9]*) ;&
silencedetect)
for ((y=0;y<6;y++)); do
((x=3+(y*4))); k="${match[x]}"; v="${match[++x]}"
[ -z "$k" ] && break; [ "$k" = 'silence_start' -o "$k" = 'frame' ] && temp=()
[[ "$k" = silence_* ]] && { # redundant
temp+=("[\"${k:8}\",$v]")
[ "$k" = silence_duration ] && {
(( cuts++ ))
jq -nc --argjson r "$srem" '$ARGS.positional | map({key: .[0], value: .[1]}) |
from_entries | . + {cut: ([$r,(.duration - $r)] | max)}' \
--jsonargs "${temp[@]}" | readinto test
[[ "$test" =~ '"cut":'([0-9]+(\.[0-9]+)?) ]] && ((tc+=(match[1]))) && (
cut=($(jq -bncr --argjson r "$srem" --argjson j "$test" '$j | [.start, .end, .cut] | join(" ")'))
printf "$cut_fmt" "${cut[@]}" "$tc" "$cuts"
) &
sil+=("${test//$cr/}")
}
continue
}
[[ "$filt" = Parsed_blackframe_[0-9]* ]] && {
[ "$k" = type ] && continue # THANKS STUPIDS
temp+=("{\"key\":\"$k\",\"value\":$v}")
[ "$k" = 'last_keyframe' ] && {
jq -nc '$ARGS.positional | from_entries' --jsonargs "${temp[@]}" | readinto test
jq -ncr '$j | "\u001b[97mBAD: \u001b[91m"+
(.t | strftime("%H:%M:%S.")+((.*$hate%$hate+$hate)|tostring|.[1:]))+
"\u001b[0m"' --argjson hate "$hate" --argjson j "$test" &
mas+=("${test//$cr/}")
}
continue
}
echo "?????: $k = $v"
done
;;
*) echo "Uncaught $filt: $MATCH"
;;
esac
else
if ! [[ "${i:l}" =~ ^(metadata|m(aj|in)or_|encoder|output \#|stream \#[0-9]:[0-9](\[[0-9]x[0-9]\([a-z]*\)\])?: [av]|duration: |handler_|vendor|compati) ]]; then
printf "\x1b[90m%s\x1b[0m\n" "${i//$cr/}"
fi
fi
done
why=(); (( nick != 0 )) && {
((s=-1,end=-1,m_dist*=hate))
jq -bnrc '$ARGS.positional | .[].t' --jsonargs "${mas[@]}" | while read -r t; do
((s<(t*=hate)-m_dist)) && {
((s!=-1)) && why+=("$s $e"); ((s=t))
}; ((e=t))
done; ((s!=-1)) && why+=("$s $e")
}
echo 'writing detected data'
jq -nc --argjson hate "$hate" --argjson r "$srem" --argjson j "$base" \
'$j|.sil = ($ARGS.positional | map([.start, .end, ([$r,.duration] | min/2)]))' --jsonargs "${sil[@]}" | \
jq -c --argjson hate "$hate" '.mas = ($ARGS.positional | map(. | split(" ") | map(.|tonumber/$hate)))' \
--args "${why[@]}" | tee "c:/skim_$salt.json" | readinto base; base="${base//$cr/}"
# could i possibly somehow merge below into above part
wait
echo 'generating cut points'; jq -ncr \
--argjson hate "$((hate/cut_res))" --argjson ml "$m_lead" --argjson mt "$m_trail" \
--argjson tb "$cut_res" --argjson j "$base" '($j | .sil | map(
[ (.[0] + .[2]), (.[1] - .[2]) ] | map((. * $tb | round / $tb) * $hate | floor / $hate)
) | . + ( $j | .mas | map( [ (.[0] - $ml), (.[1] + $mt) ] ) ) ) | flatten | sort_by(.) | # die
[ range(0; (length/2)) as $i | [ .[(2*$i)], .[(2*$i)+1] ] ]#[1:]
# i hate this language now, why cant this just be like actual javascript
' | tee | readinto trim # halve silence buffer time and distribute (forgot what to write for why...probably something about preserving a little more of the end sound and start of a new one)
# need to fix inverse ranges when srem < sdur
echo 'assembling script'
hack=("TOGGLE") # change to substring
# generative programming!!!
jq -nr --argjson t "$trim" --argjson s "$start" --argjson fps "$cut_res" '($t | flatten | [0]+.+[.[-1]+1] | map(.+$s) | # awful
[ range(0; (length/2)) as $i | [ .[(2*$i)], .[(2*$i)+1]-.[(2*$i)] ] ] | map(
"cuts.AddRange("+(. | to_entries | map(((((.value)*1000)|round/1000)*$fps|round)|tostring) | join(","))+");"
) | join("\n"))' | sed -e "/^\/\/ ${hack[nick]:-NOTOGGLE}/a vfilts.Add(\"fill\");\nvfilts.instance[3].Config(360,180,0,0,0x0000ff);" \
-e "/^cuts\.Clear()/r /dev/stdin" <(cat <<BASE_SCRIPT
declare aud; aud = VirtualDub.audio; declare afilts; afilts = aud.filters;
declare vid; vid = VirtualDub.video; declare vfilts; vfilts = vid.filters;
declare cuts; cuts = VirtualDub.subset;
declare argv; argv = VirtualDub.params;
VirtualDub.Close();
VirtualDub.Open(argv[0]);
// ----------
aud.SetSource(1);
aud.SetMode(1);
aud.SetEditMode(1);
aud.SetInterleave(1,500,1,0,0);
aud.SetClipMode(1,1);
aud.SetConversion(0,0,0,0,0);
aud.SetVolume();
aud.SetCompressionWithHint(65534,48000,2,0,18615,0,45,"wAMAAAAAlpmTVEn110Koc72wY4Xlnz1QAQBPcHVzSGVhZAECOAGAuwAAAAAA","ffmpeg_opus");
aud.SetCompData(16,"AAAAAAoAAABnbAEAAAAAAA==");
// ----------
vid.SetInputFormat(0);
vid.SetOutputFormat(0);
vid.SetMode(3);
vid.SetSmartRendering(0);
vid.SetPreserveEmptyFrames(0);
vid.SetCompression(0x30395056,0,10000,0,"avlib-1.vdplugin");
vid.SetCompData(20,"AAAAAAMAAAAIAAAAHwAAAAAAAAA=");
VirtualDub.SaveFormatAVI(); // ???
VirtualDub.SaveAudioFormat("");
VirtualDub.SaveFormat("ffmpeg", "webm"); // ???
// ----------
vfilts.BeginUpdate();
vfilts.Clear();
vfilts.Add("resize");
vfilts.instance[0].Config(640,360,0,4,3,1,320,240,4,3,0,4,1,0x000000);
vfilts.Add("logo");
vfilts.instance[1].Config(U"E:\kys_vd2.png", 4, 4, 0, 0, 0, 0, 39322);
vfilts.Add("DrawTime");
vfilts.instance[2].DataPrefix("75ae");
vfilts.instance[2].Config(4,4,0,0, 0xffffff, 0x000000, 0,24,400,0,"Gossix",1);
// TOGGLE!!!!!!!!
// ----------
cuts.Clear();
vfilts.EndUpdate();
// ----------
VirtualDub.ExportViaEncoderSet(argv[1], "_skim test");
//VirtualDub.SaveAVI(argv[1]);
BASE_SCRIPT
) > "c:\\skim_${salt}.vdscript"
# move base script here # jq -Rs ". | split(\"\n\")" <<HEREDOC
echo 'rendering'
# <s>SPEED UP USING MPC AUDIO RENDERER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</s> use external encoder
# TURNS OUT VIRTUALDUB SUCKS JUST AS WELL (pause)!!!!!!!!!!!!!!!!!!!!!!!
# NOW RENDER CUTS OFF AT 1H10M
# BREAKS ON THEBROKEN 3
# remove /x to get log # how do i even route the log to my terminal
"$vd2" /i "c:\\skim_${salt}.vdscript" "${a//\//\\}" "c:\\skim_$salt.webm" /x & #vd=$!
for (( i = 0; i < 4; i++ )); do
nircmdc win min etitle '(dub in progress)'
sleep 0.5
done
#wait $vd
done
#-ss "$start" -t "$limit" -i "$a" -loop 1 \
# -i 'C:\dummy_target.jpg' -i 'C:\dummy_target2.jpg' -lavfi "
# [0:a]$comp,silencedetect=n=-25dB:d=0.16,anullsink;
# [1][0:v]scale2ref[why1][trash1];
# [2][trash1]scale2ref[why2][trash2];
# [trash1][why1]$bthresh,nullsink;
# [trash2][why2]$bthresh
#" -f null nul 2>&1 | while read -r i; do
# USES 7 GB COMMIT JUST FOR A SECOND COMPARISON FRAME WTFFFFFFF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment