Created
June 8, 2017 02:11
-
-
Save missingno15/ad8e324895a4be9f01b96b085815f2a5 to your computer and use it in GitHub Desktop.
Mute the audio of certain parts of a video with ffmpeg via Ruby CLI script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "optparse" | |
require "active_support/all" | |
options = [] | |
input = nil | |
output = nil | |
has_two_timestamps= ->(arg) { | |
if arg.split(",").count == 2 | |
nil | |
else | |
"Needs to have two timestamps (e.g. '01:46:48,01:48:46')" | |
end | |
} | |
intervals_are_delimited_with_colons = ->(arg) { | |
start_interval, end_interval = arg.split(",") | |
if /\d{2}:\d{2}:\d{2}/.match?(start_interval.to_s) && /\d{2}:\d{2}:\d{2}/.match?(end_interval.to_s) | |
nil | |
else | |
"Intervals must be separated by colons (e.g. 01:48:46')" | |
end | |
} | |
intervals_have_proper_start_and_end = ->(arg) { | |
# start should not be greater than end | |
intervals = arg.split(",").map { |interval| interval.split(":") } | |
start_interval = intervals[0] || [] | |
end_interval = intervals[1] || [] | |
start_in_seconds = (start_interval[0].to_i.hours + start_interval[1].to_i.minutes + start_interval[2].to_i.seconds).to_i | |
end_in_seconds = (end_interval[0].to_i.hours + end_interval[1].to_i.minutes + end_interval[2].to_i.seconds).to_i | |
if start_in_seconds > end_in_seconds | |
nil | |
else | |
"The end interval must be greater than the start interval" | |
end | |
} | |
checks = [ | |
has_two_timestamps, | |
intervals_are_delimited_with_colons, | |
intervals_have_proper_start_and_end | |
] | |
option_parser = OptionParser.new do |opts| | |
opts.on("-t", "--interval INTERVAL", "Specify time interval to be muted") do |t| | |
# Check if interval is in the following format | |
# 1:46:48,1:48:46 | |
errors = checks.map { |check| check.call(t) }.compact | |
options << [t, errors] | |
end | |
opts.on("-i", "--input INPUT", "Name of the input file") do |i| | |
if o.empty? | |
fail "Input file must be provided" | |
else | |
input = i | |
end | |
end | |
opts.on("-o", "--output OUTPUT", "Name of the output file") do |o| | |
if o.empty? | |
fail "Output file must be provided" | |
else | |
output = o | |
end | |
end | |
end | |
option_parser.parse! | |
# See if there are any errors | |
option_errors = options.select { |interval| _t, errors = interval; errors.any? } | |
option_errors << ["", ["An input file was not detected"]] if input.nil? | |
option_errors << ["", ["An output file was not detected, you need to put an "]] if output.nil? | |
if option_errors.any? | |
puts "\n\n" | |
error_message = option_errors.inject("Some of the timestamps given were found to have the following errors:\n\n") do |message, interval| | |
timestamp, errors = interval | |
message << timestamp + "\n" | |
message << errors.join("\n") | |
message << "\n\n" | |
message | |
end | |
puts error_message | |
else | |
af = options.map do |set| | |
timestamps, _errors = set | |
start_time, end_time = timestamps.split(",").map { |timestamp| timestamp.split(":").map(&:to_i) } | |
start_time_in_seconds = start_time[0].hours + start_time[1].minutes + start_time[2].seconds | |
end_time_in_seconds = end_time[0].hours + end_time[1].minutes + end_time[2].seconds | |
"volume=enable='between(t,#{start_time_in_seconds},#{end_time_in_seconds})':volume=0" | |
end.join(", ") | |
# ffmpeg -i 20170608004526_SHOWROOM_AKB48のオールナイトニッポン.flv -af "volume=enable='between(t,1720, 1852)':volume=0, volume=enable='between(t,5822,5940)':volume=0, volume=enable='between(t,6479,6597)':volume=0, volume=enable='between(t,7964,8088)':volume=0" -vcodec copy 20170608004526_SHOWROOM_AKB48のオ ールナイトニッポンmaster.mp4 | |
`ffmpeg -i #{input} -af "#{af}" -vcodec copy #{output}` | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment