MAX_SPEED = 100 NORMAL_SPEED = 1 ONE_SECOND = 1 skip = false -- Max noise (dB) and min silence duration (s) to trigger opts = { quietness = -30, duration = 0.5 } function setOptions() local options = require 'mp.options' options.read_options(opts) end function setTime(time) mp.set_property_number('time-pos', time) end function getTime() return mp.get_property_native('time-pos') end function setSpeed(speed) mp.set_property('speed', speed) end function setPause(state) mp.set_property_bool('pause', state) end function setMute(state) mp.set_property_bool('mute', state) end function initAudioFilter() local af_table = mp.get_property_native('af') af_table[#af_table + 1] = { enabled = false, label = 'silencedetect', name = 'lavfi', params = { graph = 'silencedetect=noise=' .. opts.quietness .. 'dB:d=' .. opts.duration } } mp.set_property_native('af', af_table) end function initVideoFilter() local vf_table = mp.get_property_native('vf') vf_table[#vf_table + 1] = { enabled = false, label = 'blackout', name = 'lavfi', params = { graph = '' } } mp.set_property_native('vf', vf_table) end function setAudioFilter(state) local af_table = mp.get_property_native('af') if #af_table > 0 then for i = #af_table, 1, -1 do if af_table[i].label == 'silencedetect' then af_table[i].enabled = state mp.set_property_native('af', af_table) break end end end end function dim(state) local dim = { width = 0, height = 0 } if state == true then dim.width = mp.get_property_native('width') dim.height = mp.get_property_native('height') end return dim.width .. 'x' .. dim.height end function setVideoFilter(state) local vf_table = mp.get_property_native('vf') if #vf_table > 0 then for i = #vf_table, 1, -1 do if vf_table[i].label == 'blackout' then vf_table[i].enabled = state vf_table[i].params = { graph = 'nullsink,color=c=black:s=' .. dim(state) } mp.set_property_native('vf', vf_table) break end end end end function silenceTrigger(name, value) if value == '{}' or value == nil then return end local skipTime = tonumber(string.match(value, '%d+%.?%d+')) local currTime = getTime() if skipTime == nil or skipTime < currTime + ONE_SECOND then return end stopSkip() setTime(skipTime) skip = false end function setAudioTrigger(state) if state == true then mp.observe_property('af-metadata/silencedetect', 'string', silenceTrigger) else mp.unobserve_property(silenceTrigger) end end function startSkip() startTime = getTime() -- This audio filter detects moments of silence setAudioFilter(true) -- This video filter makes fast-forward faster setVideoFilter(true) setAudioTrigger(true) setPause(false) setMute(true) setSpeed(MAX_SPEED) end function stopSkip() setAudioFilter(false) setVideoFilter(false) setAudioTrigger(false) setMute(false) setSpeed(NORMAL_SPEED) end function keypress() skip = not skip if skip then startSkip() else stopSkip() setTime(startTime) end end setOptions(opts) initAudioFilter() initVideoFilter() mp.add_key_binding('Tab', 'skip-key', keypress)