viddl-rb 0.8 → 0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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