viddl-rb 0.8 → 0.61

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt ADDED
@@ -0,0 +1,14 @@
1
+ === 0.6
2
+ * Soundcloud support
3
+ * Removed megavideo plugin
4
+
5
+ === 0.4.x
6
+ * New Features
7
+ * Use wget or curl (if present)
8
+
9
+ * Bugfixes
10
+ * Fixed Vimeo Plugin
11
+
12
+ === 0.3
13
+ * New Features
14
+ * added megavideo plugin
data/Gemfile.lock CHANGED
@@ -1,43 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- viddl-rb (0.79)
5
- mechanize
6
- nokogiri (~> 1.5.0)
7
- progressbar
4
+ viddl-rb (0.6)
5
+ nokogiri
8
6
 
9
7
  GEM
10
8
  remote: http://rubygems.org/
11
9
  specs:
12
- domain_name (0.5.12)
13
- unf (>= 0.0.5, < 1.0.0)
14
- http-cookie (1.0.1)
15
- domain_name (~> 0.5)
16
- mechanize (2.7.1)
17
- domain_name (~> 0.5, >= 0.5.1)
18
- http-cookie (~> 1.0.0)
19
- mime-types (~> 1.17, >= 1.17.2)
20
- net-http-digest_auth (~> 1.1, >= 1.1.1)
21
- net-http-persistent (~> 2.5, >= 2.5.2)
22
- nokogiri (~> 1.4)
23
- ntlm-http (~> 0.1, >= 0.1.1)
24
- webrobots (>= 0.0.9, < 0.2)
25
- mime-types (1.23)
26
- minitest (5.0.4)
27
- net-http-digest_auth (1.3)
28
- net-http-persistent (2.8)
29
- nokogiri (1.5.10)
30
- ntlm-http (0.1.1)
31
- progressbar (0.20.0)
32
- rake (10.0.4)
10
+ mime-types (1.17.2)
11
+ minitest (2.11.3)
12
+ nokogiri (1.5.0)
13
+ rake (0.9.2.2)
33
14
  rest-client (1.6.7)
34
15
  mime-types (>= 1.16)
35
- unf (0.1.1)
36
- unf_ext
37
- unf_ext (0.0.6)
38
- webrobots (0.1.1)
39
16
 
40
17
  PLATFORMS
18
+ java
41
19
  ruby
42
20
 
43
21
  DEPENDENCIES
data/README.md CHANGED
@@ -1,122 +1,34 @@
1
- __viddl-rb:__
2
- Initially created by Marc Seeger (@rb2k)
3
- Repo: http://github.com/rb2k/viddl-rb
4
- [![Gem Version](https://badge.fury.io/rb/viddl-rb.png)](http://badge.fury.io/rb/viddl-rb)[![Build Status](https://secure.travis-ci.org/rb2k/viddl-rb.png)](http://travis-ci.org/rb2k/viddl-rb) [![Dependency Status](https://gemnasium.com/rb2k/viddl-rb.png)](https://gemnasium.com/rb2k/viddl-rb)
5
-
6
- __Installation:__
7
-
8
- gem install viddl-rb
9
-
10
- __Usage:__
11
-
12
- Download a video:
13
- ```viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4```
14
-
15
- Viddl-rb supports the following command line options:
16
- ```
17
- -e, --extract-audio Save video audio to file
18
- -u, --url-only Prints url without downloading
19
- -t, --title-only Prints title without downloading
20
- -f, --filter REGEX Filters a video playlist according to the regex (Youtube only right now)
21
- -s, --save-dir DIRECTORY Specifies the directory where videos should be saved
22
- -d, --downloader TOOL Specifies the tool to download with. Supports 'wget', 'curl' and 'net-http'
23
- -q, --quality QUALITY Specifies the video format and resolution in the following way => resolution:extension (e.g. 720:mp4). Currently only supported by the Youtube plugin.
24
- -h, --help Displays the help screen
25
- ```
26
-
27
- Download a video and extract the audio:
28
- ```viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4 --extract-audio```
29
-
30
- In both cases we'll name the output file according to the video title.
31
-
32
- Setting the video save directory:
33
- ```viddl-rb http://vimeo.com/38372260 --save-dir C:/myvideos```
34
-
35
- The --save-dir option works with both absolute and relative paths (relative based on the directory viddl-rb is run from).
36
- If you want to save to a folder with spaces in it, you have to quote the path like this: --save-dir "C:/my videos"
37
-
38
- __Youtube plugin specifics:__
39
-
40
- Download all videos on a playlist:
41
- ```viddl-rb http://www.youtube.com/playlist?list=PL7E8DA0A515924126```
42
-
43
- Download all videos from a user:
44
- ```viddl-rb http://www.youtube.com/user/tedtalksdirector```
45
-
46
- Filter videos to download from a user/playlist:
47
- ```viddl-rb http://www.youtube.com/user/tedtalksdirector --filter /internet/i```
48
-
49
- The --filter argument accepts a regular expression and will only download videos where the title matches the regex.
50
- It uses the same syntax as Ruby regular expression literals do.
51
-
52
- __Library Usage:__
53
-
54
- ```ruby
55
- require 'viddl-rb'
56
-
57
- download_urls = ViddlRb.get_urls("http://www.youtube.com/watch?v=QH2-TGUlwu4")
58
- download_urls.first # => "http://o-o.preferred.arn06s04.v3.lscac ..."
59
- ```
60
-
61
- The ViddlRb module has the following module public methods:
62
-
63
- * __get_urls_names(url)__
64
- -- Returns an array of one or more hashes that has the keys :url which
65
- points to the download url and :name which points to the name
66
- (which is a filename safe version of the video title with a file extension).
67
- Returns nil if the url is not recognized by any plugins.
68
-
69
- * __get_urls_exts(url)__
70
- -- Same as get_urls_names but with just the file extension (for example ".mp4")
71
- instead of the full filename, and the :name key is replaced with :ext.
72
- Returns nil if the url is not recognized by any plugins.
73
-
74
- * __get_urls(url)__
75
- -- Returns an array of download urls for the specified video url.
76
- Returns nil if the url is not recognized by any plugins.
77
-
78
- * __get_names(url)__
79
- -- Returns an array of filenames for the specified video url.
80
- Returns nil if the url is not recognized by any plugins.
81
-
82
- * __io=(io_object)__
83
- -- By default all plugin output to stdout will be suppressed when the library is used.
84
- If you are interested in the output of a plugin, you can set an IO object that
85
- will receive all plugin output using this method. For example:
86
-
87
- ```ruby
88
- require 'viddl-rb'
89
-
90
- ViddlRb.io = $stdout # plugins will now write their output to $stdout
91
- ```
92
-
93
- All the __get__ methods in the ViddlRb module will raise either a ViddlRb::PluginError or a ViddlRb::DownloadError if the plugin fails.
94
- A ViddlRb::PluginError is raised if the plugin fails in an unexpected way, and a ViddlRb::DownloadError is raised if the video could not be downloaded for some reason.
95
- An example of that is if a Youtube video is not embeddable - then it can't be downloaded.
96
-
97
- ```ruby
98
- begin
99
- ViddlRb.get_urls(video_url)
100
- rescue ViddlRb::DownloadError => e
101
- puts "Could not get download url: #{e.message}"
102
- rescue ViddlRb::PluginError => e
103
- puts "Plugin blew up! #{e.message}\n" +
104
- "Backtrace:\n#{e.backtrace.join("\n")}"
105
- end
106
- ```
107
-
108
- __Requirements:__
109
-
110
- * curl/wget or the [progress bar](http://github.com/nex3/ruby-progressbar/) gem
111
- * [Nokogiri](http://nokogiri.org/)
112
- * [Mechanize](http://mechanize.rubyforge.org/)
113
- * ffmpeg if you want to extract audio tracks from the videos
114
-
115
- __Co Maintainer:__
116
- * [kl](https://github.com/kl): Windows support (who knew!), bug fixes, veoh plugin, metacafe plugin, refactoring it into a library, ...
117
-
118
- __Contributors:__
119
- * [divout](https://github.com/divout) aka Ivan K: blip.tv plugin, bugfixes
120
- * Sniper: bugfixes
121
- * [Serabe](https://github.com/Serabe) aka Sergio Arbeo: packaging viddl as a binary
122
- * [laserlemon](https://github.com/laserlemon): Adding gemnasium images to readme
1
+ __viddl-rb:__
2
+ Created by Marc Seeger (@rb2k)
3
+ Repo: http://github.com/rb2k/viddl-rb
4
+ [![Build Status](https://secure.travis-ci.org/rb2k/viddl-rb.png)](http://travis-ci.org/rb2k/viddl-rb)
5
+
6
+
7
+
8
+ __Installation:__
9
+ gem install viddl-rb
10
+
11
+ __Usage:__
12
+
13
+ Download a video:
14
+ viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4
15
+
16
+ Download a video and extract the audio:
17
+ viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4 --extract-audio
18
+
19
+ In both cases we'll name the output file according to the video title.
20
+
21
+
22
+ __Requirements:__
23
+
24
+ * curl/wget or the [progress bar](http://github.com/nex3/ruby-progressbar/) gem
25
+ * [Nokogiri](http://nokogiri.org/)
26
+ * ffmpeg if you want to extract audio tracks from the videos
27
+
28
+
29
+ __Contributors:__
30
+
31
+ * [kl](https://github.com/kl): Windows support (who knew!), bug fixes, veoh plugin, metacafe plugin
32
+ * [divout](https://github.com/divout) aka Ivan K: blip.tv plugin, bugfixes
33
+ * Sniper: bugfixes
34
+ * [Serabe](https://github.com/Serabe) aka Sergio Arbeo: packaging viddl as a binary
data/Rakefile CHANGED
@@ -1,22 +1,8 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
- require 'rake/testtask'
4
-
5
- task :default => [:test]
6
-
7
- Rake::TestTask.new(:test) do |t|
8
- #t.pattern = "spec/*_spec.rb"
9
- t.test_files = ["spec/lib_spec.rb", "spec/url_extraction_spec.rb", "spec/integration_spec.rb"]
10
- end
11
-
12
- Rake::TestTask.new(:test_lib) do |t|
13
- t.test_files = FileList["spec/lib_spec.rb"]
14
- end
15
-
16
- Rake::TestTask.new(:test_extract) do |t|
17
- t.test_files = FileList["spec/url_extraction_spec.rb"]
18
- end
19
-
20
- Rake::TestTask.new(:test_integration) do |t|
21
- t.test_files = FileList["spec/integration_spec.rb"]
22
- end
1
+ require 'rubygems'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = "spec/*_spec.rb"
8
+ end
data/bin/viddl-rb CHANGED
@@ -1,45 +1,117 @@
1
- #!/usr/bin/env ruby
2
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'helper') # general helpers
3
- $LOAD_PATH << File.join(File.dirname(__FILE__), 'helper') # bin-specific helpers
4
-
5
- require "rubygems"
6
- require "nokogiri"
7
- require "mechanize"
8
- require "cgi"
9
- require "open-uri"
10
- require "open3"
11
- require "optparse"
12
-
13
- require "driver.rb"
14
- require "downloader.rb"
15
- require "download-helper.rb"
16
- require "parameter-parser.rb"
17
- require "plugin-helper.rb"
18
- require "audio-helper.rb"
19
- require "utility-helper.rb"
20
-
21
- begin
22
- # params is a hash with keys for each of the parameters passed in.
23
- # see helper/parameter-parser.rb for what those keys are.
24
- params = ParameterParser.parse_app_parameters(ARGV)
25
-
26
- puts "Loading Plugins"
27
- ViddlRb::UtilityHelper.load_plugins
28
- puts "Plugins loaded: #{ViddlRb::PluginBase.registered_plugins.inspect}"
29
-
30
- puts "Will try to extract audio: #{params[:extract_audio] == true}."
31
- puts "Analyzing URL: #{params[:url]}"
32
-
33
- app = Driver.new(params)
34
- app.start # starts the download process
35
-
36
- rescue OptionParser::ParseError, ViddlRb::RequirementError => e
37
- puts "Error: #{e.message}"
38
- exit(1)
39
-
40
- rescue StandardError => e
41
- puts "Error: #{e.message}"
42
- puts "\nBacktrace:"
43
- puts e.backtrace
44
- exit(1)
45
- end
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'helper')
3
+
4
+ require "rubygems"
5
+ require "nokogiri"
6
+ require "cgi"
7
+ require "open-uri"
8
+ require "open3"
9
+ require "download-helper.rb"
10
+ require "plugin-helper.rb"
11
+
12
+ if ARGV[0].nil?
13
+ puts "Usage: viddl-rb URL [--extract-audio]"
14
+ exit
15
+ end
16
+
17
+ puts "Loading Plugins"
18
+ Dir[File.join(File.dirname(__FILE__),"../plugins/*.rb")].each do |plugin|
19
+ load plugin
20
+ end
21
+
22
+ puts "Plugins loaded: #{PluginBase.registered_plugins.inspect}"
23
+
24
+ url = ARGV[0]
25
+ extract_audio = ARGV.include?('--extract-audio')
26
+ url_only = ARGV.include?('--url-only')
27
+ title_only = ARGV.include?('--title-only')
28
+
29
+ puts "Will try to extract audio: #{extract_audio}."
30
+
31
+ unless url.match(/^http/)
32
+ puts "Please include 'http' with your URL e.g. http://www.youtube.com/watch?v=QH2-TGUlwu4"
33
+ exit(1)
34
+ end
35
+
36
+ puts "Analyzing URL: #{url}"
37
+ #Check all plugins for a match
38
+ PluginBase.registered_plugins.each do |plugin|
39
+ if plugin.matches_provider?(url)
40
+ puts "#{plugin}: true"
41
+ begin
42
+ #we'll end up with an array of hashes with they keys :url and :name
43
+ download_queue = plugin.get_urls_and_filenames(url)
44
+ rescue StandardError => e
45
+ puts "Error while running the #{plugin.name.inspect} plugin. Maybe it has to be updated? Error: #{e.message}."
46
+ exit(1)
47
+ end
48
+
49
+ if url_only
50
+ download_queue.each{|url_name| puts url_name[:url]}
51
+ exit
52
+ elsif title_only
53
+ download_queue.each{|url_name| puts url_name[:name]}
54
+ exit
55
+ end
56
+
57
+ download_queue.each do |url_name|
58
+ result = DownloadHelper.save_file(url_name[:url], url_name[:name])
59
+ if result
60
+ puts "Download for #{url_name[:name]} successful."
61
+ if extract_audio
62
+ puts "Extracting audio for #{url_name[:name]}"
63
+ if DownloadHelper.os_has?('ffmpeg')
64
+ no_ext_filename = url_name[:name].split('.')[0..-1][0]
65
+ #capture stderr because ffmpeg expects an output param and will error out
66
+ puts "Gathering information about the downloaded file."
67
+ file_info = Open3.popen3("ffmpeg -i #{url_name[:name]}") {|stdin, stdout, stderr, wait_thr| stderr.read }
68
+ puts "Done gathering information about the downloaded file."
69
+ if !file_info.to_s.empty?
70
+ audio_format_matches = file_info.match(/Audio: (\w*)/)
71
+ if audio_format_matches
72
+ audio_format = audio_format_matches[1]
73
+ puts "detected audio format: #{audio_format}"
74
+ else
75
+ puts "Couldn't find any audio:\n#{file_info.inspect}"
76
+ next
77
+ end
78
+
79
+ extension_mapper = {
80
+ 'aac' => 'm4a',
81
+ 'mp3' => 'mp3',
82
+ 'vorbis' => 'ogg'
83
+ }
84
+
85
+ if extension_mapper.key?(audio_format)
86
+ output_extension = extension_mapper[audio_format]
87
+ else
88
+ #lame fallback
89
+ puts "Unknown audio format: #{audio_format}, using name as extension: '.#{audio_format}'."
90
+ output_extension = audio_format
91
+ end
92
+ output_filename = "#{no_ext_filename}.#{output_extension}"
93
+ if File.exist?(output_filename)
94
+ puts "Audio file seems to exist already, removing it before extraction."
95
+ File.delete(output_filename)
96
+ end
97
+ Open3.popen3("ffmpeg -i #{url_name[:name]} -vn -acodec copy #{output_filename}") {|stdin, stdout, stderr, wait_thr| stdout.read }
98
+ puts "Done extracting audio to #{output_filename}"
99
+ else
100
+ puts "Error while checking audio track of #{url_name[:name]}"
101
+ end
102
+ else
103
+ puts "Didn't detect ffmpeg on your system, can't extract audio."
104
+ end
105
+ end
106
+ else
107
+ puts "Download for #{url_name[:name]} failed."
108
+ end
109
+ end
110
+ #plugin matched and downloaded, we're done
111
+ exit
112
+ else
113
+ puts "#{plugin}: false"
114
+ end
115
+ end
116
+
117
+ puts "No plugin seems to feel responsible for this URL."
@@ -1,94 +1,67 @@
1
- module ViddlRb
2
-
3
- class RequirementError < StandardError; end
4
-
5
- class DownloadHelper
6
-
7
- #viddl will use the first of these tools it finds on the system to download the video.
8
- #if the system does not have any of these tools, net/http is used instead.
9
- TOOLS_PRIORITY_LIST = [:wget, :curl]
10
-
11
- #simple helper that will save a file from the web and save it with a progress bar
12
- def self.save_file(file_url, file_name, opts = {})
13
- trap("SIGINT") { puts "goodbye"; exit }
14
-
15
- #default options
16
- options = {:save_dir => ".",
17
- :amount_of_retries => 6,
18
- :tool => get_tool}
19
-
20
- opts[:tool] = options[:tool] if opts[:tool].nil?
21
- options.merge!(opts)
22
-
23
- file_path = File.expand_path(File.join(options[:save_dir], file_name))
24
- success = false
25
-
26
- #Some providers seem to flake out every now end then
27
- options[:amount_of_retries].times do |i|
28
- case options[:tool].to_sym
29
- when :wget
30
- puts "Using wget"
31
- success = system "wget \"#{file_url}\" -O #{file_path.inspect}"
32
- when :curl
33
- puts "Using curl"
34
- #-L means: follow redirects, We set an agent because Vimeo seems to want one
35
- success = system "curl -A 'Wget/1.8.1' --retry 10 --retry-delay 5 --retry-max-time 4 -L \"#{file_url}\" -o #{file_path.inspect}"
36
- else
37
- require_progressbar
38
- puts "Using net/http"
39
- success = download_and_save_file(file_url, file_path)
40
- end
41
- #we were successful, we're outta here
42
- if success
43
- break
44
- else
45
- puts "Download seems to have failed (retrying, attempt #{i+1}/#{options[:amount_of_retries]})"
46
- sleep 2
47
- end
48
- end
49
- success
50
- end
51
-
52
- def self.get_tool
53
- tool = TOOLS_PRIORITY_LIST.find { |tool| ViddlRb::UtilityHelper.os_has?(tool) }
54
- tool || :net_http
55
- end
56
-
57
- def self.require_progressbar
58
- begin
59
- require "progressbar"
60
- rescue LoadError
61
- raise RequirementError,
62
- "you don't seem to have curl or wget on your system. In this case you'll need to install the 'progressbar' gem."
63
- end
64
- end
65
-
66
- # downloads and saves a file using the net/http streaming api
67
- # return true if the download was successful, else returns false
68
- def self.download_and_save_file(download_url, full_path)
69
- final_url = UtilityHelper.get_final_location(download_url) # follow all redirects
70
- uri = URI(final_url)
71
- file = File.new(full_path, "wb")
72
- file_size = 0
73
-
74
- Net::HTTP.start(uri.host, uri.port) do |http|
75
- http.request_get(uri.request_uri) do |res|
76
- file_size = res.read_header["content-length"].to_i
77
- bar = ProgressBar.new(File.basename(full_path), file_size)
78
- bar.file_transfer_mode
79
- res.read_body do |segment|
80
- bar.inc(segment.size)
81
- file.write(segment)
82
- end
83
- end
84
- end
85
- file.close
86
- print "\n"
87
- download_successful?(full_path, file_size) #because Net::HTTP.start does not throw Net exceptions
88
- end
89
-
90
- def self.download_successful?(full_file_path, file_size)
91
- File.exist?(full_file_path) && File.size(full_file_path) == file_size
92
- end
93
- end
94
- end
1
+ class DownloadHelper
2
+ #usually not called directly
3
+ def self.fetch_file(uri)
4
+
5
+ begin
6
+ require "progressbar" #http://github.com/nex3/ruby-progressbar
7
+ rescue LoadError
8
+ puts "ERROR: You don't seem to have curl or wget on your system. In this case you'll need to install the 'progressbar' gem."
9
+ exit
10
+ end
11
+ progress_bar = nil
12
+ open(uri, :proxy => nil,
13
+ :content_length_proc => lambda { |length|
14
+ if length && 0 < length
15
+ progress_bar = ProgressBar.new(uri.to_s, length)
16
+ end
17
+ },
18
+ :progress_proc => lambda { |progress|
19
+ progress_bar.set(progress) if progress_bar
20
+ }) {|file| return file.read}
21
+ end
22
+
23
+ #simple helper that will save a file from the web and save it with a progress bar
24
+ def self.save_file(file_uri, file_name)
25
+ unescaped_uri = CGI::unescape(file_uri)
26
+ result = false
27
+ if os_has?("wget")
28
+ puts "using wget"
29
+ result = system("wget \"#{unescaped_uri}\" -O #{file_name}")
30
+ elsif os_has?("curl")
31
+ puts "using curl"
32
+ #-L means: follow redirects, We set an agent because Vimeo seems to want one
33
+ result = system("curl -A 'Wget/1.8.1' -L \"#{unescaped_uri}\" -o #{file_name}")
34
+ else
35
+ puts "using net/http"
36
+ open(file_name, 'wb') { |file|
37
+ file.write(fetch_file(unescaped_uri)); puts
38
+ }
39
+ result = true
40
+ end
41
+ result
42
+ end
43
+
44
+ #checks to see whether the os has a certain utility like wget or curl
45
+ def self.os_has?(utility)
46
+ windows = ENV['OS'] =~ /windows/i
47
+ return `which #{utility}`.include?(utility) unless windows # if not Windows
48
+
49
+ #use where (simliar to which) if present to reduce console clutter
50
+ begin
51
+ has_where? ? `where #{utility}` : `#{utility}`
52
+ return true
53
+ rescue Errno::ENOENT
54
+ return false
55
+ end
56
+ end
57
+
58
+ #checks if Windows has the where utility (Server 2003 and later)
59
+ def self.has_where?
60
+ begin
61
+ `where`
62
+ true
63
+ rescue Errno::ENOENT
64
+ false
65
+ end
66
+ end
67
+ end