vidload 0.1.7 → 0.1.9
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/vidload/mp2t/api.rb +94 -9
- data/lib/vidload/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1e31985b06dadaf2785ef93d95c31d4be1344f7009c3aa8249e82b98f595c241
|
|
4
|
+
data.tar.gz: a4fbe5dc7da663e70a3cdc6d7cd0642e0229d993f918b6d5e8a619b9716ec037
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea9730f179412b53445d348768212ca95d16cf921c674c0b00e9c370e36ed80ec710cba6a3fdbac4f312f86faed169e619b5608b1f2429cd0fc358e9dde802ed
|
|
7
|
+
data.tar.gz: ff0ee458009eeb3ee81a063dbcc7f14909e7d57a5aed3a802c8cf952ba3f9e0223bd837128e650c2bd97feb73e808b1848489250b05aeb7edc2246dfd1d4a684
|
data/lib/vidload/mp2t/api.rb
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
require "playwright"
|
|
2
2
|
require "thread"
|
|
3
3
|
require "tty-spinner"
|
|
4
|
+
require "open3"
|
|
5
|
+
require "m3u8"
|
|
6
|
+
require "io/console"
|
|
4
7
|
|
|
5
8
|
module Vidload::Mp2t::Api
|
|
6
9
|
DEMUXER_PATH = "#{__dir__}/remuxer.sh"
|
|
7
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"
|
|
8
15
|
|
|
9
16
|
class Downloader
|
|
10
17
|
attr_reader :video_url, :video_name, :hls_url, :master_playlist_name, :playwright_cli_path, :video_referer
|
|
@@ -15,7 +22,9 @@ module Vidload::Mp2t::Api
|
|
|
15
22
|
hls_url:,
|
|
16
23
|
master_playlist_name:,
|
|
17
24
|
playwright_cli_path:,
|
|
18
|
-
video_referer
|
|
25
|
+
video_referer:,
|
|
26
|
+
ts_seg_pattern:,
|
|
27
|
+
hls_index_pattern:
|
|
19
28
|
)
|
|
20
29
|
raise ArgumentError, "video_url must be provided" unless video_url
|
|
21
30
|
raise ArgumentError, "video_name must be provided" unless video_name
|
|
@@ -23,6 +32,8 @@ module Vidload::Mp2t::Api
|
|
|
23
32
|
raise ArgumentError, "master_playlist_name must be provided" unless master_playlist_name
|
|
24
33
|
raise ArgumentError, "playwright_cli_path must be provided" unless playwright_cli_path
|
|
25
34
|
raise ArgumentError, "video_referer must be provided" unless video_referer
|
|
35
|
+
raise ArgumentError, "ts_seg_pattern must be provided" unless ts_seg_pattern
|
|
36
|
+
raise ArgumentError, "hls_index_pattern must be provided" unless hls_index_pattern
|
|
26
37
|
|
|
27
38
|
@video_url = video_url
|
|
28
39
|
@video_name = video_name
|
|
@@ -30,6 +41,9 @@ module Vidload::Mp2t::Api
|
|
|
30
41
|
@master_playlist_name = master_playlist_name
|
|
31
42
|
@playwright_cli_path = playwright_cli_path
|
|
32
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]
|
|
33
47
|
end
|
|
34
48
|
|
|
35
49
|
def self.from_argv
|
|
@@ -39,7 +53,9 @@ module Vidload::Mp2t::Api
|
|
|
39
53
|
hls_url: ARGV[2],
|
|
40
54
|
master_playlist_name: ARGV[3],
|
|
41
55
|
playwright_cli_path: ARGV[4],
|
|
42
|
-
video_referer: ARGV[5]
|
|
56
|
+
video_referer: ARGV[5],
|
|
57
|
+
ts_seg_pattern: ARGV[6],
|
|
58
|
+
hls_index_pattern: ARGV[7],
|
|
43
59
|
)
|
|
44
60
|
end
|
|
45
61
|
|
|
@@ -78,7 +94,10 @@ module Vidload::Mp2t::Api
|
|
|
78
94
|
private
|
|
79
95
|
|
|
80
96
|
def manage_video_download(page, *video_starter_callbacks)
|
|
81
|
-
|
|
97
|
+
@seg_qty = nil
|
|
98
|
+
@pending_hls_response = nil
|
|
99
|
+
@lines = [""] * @max_lines
|
|
100
|
+
page.on("response", -> (resp) { listen_to_video_starts(resp) })
|
|
82
101
|
navigate_to_url(@video_url, page)
|
|
83
102
|
video_starter_callbacks.each do |callback|
|
|
84
103
|
callback.call(page)
|
|
@@ -89,12 +108,37 @@ module Vidload::Mp2t::Api
|
|
|
89
108
|
VIDEO_DOWNLOADED_EVENT_QUEUE.pop
|
|
90
109
|
end
|
|
91
110
|
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
111
|
+
def trigger_video_download(video_url, seg_qty)
|
|
112
|
+
puts "Video starts. Starting download..."
|
|
113
|
+
run_cmd(DEMUXER_PATH, video_url, @video_name, @video_referer) do |line|
|
|
114
|
+
if (line.include?("hls @") || line.include?("https @")) && line.match?(/#{@ts_seg_pattern}/i)
|
|
115
|
+
seg_nb = line.match(/#{@ts_seg_pattern}/i)[:seg_nb]
|
|
116
|
+
add_line(line)
|
|
117
|
+
progress_bar(seg_nb, seg_qty)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
print "\r\e[2K"
|
|
121
|
+
puts "✔ Video downloaded successfully! Available in ./#{@video_name}.mp4"
|
|
122
|
+
VIDEO_DOWNLOADED_EVENT_QUEUE << true
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def listen_to_video_starts(response)
|
|
126
|
+
if response.url.start_with?(@hls_url) && response.url.match?(/#{@hls_index_pattern}/i)
|
|
127
|
+
body = response.text
|
|
128
|
+
playlist = M3u8::Playlist.read(body)
|
|
129
|
+
last_item = playlist.items.last.segment
|
|
130
|
+
match = last_item.match(/#{@ts_seg_pattern}/i)
|
|
131
|
+
@seg_qty = match[:seg_nb].to_i
|
|
132
|
+
|
|
133
|
+
if @pending_hls_response
|
|
134
|
+
trigger_video_download(@pending_hls_response.url, @seg_qty)
|
|
135
|
+
end
|
|
136
|
+
elsif response.url.start_with?(@hls_url) && response.url.include?(@master_playlist_name)
|
|
137
|
+
if @seg_qty
|
|
138
|
+
trigger_video_download(response.url, @seg_qty)
|
|
139
|
+
else
|
|
140
|
+
@pending_hls_response = response
|
|
141
|
+
end
|
|
98
142
|
end
|
|
99
143
|
end
|
|
100
144
|
|
|
@@ -103,5 +147,46 @@ module Vidload::Mp2t::Api
|
|
|
103
147
|
page.goto(url)
|
|
104
148
|
end
|
|
105
149
|
end
|
|
150
|
+
|
|
151
|
+
def run_cmd(*cmd)
|
|
152
|
+
Open3.popen2e(*cmd) do |_stdin, stdout_and_stderr, wait_thr|
|
|
153
|
+
stdout_and_stderr.each_line do |line|
|
|
154
|
+
yield line
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def redraw_lines()
|
|
160
|
+
return if @lines.empty?
|
|
161
|
+
|
|
162
|
+
printf "\e[H"
|
|
163
|
+
printf "\e[0J"
|
|
164
|
+
|
|
165
|
+
_rows, cols = IO.console.winsize
|
|
166
|
+
@lines.each do |line|
|
|
167
|
+
if line.length > cols
|
|
168
|
+
puts "#{line.slice(0, cols - 3)}..."
|
|
169
|
+
else
|
|
170
|
+
puts line
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def add_line(line)
|
|
176
|
+
@lines << line
|
|
177
|
+
@lines.shift if @lines.size > @max_lines
|
|
178
|
+
redraw_lines()
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def progress_bar(current, total, width: 40)
|
|
182
|
+
ratio = current.to_f / total
|
|
183
|
+
filled = (ratio * width).round
|
|
184
|
+
empty = width - filled
|
|
185
|
+
|
|
186
|
+
bar = "█" * filled + "░" * empty
|
|
187
|
+
percent = (ratio * 100).round(1)
|
|
188
|
+
|
|
189
|
+
print "\r[#{bar}] #{percent}% (#{current}/#{total})"
|
|
190
|
+
end
|
|
106
191
|
end
|
|
107
192
|
end
|
data/lib/vidload/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vidload
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patacode <pata.codegineer@gmail.com>
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: playwright-ruby-client
|
|
@@ -38,6 +38,20 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0.9'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: m3u8
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.8'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.8'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: rake
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|