vidload 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f2f19f4a3e68894970ee46251031cabb28592bd242f0e1b7e2ecc8f5d40c3ee
4
- data.tar.gz: 78b597dba867b0b988021cee4b8d35ea2a42d5df224af9cd052873c92687cada
3
+ metadata.gz: e25ffa5a4bdbfdadd4ee261da31fab7f78e15f6865196bec9ed6824d827918cc
4
+ data.tar.gz: 85cbad777cffda334cf26c8992fe42b8a209eaed2b6210cea733e1f54f7cadcb
5
5
  SHA512:
6
- metadata.gz: a4261172dc43b40d8f652f96103612d286825816c3d0acc57c2819364545158935c358a0b13b3cb7280d0b9281edc966cb8104c019306ad847548cf7de281120
7
- data.tar.gz: ea0934e1a52dee15f4204a16c5e1bd08580742b634ad02f86cf17f776373b5b60216098ef94e07e4770903d341c482fd0c1f15b8b4bf738ab1614649588e90e9
6
+ metadata.gz: 898294dbb222d1d84f31cde9b4b30f7689de6cd18bacf2dd452496346be24f83245d24f52c1125291256020533e5b759091f4c67a7d7a9b47ed7457416a29633
7
+ data.tar.gz: 6bfae7fb0047df91c7aecfc6cc0f6302f895b6872e52dedad7751a2fbb39f97ee29966a437a5f1ba8b1dfd8324c34704e846cd930e1768324e8a2f0d64343bde
data/lib/vidload/cli.rb CHANGED
@@ -1,36 +1,32 @@
1
- require "thor"
1
+ # frozen_string_literal: true
2
2
 
3
- class Vidload::Cli < Thor
4
- desc "mp2t VIDEO_URL", "download a mp2t containerized video"
5
- method_option :video_name, type: :string, required: false
6
- method_option :author_name, type: :string, required: false
7
- method_option :output_dir, type: :string, required: false
8
- method_option :hls_url, type: :string, required: true
9
- method_option :master_playlist_name, type: :string, required: true
10
- method_option :playwright_cli_path, type: :string, required: true
11
- method_option :video_referer, type: :string, required: true
12
- method_option :ts_seg_pattern, type: :string, required: true
13
- method_option :hls_index_pattern, type: :string, required: true
14
- def mp2t(video_url)
15
- params = {
16
- video_url: video_url,
17
- video_name: options[:video_name],
18
- hls_url: options[:hls_url],
19
- master_playlist_name: options[:master_playlist_name],
20
- playwright_cli_path: options[:playwright_cli_path],
21
- video_referer: options[:video_referer],
22
- ts_seg_pattern: options[:ts_seg_pattern],
23
- hls_index_pattern: options[:hls_index_pattern],
24
- author_name: options[:author_name],
25
- output_dir: options[:output_dir],
26
- }
3
+ require 'thor'
27
4
 
28
- process_mp2t(params)
29
- end
5
+ module Vidload
6
+ class Cli < Thor
7
+ desc 'mp2t VIDEO_URL', 'download a mp2t containerized video'
8
+ method_option :video_name, type: :string, required: false
9
+ method_option :author_name, type: :string, required: false
10
+ method_option :output_dir, type: :string, required: false
11
+ method_option :hls_url, type: :string, required: true
12
+ method_option :master_playlist_name, type: :string, required: true
13
+ method_option :playwright_cli_path, type: :string, required: true
14
+ method_option :video_referer, type: :string, required: true
15
+ method_option :ts_seg_pattern, type: :string, required: true
16
+ method_option :hls_index_pattern, type: :string, required: true
17
+ def mp2t(video_url)
18
+ params = {
19
+ video_url: video_url,
20
+ **options
21
+ }
22
+
23
+ process_mp2t(params)
24
+ end
30
25
 
31
- private
26
+ private
32
27
 
33
- def process_mp2t(params)
34
- raise NotImplementedError
28
+ def process_mp2t(params)
29
+ raise NotImplementedError
30
+ end
35
31
  end
36
32
  end
@@ -1,220 +1,239 @@
1
- require "playwright"
2
- require "thread"
3
- require "tty-spinner"
4
- require "open3"
5
- require "m3u8"
6
- require "io/console"
7
-
8
- module Vidload::Mp2t::Api
9
- DEMUXER_PATH = "#{__dir__}/remuxer.sh"
10
- VIDEO_DOWNLOADED_EVENT_QUEUE = Queue.new
11
- VIDEO_INDEX_EVENT_QUEUE = Queue.new
12
- ANSI_BOLD_WHITE="\033[1;97m"
13
- ANSI_LIGHT_GREY="\033[37m"
14
- ANSI_RESET="\033[0m"
15
-
16
- class Downloader
17
- attr_reader :video_url, :video_name, :hls_url, :master_playlist_name, :playwright_cli_path, :video_referer
18
-
19
- def initialize(
20
- video_url:,
21
- video_name:,
22
- author_name:,
23
- hls_url:,
24
- master_playlist_name:,
25
- playwright_cli_path:,
26
- video_referer:,
27
- ts_seg_pattern:,
28
- hls_index_pattern:,
29
- output_dir:
30
- )
31
- raise ArgumentError, "video_url must be provided" unless video_url
32
- raise ArgumentError, "hls_url must be provided" unless hls_url
33
- raise ArgumentError, "master_playlist_name must be provided" unless master_playlist_name
34
- raise ArgumentError, "playwright_cli_path must be provided" unless playwright_cli_path
35
- raise ArgumentError, "video_referer must be provided" unless video_referer
36
- raise ArgumentError, "ts_seg_pattern must be provided" unless ts_seg_pattern
37
- raise ArgumentError, "hls_index_pattern must be provided" unless hls_index_pattern
38
-
39
- @video_url = video_url
40
- @hls_url = hls_url
41
- @master_playlist_name = master_playlist_name
42
- @playwright_cli_path = playwright_cli_path
43
- @video_referer = video_referer
44
- @ts_seg_pattern = ts_seg_pattern
45
- @hls_index_pattern = hls_index_pattern
46
- @max_lines = IO.console.winsize[0]
47
- @author_name = author_name
48
- @video_name = if @author_name then "#{@author_name}_#{video_name}" else nil end
49
- @output_dir = output_dir || "./"
50
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'playwright'
4
+ require 'tty-spinner'
5
+ require 'open3'
6
+ require 'm3u8'
7
+ require 'io/console'
8
+
9
+ module Vidload
10
+ module Mp2t
11
+ module Api
12
+ DEMUXER_PATH = "#{__dir__}/remuxer.sh"
13
+ VIDEO_DOWNLOADED_EVENT_QUEUE = Queue.new
14
+ VIDEO_INDEX_EVENT_QUEUE = Queue.new
15
+ ANSI_BOLD_WHITE = "\033[1;97m"
16
+ ANSI_LIGHT_GREY = "\033[37m"
17
+ ANSI_RESET = "\033[0m"
18
+
19
+ class DownloaderBuilder
20
+ REQUIRED_ARGS = %i[video_url hls_url master_playlist_name playwright_cli_path video_referer
21
+ ts_seg_pattern hls_index_pattern].freeze
22
+
23
+ def initialize
24
+ @kwargs = {}
25
+ end
51
26
 
52
- def self.from_argv
53
- new(
54
- video_url: ARGV[0],
55
- video_name: ARGV[1],
56
- hls_url: ARGV[2],
57
- master_playlist_name: ARGV[3],
58
- playwright_cli_path: ARGV[4],
59
- video_referer: ARGV[5],
60
- ts_seg_pattern: ARGV[6],
61
- hls_index_pattern: ARGV[7],
62
- author_name: ARGV[8],
63
- )
64
- end
27
+ def with_kwargs(**kwargs)
28
+ @kwargs = kwargs
29
+ self
30
+ end
65
31
 
66
- def self.from_hash(hash)
67
- new(
68
- video_url: hash[:video_url],
69
- author_name: hash[:author_name],
70
- video_name: hash[:video_name],
71
- hls_url: hash[:hls_url],
72
- master_playlist_name: hash[:master_playlist_name],
73
- playwright_cli_path: hash[:playwright_cli_path],
74
- video_referer: hash[:video_referer],
75
- ts_seg_pattern: hash[:ts_seg_pattern],
76
- hls_index_pattern: hash[:hls_index_pattern],
77
- )
78
- end
32
+ def with_video_url(video_url)
33
+ @kwargs[:video_url] = video_url
34
+ self
35
+ end
79
36
 
80
- # main func to be called in your own scripts defined under web/
81
- def download_video(video_starter_callbacks: [])
82
- Playwright.create(playwright_cli_executable_path: @playwright_cli_path) do |playwright|
83
- browser = playwright.chromium.launch
84
- page = browser.new_page
37
+ def with_video_name(video_name)
38
+ @kwargs[:video_name] = video_name
39
+ self
40
+ end
85
41
 
86
- manage_video_download(page, *video_starter_callbacks)
87
- wait_until_video_downloaded
42
+ def with_author_name(author_name)
43
+ @kwargs[:author_name] = author_name
44
+ self
45
+ end
88
46
 
89
- browser.close
90
- end
91
- end
47
+ def with_hls_url(hls_url)
48
+ @kwargs[:hls_url] = hls_url
49
+ self
50
+ end
92
51
 
93
- def display_calling_args
94
- puts "Constants:"
95
- puts "\tDEMUXER_PATH=#{DEMUXER_PATH}"
96
- puts "Called with:"
97
- puts "\tvideo_url=#{@video_url}"
98
- puts "\tvideo_name=#{@video_name}"
99
- puts "\thls_url=#{@hls_url}"
100
- puts "\tmaster_playlist_name=#{@master_playlist_name}"
101
- puts "\tplaywright_cli_path=#{@playwright_cli_path}"
102
- puts "\tvideo_referer=#{@video_referer}"
103
- puts "\tts_seg_pattern=#{@ts_seg_pattern}"
104
- puts "\thls_index_pattern=#{@hls_index_pattern}"
105
- puts "\tauthor_name=#{@author_name}"
106
- end
52
+ def with_master_playlist_name(master_playlist_name)
53
+ @kwargs[:master_playlist_name] = master_playlist_name
54
+ self
55
+ end
107
56
 
108
- def self.display_with_spinner(loading_msg = "Loading...")
109
- spinner = TTY::Spinner.new("[:spinner] #{loading_msg}")
110
- spinner.auto_spin
111
- yield
112
- spinner.success("(done)")
113
- end
57
+ def with_playwright_cli_path(playwright_cli_path)
58
+ @kwargs[:playwright_cli_path] = playwright_cli_path
59
+ self
60
+ end
114
61
 
115
- private
62
+ def with_video_referer(video_referer)
63
+ @kwargs[:video_referer] = video_referer
64
+ self
65
+ end
116
66
 
117
- def manage_video_download(page, *video_starter_callbacks)
118
- @seg_qty = nil
119
- @pending_hls_response = nil
120
- @lines = [""] * @max_lines
121
- page.on("response", -> (resp) { listen_to_video_starts(resp) })
122
- navigate_to_url(@video_url, page)
123
- video_starter_callbacks.each do |callback|
124
- res = callback.call(page)
125
- if !@video_name && res[:video_name]
126
- @video_name = res[:video_name]
67
+ def with_ts_seg_pattern(ts_seg_pattern)
68
+ @kwargs[:ts_seg_pattern] = ts_seg_pattern
69
+ self
127
70
  end
128
- if !@author_name && res[:author_name]
129
- @author_name = res[:author_name]
130
- @video_name = "#{@author_name}_#{@video_name}"
71
+
72
+ def with_hls_index_pattern(hls_index_pattern)
73
+ @kwargs[:hls_index_pattern] = hls_index_pattern
74
+ self
131
75
  end
132
- end
133
- end
134
76
 
135
- def wait_until_video_downloaded
136
- VIDEO_DOWNLOADED_EVENT_QUEUE.pop
137
- end
77
+ def with_output_dir(output_dir)
78
+ @kwargs[:output_dir] = output_dir
79
+ self
80
+ end
138
81
 
139
- def trigger_video_download(video_url, seg_qty)
140
- puts "Video starts. Starting download..."
141
- run_cmd(DEMUXER_PATH, video_url, "#{@output_dir}#{@video_name}", @video_referer) do |line|
142
- if (line.include?("hls @") || line.include?("https @")) && line.match?(/#{@ts_seg_pattern}/i)
143
- seg_nb = line.match(/#{@ts_seg_pattern}/i)[:seg_nb]
144
- add_line(line)
145
- progress_bar(seg_nb, seg_qty)
82
+ def build
83
+ REQUIRED_ARGS.each do |required_arg|
84
+ raise ArgumentError, "#{required_arg} must be provided" unless @kwargs[required_arg]
85
+ end
86
+
87
+ @kwargs[:output_dir] = './' unless @kwargs[:output_dir]
88
+ @kwargs[:video_name] = "#{@kwargs[:author_name]}_#{@kwargs[:video_name]}" if @kwargs[:author_name]
89
+
90
+ Downloader.new(**@kwargs)
146
91
  end
147
92
  end
148
- print "\r\e[2K"
149
- puts "✔ Video downloaded successfully! Available in #{@output_dir}#{@video_name}.mp4"
150
- VIDEO_DOWNLOADED_EVENT_QUEUE << true
151
- end
152
93
 
153
- def listen_to_video_starts(response)
154
- if response.url.start_with?(@hls_url) && response.url.match?(/#{@hls_index_pattern}/i)
155
- body = response.text
156
- playlist = M3u8::Playlist.read(body)
157
- last_item = playlist.items.last.segment
158
- match = last_item.match(/#{@ts_seg_pattern}/i)
159
- @seg_qty = match[:seg_nb].to_i
94
+ class Downloader
95
+ def initialize(**kwargs)
96
+ @max_lines = IO.console.winsize[0]
97
+ @kwargs = kwargs
98
+ end
160
99
 
161
- if @pending_hls_response
162
- trigger_video_download(@pending_hls_response.url, @seg_qty)
100
+ def self.builder
101
+ DownloaderBuilder.new
163
102
  end
164
- elsif response.url.start_with?(@hls_url) && response.url.include?(@master_playlist_name)
165
- if @seg_qty
166
- trigger_video_download(response.url, @seg_qty)
167
- else
168
- @pending_hls_response = response
103
+
104
+ def self.from_hash(hash)
105
+ builder.with_kwargs(**hash).build
169
106
  end
170
- end
171
- end
172
107
 
173
- def navigate_to_url(url, page)
174
- Downloader.display_with_spinner("Page #{url} loading...") do
175
- page.goto(url)
176
- end
177
- end
108
+ # main func to be called in your own scripts defined under web/
109
+ def download_video(video_starter_callbacks: [])
110
+ Playwright.create(playwright_cli_executable_path: @kwargs[:playwright_cli_path]) do |playwright|
111
+ browser = playwright.chromium.launch
112
+ page = browser.new_page
178
113
 
179
- def run_cmd(*cmd)
180
- Open3.popen2e(*cmd) do |_stdin, stdout_and_stderr, wait_thr|
181
- stdout_and_stderr.each_line do |line|
182
- yield line
114
+ manage_video_download(page, *video_starter_callbacks)
115
+ wait_until_video_downloaded
116
+
117
+ browser.close
118
+ end
183
119
  end
184
- end
185
- end
186
120
 
187
- def redraw_lines()
188
- return if @lines.empty?
121
+ def display_calling_args
122
+ puts 'Constants:'
123
+ puts "\tDEMUXER_PATH=#{DEMUXER_PATH}"
124
+ puts 'Called with:'
125
+ @kwargs.each do |key, value|
126
+ puts "\t#{key}=#{value}"
127
+ end
128
+ end
189
129
 
190
- printf "\e[H"
191
- printf "\e[0J"
130
+ def self.display_with_spinner(loading_msg = 'Loading...')
131
+ spinner = TTY::Spinner.new("[:spinner] #{loading_msg}")
132
+ spinner.auto_spin
133
+ yield
134
+ spinner.success('(done)')
135
+ end
192
136
 
193
- _rows, cols = IO.console.winsize
194
- @lines.each do |line|
195
- if line.length > cols
196
- puts "#{line.slice(0, cols - 3)}..."
197
- else
198
- puts line
137
+ private
138
+
139
+ def manage_video_download(page, *video_starter_callbacks)
140
+ @seg_qty = nil
141
+ @pending_hls_response = nil
142
+ @lines = [''] * @max_lines
143
+ page.on('response', ->(resp) { listen_to_video_starts(resp) })
144
+ navigate_to_url(@kwargs[:video_url], page)
145
+ video_starter_callbacks.each do |callback|
146
+ res = callback.call(page)
147
+ @kwargs[:video_name] = res[:video_name] if !@kwargs[:video_name] && res[:video_name]
148
+ if !@kwargs[:author_name] && res[:author_name]
149
+ @kwargs[:author_name] = res[:author_name]
150
+ @kwargs[:video_name] = "#{@kwargs[:author_name]}_#{@kwargs[:video_name]}"
151
+ end
152
+ end
199
153
  end
200
- end
201
- end
202
154
 
203
- def add_line(line)
204
- @lines << line
205
- @lines.shift if @lines.size > @max_lines
206
- redraw_lines()
207
- end
155
+ def wait_until_video_downloaded
156
+ VIDEO_DOWNLOADED_EVENT_QUEUE.pop
157
+ end
208
158
 
209
- def progress_bar(current, total, width: 40)
210
- ratio = current.to_f / total
211
- filled = (ratio * width).round
212
- empty = width - filled
159
+ def trigger_video_download(video_url, seg_qty)
160
+ puts 'Video starts. Starting download...'
161
+ run_cmd(DEMUXER_PATH, video_url, "#{@kwargs[:output_dir]}#{@kwargs[:video_name]}",
162
+ @kwargs[:video_referer]) do |line|
163
+ if (line.include?('hls @') || line.include?('https @')) && line.match?(/#{@kwargs[:ts_seg_pattern]}/i)
164
+ seg_nb = line.match(/#{@kwargs[:ts_seg_pattern]}/i)[:seg_nb]
165
+ add_line(line)
166
+ progress_bar(seg_nb, seg_qty)
167
+ end
168
+ end
169
+ print "\r\e[2K"
170
+ puts "✔ Video downloaded successfully! Available in #{@kwargs[:output_dir]}#{@kwargs[:video_name]}.mp4"
171
+ VIDEO_DOWNLOADED_EVENT_QUEUE << true
172
+ end
213
173
 
214
- bar = "█" * filled + "░" * empty
215
- percent = (ratio * 100).round(1)
174
+ def listen_to_video_starts(response)
175
+ if response.url.start_with?(@kwargs[:hls_url]) && response.url.match?(/#{@kwargs[:hls_index_pattern]}/i)
176
+ body = response.text
177
+ playlist = M3u8::Playlist.read(body)
178
+ last_item = playlist.items.last.segment
179
+ match = last_item.match(/#{@kwargs[:ts_seg_pattern]}/i)
180
+ @seg_qty = match[:seg_nb].to_i
181
+
182
+ trigger_video_download(@pending_hls_response.url, @seg_qty) if @pending_hls_response
183
+ elsif response.url.start_with?(@kwargs[:hls_url]) && response.url.include?(@kwargs[:master_playlist_name])
184
+ if @seg_qty
185
+ trigger_video_download(response.url, @seg_qty)
186
+ else
187
+ @pending_hls_response = response
188
+ end
189
+ end
190
+ end
216
191
 
217
- print "\r[#{bar}] #{percent}% (#{current}/#{total})"
192
+ def navigate_to_url(url, page)
193
+ Downloader.display_with_spinner("Page #{url} loading...") do
194
+ page.goto(url)
195
+ end
196
+ end
197
+
198
+ def run_cmd(*cmd, &block)
199
+ Open3.popen2e(*cmd) do |_stdin, stdout_and_stderr, _wait_thr|
200
+ stdout_and_stderr.each_line(&block)
201
+ end
202
+ end
203
+
204
+ def redraw_lines
205
+ return if @lines.empty?
206
+
207
+ printf "\e[H"
208
+ printf "\e[0J"
209
+
210
+ _rows, cols = IO.console.winsize
211
+ @lines.each do |line|
212
+ if line.length > cols
213
+ puts "#{line.slice(0, cols - 3)}..."
214
+ else
215
+ puts line
216
+ end
217
+ end
218
+ end
219
+
220
+ def add_line(line)
221
+ @lines << line
222
+ @lines.shift if @lines.size > @max_lines
223
+ redraw_lines
224
+ end
225
+
226
+ def progress_bar(current, total, width: 40)
227
+ ratio = current.to_f / total
228
+ filled = (ratio * width).round
229
+ empty = width - filled
230
+
231
+ bar = '█' * filled + '░' * empty
232
+ percent = (ratio * 100).round(1)
233
+
234
+ print "\r[#{bar}] #{percent}% (#{current}/#{total})"
235
+ end
236
+ end
218
237
  end
219
238
  end
220
239
  end
data/lib/vidload/mp2t.rb CHANGED
@@ -1,3 +1,7 @@
1
- module Vidload::Mp2t
2
- require_relative "mp2t/api"
1
+ # frozen_string_literal: true
2
+
3
+ module Vidload
4
+ module Mp2t
5
+ require_relative 'mp2t/api'
6
+ end
3
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Vidload
2
- VERSION = "0.2.0"
4
+ VERSION = '0.2.1'
3
5
  end
data/lib/vidload.rb CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Vidload
2
- require_relative "vidload/version"
3
- require_relative "vidload/mp2t"
4
- require_relative "vidload/cli"
4
+ require_relative 'vidload/version'
5
+ require_relative 'vidload/mp2t'
6
+ require_relative 'vidload/cli'
5
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vidload
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patacode <pata.codegineer@gmail.com>
@@ -10,6 +10,20 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2026-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: m3u8
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: playwright-ruby-client
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,61 +39,61 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: '1.58'
27
41
  - !ruby/object:Gem::Dependency
28
- name: tty-spinner
42
+ name: thor
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '0.9'
47
+ version: '1.5'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '0.9'
54
+ version: '1.5'
41
55
  - !ruby/object:Gem::Dependency
42
- name: m3u8
56
+ name: tty-spinner
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '1.8'
61
+ version: '0.9'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '1.8'
68
+ version: '0.9'
55
69
  - !ruby/object:Gem::Dependency
56
- name: thor
70
+ name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '1.5'
62
- type: :runtime
75
+ version: '13.3'
76
+ type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '1.5'
82
+ version: '13.3'
69
83
  - !ruby/object:Gem::Dependency
70
- name: rake
84
+ name: rubocop
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">="
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '0'
89
+ version: '1.85'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ">="
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '0'
96
+ version: '1.85'
83
97
  description:
84
98
  email:
85
99
  executables: []