/ youtube-snarf-audio
youtube-snarf-audio
 1  #!/usr/bin/env ruby
 2  #
 3  # youtube-snarf-audio - Extract audio from YouTube videos
 4  #
 5  # Downloads YouTube videos and extracts audio to m4a format.
 6  # Accepts YouTube URLs or just video IDs as arguments.
 7  # Skips audio extraction if output file already exists.
 8  #
 9  # Usage: youtube-snarf-audio <youtube-url> [<youtube-url> ...]
10  #
11  # Examples:
12  #   youtube-snarf-audio https://youtube.com/watch?v=abc123
13  #   youtube-snarf-audio abc123
14  #
15  # Requires: youtube-dl, ffmpeg
16  
17  require 'cgi'
18  require 'faraday'
19  require 'rack'
20  require 'uri'
21  
22  def main
23    while youtube_url = ARGV.shift
24      puts ">>> Snarfing audio from #{youtube_url}..."
25      if YouTubeSnarfer.snarf(youtube_url)
26        sleep 60
27      end
28    end
29  end
30  
31  class YouTubeSnarfer
32  
33    attr_reader :url, :video_filename
34  
35    def self.snarf(url)
36      new(url).snarf
37    end
38  
39    def initialize(url)
40      @url = url
41      unless @url =~ /^http/
42        @url = "http://youtube.com/watch?v=#{@url}"
43      end
44    end
45  
46    def snarf
47      encode_audio
48    end
49  
50    def title
51      video_filename.sub(/\s*-\w+.mp4\s*$/, '')
52    end
53  
54    def audio_filename
55      "#{title}.m4a"
56    end
57  
58    def encode_audio
59      save_video
60      if File.exists?(audio_filename)
61        puts ">>> Skipping, #{audio_filename} already exists. Delete it if you want to re-extract the audio."
62        return false
63      end
64      cmd = "ffmpeg -i '#{video_filename}' -vn -acodec copy '#{audio_filename}'"
65      IO.popen(cmd) do |io|
66        io.each_line do |line|
67          puts line
68        end
69      end
70      true
71    end
72  
73    def save_video
74      IO.popen("youtube-dl #{url}") do |io|
75        io.each_line do |line|
76          puts line
77  
78          if line =~ /^\[download\] /
79            @video_filename =
80              if line =~ /Destination:/
81                line.split(': ').last
82              else
83                line.sub('[download] ', '').sub(' has already been downloaded', '')
84              end.sub(/[\s\r\n]*$/, '')
85          end
86        end
87      end
88    end
89  
90  end
91  
92  main if $0 == __FILE__