yt-dlp.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5376972dc27fa3ad59be7ba8c80c0ff9a5046854aefbdf3a33fca45433fc1c16
4
+ data.tar.gz: e96a6c8677803fb682bb03c7add405dc0a20c38b49997696dac30b4f66cefa31
5
+ SHA512:
6
+ metadata.gz: cf93abf7e6ece1e46dc3a116c2a8220b2018654c2d34c152379b690bb60fbe2f0aea0f557e60544fa1a4c415c8d7cdd11c1041fde5924163eefe0f1295eea971
7
+ data.tar.gz: 8c4beb1285df288c15fe9b2cfb63c628f17ee77752ee82bd856f8faccaebc470ab6bd36203c574d708d2d89d09960a979cf391aa60d9a0fceaf0d8efc7bbd684
@@ -0,0 +1,54 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ ruby_dependencies:
11
+ name: Ruby - download and cache dependencies
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v2
17
+
18
+ - name: Setup Ruby
19
+ uses: ruby/setup-ruby@v1
20
+
21
+ - name: Ruby gem cache
22
+ uses: actions/cache@v1
23
+ with:
24
+ path: vendor/bundle
25
+ key: gems-${{ hashFiles('**/Gemfile.lock') }}
26
+ restore-keys: gems-
27
+
28
+ - name: Install gems
29
+ run: bundle install --jobs 4 --retry 3 --path vendor/bundle
30
+
31
+ tests:
32
+ name: Run tests
33
+ runs-on: ubuntu-latest
34
+ needs: ruby_dependencies
35
+
36
+ steps:
37
+ - name: Checkout code
38
+ uses: actions/checkout@v2
39
+
40
+ - name: Setup Ruby
41
+ uses: ruby/setup-ruby@v1
42
+
43
+ - name: Ruby gem cache
44
+ uses: actions/cache@v1
45
+ with:
46
+ path: vendor/bundle
47
+ key: gems-${{ hashFiles('**/Gemfile.lock') }}
48
+ restore-keys: gems-
49
+
50
+ - name: Install gems
51
+ run: bundle install --jobs 4 --retry 3 --path vendor/bundle
52
+
53
+ - name: Run tests
54
+ run: bundle exec rake test
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *nope.avi*
16
+ .byebug_history
data/.rubocop.yml ADDED
@@ -0,0 +1,11 @@
1
+ # Metrics/AbcSize:
2
+ # Max: 22
3
+
4
+ Metrics/MethodLength:
5
+ Max: 14
6
+
7
+ Style/ModuleFunction:
8
+ Enabled: false
9
+
10
+ Style/FileName:
11
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,135 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2015-10-19 08:34:35 -0400 using RuboCop version 0.34.2.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 7
10
+ Lint/AmbiguousRegexpLiteral:
11
+ Exclude:
12
+ - 'test/yt-dlp/runner_test.rb'
13
+ - 'test/yt-dlp/support_test.rb'
14
+ - 'test/yt-dlp_test.rb'
15
+
16
+ # Offense count: 1
17
+ Lint/Debugger:
18
+ Exclude:
19
+ - 'tmp/parse_formats.rb'
20
+
21
+ # Offense count: 2
22
+ # Cop supports --auto-correct.
23
+ Lint/DeprecatedClassMethods:
24
+ Exclude:
25
+ - 'test/yt-dlp/runner_test.rb'
26
+ - 'test/yt-dlp/support_test.rb'
27
+
28
+ # Offense count: 3
29
+ Metrics/AbcSize:
30
+ Max: 22
31
+
32
+ # Offense count: 3
33
+ # Configuration parameters: CountComments.
34
+ Metrics/MethodLength:
35
+ Max: 14
36
+
37
+ # Offense count: 2
38
+ # Cop supports --auto-correct.
39
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
40
+ Style/AccessModifierIndentation:
41
+ Enabled: false
42
+
43
+ # Offense count: 1
44
+ # Cop supports --auto-correct.
45
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
46
+ Style/BlockDelimiters:
47
+ Enabled: false
48
+
49
+ # Offense count: 2
50
+ # Cop supports --auto-correct.
51
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
52
+ Style/BracesAroundHashParameters:
53
+ Exclude:
54
+ - 'test/yt-dlp/output_test.rb'
55
+ - 'test/yt-dlp/runner_test.rb'
56
+
57
+ # Offense count: 1
58
+ # Configuration parameters: Exclude.
59
+ Style/Documentation:
60
+ Exclude:
61
+ - 'lib/yt-dlp/version.rb'
62
+
63
+ # Offense count: 1
64
+ # Cop supports --auto-correct.
65
+ Style/EmptyLinesAroundAccessModifier:
66
+ Exclude:
67
+ - 'lib/yt-dlp/video.rb'
68
+
69
+ # Offense count: 1
70
+ # Cop supports --auto-correct.
71
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
72
+ Style/EmptyLinesAroundClassBody:
73
+ Exclude:
74
+ - 'lib/yt-dlp/output.rb'
75
+
76
+ # Offense count: 5
77
+ # Cop supports --auto-correct.
78
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
79
+ Style/EmptyLinesAroundModuleBody:
80
+ Exclude:
81
+ - 'lib/yt-dlp/output.rb'
82
+ - 'lib/yt-dlp/runner.rb'
83
+ - 'lib/yt-dlp/support.rb'
84
+ - 'lib/yt-dlp/video.rb'
85
+
86
+ # Offense count: 2
87
+ # Configuration parameters: Exclude.
88
+ Style/FileName:
89
+ Exclude:
90
+ - 'lib/yt-dlp.rb'
91
+ - 'test/yt-dlp_test.rb'
92
+
93
+ # Offense count: 1
94
+ Style/ModuleFunction:
95
+ Exclude:
96
+ - 'lib/yt-dlp.rb'
97
+
98
+ # Offense count: 1
99
+ # Cop supports --auto-correct.
100
+ # Configuration parameters: AllowMultipleReturnValues.
101
+ Style/RedundantReturn:
102
+ Exclude:
103
+ - 'lib/yt-dlp/support.rb'
104
+
105
+ # Offense count: 1
106
+ # Cop supports --auto-correct.
107
+ # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
108
+ Style/RegexpLiteral:
109
+ Exclude:
110
+ - 'test/yt-dlp_test.rb'
111
+
112
+ # Offense count: 3
113
+ # Cop supports --auto-correct.
114
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
115
+ Style/SpaceAroundEqualsInParameterDefault:
116
+ Enabled: false
117
+
118
+ # Offense count: 12
119
+ # Cop supports --auto-correct.
120
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
121
+ Style/SpaceInsideHashLiteralBraces:
122
+ Enabled: false
123
+
124
+ # Offense count: 2
125
+ # Cop supports --auto-correct.
126
+ Style/SpecialGlobalVars:
127
+ Exclude:
128
+ - 'test/test_helper.rb'
129
+ - 'tmp/parse_formats.rb'
130
+
131
+ # Offense count: 22
132
+ # Cop supports --auto-correct.
133
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
134
+ Style/StringLiterals:
135
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.2
@@ -0,0 +1,7 @@
1
+ yt-dlp.rb hits 1.0 when:
2
+
3
+ * [x] It works on all major Unix platforms
4
+ * [x] It works on Windows
5
+ * [ ] It fully supports all features of yt-dlp in a Ruby-friendly way
6
+ * [ ] It supports logging
7
+ * [ ] [It uses v1.0 Terrapin](https://github.com/thoughtbot/terrapin/blob/master/GOALS)
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in yt-dlp.rb.gemspec
6
+ gemspec
7
+
8
+ gem 'erb'
9
+
10
+ group :development do
11
+ gem 'rubocop', '~> 1.22', '>= 1.22.3'
12
+ end
13
+
14
+ group :extras do
15
+ gem 'byebug'
16
+ gem 'm'
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 sapslaj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # yt-dlp
2
+
3
+ Wrapper for the [yt-dlp](https://github.com/yt-dlp/yt-dlp) video download tool. This gem is heavily inspired by the youtube_dl.rb gem
4
+
5
+ ![CI](https://github.com/andrepcg/yt-dlp.rb/workflows/CI/badge.svg)
6
+
7
+
8
+ ## Install the gem
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'yt-dlp.rb'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install yt-dlp.rb
23
+
24
+ ## Install yt-dlp
25
+ This gem ships with the latest (working) version of yt-dlp built-in, so you don't have to install yt-dlp at all! Unless you want to.
26
+
27
+ Some features of yt-dlp require ffmpeg or avconf to be installed. Normally these are available for installation from your distribution's repositories.
28
+
29
+ ## Usage
30
+
31
+ Pretty simple.
32
+
33
+ ```ruby
34
+ YtDlp.download "https://www.youtube.com/watch?v=gvdf5n-zI14", output: 'some_file.mp4'
35
+ ```
36
+
37
+ All options available to yt-dlp can be passed to the options hash
38
+
39
+ ```ruby
40
+ options = {
41
+ username: 'someone',
42
+ password: 'password1',
43
+ rate_limit: '50K',
44
+ format: :worst,
45
+ continue: false
46
+ }
47
+
48
+ YtDlp.download "https://www.youtube.com/watch?v=gvdf5n-zI14", options
49
+ ```
50
+
51
+ Options passed as `options = {option: true}` or `options = {option: false}` are passed to yt-dlp as `--option` or `--no-option`
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Pass test suite (`rake test`)
59
+ 5. Push to the branch (`git push origin my-new-feature`)
60
+ 6. Create a new Pull Request
61
+
62
+ Remember: commit now, commit often.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'erb'
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = 'test/**/*_test.rb'
9
+ end
10
+
11
+ task default: [:test]
12
+
13
+ namespace :binaries do
14
+ def get_binaries(version)
15
+ puts 'Updating python script'
16
+ system("wget -O ./vendor/bin/yt-dlp https://github.com/yt-dlp/yt-dlp/releases/download/#{version}/yt-dlp")
17
+ puts 'Updating Windows EXE'
18
+ system("wget -O ./vendor/bin/yt-dlp.exe https://github.com/yt-dlp/yt-dlp/releases/download/#{version}/yt-dlp.exe")
19
+ end
20
+
21
+ desc 'Get binaries for specific version (run with `rake binaries:version[2015.07.07]`)'
22
+ task :version, [:ver] do |_t, a|
23
+ get_binaries(a[:ver])
24
+ end
25
+ end
26
+
27
+ __END__
28
+ # Version file
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YtDlp
4
+ # Option and configuration getting, setting, and storage, and all that
5
+ class Options
6
+ # @return [Hash] key value storage object
7
+ attr_accessor :store
8
+
9
+ # @return [Array] array of keys that won't be saved to the options store
10
+ attr_accessor :banned_keys
11
+
12
+ # Options initializer
13
+ #
14
+ # @param options [Hash] a hash of options
15
+ def initialize(options = {})
16
+ @store = if options.is_a? Hash
17
+ options
18
+ else
19
+ options.to_h
20
+ end
21
+
22
+ @banned_keys = []
23
+ end
24
+
25
+ # Returns options as a hash
26
+ #
27
+ # @return [Hash] hash of options
28
+ def to_hash
29
+ remove_banned
30
+ @store
31
+ end
32
+ alias to_h to_hash
33
+
34
+ # Iterate through the paramized keys and values.
35
+ #
36
+ # @yield [paramized_key, value]
37
+ # @return [Object] @store
38
+ #
39
+ # TODO: Enumerable?
40
+ def each_paramized
41
+ @store.each do |key, value|
42
+ yield(paramize(key), value)
43
+ end
44
+ end
45
+
46
+ # Iterate through the keys and their paramized counterparts.
47
+ #
48
+ # @yield [key, paramized_key]
49
+ # @return [Object] @store
50
+ def each_paramized_key
51
+ @store.each_key do |key|
52
+ yield(key, paramize(key))
53
+ end
54
+ end
55
+
56
+ # Set options using a block
57
+ #
58
+ # @yield [config] self
59
+ def configure
60
+ yield(self) if block_given?
61
+ remove_banned
62
+ self
63
+ end
64
+
65
+ # Get option with brackets syntax
66
+ #
67
+ # @param key [Object] key
68
+ # @return [Object] value
69
+ def [](key)
70
+ remove_banned
71
+ return nil if banned? key
72
+
73
+ @store[key.to_sym]
74
+ end
75
+
76
+ # Set option with brackets syntax
77
+ #
78
+ # @param key [Object] key
79
+ # @param value [Object] value
80
+ # @return [Object] whatever Hash#= returns
81
+ def []=(key, value)
82
+ remove_banned
83
+ return if banned? key
84
+
85
+ @store[key.to_sym] = value
86
+ end
87
+
88
+ # Merge options with given hash, removing banned keys, and returning a
89
+ # new instance of Options.
90
+ #
91
+ # @param hash [Hash] Hash to merge options with
92
+ # @return [YtDlp::Options] Merged Options instance
93
+ def with(hash)
94
+ merged = Options.new(@store.merge(hash.to_h))
95
+ merged.banned_keys = @banned_keys
96
+ merged.send(:remove_banned)
97
+ merged
98
+ end
99
+
100
+ # Option getting and setting using ghost methods
101
+ #
102
+ # @param method [Symbol] method name
103
+ # @param args [Array] list of arguments passed
104
+ # @param block [Proc] implicit block given
105
+ # @return [Object] the value of method in the options store
106
+ def method_missing(method, *args, &_block)
107
+ remove_banned
108
+ if method.to_s.include? '='
109
+ method = method.to_s.tr('=', '').to_sym
110
+ return nil if banned? method
111
+
112
+ @store[method] = args.first
113
+ else
114
+ return nil if banned? method
115
+
116
+ @store[method]
117
+ end
118
+ end
119
+
120
+ # Calls a block to do operations on keys
121
+ # See sanitize_keys! for examples
122
+ #
123
+ # @param block [Proc] Block with operations on keys
124
+ # @yieldparam key [Object] Original key
125
+ # @yieldreturn [Object] Manipulated key
126
+ def manipulate_keys!(&block)
127
+ @store.keys.each do |old_name|
128
+ new_name = block.call(old_name)
129
+ unless new_name == old_name
130
+ @store[new_name] = @store[old_name]
131
+ @store.delete(old_name)
132
+ end
133
+ end
134
+ end
135
+
136
+ # Symbolizes and sanitizes keys in the option store
137
+ #
138
+ # @return [Object] @store
139
+ def sanitize_keys!
140
+ # Symbolize
141
+ manipulate_keys! { |key_name| key_name.is_a?(Symbol) ? key_name : key_name.to_sym }
142
+
143
+ # Underscoreize (because Terrapin doesn't like hyphens)
144
+ manipulate_keys! { |key_name| key_name.to_s.tr('-', '_').to_sym }
145
+ end
146
+
147
+ # Symbolizes and sanitizes keys and returns a copy of self
148
+ #
149
+ # @return [YtDlp::Options] Options with sanitized keys.
150
+ def sanitize_keys
151
+ safe_copy = dup
152
+ safe_copy.sanitize_keys!
153
+ safe_copy
154
+ end
155
+
156
+ # Check if key is a banned key
157
+ #
158
+ # @param key [Object] key to check
159
+ # @return [Boolean] true if key is banned, false if not.
160
+ def banned?(key)
161
+ @banned_keys.include? key
162
+ end
163
+
164
+ private
165
+
166
+ # Helper function to convert option keys into command-line-friendly parameters
167
+ #
168
+ # @param key [Symbol, String] key to paramize
169
+ # @return [String] paramized key
170
+ def paramize(key)
171
+ key.to_s.tr('_', '-')
172
+ end
173
+
174
+ # Helper to remove banned keys from store
175
+ def remove_banned
176
+ @store.delete_if { |key, _value| banned? key }
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YtDlp
4
+ # Utility class for running and managing yt-dlp
5
+ class Runner
6
+ include YtDlp::Support
7
+
8
+ # @return [String] URL to download
9
+ attr_accessor :url
10
+
11
+ # @return [YtDlp::Options] Options access.
12
+ attr_accessor :options
13
+
14
+ # @return [String] Executable path
15
+ attr_reader :executable_path
16
+
17
+ # @return [String] Executable name to use
18
+ attr_accessor :executable
19
+
20
+ # Command Line runner initializer
21
+ #
22
+ # @param url [String] URL to pass to yt-dlp executable
23
+ # @param options [Hash, Options] options to pass to the executable. Automatically converted to Options if it isn't already
24
+ def initialize(url, options = {})
25
+ @url = url
26
+ @options = YtDlp::Options.new(options)
27
+ @executable = 'yt-dlp'
28
+ end
29
+
30
+ # Returns usable executable path for yt-dlp
31
+ #
32
+ # @return [String] usable executable path for yt-dlp
33
+ def executable_path
34
+ @executable_path ||= usable_executable_path_for(@executable)
35
+ end
36
+
37
+ # Returns Terrapin's runner engine
38
+ #
39
+ # @return [CommandLineRunner] backend runner class
40
+ def backend_runner
41
+ Terrapin::CommandLine.runner
42
+ end
43
+
44
+ # Sets Terrapin's runner engine
45
+ #
46
+ # @param terrapin_runner [CommandLineRunner] backend runner class
47
+ # @return [Object] whatever Terrapin::CommandLine.runner= returns.
48
+ def backend_runner=(terrapin_runner)
49
+ Terrapin::CommandLine.runner = terrapin_runner
50
+ end
51
+
52
+ # Returns the command string without running anything
53
+ #
54
+ # @return [String] command line string
55
+ def to_command
56
+ terrapin_line(options_to_commands).command(@options.store)
57
+ end
58
+ alias command to_command
59
+
60
+ # Runs the command
61
+ #
62
+ # @return [String] the output of yt-dlp
63
+ def run
64
+ terrapin_line(options_to_commands).run(@options.store)
65
+ end
66
+ alias download run
67
+
68
+ # Options configuration.
69
+ # Just aliases to options.configure
70
+ #
71
+ # @yield [config] options
72
+ # @param a [Array] arguments to pass to options#configure
73
+ # @param b [Proc] block to pass to options#configure
74
+ def configure(*a, &b)
75
+ options.configure(*a, &b)
76
+ end
77
+
78
+ private
79
+
80
+ # Parses options and converts them to Terrapin's syntax
81
+ #
82
+ # @return [String] commands ready to do terrapin
83
+ def options_to_commands
84
+ commands = []
85
+ @options.sanitize_keys.each_paramized_key do |key, paramized_key|
86
+ case @options[key].to_s
87
+ when 'true'
88
+ commands.push "--#{paramized_key}"
89
+ when 'false'
90
+ commands.push "--no-#{paramized_key}"
91
+ else
92
+ commands.push "--#{paramized_key} :#{key}"
93
+ end
94
+ end
95
+ commands.push quoted(url)
96
+ commands.join(' ')
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YtDlp
4
+ # Some support methods and glue logic.
5
+ module Support
6
+ # Returns a usable yt-dlp executable (system or vendor)
7
+ #
8
+ # @param exe [String] Executable to search for
9
+ # @return [String] executable path
10
+ def usable_executable_path_for(exe)
11
+ system_path = which(exe)
12
+ if system_path.nil?
13
+ # TODO: Search vendor bin for executable before just saying it's there.
14
+ vendor_path = File.absolute_path("#{__FILE__}/../../../vendor/bin/#{exe}")
15
+ File.chmod(775, vendor_path) unless File.executable?(vendor_path) # Make sure vendor binary is executable
16
+ vendor_path
17
+ else
18
+ system_path.strip
19
+ end
20
+ end
21
+
22
+ alias executable_path_for usable_executable_path_for
23
+
24
+ # Helper for doing lines of terrapin (initializing, auto executable stuff, etc)
25
+ #
26
+ # @param command [String] command switches to run
27
+ # @param executable_path [String] executable to run. Defaults to usable yt-dlp.
28
+ # @return [Terrapin::CommandLine] initialized Terrapin instance
29
+ def terrapin_line(command, executable_path = nil)
30
+ executable_path = executable_path_for('yt-dlp') if executable_path.nil?
31
+ Terrapin::CommandLine.new(executable_path, command)
32
+ end
33
+
34
+ # Helper to add quotes to beginning and end of a URL or whatever you want....
35
+ #
36
+ # @param url [String] Raw URL
37
+ # @return [String] Quoted URL
38
+ def quoted(url)
39
+ "\"#{url}\""
40
+ end
41
+
42
+ # Cross-platform way of finding an executable in the $PATH.
43
+ # Stolen from http://stackoverflow.com/a/5471032
44
+ #
45
+ # which('ruby') #=> /usr/bin/ruby
46
+ #
47
+ # @param cmd [String] cmd to search for
48
+ # @return [String] full path for the cmd
49
+ def which(cmd)
50
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
51
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
52
+ exts.each do |ext|
53
+ exe = File.join(path, "#{cmd}#{ext}")
54
+ return exe if File.executable?(exe) && !File.directory?(exe)
55
+ end
56
+ end
57
+ nil
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Version file
4
+ # If you are updating this code, make sure you are updating
5
+ # lib/yt-dlp/version.rb as well as the Rakefile.
6
+
7
+ module YtDlp
8
+ # Semantic Version as well as the bundled binary version.
9
+ # "(major).(minor).(teeny).(pre-release).(binary-version)"
10
+ VERSION = '0.1.0'
11
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YtDlp
4
+ # Video model for using and downloading a single video.
5
+ class Video < Runner
6
+ class << self
7
+ # Instantiate a new Video model and download the video
8
+ #
9
+ # YtDlp.download 'https://www.youtube.com/watch?v=KLRDLIIl8bA' # => #<YtDlp::Video:0x00000000000000>
10
+ # YtDlp.get 'https://www.youtube.com/watch?v=ia1diPnNBgU', extract_audio: true, audio_quality: 0
11
+ #
12
+ # @param url [String] URL to use and download
13
+ # @param options [Hash] Options to pass in
14
+ # @return [YtDlp::Video] new Video model
15
+ def download(url, options = {})
16
+ video = new(url, options)
17
+ video.download
18
+ video
19
+ end
20
+ alias get download
21
+
22
+ def information(url, options = {})
23
+ video = new(url, options)
24
+ video.information
25
+ end
26
+ end
27
+
28
+ # @return [YtDlp::Options] Download Options for the last download
29
+ attr_reader :download_options
30
+
31
+ # Instantiate new model
32
+ #
33
+ # @param url [String] URL to initialize with
34
+ # @param options [Hash] Options to populate the everything with
35
+ def initialize(url, options = {})
36
+ @url = url
37
+ @options = YtDlp::Options.new(options.merge(default_options))
38
+ @options.banned_keys = banned_keys
39
+ end
40
+
41
+ # Download the video.
42
+ def download
43
+ raise ArgumentError, 'url cannot be nil' if @url.nil?
44
+ raise ArgumentError, 'url cannot be empty' if @url.empty?
45
+
46
+ set_information_from_json(YtDlp::Runner.new(url, runner_options).run)
47
+ end
48
+
49
+ alias get download
50
+
51
+ # Returns the expected filename
52
+ #
53
+ # @return [String] Filename downloaded to
54
+ def filename
55
+ _filename
56
+ end
57
+
58
+ # Metadata information for the video, gotten from --print-json
59
+ #
60
+ # @return [OpenStruct] information
61
+ def information
62
+ @information || grab_information_without_download
63
+ end
64
+
65
+ # Redirect methods for information getting
66
+ #
67
+ # @param method [Symbol] method name
68
+ # @param args [Array] method arguments
69
+ # @param block [Proc] explict block
70
+ # @return [Object] The value from @information
71
+ def method_missing(method, *args, &block)
72
+ value =
73
+ if information.is_a?(Array)
74
+ information.first[method]
75
+ else
76
+ information[method]
77
+ end
78
+
79
+ if value.nil?
80
+ super
81
+ else
82
+ value
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ # Add in other default options here.
89
+ def default_options
90
+ {
91
+ color: false,
92
+ progress: false,
93
+ print_json: true
94
+ }
95
+ end
96
+
97
+ def banned_keys
98
+ %i[
99
+ get_url
100
+ get_title
101
+ get_id
102
+ get_thumbnail
103
+ get_description
104
+ get_duration
105
+ get_filename
106
+ get_format
107
+ ]
108
+ end
109
+
110
+ def runner_options
111
+ YtDlp::Options.new(@options.to_h.merge(default_options))
112
+ end
113
+
114
+ def set_information_from_json(json) # :nodoc:
115
+ @information =
116
+ if json.include?("\n")
117
+ json.split("\n").collect do |root_node|
118
+ JSON.parse(root_node, symbolize_names: true)
119
+ end
120
+ else
121
+ JSON.parse(json, symbolize_names: true)
122
+ end
123
+ end
124
+
125
+ def grab_information_without_download # :nodoc:
126
+ set_information_from_json(YtDlp::Runner.new(url, runner_options.with({ skip_download: true })).run)
127
+ end
128
+ end
129
+ end
data/lib/yt-dlp.rb ADDED
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terrapin'
4
+ require 'json'
5
+ require 'ostruct'
6
+
7
+ require 'yt-dlp/version'
8
+ require 'yt-dlp/support'
9
+ require 'yt-dlp/options'
10
+ require 'yt-dlp/runner'
11
+ require 'yt-dlp/video'
12
+
13
+ # Global YtDlp module. Contains some convenience methods and all of the business classes.
14
+ module YtDlp
15
+ extend self
16
+ extend Support
17
+
18
+ # Downloads given array of URLs with any options passed
19
+ #
20
+ # @param urls [String, Array] URLs to download
21
+ # @param options [Hash] Downloader options
22
+ # @return [YtDlp::Video, Array] Video model or array of Video models
23
+ def download(urls, options = {})
24
+ if urls.is_a? Array
25
+ urls.map { |url| YtDlp::Video.get(url, options) }
26
+ else
27
+ YtDlp::Video.get(urls, options) # Urls should be singular but oh well. url = urls. There. Go cry in a corner.
28
+ end
29
+ end
30
+
31
+ alias get download
32
+
33
+ def information(urls, options = {})
34
+ if urls.is_a? Array
35
+ urls.map { |url| YtDlp::Video.information(url, options) }
36
+ else
37
+ YtDlp::Video.information(urls, options) # Urls should be singular but oh well. url = urls. There. Go cry in a corner.
38
+ end
39
+ end
40
+
41
+ # Lists extractors
42
+ #
43
+ # @return [Array] list of extractors
44
+ def extractors
45
+ @extractors ||= terrapin_line('--list-extractors').run.split("\n")
46
+ end
47
+
48
+ # Returns yt-dlp's version
49
+ #
50
+ # @return [String] yt-dlp version
51
+ def binary_version
52
+ @binary_version ||= terrapin_line('--version').run.strip
53
+ end
54
+
55
+ # Returns user agent
56
+ #
57
+ # @return [String] user agent
58
+ def user_agent
59
+ @user_agent ||= terrapin_line('--dump-user-agent').run.strip
60
+ end
61
+ end
data/vendor/bin/yt-dlp ADDED
Binary file
Binary file
data/yt-dlp.rb.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'yt-dlp/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'yt-dlp.rb'
9
+ spec.version = YtDlp::VERSION
10
+ spec.authors = %w[andrepcg]
11
+ spec.email = ['andrepcg@gmail.com']
12
+ spec.summary = 'yt-dlp wrapper for Ruby'
13
+ spec.description = 'yt-dlp.rb is a command line wrapper for the python script yt-dlp'
14
+ spec.homepage = 'https://github.com/andrepcg/yt-dlp.rb'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ # spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+ spec.required_ruby_version = '>= 2.6'
22
+
23
+ spec.add_dependency 'terrapin', '>=0.6.0'
24
+
25
+ spec.add_development_dependency 'bundler', '>= 1.6'
26
+ spec.add_development_dependency 'codeclimate-test-reporter'
27
+ spec.add_development_dependency 'minitest', '~> 5.14.3'
28
+ spec.add_development_dependency 'purdytest'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yt-dlp.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - andrepcg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terrapin
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: codeclimate-test-reporter
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 5.14.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 5.14.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: purdytest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ description: yt-dlp.rb is a command line wrapper for the python script yt-dlp
98
+ email:
99
+ - andrepcg@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".github/workflows/ci.yml"
105
+ - ".gitignore"
106
+ - ".rubocop.yml"
107
+ - ".rubocop_todo.yml"
108
+ - ".ruby-version"
109
+ - 1.0_RELEASE_GOALS.md
110
+ - Gemfile
111
+ - LICENSE.txt
112
+ - README.md
113
+ - Rakefile
114
+ - lib/yt-dlp.rb
115
+ - lib/yt-dlp/options.rb
116
+ - lib/yt-dlp/runner.rb
117
+ - lib/yt-dlp/support.rb
118
+ - lib/yt-dlp/version.rb
119
+ - lib/yt-dlp/video.rb
120
+ - vendor/bin/yt-dlp
121
+ - vendor/bin/yt-dlp.exe
122
+ - yt-dlp.rb.gemspec
123
+ homepage: https://github.com/andrepcg/yt-dlp.rb
124
+ licenses:
125
+ - MIT
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '2.6'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubygems_version: 3.1.4
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: yt-dlp wrapper for Ruby
146
+ test_files: []