Skip to content

Instantly share code, notes, and snippets.

@arirusso
Forked from marcel/gist:2100703
Created April 23, 2012 19:52
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arirusso/2473383 to your computer and use it in GitHub Desktop.
Save arirusso/2473383 to your computer and use it in GitHub Desktop.
vidsampler – extract audio samples from online video
#!/usr/bin/env ruby
#
# vidsampler – extract audio samples from online video
#
# for OSX only
#
# Usage:
#
# ruby vidsampler.rb [youtube url] [minute:second] [duration]
#
# ex.
#
# ruby vidsampler.rb 'http://www.youtube.com/watch?v=LBRy4HfDuxc' 0:20 5
#
# will output
#
# LBRy4HfDuxc.mp3
#
# which is a 5 second, 256 constant bitrate mp3 in the current directory
#
# if you don't have lame installed, only wav files will be outputted
# http://wiki.audacityteam.org/index.php?title=Lame_Installation#Mac_Instructions
#
# options:
#
# -c [num] - a constant bitrate value for the mp3 (eg 320)
# -V [num] - a variable bitrate value for the mp3 (eg 1)
# -o [filename] - an output filename/path. if the filename has a .wav extension,
# a wav file will be outputted and any bitrate settings disregarded
#
#
END {
if __FILE__ == $0
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: sampletube.rb [youtube url] [minute:second] [duration] [options]"
opts.on("-b", "--cbr NUM", Integer, "constant bitrate") do |rate|
options[:bitrate_type] = :constant
options[:bitrate] = rate
end
opts.on("-o", "--output-file NAME", String, "output file") do |file|
options[:output_file] = file
end
opts.on("-V", "--vbr NUM", Integer, "variable bitrate") do |rate|
options[:bitrate_type] = :variable
options[:bitrate] = rate
end
end.parse!
url, start_time, duration = *ARGV
output = SampleGenerator.generate({
:source_file => VideoDownloader.download(url).download_path,
:start_time => start_time,
:duration => duration
}.merge(options))
puts "Sample: #{output}"
end
}
require "optparse"
require "uri"
class CommandLineUtility
def self.path
new.path
end
def initialize
install unless installed?
end
end
class YoutubeDLCommandLineUtility < CommandLineUtility
INSTALL_PATH = "/tmp/youtube-dl"
INSTALL_URL = 'https://raw.github.com/rg3/youtube-dl/2012.02.27/youtube-dl'
def installed?
File.exists?(INSTALL_PATH) || (%x|which youtube-dl| && $?.success?)
end
def path
if File.exists?(INSTALL_PATH)
INSTALL_PATH
else
%x|which youtube-dl|.chomp
end
end
def install
%x|curl '#{INSTALL_URL}' > #{INSTALL_PATH}|
%x|chmod +x #{INSTALL_PATH}|
end
end
class MplayerCommandLineUtility < CommandLineUtility
INSTALL_URL = 'http://mplayerosxext.googlecode.com/files/MPlayer-OSX-Extended_rev14.zip'
DOWNLOAD_PATH = '/tmp/mplayer.zip'
EXECUTABLE = "/tmp/MPlayer OSX Extended.app/Contents/" +
"Resources/Binaries/mpextended.mpBinaries/" +
"Contents/mpextended.mpBinaries/Contents/MacOS/mplayer"
def installed?
File.exists?(EXECUTABLE) || (%x|which mplayer| && $?.success?)
end
def path
if File.exists?(EXECUTABLE)
EXECUTABLE
else
%x|which mplayer|.chomp
end
end
def install
%x|curl '#{INSTALL_URL}' > #{DOWNLOAD_PATH}| unless File.exists?(DOWNLOAD_PATH)
Dir.chdir('/tmp') do
%x|unzip #{DOWNLOAD_PATH}|
end
end
end
class VideoDownloader
DOWNLOAD_PATH = '/tmp'
attr_reader :url
def self.download(url)
downloader = new(url)
downloader.download
downloader
end
def initialize(url)
@url = URI.parse(url)
ensure_url_is_valid
end
def id
@id ||= query_string['v']
end
def download
system("#{youtube_dl} -o #{download_path} '#{url}'")
end
def youtube_dl
YoutubeDLCommandLineUtility.path
end
def download_path
File.join(DOWNLOAD_PATH, target_file_name)
end
private
def target_file_name
"#{id}.flv"
end
def ensure_url_is_valid
if id.nil?
raise ArgumentError, "YouTube url '#{url}' doesn't include video identifier"
end
end
def query_string
@query_string ||= url.query.split('&').inject({}) do |params, param|
key, value = param.split('=')
params[key] = value
params
end
end
end
class SampleGenerator
attr_reader :source_file, :start_time, :duration
def self.generate(configuration)
generator = new(configuration)
generator.generate
end
def initialize(configuration)
@source_file = configuration[:source_file]
@start_time = configuration[:start_time]
@duration = configuration[:duration]
@bitrate = configuration[:bitrate] || 256
@bitrate_type = configuration[:bitrate_type] || :constant
@output_file = configuration[:output_file]
end
def generate
%x{'#{mplayer}' -nocorrect-pts -ao pcm:file=#{wav_output_path} -vo null -vc null #{source_file} -ss #{start_time} -endpos #{duration}}
if !asking_for_wav? && has_lame?
AudioConverter.process(wav_output_path, mp3_output_path, { @bitrate_type => @bitrate })
%x{rm #{wav_output_path}}
mp3_output_path
else
wav_output_path
end
end
def mplayer
MplayerCommandLineUtility.path
end
def mp3_output_path
@output_file.nil? ? "#{basename}.mp3" : @output_file
end
def wav_output_path
asking_for_wav? ? @output_file : "#{basename}.wav"
end
private
def basename
File.basename(source_file, '.*')
end
def has_lame?
(%x|which lame| && $?.success?)
end
def asking_for_wav?
!@output_file.nil? && @output_file.split(/\./).last.to_s.downcase == "wav"
end
end
class AudioConverter
def self.process(input, output, bitrate)
converter = new(input, output, bitrate)
converter.process
end
def initialize(input, output, bitrate)
@bitrate = bitrate
@input = input
@output = output
end
def process
%x{'lame' "#{@input}" #{args}}
end
private
def args
"#{bitrate_as_args} #{output_as_args}"
end
def output_as_args
"-o #{@output}"
end
def bitrate_as_args
key, val = *@bitrate.to_a.first
case key
when :constant then "-b #{val}"
when :variable then "-V #{val}"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment