yt-dlp.rb 0.1.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 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: []