viddl-rb 0.73 → 0.74
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -6
- data/bin/helper/downloader.rb +1 -6
- data/bin/helper/parameter-parser.rb +14 -6
- data/bin/viddl-rb +2 -2
- data/helper/download-helper.rb +72 -35
- data/helper/utility-helper.rb +11 -2
- data/lib/viddl-rb.rb +1 -11
- metadata +19 -5
data/README.md
CHANGED
@@ -10,7 +10,7 @@ gem install viddl-rb
|
|
10
10
|
__Usage:__
|
11
11
|
|
12
12
|
Download a video:
|
13
|
-
viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4
|
13
|
+
```viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4```
|
14
14
|
|
15
15
|
Viddl-rb supports the following command line options:
|
16
16
|
```
|
@@ -19,16 +19,17 @@ Viddl-rb supports the following command line options:
|
|
19
19
|
-t, --title-only Prints title without downloading
|
20
20
|
-f, --filter REGEX Filters a video playlist according to the regex (Youtube only right now)
|
21
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'
|
22
23
|
-h, --help Displays the help screen
|
23
24
|
```
|
24
25
|
|
25
26
|
Download a video and extract the audio:
|
26
|
-
viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4 --extract-audio
|
27
|
+
```viddl-rb http://www.youtube.com/watch?v=QH2-TGUlwu4 --extract-audio```
|
27
28
|
|
28
29
|
In both cases we'll name the output file according to the video title.
|
29
30
|
|
30
31
|
Setting the video save directory:
|
31
|
-
viddl-rb http://vimeo.com/38372260 --save-dir C:/myvideos
|
32
|
+
```viddl-rb http://vimeo.com/38372260 --save-dir C:/myvideos```
|
32
33
|
|
33
34
|
The --save-dir option works with both absolute and relative paths (relative based on the directory viddl-rb is run from).
|
34
35
|
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"
|
@@ -36,13 +37,13 @@ If you want to save to a folder with spaces in it, you have to quote the path li
|
|
36
37
|
__Youtube plugin specifics:__
|
37
38
|
|
38
39
|
Download all videos on a playlist:
|
39
|
-
viddl-rb http://www.youtube.com/playlist?list=PL7E8DA0A515924126
|
40
|
+
```viddl-rb http://www.youtube.com/playlist?list=PL7E8DA0A515924126```
|
40
41
|
|
41
42
|
Download all videos from a user:
|
42
|
-
viddl-rb http://www.youtube.com/user/tedtalksdirector
|
43
|
+
```viddl-rb http://www.youtube.com/user/tedtalksdirector```
|
43
44
|
|
44
45
|
Filter videos to download from a user/playlist:
|
45
|
-
viddl-rb http://www.youtube.com/user/tedtalksdirector --filter /internet/i
|
46
|
+
```viddl-rb http://www.youtube.com/user/tedtalksdirector --filter /internet/i```
|
46
47
|
|
47
48
|
The --filter argument accepts a regular expression and will only download videos where the title matches the regex.
|
48
49
|
It uses the same syntax as Ruby regular expression literals do.
|
data/bin/helper/downloader.rb
CHANGED
@@ -8,7 +8,7 @@ class Downloader
|
|
8
8
|
url = url_name[:url]
|
9
9
|
name = url_name[:name]
|
10
10
|
|
11
|
-
result = save_file(url, name, params[:save_dir])
|
11
|
+
result = ViddlRb::DownloadHelper.save_file(url, name, :save_dir => params[:save_dir], :tool => params[:tool])
|
12
12
|
unless result
|
13
13
|
raise DownloadFailedError, "Download for #{name} failed."
|
14
14
|
else
|
@@ -17,9 +17,4 @@ class Downloader
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
# TODO save_dir is not used yet
|
22
|
-
def save_file(url, name, save_dir)
|
23
|
-
ViddlRb::DownloadHelper.save_file(url, name, save_dir)
|
24
|
-
end
|
25
20
|
end
|
@@ -22,7 +22,8 @@ class ParameterParser
|
|
22
22
|
:url_only => false,
|
23
23
|
:title_only => false,
|
24
24
|
:playlist_filter => nil,
|
25
|
-
:save_dir => DEFAULT_SAVE_DIR
|
25
|
+
:save_dir => DEFAULT_SAVE_DIR,
|
26
|
+
:tool => nil
|
26
27
|
}
|
27
28
|
|
28
29
|
optparse = OptionParser.new do |opts|
|
@@ -56,6 +57,14 @@ class ParameterParser
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
60
|
+
opts.on("-d", "--downloader TOOL", "Specifies the tool to download with. Supports 'wget', 'curl' and 'net-http'") do |tool|
|
61
|
+
if tool =~ /(^wget$)|(^curl$)|(^net-http$)/
|
62
|
+
options[:tool] = tool
|
63
|
+
else
|
64
|
+
raise OptionParser::InvalidArgument.new("'#{tool}' is not a valid tool.")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
59
68
|
opts.on_tail('-h', '--help', 'Display this screen') do
|
60
69
|
print_help_and_exit(opts)
|
61
70
|
end
|
@@ -63,7 +72,8 @@ class ParameterParser
|
|
63
72
|
|
64
73
|
optparse.parse!(args) # removes all options from args
|
65
74
|
print_help_and_exit(optparse) if args.empty? # exit if no video url
|
66
|
-
url =
|
75
|
+
url = args.first # the url is the only element left
|
76
|
+
validate_url!(url) # raise exception if invalid url
|
67
77
|
options[:url] = url
|
68
78
|
options
|
69
79
|
end
|
@@ -73,10 +83,8 @@ class ParameterParser
|
|
73
83
|
exit(0)
|
74
84
|
end
|
75
85
|
|
76
|
-
def self.validate_url(url)
|
77
|
-
|
78
|
-
url
|
79
|
-
else
|
86
|
+
def self.validate_url!(url)
|
87
|
+
unless url =~ /^http/
|
80
88
|
raise OptionParser::InvalidArgument.new(
|
81
89
|
"please include 'http' with your URL e.g. http://www.youtube.com/watch?v=QH2-TGUlwu4")
|
82
90
|
end
|
data/bin/viddl-rb
CHANGED
@@ -25,7 +25,7 @@ begin
|
|
25
25
|
|
26
26
|
puts "Loading Plugins"
|
27
27
|
ViddlRb::UtilityHelper.load_plugins
|
28
|
-
"Plugins loaded: #{ViddlRb::PluginBase.registered_plugins.inspect}"
|
28
|
+
puts "Plugins loaded: #{ViddlRb::PluginBase.registered_plugins.inspect}"
|
29
29
|
|
30
30
|
puts "Will try to extract audio: #{params[:extract_audio] == true}."
|
31
31
|
puts "Analyzing URL: #{params[:url]}"
|
@@ -33,7 +33,7 @@ begin
|
|
33
33
|
app = Driver.new(params)
|
34
34
|
app.start # starts the download process
|
35
35
|
|
36
|
-
rescue OptionParser::ParseError => e
|
36
|
+
rescue OptionParser::ParseError, ViddlRb::RequirementError => e
|
37
37
|
puts "Error: #{e.message}"
|
38
38
|
exit(1)
|
39
39
|
|
data/helper/download-helper.rb
CHANGED
@@ -1,57 +1,94 @@
|
|
1
1
|
module ViddlRb
|
2
2
|
|
3
|
+
class RequirementError < StandardError; end
|
4
|
+
|
3
5
|
class DownloadHelper
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
rescue LoadError
|
9
|
-
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."
|
10
|
-
exit
|
11
|
-
end
|
12
|
-
progress_bar = nil
|
13
|
-
open(uri, :proxy => nil,
|
14
|
-
:content_length_proc => lambda { |length|
|
15
|
-
if length && 0 < length
|
16
|
-
progress_bar = ProgressBar.new(uri.to_s, length)
|
17
|
-
progress_bar.file_transfer_mode #to show download speed and file size
|
18
|
-
end
|
19
|
-
},
|
20
|
-
:progress_proc => lambda { |progress|
|
21
|
-
progress_bar.set(progress) if progress_bar
|
22
|
-
}) {|file| return file.read}
|
23
|
-
end
|
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]
|
24
10
|
|
25
11
|
#simple helper that will save a file from the web and save it with a progress bar
|
26
|
-
def self.save_file(
|
12
|
+
def self.save_file(file_url, file_name, opts = {})
|
27
13
|
trap("SIGINT") { puts "goodbye"; exit }
|
28
14
|
|
29
|
-
|
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
|
+
|
30
26
|
#Some providers seem to flake out every now end then
|
31
|
-
amount_of_retries.times do |i|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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"
|
37
34
|
#-L means: follow redirects, We set an agent because Vimeo seems to want one
|
38
|
-
|
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}"
|
39
36
|
else
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
37
|
+
require_progressbar
|
38
|
+
puts "Using net/http"
|
39
|
+
success = download_and_save_file(file_url, file_path)
|
44
40
|
end
|
45
41
|
#we were successful, we're outta here
|
46
|
-
if
|
42
|
+
if success
|
47
43
|
break
|
48
44
|
else
|
49
45
|
puts "Download seems to have failed (retrying, attempt #{i+1}/#{amount_of_retries})"
|
50
46
|
sleep 2
|
51
47
|
end
|
52
48
|
end
|
53
|
-
|
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
|
54
55
|
end
|
55
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
|
56
93
|
end
|
57
94
|
end
|
data/helper/utility-helper.rb
CHANGED
@@ -18,7 +18,7 @@ module ViddlRb
|
|
18
18
|
windows = ENV['OS'] =~ /windows/i
|
19
19
|
|
20
20
|
unless windows
|
21
|
-
`which #{utility}`.include?(utility)
|
21
|
+
`which #{utility}`.include?(utility.to_s)
|
22
22
|
else
|
23
23
|
if !system("where /q where").nil? #if Windows has the where utility
|
24
24
|
system("where /q #{utility}") #/q is the quiet mode flag
|
@@ -31,6 +31,15 @@ module ViddlRb
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
|
+
#recursively get the final location (after following all redirects) for an url.
|
36
|
+
def self.get_final_location(url)
|
37
|
+
Net::HTTP.get_response(URI(url)) do |res|
|
38
|
+
location = res["location"]
|
39
|
+
return url if location.nil?
|
40
|
+
return get_final_location(location)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
35
44
|
end
|
36
45
|
end
|
data/lib/viddl-rb.rb
CHANGED
@@ -95,19 +95,9 @@ module ViddlRb
|
|
95
95
|
def self.follow_all_redirects(urls_filenames)
|
96
96
|
urls_filenames.map do |uf|
|
97
97
|
url = uf[:url]
|
98
|
-
final_location = get_final_location(url)
|
98
|
+
final_location = UtilityHelper.get_final_location(url)
|
99
99
|
{:url => final_location, :name => uf[:name]}
|
100
100
|
end
|
101
101
|
end
|
102
102
|
private_class_method :follow_all_redirects
|
103
|
-
|
104
|
-
#recursively get the final location (after following all redirects) for an url.
|
105
|
-
def self.get_final_location(url)
|
106
|
-
Net::HTTP.get_response(URI(url)) do |res|
|
107
|
-
location = res["location"]
|
108
|
-
return url if location.nil?
|
109
|
-
return get_final_location(location)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
private_class_method :get_final_location
|
113
103
|
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: viddl-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 159
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 74
|
9
|
+
version: "0.74"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Marc Seeger
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-10-
|
17
|
+
date: 2012-10-07 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -87,7 +87,21 @@ dependencies:
|
|
87
87
|
version: "0"
|
88
88
|
type: :development
|
89
89
|
version_requirements: *id005
|
90
|
-
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: progressbar
|
92
|
+
prerelease: false
|
93
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id006
|
104
|
+
description: An extendable commandline video downloader for flash video sites. Includes plugins for vimeo, youtube, dailymotion and more
|
91
105
|
email: mail@marc-seeger.de
|
92
106
|
executables:
|
93
107
|
- viddl-rb
|