youtube-dl.rb 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/lib/youtube-dl.rb +21 -8
- data/lib/youtube-dl/options.rb +7 -4
- data/lib/youtube-dl/output.rb +51 -0
- data/lib/youtube-dl/runner.rb +27 -48
- data/lib/youtube-dl/support.rb +21 -1
- data/lib/youtube-dl/version.rb +1 -1
- data/lib/youtube-dl/video.rb +60 -0
- data/test/test_helper.rb +1 -1
- data/test/youtube-dl/options_test.rb +105 -51
- data/test/youtube-dl/output_test.rb +100 -0
- data/test/youtube-dl/runner_test.rb +46 -53
- data/test/youtube-dl/support_test.rb +22 -0
- data/test/youtube-dl/video_test.rb +89 -0
- data/test/youtube-dl_test.rb +84 -0
- data/youtube-dl.rb.gemspec +1 -0
- metadata +24 -4
- data/test/youtube-dl/youtube-dl_test.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c86f76bf2febd54113c84142274c4c496855ebf
|
4
|
+
data.tar.gz: 0da55077bb17767338d0bde1ae75ed1fc1d9e78d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef750607464a9a53882193569508b45b5f59d9b8c60fa30166bcded52a7a4ef1ae46223849aded5de47cbef64960a4958c78591d15528a46971465ca5d545d7a
|
7
|
+
data.tar.gz: b18889569bf6401ee10bffc6edab536d0f066cd3379cd487b65f2038b743ec1a7509f333e01c492d0dd81791df8c070d53e7b4de9dc9eb1a967d292b8ef0cc2d
|
data/lib/youtube-dl.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'youtube-dl/version'
|
2
2
|
require 'youtube-dl/support'
|
3
3
|
require 'youtube-dl/options'
|
4
|
+
require 'youtube-dl/output'
|
4
5
|
require 'youtube-dl/runner'
|
6
|
+
require 'youtube-dl/video'
|
5
7
|
|
6
8
|
module YoutubeDL
|
7
9
|
extend self
|
@@ -12,22 +14,33 @@ module YoutubeDL
|
|
12
14
|
# @param urls [String, Array] URLs to download
|
13
15
|
# @param options [Hash] Downloader options
|
14
16
|
def download(urls, options={})
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
runner = YoutubeDL::Runner.new(url, YoutubeDL::Options.new(options))
|
20
|
-
runner.run
|
17
|
+
if urls.is_a? Array
|
18
|
+
urls.map { |url| YoutubeDL::Video.get(url, options) }
|
19
|
+
else
|
20
|
+
YoutubeDL::Video.get(urls, options) # Urls should be singular but oh well. url = urls. There. Go cry in a corner.
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
alias_method :get, :download
|
25
25
|
|
26
|
+
# Lists extractors
|
27
|
+
#
|
28
|
+
# @return [Array] list of extractors
|
26
29
|
def extractors
|
27
|
-
|
30
|
+
@extractors ||= cocaine_line('--list-extractors').run.split("\n")
|
28
31
|
end
|
29
32
|
|
33
|
+
# Returns youtube-dl's version
|
34
|
+
#
|
35
|
+
# @return [String] youtube-dl version
|
30
36
|
def binary_version
|
31
|
-
|
37
|
+
@binary_version ||= cocaine_line('--version').run.strip
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns user agent
|
41
|
+
#
|
42
|
+
# @return [String] user agent
|
43
|
+
def user_agent
|
44
|
+
@user_agent ||= cocaine_line('--dump-user-agent').run.strip
|
32
45
|
end
|
33
46
|
end
|
data/lib/youtube-dl/options.rb
CHANGED
@@ -6,7 +6,11 @@ module YoutubeDL
|
|
6
6
|
#
|
7
7
|
# @param options [Hash] a hash of options
|
8
8
|
def initialize(options={})
|
9
|
-
|
9
|
+
if options.is_a? Hash
|
10
|
+
@store = options
|
11
|
+
else
|
12
|
+
@store = options.to_h
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
# Returns options as a hash
|
@@ -40,9 +44,8 @@ module YoutubeDL
|
|
40
44
|
# Set options using a block
|
41
45
|
#
|
42
46
|
# @yield [config] self
|
43
|
-
|
44
|
-
|
45
|
-
block.call(self)
|
47
|
+
def configure
|
48
|
+
yield(self) if block_given?
|
46
49
|
end
|
47
50
|
|
48
51
|
# Get option with brackets syntax
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module YoutubeDL
|
2
|
+
# A class of voodoo methods for parsing youtube-dl output
|
3
|
+
class Output < Struct.new(:output)
|
4
|
+
# Takes the output of '--list-formats'
|
5
|
+
#
|
6
|
+
# @return [Array] Array of supported formats
|
7
|
+
def supported_formats
|
8
|
+
# WARNING: This shit won't be documented or even properly tested. It's almost 3 in the morning and I have no idea what I'm doing.
|
9
|
+
header_index = output.index('format code')
|
10
|
+
return nil if header_index.nil?
|
11
|
+
|
12
|
+
formats = []
|
13
|
+
output.slice(header_index..-1).split("\n").each do |line|
|
14
|
+
format = {}
|
15
|
+
format[:format_code], format[:extension], format[:resolution], format[:note] = line.scan(/\A(\d+)\s+(\w+)\s+(\S+)\s(.*)/)[0]
|
16
|
+
formats.push format
|
17
|
+
end
|
18
|
+
formats.shift # The first line is just headers
|
19
|
+
formats.map do |format|
|
20
|
+
format[:note].strip! # Get rid of any trailing whitespace on the note.
|
21
|
+
format[:format_code] = format[:format_code].to_i # convert format code to integer
|
22
|
+
format
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Takes the output of a download
|
27
|
+
#
|
28
|
+
# @return [String] filename saved, nil if no match
|
29
|
+
def filename
|
30
|
+
# Check to see if file was already downloaded
|
31
|
+
if already_downloaded?
|
32
|
+
output.scan(/\[download\]\s(.*)\shas already been downloaded/)[0][0]
|
33
|
+
else
|
34
|
+
if output.include? 'Merging formats into'
|
35
|
+
output.scan(/Merging formats into \"(.*)\"/)[0][0]
|
36
|
+
else
|
37
|
+
output.scan(/\[download\] Destination:\s(.*)$/)[0][0]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue NoMethodError # There wasn't a match somewhere. Kill it with fire
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Takes the output of a download
|
45
|
+
#
|
46
|
+
# @return [Boolean] Has the file already been downloaded?
|
47
|
+
def already_downloaded?
|
48
|
+
output.include? 'has already been downloaded'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/youtube-dl/runner.rb
CHANGED
@@ -4,18 +4,33 @@ module YoutubeDL
|
|
4
4
|
class Runner
|
5
5
|
include YoutubeDL::Support
|
6
6
|
|
7
|
+
# [String] URL to download
|
7
8
|
attr_accessor :url
|
9
|
+
|
10
|
+
# [YoutubeDL::Options] Options access.
|
8
11
|
attr_accessor :options
|
9
|
-
|
12
|
+
|
13
|
+
# [String] Executable path
|
14
|
+
attr_reader :executable_path
|
15
|
+
|
16
|
+
# [String] Executable name to use
|
17
|
+
attr_accessor :executable
|
10
18
|
|
11
19
|
# Command Line runner initializer
|
12
20
|
#
|
13
21
|
# @param url [String] URL to pass to youtube-dl executable
|
14
22
|
# @param options [Hash, Options] options to pass to the executable. Automatically converted to Options if it isn't already
|
15
|
-
def initialize(url, options=
|
23
|
+
def initialize(url, options = {})
|
16
24
|
@url = url
|
17
|
-
@options = YoutubeDL::Options.new(options
|
18
|
-
@
|
25
|
+
@options = YoutubeDL::Options.new(options)
|
26
|
+
@executable = 'youtube-dl'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns usable executable path for youtube-dl
|
30
|
+
#
|
31
|
+
# @return [String] usable executable path for youtube-dl
|
32
|
+
def executable_path
|
33
|
+
@executable_path ||= usable_executable_path_for(@executable)
|
19
34
|
end
|
20
35
|
|
21
36
|
# Returns Cocaine's runner engine
|
@@ -28,6 +43,7 @@ module YoutubeDL
|
|
28
43
|
# Sets Cocaine's runner engine
|
29
44
|
#
|
30
45
|
# @param [CommandLineRunner] backend runner class
|
46
|
+
# @return [Object] whatever Cocaine::CommandLine.runner= returns.
|
31
47
|
def backend_runner=(cocaine_runner)
|
32
48
|
Cocaine::CommandLine.runner = cocaine_runner
|
33
49
|
end
|
@@ -41,30 +57,25 @@ module YoutubeDL
|
|
41
57
|
alias_method :command, :to_command
|
42
58
|
|
43
59
|
# Runs the command
|
60
|
+
#
|
61
|
+
# @return [String] the output of youtube-dl
|
44
62
|
def run
|
45
63
|
cocaine_line(options_to_commands).run(@options.store)
|
46
64
|
end
|
47
65
|
alias_method :download, :run
|
48
66
|
|
49
|
-
|
50
|
-
# [{:format_code => '000', :extension => 'avi', :resolution => '320x240', :note => 'More details about the format'}]
|
51
|
-
#
|
52
|
-
# @return [Array] Format list
|
53
|
-
def formats
|
54
|
-
# TODO: Move formats to its own model?
|
55
|
-
parse_format_output(cocaine_line("--list-formats #{quoted(url)}").run)
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
67
|
+
private
|
59
68
|
|
60
69
|
# Parses options and converts them to Cocaine's syntax
|
61
70
|
#
|
62
71
|
# @return [String] commands ready to do cocaine
|
63
72
|
def options_to_commands
|
64
73
|
commands = []
|
65
|
-
options.sanitize_keys.each_paramized_key do |key, paramized_key|
|
66
|
-
if options[key].to_s == 'true'
|
74
|
+
@options.sanitize_keys.each_paramized_key do |key, paramized_key|
|
75
|
+
if @options[key].to_s == 'true'
|
67
76
|
commands.push "--#{paramized_key}"
|
77
|
+
elsif @options[key].to_s == 'false'
|
78
|
+
commands.push "--no-#{paramized_key}"
|
68
79
|
else
|
69
80
|
commands.push "--#{paramized_key} :#{key}"
|
70
81
|
end
|
@@ -72,37 +83,5 @@ module YoutubeDL
|
|
72
83
|
commands.push quoted(url)
|
73
84
|
commands.join(' ')
|
74
85
|
end
|
75
|
-
|
76
|
-
# Helper to add quotes to beginning and end of a URL.
|
77
|
-
#
|
78
|
-
# @param url [String] Raw URL
|
79
|
-
# @return [String] Quoted URL
|
80
|
-
def quoted(url)
|
81
|
-
"\"#{url}\""
|
82
|
-
end
|
83
|
-
|
84
|
-
# Helper for doing lines of cocaine (initializing, auto executable stuff, etc)
|
85
|
-
#
|
86
|
-
# @param command [String] command switches to run
|
87
|
-
# @return [Cocaine::CommandLine] initialized Cocaine instance
|
88
|
-
def cocaine_line(command)
|
89
|
-
Cocaine::CommandLine.new(@executable_path, command)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Do you like voodoo?
|
93
|
-
#
|
94
|
-
# @param format_output [String] output from youtube-dl --list-formats
|
95
|
-
# @return [Array] Magic.
|
96
|
-
def parse_format_output(format_output)
|
97
|
-
# WARNING: This shit won't be documented or even properly tested. It's almost 3 in the morning and I have no idea what I'm doing.
|
98
|
-
this_shit = []
|
99
|
-
format_output.slice(format_output.index('format code')..-1).split("\n").each do |line|
|
100
|
-
a = {}
|
101
|
-
a[:format_code], a[:extension], a[:resolution], a[:note] = line.scan(/\A(\d+)\s+(\w+)\s+(\S+)\s(.*)/)[0]
|
102
|
-
this_shit.push a
|
103
|
-
end
|
104
|
-
this_shit.shift
|
105
|
-
this_shit.map { |gipo| gipo[:note].strip!; gipo }
|
106
|
-
end
|
107
86
|
end
|
108
87
|
end
|
data/lib/youtube-dl/support.rb
CHANGED
@@ -11,11 +11,31 @@ module YoutubeDL
|
|
11
11
|
if $?.exitstatus == 0 # $? is an object with information on that last command run with backticks.
|
12
12
|
system_path.strip
|
13
13
|
else
|
14
|
-
# TODO: Search vendor bin for executable before just saying it's there.
|
14
|
+
# TODO: Search vendor bin for executable before just saying it's there.
|
15
15
|
vendor_path = File.absolute_path("#{__FILE__}/../../../vendor/bin/#{exe}")
|
16
16
|
File.chmod(775, vendor_path) unless File.executable?(vendor_path) # Make sure vendor binary is executable
|
17
17
|
vendor_path
|
18
18
|
end
|
19
19
|
end
|
20
|
+
|
21
|
+
alias_method :executable_path_for, :usable_executable_path_for
|
22
|
+
|
23
|
+
# Helper for doing lines of cocaine (initializing, auto executable stuff, etc)
|
24
|
+
#
|
25
|
+
# @param command [String] command switches to run
|
26
|
+
# @param executable_path [String] executable to run. Defaults to usable youtube-dl.
|
27
|
+
# @return [Cocaine::CommandLine] initialized Cocaine instance
|
28
|
+
def cocaine_line(command, executable_path = nil)
|
29
|
+
executable_path = executable_path_for('youtube-dl') if executable_path.nil?
|
30
|
+
Cocaine::CommandLine.new(executable_path, command)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Helper to add quotes to beginning and end of a URL or whatever you want....
|
34
|
+
#
|
35
|
+
# @param url [String] Raw URL
|
36
|
+
# @return [String] Quoted URL
|
37
|
+
def quoted(url)
|
38
|
+
"\"#{url}\""
|
39
|
+
end
|
20
40
|
end
|
21
41
|
end
|
data/lib/youtube-dl/version.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
module YoutubeDL
|
2
|
+
# Video model
|
3
|
+
class Video < Runner
|
4
|
+
class << self
|
5
|
+
# Instantiate a new Video model and download the video
|
6
|
+
#
|
7
|
+
# @param url [String] URL to use and download
|
8
|
+
# @param options [Hash] Options to pass in
|
9
|
+
# @return [YoutubeDL::Video] new Video model
|
10
|
+
def download(url, options={})
|
11
|
+
video = new(url, options)
|
12
|
+
video.download
|
13
|
+
video
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :get, :download
|
17
|
+
end
|
18
|
+
|
19
|
+
# [YoutubeDL::Options] Download Options for the last download
|
20
|
+
attr_reader :download_options
|
21
|
+
|
22
|
+
# Instantiate new model
|
23
|
+
#
|
24
|
+
# @param url [String] URL to initialize with
|
25
|
+
# @param options [Hash] Options to populate the everything with
|
26
|
+
def initialize(url, options={})
|
27
|
+
@url = url
|
28
|
+
@options = YoutubeDL::Options.new(options)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Download the video.
|
32
|
+
def download
|
33
|
+
@download_options = YoutubeDL::Options.new(runner_options)
|
34
|
+
@last_download_output = YoutubeDL::Runner.new(url, @download_options).run
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :get, :download
|
38
|
+
|
39
|
+
# Returns a list of supported formats for the video in the form of
|
40
|
+
# [{:format_code => '000', :extension => 'avi', :resolution => '320x240', :note => 'More details about the format'}]
|
41
|
+
#
|
42
|
+
# @return [Array] Format list
|
43
|
+
def formats
|
44
|
+
@formats ||= YoutubeDL::Output.new(cocaine_line("--list-formats #{quoted(url)}").run).supported_formats
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [String] Filename downloaded to
|
48
|
+
def filename
|
49
|
+
@filename ||= YoutubeDL::Output.new(@last_download_output).filename
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
# Add in other default options here.
|
54
|
+
def runner_options
|
55
|
+
{
|
56
|
+
no_color: true
|
57
|
+
}.merge(@options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -5,87 +5,141 @@ describe YoutubeDL::Options do
|
|
5
5
|
@options = YoutubeDL::Options.new
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'should symbolize option keys' do
|
10
|
+
@options.store['key'] = "value"
|
11
|
+
@options.sanitize_keys!
|
12
|
+
assert_equal({key: 'value'}, @options.store)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should accept a parent Options as a param' do
|
16
|
+
parent = YoutubeDL::Options.new(parent_key: 'parent value')
|
17
|
+
child = YoutubeDL::Options.new(parent)
|
18
|
+
assert_equal parent.store, child.store
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should accept a Hash as a param' do
|
22
|
+
hash = {parent_key: 'parent value'}
|
23
|
+
options = YoutubeDL::Options.new(hash)
|
24
|
+
assert_equal hash, options.store
|
25
|
+
end
|
12
26
|
end
|
13
27
|
|
14
|
-
|
15
|
-
|
28
|
+
describe '#to_hash, #to_h' do
|
29
|
+
before do
|
30
|
+
@options.store[:key] = "value"
|
31
|
+
end
|
16
32
|
|
17
|
-
|
33
|
+
it 'should return a hash' do
|
34
|
+
assert_instance_of Hash, @options.to_hash
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should be equal to store' do
|
38
|
+
assert_equal @options.store, @options.to_hash
|
39
|
+
end
|
18
40
|
end
|
19
41
|
|
20
|
-
|
21
|
-
|
42
|
+
describe '#each_paramized' do
|
43
|
+
it 'should properly paramize keys and not values' do
|
44
|
+
@options.some_key = "some value"
|
22
45
|
|
23
|
-
|
46
|
+
@options.each_paramized do |key, value|
|
47
|
+
assert_equal key, 'some-key'
|
48
|
+
assert_equal value, 'some value'
|
49
|
+
end
|
50
|
+
end
|
24
51
|
end
|
25
52
|
|
26
|
-
|
27
|
-
|
28
|
-
|
53
|
+
describe '#each_paramized_key' do
|
54
|
+
it 'should properly paramize keys' do # TODO: Write a better test name
|
55
|
+
@options.some_key = "some value"
|
56
|
+
|
57
|
+
@options.each_paramized_key do |key, paramized_key|
|
58
|
+
assert_equal :some_key, key
|
59
|
+
assert_equal 'some-key', paramized_key
|
60
|
+
end
|
61
|
+
end
|
29
62
|
end
|
30
63
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
64
|
+
describe '#configure' do
|
65
|
+
it 'should be able to use an explicit configuration block' do
|
66
|
+
@options.configure do |c|
|
67
|
+
c.get_operator = true
|
68
|
+
c['get_index'] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
assert @options.store[:get_operator], "Actual: #{@options.store[:get_operator]}"
|
72
|
+
assert @options.store[:get_index], "Actual: #{@options.store[:get_index]}"
|
35
73
|
end
|
36
74
|
|
37
|
-
|
38
|
-
|
75
|
+
it 'should not override parent configuration' do
|
76
|
+
opts = YoutubeDL::Options.new(parent: 'value')
|
77
|
+
opts.configure do |c|
|
78
|
+
c.child = 'vlaue'
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal opts.store[:parent], 'value'
|
82
|
+
assert_equal opts.store[:child], 'vlaue'
|
83
|
+
end
|
39
84
|
end
|
40
85
|
|
41
|
-
|
42
|
-
|
43
|
-
|
86
|
+
describe '#[], #[]==' do
|
87
|
+
it 'should be able to use brackets' do
|
88
|
+
@options[:mtn] = :dew
|
89
|
+
assert @options[:mtn] == :dew
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should automatically symbolize keys' do
|
93
|
+
@options.get_operator = true
|
94
|
+
@options['get_index'] = true
|
44
95
|
|
45
|
-
|
46
|
-
|
96
|
+
[:get_operator, :get_index].each do |d|
|
97
|
+
assert @options.store.keys.include?(d), "keys not symbolizing automatically: #{d}"
|
98
|
+
end
|
47
99
|
end
|
48
100
|
end
|
49
101
|
|
50
|
-
|
51
|
-
|
102
|
+
describe '#method_missing' do
|
103
|
+
it 'should be able to set options with method_missing' do
|
104
|
+
@options.test = true
|
52
105
|
|
53
|
-
|
54
|
-
assert_equal key, 'some-key'
|
55
|
-
assert_equal value, 'some value'
|
106
|
+
assert @options.store[:test]
|
56
107
|
end
|
57
|
-
end
|
58
108
|
|
59
|
-
|
60
|
-
|
109
|
+
it 'should be able to retrieve options with method_missing' do
|
110
|
+
@options.store[:walrus] = 'haswalrus'
|
61
111
|
|
62
|
-
|
63
|
-
assert_equal :some_key, key
|
64
|
-
assert_equal 'some-key', paramized_key
|
112
|
+
assert @options.walrus == 'haswalrus'
|
65
113
|
end
|
66
114
|
end
|
67
115
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
116
|
+
describe '#manipulate_keys!' do
|
117
|
+
it 'should manipulate keys' do
|
118
|
+
@options.some_key = 'value'
|
119
|
+
@options.manipulate_keys! do |key|
|
120
|
+
key.to_s.upcase
|
121
|
+
end
|
122
|
+
assert_equal({'SOME_KEY' => 'value'}, @options.store)
|
123
|
+
end
|
72
124
|
end
|
73
125
|
|
74
|
-
|
75
|
-
|
76
|
-
|
126
|
+
describe '#sanitize_keys!' do
|
127
|
+
it 'should convert hyphens to underscores in keys' do # See issue #9
|
128
|
+
@options.store[:"hyphenated-key"] = 'value'
|
129
|
+
@options.sanitize_keys!
|
130
|
+
assert_equal({hyphenated_key: 'value'}, @options.to_h)
|
131
|
+
end
|
77
132
|
end
|
78
133
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
134
|
+
describe '#sanitize_keys' do
|
135
|
+
it 'should not modify the original by calling sanitize_keys without bang' do
|
136
|
+
@options.store['some-key'] = "some_value"
|
137
|
+
refute_equal @options.sanitize_keys, @options
|
138
|
+
end
|
83
139
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
key.to_s.upcase
|
140
|
+
it 'should return instance of Options when calling sanitize_keys' do
|
141
|
+
@options.store['some-key'] = "some_value"
|
142
|
+
assert_instance_of YoutubeDL::Options, @options.sanitize_keys
|
88
143
|
end
|
89
|
-
assert_equal({'SOME_KEY' => 'value'}, @options.store)
|
90
144
|
end
|
91
145
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
module OutputFactory
|
4
|
+
extend self
|
5
|
+
extend YoutubeDL::Support
|
6
|
+
|
7
|
+
def download
|
8
|
+
remove_downloaded_files # Make sure there isn't a file there
|
9
|
+
@download ||= cocaine_line(quoted(TEST_URL)).run
|
10
|
+
end
|
11
|
+
|
12
|
+
def download_exists
|
13
|
+
@download_exists ||= lambda do
|
14
|
+
cocaine_line(quoted(TEST_URL)).run # two times to make sure it's there.
|
15
|
+
cocaine_line(quoted(TEST_URL)).run
|
16
|
+
end.call
|
17
|
+
end
|
18
|
+
|
19
|
+
def list_formats
|
20
|
+
@list_formats ||= cocaine_line("--list-formats #{quoted(TEST_URL)}").run
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# For debugging
|
25
|
+
# puts
|
26
|
+
# puts " --------------- OutputFactory.download --------------- "
|
27
|
+
# puts OutputFactory.download
|
28
|
+
# puts
|
29
|
+
# puts " --------------- OutputFactory.download_exists --------------- "
|
30
|
+
# puts OutputFactory.download_exists
|
31
|
+
# puts
|
32
|
+
# puts " --------------- OutputFactory.list_formats --------------- "
|
33
|
+
# puts OutputFactory.list_formats
|
34
|
+
# puts
|
35
|
+
|
36
|
+
describe YoutubeDL::Output do
|
37
|
+
describe '#initialize' do
|
38
|
+
it 'should set the output variable' do
|
39
|
+
sample_output = "some sample output\n\n"
|
40
|
+
parser = YoutubeDL::Output.new(sample_output)
|
41
|
+
assert_equal sample_output, parser.output
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#supported_formats' do
|
46
|
+
before do
|
47
|
+
@parser = YoutubeDL::Output.new(OutputFactory.list_formats)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should find a match given the correct output' do
|
51
|
+
refute_nil @parser.supported_formats
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should find the correct match and in the correct format' do
|
55
|
+
assert_includes(@parser.supported_formats, {format_code: 5, extension: 'flv', resolution: '400x240', note: 'small'})
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should return nil if no match or wrong log format' do
|
59
|
+
bad_parser = YoutubeDL::Output.new(OutputFactory.download)
|
60
|
+
assert_nil bad_parser.supported_formats
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#filename' do
|
65
|
+
before do
|
66
|
+
@parser_download = YoutubeDL::Output.new(OutputFactory.download)
|
67
|
+
@parser_download_exists = YoutubeDL::Output.new(OutputFactory.download_exists)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should find a match given the correct output' do
|
71
|
+
refute_nil @parser_download.filename
|
72
|
+
refute_nil @parser_download_exists.filename
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should find the correct match' do
|
76
|
+
assert_equal 'nope.avi-gvdf5n-zI14.mp4', @parser_download.filename
|
77
|
+
assert_equal 'nope.avi-gvdf5n-zI14.mp4', @parser_download_exists.filename
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return nil if no match or wrong log format' do
|
81
|
+
bad_parser = YoutubeDL::Output.new(OutputFactory.list_formats)
|
82
|
+
assert_nil bad_parser.filename
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#already_downloaded?' do
|
87
|
+
before do
|
88
|
+
@parser_download = YoutubeDL::Output.new(OutputFactory.download)
|
89
|
+
@parser_download_exists = YoutubeDL::Output.new(OutputFactory.download_exists)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should return a truthy value if true' do
|
93
|
+
assert @parser_download_exists.already_downloaded?
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should return a falsy value if false' do
|
97
|
+
refute @parser_download.already_downloaded?
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -9,75 +9,68 @@ describe YoutubeDL::Runner do
|
|
9
9
|
remove_downloaded_files
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
describe '#initialize' do
|
13
|
+
it 'should take options as a hash yet still have configuration blocks work' do
|
14
|
+
r = YoutubeDL::Runner.new(TEST_URL, {some_key: 'some value'})
|
15
|
+
r.options.configure do |c|
|
16
|
+
c.another_key = 'another_value'
|
17
|
+
end
|
18
|
+
|
19
|
+
assert_includes r.to_command, "--some-key"
|
20
|
+
assert_includes r.to_command, "--another-key"
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
describe '#executable_path' do
|
25
|
+
it 'should set executable path automatically' do
|
26
|
+
assert_match 'youtube-dl', @runner.executable_path
|
27
|
+
end
|
23
28
|
|
24
|
-
|
25
|
-
|
29
|
+
it 'should not have a newline char in the executable_path' do
|
30
|
+
assert_match /youtube-dl\z/, @runner.executable_path
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
|
-
|
29
|
-
|
34
|
+
describe '#backend_runner=, #backend_runner' do
|
35
|
+
it 'should set cocaine runner' do
|
36
|
+
@runner.backend_runner = Cocaine::CommandLine::BackticksRunner.new
|
37
|
+
assert_instance_of Cocaine::CommandLine::BackticksRunner, @runner.backend_runner
|
38
|
+
|
39
|
+
@runner.backend_runner = Cocaine::CommandLine::PopenRunner.new
|
40
|
+
assert_instance_of Cocaine::CommandLine::PopenRunner, @runner.backend_runner
|
41
|
+
end
|
30
42
|
end
|
31
43
|
|
32
|
-
|
33
|
-
|
44
|
+
describe '#to_command' do
|
45
|
+
it 'should parse key-values from options' do
|
46
|
+
@runner.options.some_key = "a value"
|
34
47
|
|
35
|
-
|
36
|
-
|
48
|
+
refute_nil @runner.to_command.match(/--some-key\s.*a value.*/)
|
49
|
+
end
|
37
50
|
|
38
|
-
|
39
|
-
|
51
|
+
it 'should handle true boolean values' do
|
52
|
+
@runner.options.truthy_value = true
|
40
53
|
|
41
|
-
|
42
|
-
|
54
|
+
assert_match /youtube-dl .*--truthy-value\s--|\"http.*/, @runner.to_command
|
55
|
+
end
|
43
56
|
|
44
|
-
|
45
|
-
|
46
|
-
@runner.options.format = TEST_FORMAT
|
47
|
-
@runner.run
|
48
|
-
assert File.exists? TEST_FILENAME
|
49
|
-
end
|
57
|
+
it 'should handle false boolean values' do
|
58
|
+
@runner.options.false_value = false
|
50
59
|
|
51
|
-
|
52
|
-
r = YoutubeDL::Runner.new(TEST_URL, {some_key: 'some value'})
|
53
|
-
r.options.configure do |c|
|
54
|
-
c.another_key = 'another_value'
|
60
|
+
assert_match /youtube-dl .*--no-false-value\s--|\"http.*/, @runner.to_command
|
55
61
|
end
|
56
62
|
|
57
|
-
|
58
|
-
|
63
|
+
it 'should not have newline char in to_command' do
|
64
|
+
assert_match /youtube-dl\s/, @runner.to_command
|
65
|
+
end
|
59
66
|
end
|
60
67
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
assert_includes formats.first, key
|
68
|
-
assert_includes formats.last, key
|
68
|
+
describe '#run' do
|
69
|
+
it 'should run commands' do
|
70
|
+
@runner.options.output = TEST_FILENAME
|
71
|
+
@runner.options.format = TEST_FORMAT
|
72
|
+
@runner.run
|
73
|
+
assert File.exists? TEST_FILENAME
|
69
74
|
end
|
70
75
|
end
|
71
|
-
|
72
|
-
it 'should handle strangely-formatted options correctly' do # See issue #9
|
73
|
-
options = {
|
74
|
-
format: 'bestaudio',
|
75
|
-
:"prefer-ffmpeg" => "true",
|
76
|
-
:"extract-audio" => true,
|
77
|
-
:"audio-format" => "mp3"
|
78
|
-
}
|
79
|
-
|
80
|
-
@runner.options = YoutubeDL::Options.new(options)
|
81
|
-
assert_match /youtube-dl --format 'bestaudio' --prefer-ffmpeg --extract-audio --audio-format 'mp3'/, @runner.to_command
|
82
|
-
end
|
83
76
|
end
|
@@ -33,4 +33,26 @@ describe YoutubeDL::Support do
|
|
33
33
|
assert_match /youtube-dl\z/, @klass.executable_path
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
describe '#cocaine_line' do
|
38
|
+
it 'should return a Cocaine::CommandLine instance' do
|
39
|
+
assert_instance_of Cocaine::CommandLine, @klass.cocaine_line('')
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should be able to override the executable' do
|
43
|
+
line = @klass.cocaine_line('hello', 'echo')
|
44
|
+
assert_equal "echo hello", line.command
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should default to youtube-dl' do
|
48
|
+
line = @klass.cocaine_line(@klass.quoted(TEST_URL))
|
49
|
+
assert_includes line.command, "youtube-dl \"#{TEST_URL}\""
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#quoted' do
|
54
|
+
it 'should add quotes' do
|
55
|
+
assert_equal "\"#{TEST_URL}\"", @klass.quoted(TEST_URL)
|
56
|
+
end
|
57
|
+
end
|
36
58
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
describe YoutubeDL::Video do
|
4
|
+
before do
|
5
|
+
@video = YoutubeDL::Video.new TEST_URL
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
remove_downloaded_files
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.download' do
|
13
|
+
it 'should download videos without options' do
|
14
|
+
YoutubeDL::Video.download TEST_URL
|
15
|
+
assert_equal 1, Dir.glob(TEST_GLOB).length
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should download videos with options' do
|
19
|
+
YoutubeDL::Video.download TEST_URL, output: TEST_FILENAME, format: TEST_FORMAT
|
20
|
+
assert File.exist? TEST_FILENAME
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return an instance of YoutubeDL::Video' do
|
24
|
+
video = YoutubeDL::Video.download TEST_URL
|
25
|
+
assert_instance_of YoutubeDL::Video, video
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.get' do
|
30
|
+
it 'should download videos, exactly like .download' do
|
31
|
+
YoutubeDL::Video.get TEST_URL
|
32
|
+
assert_equal Dir.glob(TEST_GLOB).length, 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#initialize' do
|
37
|
+
it 'should return an instance of YoutubeDL::Video' do
|
38
|
+
assert_instance_of YoutubeDL::Video, @video
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should not download anything' do
|
42
|
+
assert_empty Dir.glob(TEST_GLOB)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#download' do
|
47
|
+
it 'should download the file' do
|
48
|
+
assert_equal 0, Dir.glob(TEST_GLOB).length
|
49
|
+
@video.download
|
50
|
+
assert_equal 1, Dir.glob(TEST_GLOB).length
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should set model variables accordingly' do
|
54
|
+
@video.download
|
55
|
+
assert_equal Dir.glob(TEST_GLOB).first, @video.filename
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#formats' do
|
60
|
+
before do
|
61
|
+
@formats = @video.formats
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should be an Array' do
|
65
|
+
assert_instance_of Array, @formats
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should be an Array of Hashes' do
|
69
|
+
assert_instance_of Hash, @formats.first
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should have a hash size of 4' do
|
73
|
+
assert_equal 4, @formats.first.size
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should include the correct information' do
|
77
|
+
[:format_code, :resolution, :extension, :note].each do |key|
|
78
|
+
assert_includes @formats.first, key
|
79
|
+
assert_includes @formats.last, key
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should not have any whitespace in the notes' do
|
84
|
+
@formats.each do |format|
|
85
|
+
assert_nil format[:note].strip!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative './test_helper'
|
2
|
+
|
3
|
+
describe YoutubeDL do
|
4
|
+
describe '.download' do
|
5
|
+
after do
|
6
|
+
remove_downloaded_files
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should download videos without options' do
|
10
|
+
YoutubeDL.download TEST_URL
|
11
|
+
assert_equal 1, Dir.glob(TEST_GLOB).length
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should download videos with options' do
|
15
|
+
YoutubeDL.download TEST_URL, output: TEST_FILENAME, format: TEST_FORMAT
|
16
|
+
assert File.exist? TEST_FILENAME
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should download multiple videos without options' do
|
20
|
+
YoutubeDL.download [TEST_URL, TEST_URL2]
|
21
|
+
assert_equal 2, Dir.glob(TEST_GLOB).length
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should download multiple videos with options' do
|
25
|
+
YoutubeDL.download [TEST_URL, TEST_URL2], output: 'test_%(title)s-%(id)s.%(ext)s'
|
26
|
+
assert_equal 2, Dir.glob('test_' + TEST_GLOB).length
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '.get' do
|
31
|
+
after do
|
32
|
+
remove_downloaded_files
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should download videos, exactly like .download' do
|
36
|
+
YoutubeDL.get TEST_URL
|
37
|
+
assert_equal Dir.glob(TEST_GLOB).length, 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '.extractors' do
|
42
|
+
before do
|
43
|
+
@extractors = YoutubeDL.extractors
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should return an Array' do
|
47
|
+
assert_instance_of Array, @extractors
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should include the youtube extractors' do
|
51
|
+
['youtube', 'youtube:channel', 'youtube:search', 'youtube:show', 'youtube:user', 'youtube:playlist'].each do |e|
|
52
|
+
assert_includes @extractors, e
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.binary_version' do
|
58
|
+
before do
|
59
|
+
@version = YoutubeDL.binary_version
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should return a string' do
|
63
|
+
assert_instance_of String, @version
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should be a specific format with no newlines' do
|
67
|
+
assert_match /\d+.\d+.\d+\z/, @version
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '.user_agent' do
|
72
|
+
before do
|
73
|
+
@user_agent = YoutubeDL.user_agent
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should return a string' do
|
77
|
+
assert_instance_of String, @user_agent
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should be a specific format with no newlines' do
|
81
|
+
assert_match /Mozilla\/5\.0\s.*\)\z/, @user_agent
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/youtube-dl.rb.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", ">= 1.6"
|
24
24
|
spec.add_development_dependency "pry"
|
25
|
+
spec.add_development_dependency "m"
|
25
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
27
|
spec.add_development_dependency "minitest", "~> 5.5.1"
|
27
28
|
spec.add_development_dependency "purdytest"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: youtube-dl.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sapslaj
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-09-
|
12
|
+
date: 2015-09-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cocaine
|
@@ -53,6 +53,20 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: m
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
71
|
name: rake
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,14 +139,18 @@ files:
|
|
125
139
|
- Rakefile
|
126
140
|
- lib/youtube-dl.rb
|
127
141
|
- lib/youtube-dl/options.rb
|
142
|
+
- lib/youtube-dl/output.rb
|
128
143
|
- lib/youtube-dl/runner.rb
|
129
144
|
- lib/youtube-dl/support.rb
|
130
145
|
- lib/youtube-dl/version.rb
|
146
|
+
- lib/youtube-dl/video.rb
|
131
147
|
- test/test_helper.rb
|
132
148
|
- test/youtube-dl/options_test.rb
|
149
|
+
- test/youtube-dl/output_test.rb
|
133
150
|
- test/youtube-dl/runner_test.rb
|
134
151
|
- test/youtube-dl/support_test.rb
|
135
|
-
- test/youtube-dl/
|
152
|
+
- test/youtube-dl/video_test.rb
|
153
|
+
- test/youtube-dl_test.rb
|
136
154
|
- vendor/bin/youtube-dl
|
137
155
|
- vendor/bin/youtube-dl.exe
|
138
156
|
- youtube-dl.rb.gemspec
|
@@ -163,6 +181,8 @@ summary: youtube-dl wrapper for Ruby
|
|
163
181
|
test_files:
|
164
182
|
- test/test_helper.rb
|
165
183
|
- test/youtube-dl/options_test.rb
|
184
|
+
- test/youtube-dl/output_test.rb
|
166
185
|
- test/youtube-dl/runner_test.rb
|
167
186
|
- test/youtube-dl/support_test.rb
|
168
|
-
- test/youtube-dl/
|
187
|
+
- test/youtube-dl/video_test.rb
|
188
|
+
- test/youtube-dl_test.rb
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require_relative '../test_helper'
|
2
|
-
|
3
|
-
describe YoutubeDL do
|
4
|
-
describe '.download' do
|
5
|
-
after do
|
6
|
-
remove_downloaded_files
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'should download videos' do
|
10
|
-
YoutubeDL.get TEST_URL, output: TEST_FILENAME, format: TEST_FORMAT
|
11
|
-
assert File.exist? TEST_FILENAME
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'should download multiple videos' do
|
15
|
-
YoutubeDL.download [TEST_URL, TEST_URL2]
|
16
|
-
assert_equal Dir.glob('nope*').length, 2
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '.extractors' do
|
21
|
-
it 'should return an Array of Strings' do
|
22
|
-
extractors = YoutubeDL.extractors
|
23
|
-
assert_instance_of Array, extractors
|
24
|
-
assert_instance_of String, extractors.first
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '.binary_version' do
|
29
|
-
before do
|
30
|
-
@version = YoutubeDL.binary_version
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should return a string' do
|
34
|
-
assert_instance_of String, @version
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'should be a specific format with no newlines' do
|
38
|
-
assert_match /\d+.\d+.\d+\z/, @version
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|