├── LICENSE ├── README.md └── skip-intro.lua /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Arthur Jochems 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # skip-intro.lua 2 | 3 | This script skips to the next moment of silence in the video. The intended use for this is to skip until the end of an opening sequence, at which point there's often a short period of silence. 4 | 5 | ## Setup 6 | Install [mpv media player](https://mpv.io/ "mpv-link"). 7 | 8 | Download **skip-intro.lua** and save it to `mpv/scripts/`. 9 | 10 | The default keybind to *start/stop* skipping is `Tab`.
11 | You can change this by adding to `mpv/input.conf` the following line: 12 | ``` 13 | NEW_KEY script-binding skip-key 14 | ``` 15 | 16 | To tweak the script's parameters you can copy the following code to `mpv/script-opts/skip-intro.conf`: 17 | ``` 18 | # Maximum noise (dB) to trigger 19 | quietness = -30 20 | 21 | # Minimum silence duration (s) to trigger 22 | duration = 0.5 23 | ``` 24 | -------------------------------------------------------------------------------- /skip-intro.lua: -------------------------------------------------------------------------------- 1 | MAX_SPEED = 100 2 | NORMAL_SPEED = 1 3 | ONE_SECOND = 1 4 | skip = false 5 | -- Max noise (dB) and min silence duration (s) to trigger 6 | opts = { quietness = -30, duration = 0.5 } 7 | 8 | 9 | function setOptions() 10 | local options = require 'mp.options' 11 | options.read_options(opts) 12 | end 13 | 14 | function setTime(time) 15 | mp.set_property_number('time-pos', time) 16 | end 17 | 18 | function getTime() 19 | return mp.get_property_native('time-pos') 20 | end 21 | 22 | function setSpeed(speed) 23 | mp.set_property('speed', speed) 24 | end 25 | 26 | function setPause(state) 27 | mp.set_property_bool('pause', state) 28 | end 29 | 30 | function setMute(state) 31 | mp.set_property_bool('mute', state) 32 | end 33 | 34 | function initAudioFilter() 35 | local af_table = mp.get_property_native('af') 36 | af_table[#af_table + 1] = { 37 | enabled = false, 38 | label = 'silencedetect', 39 | name = 'lavfi', 40 | params = { graph = 'silencedetect=noise=' .. opts.quietness .. 'dB:d=' .. opts.duration } 41 | } 42 | mp.set_property_native('af', af_table) 43 | end 44 | 45 | function initVideoFilter() 46 | local vf_table = mp.get_property_native('vf') 47 | vf_table[#vf_table + 1] = { 48 | enabled = false, 49 | label = 'blackout', 50 | name = 'lavfi', 51 | params = { graph = '' } 52 | } 53 | mp.set_property_native('vf', vf_table) 54 | end 55 | 56 | function setAudioFilter(state) 57 | local af_table = mp.get_property_native('af') 58 | if #af_table > 0 then 59 | for i = #af_table, 1, -1 do 60 | if af_table[i].label == 'silencedetect' then 61 | af_table[i].enabled = state 62 | mp.set_property_native('af', af_table) 63 | break 64 | end 65 | end 66 | end 67 | end 68 | 69 | function dim(state) 70 | local dim = { width = 0, height = 0 } 71 | if state == true then 72 | dim.width = mp.get_property_native('width') 73 | dim.height = mp.get_property_native('height') 74 | end 75 | return dim.width .. 'x' .. dim.height 76 | end 77 | 78 | function setVideoFilter(state) 79 | local vf_table = mp.get_property_native('vf') 80 | if #vf_table > 0 then 81 | for i = #vf_table, 1, -1 do 82 | if vf_table[i].label == 'blackout' then 83 | vf_table[i].enabled = state 84 | vf_table[i].params = { graph = 'nullsink,color=c=black:s=' .. dim(state) } 85 | mp.set_property_native('vf', vf_table) 86 | break 87 | end 88 | end 89 | end 90 | end 91 | 92 | function silenceTrigger(name, value) 93 | if value == '{}' or value == nil then 94 | return 95 | end 96 | 97 | local skipTime = tonumber(string.match(value, '%d+%.?%d+')) 98 | local currTime = getTime() 99 | 100 | if skipTime == nil or skipTime < currTime + ONE_SECOND then 101 | return 102 | end 103 | 104 | stopSkip() 105 | setTime(skipTime) 106 | skip = false 107 | end 108 | 109 | function setAudioTrigger(state) 110 | if state == true then 111 | mp.observe_property('af-metadata/silencedetect', 'string', silenceTrigger) 112 | else 113 | mp.unobserve_property(silenceTrigger) 114 | end 115 | end 116 | 117 | function startSkip() 118 | startTime = getTime() 119 | -- This audio filter detects moments of silence 120 | setAudioFilter(true) 121 | -- This video filter makes fast-forward faster 122 | setVideoFilter(true) 123 | setAudioTrigger(true) 124 | setPause(false) 125 | setMute(true) 126 | setSpeed(MAX_SPEED) 127 | end 128 | 129 | function stopSkip() 130 | setAudioFilter(false) 131 | setVideoFilter(false) 132 | setAudioTrigger(false) 133 | setMute(false) 134 | setSpeed(NORMAL_SPEED) 135 | end 136 | 137 | function keypress() 138 | skip = not skip 139 | if skip then 140 | startSkip() 141 | else 142 | stopSkip() 143 | setTime(startTime) 144 | end 145 | end 146 | 147 | setOptions(opts) 148 | initAudioFilter() 149 | initVideoFilter() 150 | 151 | mp.add_key_binding('Tab', 'skip-key', keypress) 152 | --------------------------------------------------------------------------------