youtube-rb 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +149 -429
- data/lib/youtube-rb/client.rb +5 -2
- data/lib/youtube-rb/downloader.rb +64 -456
- data/lib/youtube-rb/options.rb +3 -7
- data/lib/youtube-rb/version.rb +1 -1
- data/lib/youtube-rb.rb +0 -2
- data/spec/client_spec.rb +9 -16
- data/spec/download_with_mocks_spec.rb +8 -18
- data/spec/downloader_spec.rb +21 -114
- data/spec/fixtures/rickroll_full_info.json +785 -23
- data/spec/integration/ytdlp_integration_spec.rb +1 -12
- data/spec/real_download_spec.rb +1 -30
- data/spec/support/mocking_helper.rb +103 -8
- data/spec/youtube_rb_spec.rb +2 -18
- data/youtube-rb.gemspec +2 -2
- metadata +4 -5
- data/lib/youtube-rb/extractor.rb +0 -425
data/README.md
CHANGED
|
@@ -1,45 +1,19 @@
|
|
|
1
1
|
# YoutubeRb
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A Ruby library for downloading videos, extracting video segments, and fetching subtitles from YouTube and other video platforms. Inspired by [youtube-dl](https://github.com/ytdl-org/youtube-dl) and powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp).
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- 🔧 **yt-dlp Backend** - Reliable video downloads with full YouTube support
|
|
8
8
|
- 📹 Download full videos or audio-only
|
|
9
|
-
- ✂️ Extract video segments (
|
|
9
|
+
- ✂️ Extract video segments (customizable duration limits)
|
|
10
10
|
- ⚡ **Optimized batch segment downloads** - Download video once, extract multiple segments locally (10-100x faster)
|
|
11
|
-
- 📝 Download subtitles (manual and auto-generated)
|
|
12
|
-
- 🎵 Extract audio in various formats (mp3, aac, opus, etc.)
|
|
11
|
+
- 📝 Download subtitles (manual and auto-generated) with automatic trimming for segments
|
|
12
|
+
- 🎵 Extract audio in various formats (mp3, aac, opus, flac, etc.)
|
|
13
13
|
- 📊 Get detailed video information
|
|
14
14
|
- 🔧 Flexible configuration options
|
|
15
15
|
- 🌐 Support for cookies and authentication
|
|
16
16
|
|
|
17
|
-
## Backend
|
|
18
|
-
|
|
19
|
-
YoutubeRb uses **yt-dlp** as its backend for reliable video downloads:
|
|
20
|
-
|
|
21
|
-
### yt-dlp (Required for segment downloads)
|
|
22
|
-
- Most reliable method for YouTube downloads
|
|
23
|
-
- Handles signature decryption automatically
|
|
24
|
-
- Works with all YouTube videos
|
|
25
|
-
- Bypasses 403 errors
|
|
26
|
-
- Supports authentication via cookies
|
|
27
|
-
- **Optimized for batch processing**: Downloads video once, extracts multiple segments locally
|
|
28
|
-
|
|
29
|
-
**Note**: yt-dlp is **required** for segment downloads (`download_segment` and `download_segments` methods). Full video downloads still support Pure Ruby fallback with automatic retry using yt-dlp.
|
|
30
|
-
|
|
31
|
-
## Important Notes
|
|
32
|
-
|
|
33
|
-
⚠️ **YouTube Protection**: YouTube actively protects videos with:
|
|
34
|
-
- Signature encryption (handled by yt-dlp)
|
|
35
|
-
- Bot detection (requires proper headers and cookies)
|
|
36
|
-
- Rate limiting (handled automatically)
|
|
37
|
-
|
|
38
|
-
💡 **Batch Optimization**: When downloading multiple segments from the same video, the library automatically:
|
|
39
|
-
1. Downloads the full video **once** via yt-dlp
|
|
40
|
-
2. Extracts all segments locally using FFmpeg
|
|
41
|
-
3. Result: **10-100x faster** than downloading each segment separately
|
|
42
|
-
|
|
43
17
|
## Installation
|
|
44
18
|
|
|
45
19
|
Add this line to your application's Gemfile:
|
|
@@ -60,13 +34,13 @@ Or install it yourself as:
|
|
|
60
34
|
|
|
61
35
|
### Ruby Version
|
|
62
36
|
|
|
63
|
-
- Ruby >=
|
|
37
|
+
- Ruby >= 3.4.0
|
|
64
38
|
|
|
65
39
|
### External Tools
|
|
66
40
|
|
|
67
|
-
#### yt-dlp (
|
|
41
|
+
#### yt-dlp (Required)
|
|
68
42
|
|
|
69
|
-
|
|
43
|
+
YoutubeRb uses yt-dlp as its backend for downloading videos. Install yt-dlp:
|
|
70
44
|
|
|
71
45
|
```bash
|
|
72
46
|
# Using pip (recommended)
|
|
@@ -82,11 +56,13 @@ brew install yt-dlp
|
|
|
82
56
|
# https://github.com/yt-dlp/yt-dlp/releases
|
|
83
57
|
```
|
|
84
58
|
|
|
59
|
+
**Note**: yt-dlp is **required** for all download operations.
|
|
60
|
+
|
|
85
61
|
#### FFmpeg (Optional)
|
|
86
62
|
|
|
87
63
|
Required only for:
|
|
88
64
|
- Audio extraction from video
|
|
89
|
-
- Segment extraction (
|
|
65
|
+
- Segment extraction (time-based clips)
|
|
90
66
|
- Format conversion
|
|
91
67
|
|
|
92
68
|
```bash
|
|
@@ -108,26 +84,22 @@ client.check_dependencies
|
|
|
108
84
|
# => { ffmpeg: true, ytdlp: true, ytdlp_version: "2024.01.13" }
|
|
109
85
|
```
|
|
110
86
|
|
|
111
|
-
##
|
|
112
|
-
|
|
113
|
-
### Quick Start
|
|
87
|
+
## Quick Start
|
|
114
88
|
|
|
115
89
|
```ruby
|
|
116
90
|
require 'youtube-rb'
|
|
117
91
|
|
|
118
|
-
#
|
|
92
|
+
# Simple download
|
|
119
93
|
YoutubeRb.download('https://www.youtube.com/watch?v=VIDEO_ID',
|
|
120
94
|
output_path: './downloads'
|
|
121
95
|
)
|
|
122
96
|
|
|
123
|
-
#
|
|
124
|
-
info = YoutubeRb.info('https://www.youtube.com/watch?v=
|
|
97
|
+
# Get video information
|
|
98
|
+
info = YoutubeRb.info('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
125
99
|
puts "Title: #{info.title}"
|
|
126
100
|
puts "Duration: #{info.duration_formatted}"
|
|
127
|
-
puts "Views: #{info.view_count}"
|
|
128
101
|
|
|
129
|
-
#
|
|
130
|
-
# Requires yt-dlp to be installed
|
|
102
|
+
# Download single segment (requires yt-dlp)
|
|
131
103
|
YoutubeRb.download_segment(
|
|
132
104
|
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
133
105
|
60, # start time in seconds
|
|
@@ -135,9 +107,7 @@ YoutubeRb.download_segment(
|
|
|
135
107
|
output_path: './segments'
|
|
136
108
|
)
|
|
137
109
|
|
|
138
|
-
#
|
|
139
|
-
# Downloads video ONCE via yt-dlp, then extracts all segments locally
|
|
140
|
-
# This is 10-100x faster than downloading each segment separately
|
|
110
|
+
# Download multiple segments (batch processing - 10-100x faster!)
|
|
141
111
|
YoutubeRb.download_segments(
|
|
142
112
|
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
143
113
|
[
|
|
@@ -147,160 +117,60 @@ YoutubeRb.download_segments(
|
|
|
147
117
|
],
|
|
148
118
|
output_path: './segments'
|
|
149
119
|
)
|
|
150
|
-
|
|
151
|
-
# 5. Download only subtitles
|
|
152
|
-
YoutubeRb.download_subtitles(
|
|
153
|
-
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
154
|
-
langs: ['en', 'ru'],
|
|
155
|
-
output_path: './subs'
|
|
156
|
-
)
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Backend Configuration
|
|
160
|
-
|
|
161
|
-
```ruby
|
|
162
|
-
# Recommended: Enable verbose mode to see what's happening
|
|
163
|
-
client = YoutubeRb::Client.new(verbose: true)
|
|
164
|
-
client.download(url)
|
|
165
|
-
# [YoutubeRb] Using yt-dlp backend for download
|
|
166
|
-
# [YoutubeRb] Downloaded successfully with yt-dlp: ./downloads/video.mp4
|
|
167
|
-
|
|
168
|
-
# Full video downloads: Pure Ruby with yt-dlp fallback (default)
|
|
169
|
-
client = YoutubeRb::Client.new(ytdlp_fallback: true)
|
|
170
|
-
client.download(url) # Tries Pure Ruby first, falls back to yt-dlp on 403
|
|
171
|
-
|
|
172
|
-
# Segment downloads: Always use yt-dlp (required)
|
|
173
|
-
client.download_segment(url, 10, 30) # Requires yt-dlp
|
|
174
|
-
client.download_segments(url, segments) # Requires yt-dlp, optimized for batch
|
|
175
120
|
```
|
|
176
121
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
If you encounter 403 errors:
|
|
180
|
-
|
|
181
|
-
**Option 1: Use yt-dlp backend (easiest)**
|
|
182
|
-
```ruby
|
|
183
|
-
client = YoutubeRb::Client.new(use_ytdlp: true)
|
|
184
|
-
client.download(url)
|
|
185
|
-
```
|
|
122
|
+
## Usage
|
|
186
123
|
|
|
187
|
-
|
|
188
|
-
1. Install extension: [Get cookies.txt LOCALLY](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc) (Chrome) or [cookies.txt](https://addons.mozilla.org/firefox/addon/cookies-txt/) (Firefox)
|
|
189
|
-
2. Log into YouTube in your browser
|
|
190
|
-
3. Export cookies from youtube.com
|
|
191
|
-
4. Use cookies:
|
|
124
|
+
### Creating a Client
|
|
192
125
|
|
|
193
126
|
```ruby
|
|
194
|
-
|
|
195
|
-
cookies_file: './youtube_cookies.txt',
|
|
196
|
-
use_ytdlp: true
|
|
197
|
-
)
|
|
198
|
-
client.download(url)
|
|
199
|
-
```
|
|
127
|
+
require 'youtube-rb'
|
|
200
128
|
|
|
201
|
-
|
|
129
|
+
# Basic client
|
|
130
|
+
client = YoutubeRb::Client.new
|
|
202
131
|
|
|
203
|
-
|
|
132
|
+
# Client with options
|
|
204
133
|
client = YoutubeRb::Client.new(
|
|
205
|
-
# Backend
|
|
206
|
-
use_ytdlp: true, # Force yt-dlp (recommended)
|
|
207
|
-
ytdlp_fallback: true, # Auto fallback on error (default)
|
|
208
|
-
verbose: true, # Show progress logs
|
|
209
|
-
|
|
210
|
-
# Segment options
|
|
211
|
-
segment_mode: :fast, # :fast (default, 10x faster) or :precise (frame-accurate)
|
|
212
|
-
min_segment_duration: 10, # Minimum segment duration in seconds (default: 10)
|
|
213
|
-
max_segment_duration: 60, # Maximum segment duration in seconds (default: 60)
|
|
214
|
-
cache_full_video: false, # Cache full video for multiple segments (default: false, auto-enabled for batch)
|
|
215
|
-
|
|
216
|
-
# Output
|
|
217
134
|
output_path: './downloads',
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
# Quality
|
|
221
|
-
quality: 'best', # or '1080p', '720p', etc.
|
|
222
|
-
|
|
223
|
-
# Audio extraction
|
|
224
|
-
extract_audio: true,
|
|
225
|
-
audio_format: 'mp3', # mp3, aac, opus, flac, wav
|
|
226
|
-
audio_quality: '192',
|
|
227
|
-
|
|
228
|
-
# Subtitles
|
|
135
|
+
verbose: true,
|
|
229
136
|
write_subtitles: true,
|
|
230
|
-
subtitle_langs: ['en'
|
|
231
|
-
subtitle_format: 'srt', # srt or vtt
|
|
232
|
-
|
|
233
|
-
# Metadata
|
|
234
|
-
write_info_json: true,
|
|
235
|
-
write_thumbnail: true,
|
|
236
|
-
write_description: true,
|
|
237
|
-
|
|
238
|
-
# Authentication
|
|
239
|
-
cookies_file: './cookies.txt',
|
|
240
|
-
|
|
241
|
-
# Network
|
|
242
|
-
retries: 10,
|
|
243
|
-
user_agent: 'Mozilla/5.0...'
|
|
137
|
+
subtitle_langs: ['en']
|
|
244
138
|
)
|
|
245
139
|
```
|
|
246
140
|
|
|
247
|
-
###
|
|
141
|
+
### Download Methods
|
|
248
142
|
|
|
249
|
-
####
|
|
143
|
+
#### Full Video Download
|
|
250
144
|
|
|
251
145
|
```ruby
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
client = YoutubeRb::Client.new(
|
|
255
|
-
output_path: './downloads',
|
|
256
|
-
write_subtitles: true,
|
|
257
|
-
subtitle_langs: ['en', 'ru']
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
# Скачать видео
|
|
146
|
+
# Simple download
|
|
261
147
|
client.download('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
262
148
|
```
|
|
263
149
|
|
|
264
|
-
####
|
|
265
|
-
|
|
266
|
-
Скачивание определенных интервалов видео (10-60 секунд по умолчанию):
|
|
150
|
+
#### Single Segment Download
|
|
267
151
|
|
|
268
152
|
```ruby
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
# Скачать 30-секундный сегмент начиная с 1:00
|
|
153
|
+
# Download 30-second segment
|
|
272
154
|
output_file = client.download_segment(
|
|
273
155
|
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
274
|
-
60, #
|
|
275
|
-
90 #
|
|
156
|
+
60, # start time in seconds
|
|
157
|
+
90 # end time in seconds
|
|
276
158
|
)
|
|
277
159
|
|
|
278
|
-
#
|
|
160
|
+
# With custom output filename
|
|
279
161
|
client.download_segment(
|
|
280
|
-
|
|
281
|
-
120, 150,
|
|
162
|
+
url, 120, 150,
|
|
282
163
|
output_file: './my_segment.mp4'
|
|
283
164
|
)
|
|
284
165
|
|
|
285
|
-
#
|
|
286
|
-
client.download_segment(url, 0, 10) # ✓ Валидно (10 секунд)
|
|
287
|
-
client.download_segment(url, 0, 60) # ✓ Валидно (60 секунд)
|
|
288
|
-
client.download_segment(url, 0, 5) # ✗ Ошибка (слишком короткий)
|
|
289
|
-
client.download_segment(url, 0, 120) # ✗ Ошибка (слишком длинный)
|
|
290
|
-
|
|
291
|
-
# Настройка пользовательских ограничений длительности
|
|
166
|
+
# Configure segment duration limits (default: 10-60 seconds)
|
|
292
167
|
client = YoutubeRb::Client.new(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
max_segment_duration: 300 # максимум 5 минут
|
|
168
|
+
min_segment_duration: 5, # minimum 5 seconds
|
|
169
|
+
max_segment_duration: 300 # maximum 5 minutes
|
|
296
170
|
)
|
|
297
|
-
|
|
298
|
-
client.download_segment(url, 0, 5) # ✓ Валидно с новыми настройками
|
|
299
|
-
client.download_segment(url, 0, 300) # ✓ Валидно (5 минут)
|
|
300
171
|
```
|
|
301
172
|
|
|
302
|
-
|
|
303
|
-
Cuts may be off by a few seconds due to keyframe positions. For frame-accurate cuts:
|
|
173
|
+
**Performance Note**: By default, segments use **fast mode** (10x faster). Cuts may be off by a few seconds due to keyframe positions. For frame-accurate cuts:
|
|
304
174
|
|
|
305
175
|
```ruby
|
|
306
176
|
# Fast mode (default) - 10x faster, cuts at keyframes
|
|
@@ -310,39 +180,23 @@ client = YoutubeRb::Client.new(segment_mode: :fast)
|
|
|
310
180
|
client = YoutubeRb::Client.new(segment_mode: :precise)
|
|
311
181
|
```
|
|
312
182
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
#### Пакетная загрузка сегментов (новое!)
|
|
183
|
+
#### Batch Segment Download
|
|
316
184
|
|
|
317
|
-
|
|
185
|
+
For downloading multiple segments from one video, use `download_segments` for optimal performance:
|
|
318
186
|
|
|
319
187
|
```ruby
|
|
320
|
-
client = YoutubeRb::Client.new(output_path: './segments')
|
|
321
|
-
|
|
322
188
|
url = 'https://www.youtube.com/watch?v=VIDEO_ID'
|
|
323
189
|
|
|
324
190
|
segments = [
|
|
325
|
-
{ start: 0, end: 30 },
|
|
326
|
-
{ start: 60, end: 90 },
|
|
327
|
-
{ start: 120, end: 150 }
|
|
191
|
+
{ start: 0, end: 30 },
|
|
192
|
+
{ start: 60, end: 90 },
|
|
193
|
+
{ start: 120, end: 150 }
|
|
328
194
|
]
|
|
329
195
|
|
|
330
|
-
# Загрузит все сегменты эффективно
|
|
331
196
|
output_files = client.download_segments(url, segments)
|
|
332
|
-
# => ["./segments/video-segment-0-30.mp4",
|
|
333
|
-
|
|
334
|
-
puts "Downloaded #{output_files.size} segments"
|
|
335
|
-
```
|
|
197
|
+
# => ["./segments/video-segment-0-30.mp4", ...]
|
|
336
198
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
- **Оптимизация yt-dlp**: Видео скачивается через yt-dlp **один раз**, все сегменты вырезаются локально через FFmpeg
|
|
340
|
-
- **Быстрее в 10-100x**: Не нужно перекачивать видео для каждого сегмента
|
|
341
|
-
- **Экономия трафика**: Полное видео загружается один раз вместо N раз
|
|
342
|
-
- **Надежность**: Использует yt-dlp для обхода защиты YouTube, FFmpeg для быстрой нарезки
|
|
343
|
-
|
|
344
|
-
```ruby
|
|
345
|
-
# С пользовательскими именами файлов
|
|
199
|
+
# With custom filenames
|
|
346
200
|
segments = [
|
|
347
201
|
{ start: 0, end: 30, output_file: './intro.mp4' },
|
|
348
202
|
{ start: 60, end: 90, output_file: './main.mp4' },
|
|
@@ -350,59 +204,56 @@ segments = [
|
|
|
350
204
|
]
|
|
351
205
|
|
|
352
206
|
client.download_segments(url, segments)
|
|
353
|
-
|
|
354
|
-
# Явное управление кэшированием (по умолчанию включено для batch)
|
|
355
|
-
client = YoutubeRb::Client.new(
|
|
356
|
-
output_path: './segments',
|
|
357
|
-
cache_full_video: false # отключить кэш (медленнее)
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
# Или переопределить при вызове
|
|
361
|
-
client.download_segments(url, segments, cache_full_video: true)
|
|
362
207
|
```
|
|
363
208
|
|
|
364
|
-
|
|
209
|
+
**Benefits of Batch Processing:**
|
|
210
|
+
- **10-100x faster**: Video downloaded via yt-dlp once, all segments extracted locally with FFmpeg
|
|
211
|
+
- **Bandwidth savings**: Full video loaded once instead of N times
|
|
212
|
+
- **Reliability**: Uses yt-dlp to bypass YouTube protection
|
|
213
|
+
|
|
214
|
+
#### Subtitles Download
|
|
365
215
|
|
|
366
216
|
```ruby
|
|
217
|
+
# Download subtitles with video
|
|
367
218
|
client = YoutubeRb::Client.new(
|
|
368
|
-
output_path: './downloads',
|
|
369
219
|
write_subtitles: true,
|
|
370
220
|
subtitle_langs: ['en', 'ru']
|
|
371
221
|
)
|
|
222
|
+
client.download(url)
|
|
372
223
|
|
|
373
|
-
#
|
|
374
|
-
client.download_segment(url, 60, 90)
|
|
375
|
-
# Создаст: video-segment-60-90.mp4 и video-segment-60-90.en.srt
|
|
376
|
-
|
|
377
|
-
# Скачать только субтитры (без видео)
|
|
224
|
+
# Download subtitles only
|
|
378
225
|
client.download_subtitles(url, langs: ['en', 'ru'])
|
|
379
226
|
|
|
380
|
-
#
|
|
227
|
+
# Check available subtitle languages
|
|
381
228
|
info = client.info(url)
|
|
382
229
|
puts info.available_subtitle_languages.join(', ')
|
|
230
|
+
|
|
231
|
+
# Subtitles are automatically trimmed for segments
|
|
232
|
+
client.download_segment(url, 60, 90)
|
|
233
|
+
# Creates: video-segment-60-90.mp4 and video-segment-60-90.en.srt
|
|
383
234
|
```
|
|
384
235
|
|
|
385
|
-
####
|
|
236
|
+
#### Audio Extraction
|
|
386
237
|
|
|
387
238
|
```ruby
|
|
388
|
-
#
|
|
239
|
+
# Extract audio in MP3
|
|
389
240
|
client.extract_audio(url, format: 'mp3', quality: '192')
|
|
390
241
|
|
|
391
|
-
#
|
|
242
|
+
# Other formats
|
|
392
243
|
client.extract_audio(url, format: 'aac', quality: '128')
|
|
393
244
|
client.extract_audio(url, format: 'opus')
|
|
394
|
-
client.extract_audio(url, format: 'flac') #
|
|
245
|
+
client.extract_audio(url, format: 'flac') # lossless
|
|
395
246
|
|
|
396
|
-
#
|
|
247
|
+
# Or configure client to extract audio by default
|
|
397
248
|
client = YoutubeRb::Client.new(
|
|
398
249
|
extract_audio: true,
|
|
399
250
|
audio_format: 'mp3',
|
|
400
251
|
audio_quality: '320'
|
|
401
252
|
)
|
|
402
|
-
client.download(url) #
|
|
253
|
+
client.download(url) # Downloads audio only
|
|
403
254
|
```
|
|
404
255
|
|
|
405
|
-
|
|
256
|
+
### Video Information
|
|
406
257
|
|
|
407
258
|
```ruby
|
|
408
259
|
info = client.info('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
@@ -413,70 +264,25 @@ puts info.duration_formatted # "01:23:45"
|
|
|
413
264
|
puts info.view_count
|
|
414
265
|
puts info.uploader
|
|
415
266
|
|
|
416
|
-
#
|
|
267
|
+
# Available formats
|
|
417
268
|
info.available_formats.each do |format_id|
|
|
418
269
|
format = info.get_format(format_id)
|
|
419
270
|
puts "#{format[:format_id]}: #{format[:height]}p"
|
|
420
271
|
end
|
|
421
272
|
|
|
422
|
-
#
|
|
273
|
+
# Best quality formats
|
|
423
274
|
best = info.best_format
|
|
424
275
|
video_only = info.best_video_format
|
|
425
276
|
audio_only = info.best_audio_format
|
|
426
277
|
```
|
|
427
278
|
|
|
428
|
-
###
|
|
429
|
-
|
|
430
|
-
```ruby
|
|
431
|
-
client = YoutubeRb::Client.new(
|
|
432
|
-
# Основные
|
|
433
|
-
output_path: './downloads',
|
|
434
|
-
output_template: '%(title)s-%(id)s.%(ext)s',
|
|
435
|
-
format: 'best',
|
|
436
|
-
quality: 'best',
|
|
437
|
-
|
|
438
|
-
# Сегменты
|
|
439
|
-
segment_mode: :fast, # :fast (быстро) или :precise (точно)
|
|
440
|
-
min_segment_duration: 10, # минимальная длительность сегмента (секунды)
|
|
441
|
-
max_segment_duration: 60, # максимальная длительность сегмента (секунды)
|
|
442
|
-
cache_full_video: false, # кэшировать полное видео для нескольких сегментов
|
|
443
|
-
|
|
444
|
-
# Субтитры
|
|
445
|
-
write_subtitles: true,
|
|
446
|
-
subtitle_format: 'srt', # srt, vtt, ass
|
|
447
|
-
subtitle_langs: ['en', 'ru'],
|
|
448
|
-
|
|
449
|
-
# Аудио
|
|
450
|
-
extract_audio: false,
|
|
451
|
-
audio_format: 'mp3', # mp3, aac, opus, flac, wav
|
|
452
|
-
audio_quality: '192',
|
|
453
|
-
|
|
454
|
-
# Файловая система
|
|
455
|
-
no_overwrites: true, # не перезаписывать файлы
|
|
456
|
-
continue_download: true, # продолжать прерванные загрузки
|
|
457
|
-
write_description: true,
|
|
458
|
-
write_info_json: true,
|
|
459
|
-
write_thumbnail: true,
|
|
460
|
-
|
|
461
|
-
# Сеть
|
|
462
|
-
rate_limit: '1M', # ограничение скорости
|
|
463
|
-
retries: 10,
|
|
464
|
-
user_agent: 'Mozilla/5.0...',
|
|
465
|
-
|
|
466
|
-
# Аутентификация (если нужна)
|
|
467
|
-
cookies_file: './cookies.txt',
|
|
468
|
-
username: 'user',
|
|
469
|
-
password: 'pass'
|
|
470
|
-
)
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
### Authentication and Cookies (Bypassing 403 Errors)
|
|
279
|
+
### Authentication and Cookies
|
|
474
280
|
|
|
475
|
-
For age-restricted, private, member-only videos or to bypass 403 errors:
|
|
281
|
+
For age-restricted, private, or member-only videos, or to bypass 403 errors:
|
|
476
282
|
|
|
477
|
-
####
|
|
283
|
+
#### Export Cookies from Browser (Most Reliable)
|
|
478
284
|
|
|
479
|
-
1. **Install browser extension
|
|
285
|
+
1. **Install browser extension:**
|
|
480
286
|
- Chrome/Edge: [Get cookies.txt LOCALLY](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
|
|
481
287
|
- Firefox: [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
|
|
482
288
|
|
|
@@ -487,100 +293,92 @@ For age-restricted, private, member-only videos or to bypass 403 errors:
|
|
|
487
293
|
4. **Use cookies in YoutubeRb:**
|
|
488
294
|
|
|
489
295
|
```ruby
|
|
490
|
-
# With yt-dlp backend (recommended - automatic cookie handling)
|
|
491
296
|
client = YoutubeRb::Client.new(
|
|
492
297
|
cookies_file: './youtube_cookies.txt',
|
|
493
|
-
use_ytdlp: true,
|
|
494
298
|
verbose: true
|
|
495
299
|
)
|
|
496
300
|
client.download('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
497
|
-
|
|
498
|
-
# Pure Ruby backend also supports cookies
|
|
499
|
-
client = YoutubeRb::Client.new(
|
|
500
|
-
cookies_file: './youtube_cookies.txt',
|
|
501
|
-
use_ytdlp: false,
|
|
502
|
-
ytdlp_fallback: true # Falls back to yt-dlp on 403
|
|
503
|
-
)
|
|
504
301
|
```
|
|
505
302
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
yt-dlp can directly read cookies from your browser:
|
|
509
|
-
|
|
510
|
-
```bash
|
|
511
|
-
# First, ensure browser is closed or use the right browser
|
|
512
|
-
yt-dlp --cookies-from-browser chrome <URL>
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
**Note:** This feature requires specific system dependencies and may not work on all platforms. Cookie file export (Method 1) is more reliable.
|
|
516
|
-
|
|
517
|
-
#### Cookie file format example (Netscape)
|
|
518
|
-
|
|
519
|
-
```
|
|
520
|
-
# Netscape HTTP Cookie File
|
|
521
|
-
.youtube.com TRUE / TRUE 0 CONSENT YES+
|
|
522
|
-
.youtube.com TRUE / FALSE 1735689600 VISITOR_INFO1_LIVE xxxxx
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
#### Important Notes
|
|
526
|
-
|
|
527
|
-
- ⚠️ **Username/password authentication** is NOT supported (YouTube uses OAuth)
|
|
303
|
+
**Important Notes:**
|
|
528
304
|
- 🔒 **Keep your cookies file secure** - it contains your session data
|
|
529
305
|
- 🔄 **Cookies expire** - re-export if you get 403 errors again
|
|
530
|
-
- 💡 **Use yt-dlp backend** for best cookie handling
|
|
531
306
|
|
|
532
|
-
|
|
307
|
+
## Configuration Options
|
|
533
308
|
|
|
534
309
|
```ruby
|
|
535
|
-
require 'youtube-rb'
|
|
536
|
-
|
|
537
310
|
client = YoutubeRb::Client.new(
|
|
538
|
-
|
|
311
|
+
# Logging
|
|
312
|
+
verbose: true, # Show progress logs
|
|
313
|
+
|
|
314
|
+
# Output
|
|
315
|
+
output_path: './downloads',
|
|
316
|
+
output_template: '%(title)s-%(id)s.%(ext)s',
|
|
317
|
+
no_overwrites: true, # Don't overwrite existing files
|
|
318
|
+
continue_download: true, # Resume interrupted downloads
|
|
319
|
+
|
|
320
|
+
# Quality
|
|
321
|
+
quality: 'best', # or '1080p', '720p', etc.
|
|
322
|
+
format: 'best',
|
|
323
|
+
|
|
324
|
+
# Segment Options
|
|
325
|
+
segment_mode: :fast, # :fast (10x faster) or :precise (frame-accurate)
|
|
326
|
+
min_segment_duration: 10, # Minimum segment duration in seconds
|
|
327
|
+
max_segment_duration: 60, # Maximum segment duration in seconds
|
|
328
|
+
cache_full_video: false, # Cache full video for multiple segments (auto-enabled for batch)
|
|
329
|
+
|
|
330
|
+
# Audio Extraction
|
|
331
|
+
extract_audio: true,
|
|
332
|
+
audio_format: 'mp3', # mp3, aac, opus, flac, wav
|
|
333
|
+
audio_quality: '192',
|
|
334
|
+
|
|
335
|
+
# Subtitles
|
|
539
336
|
write_subtitles: true,
|
|
540
|
-
subtitle_langs: ['en'],
|
|
541
|
-
|
|
542
|
-
|
|
337
|
+
subtitle_langs: ['en', 'ru'],
|
|
338
|
+
subtitle_format: 'srt', # srt, vtt, or ass
|
|
339
|
+
|
|
340
|
+
# Metadata
|
|
341
|
+
write_info_json: true,
|
|
342
|
+
write_thumbnail: true,
|
|
343
|
+
write_description: true,
|
|
344
|
+
|
|
345
|
+
# Authentication
|
|
346
|
+
cookies_file: './cookies.txt',
|
|
347
|
+
|
|
348
|
+
# Network
|
|
349
|
+
retries: 10,
|
|
350
|
+
rate_limit: '1M',
|
|
351
|
+
user_agent: 'Mozilla/5.0...'
|
|
543
352
|
)
|
|
353
|
+
```
|
|
544
354
|
|
|
545
|
-
|
|
355
|
+
## Troubleshooting
|
|
546
356
|
|
|
547
|
-
|
|
548
|
-
segments = [
|
|
549
|
-
{ start: 0, end: 30, output_file: './highlights/intro.mp4' },
|
|
550
|
-
{ start: 120, end: 150, output_file: './highlights/main.mp4' },
|
|
551
|
-
{ start: 300, end: 330, output_file: './highlights/conclusion.mp4' }
|
|
552
|
-
]
|
|
357
|
+
### 403 Errors or Bot Detection
|
|
553
358
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
end
|
|
359
|
+
**Export cookies from browser:**
|
|
360
|
+
```ruby
|
|
361
|
+
client = YoutubeRb::Client.new(
|
|
362
|
+
cookies_file: './youtube_cookies.txt'
|
|
363
|
+
)
|
|
364
|
+
client.download(url)
|
|
365
|
+
```
|
|
562
366
|
|
|
563
|
-
|
|
564
|
-
segments_old_way = [
|
|
565
|
-
{ start: 0, end: 30, name: 'intro' },
|
|
566
|
-
{ start: 120, end: 150, name: 'main' },
|
|
567
|
-
{ start: 300, end: 330, name: 'conclusion' }
|
|
568
|
-
]
|
|
367
|
+
### No Formats Found / Video Unavailable
|
|
569
368
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
end
|
|
369
|
+
- Export cookies from authenticated browser session
|
|
370
|
+
- Check if video is available in your region
|
|
371
|
+
- Verify the video is public and not deleted
|
|
372
|
+
|
|
373
|
+
### FFmpeg Not Found
|
|
374
|
+
|
|
375
|
+
For segment downloads, FFmpeg is required:
|
|
376
|
+
```bash
|
|
377
|
+
which ffmpeg # check
|
|
378
|
+
brew install ffmpeg # install (macOS)
|
|
581
379
|
```
|
|
582
380
|
|
|
583
|
-
|
|
381
|
+
## Error Handling
|
|
584
382
|
|
|
585
383
|
```ruby
|
|
586
384
|
begin
|
|
@@ -588,107 +386,29 @@ begin
|
|
|
588
386
|
output = client.download_segment(url, 60, 90)
|
|
589
387
|
puts "Success: #{output}"
|
|
590
388
|
rescue YoutubeRb::ExtractionError => e
|
|
591
|
-
puts "
|
|
389
|
+
puts "Failed to extract data: #{e.message}"
|
|
592
390
|
rescue YoutubeRb::DownloadError => e
|
|
593
|
-
puts "
|
|
391
|
+
puts "Download error: #{e.message}"
|
|
392
|
+
rescue YoutubeRb::ValidationError => e
|
|
393
|
+
puts "Validation error: #{e.message}"
|
|
594
394
|
rescue => e
|
|
595
|
-
puts "
|
|
395
|
+
puts "Error: #{e.message}"
|
|
596
396
|
end
|
|
597
397
|
```
|
|
598
398
|
|
|
599
|
-
##
|
|
600
|
-
|
|
601
|
-
- **Client** - Основной интерфейс для всех операций
|
|
602
|
-
- **Options** - Управление конфигурацией
|
|
603
|
-
- **Extractor** - Извлекает информацию о видео из HTML/JSON YouTube
|
|
604
|
-
- **VideoInfo** - Представляет метаданные видео
|
|
605
|
-
- **Downloader** - Обрабатывает загрузку видео и субтитров через HTTP
|
|
606
|
-
|
|
607
|
-
## Comparison with youtube-dl
|
|
608
|
-
|
|
609
|
-
This gem provides a Ruby-native API inspired by youtube-dl but designed as a library rather than a command-line tool:
|
|
610
|
-
|
|
611
|
-
| Feature | youtube-dl | youtube-rb |
|
|
612
|
-
|---------|-----------|------------|
|
|
613
|
-
| Language | Python CLI | Ruby Library |
|
|
614
|
-
| Implementation | Python executable | Pure Ruby gem |
|
|
615
|
-
| Usage | Command line | Programmatic API |
|
|
616
|
-
| Dependencies | Python + ffmpeg | Ruby + ffmpeg (optional) |
|
|
617
|
-
| Segment Download | Manual with ffmpeg | Built-in method |
|
|
618
|
-
| Subtitle Trimming | Manual | Automatic for segments |
|
|
619
|
-
| Configuration | CLI arguments | Ruby objects |
|
|
620
|
-
| Bot Detection | Less common | May require cookies |
|
|
621
|
-
|
|
622
|
-
## Решение проблем
|
|
623
|
-
|
|
624
|
-
### Ошибка "LOGIN_REQUIRED" или блокировка бота
|
|
625
|
-
|
|
626
|
-
If you're getting 403 errors or bot detection:
|
|
627
|
-
|
|
628
|
-
1. **Use yt-dlp backend (most reliable)**:
|
|
629
|
-
```ruby
|
|
630
|
-
client = YoutubeRb::Client.new(use_ytdlp: true, verbose: true)
|
|
631
|
-
client.download(url)
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
2. **Export and use cookies from authenticated browser session**:
|
|
635
|
-
```ruby
|
|
636
|
-
client = YoutubeRb::Client.new(
|
|
637
|
-
cookies_file: './youtube_cookies.txt',
|
|
638
|
-
use_ytdlp: true
|
|
639
|
-
)
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
3. **Enable fallback mode** (default):
|
|
643
|
-
```ruby
|
|
644
|
-
client = YoutubeRb::Client.new(ytdlp_fallback: true)
|
|
645
|
-
# Tries pure Ruby first, falls back to yt-dlp on 403
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
4. **Add delays between requests**:
|
|
649
|
-
```ruby
|
|
650
|
-
videos.each do |url|
|
|
651
|
-
client.download(url)
|
|
652
|
-
sleep 2
|
|
653
|
-
end
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### No formats found / Video unavailable
|
|
657
|
-
|
|
658
|
-
Try:
|
|
659
|
-
- Use yt-dlp backend: `YoutubeRb::Client.new(use_ytdlp: true)`
|
|
660
|
-
- Export cookies from authenticated browser session
|
|
661
|
-
- Check if video is available in your region
|
|
662
|
-
- Verify the video is public and not deleted
|
|
663
|
-
- Check yt-dlp directly: `yt-dlp --cookies ./cookies.txt <URL>`
|
|
664
|
-
|
|
665
|
-
### FFmpeg не найден
|
|
666
|
-
|
|
667
|
-
Для работы с сегментами нужен FFmpeg:
|
|
668
|
-
```bash
|
|
669
|
-
which ffmpeg # проверить
|
|
670
|
-
brew install ffmpeg # установить (macOS)
|
|
671
|
-
```
|
|
672
|
-
|
|
673
|
-
## Performance
|
|
674
|
-
|
|
675
|
-
Segment downloads are optimized for speed by default, using stream copy instead of re-encoding.
|
|
676
|
-
|
|
677
|
-
**Fast Mode (Default):**
|
|
678
|
-
- ⚡ 10x faster downloads
|
|
679
|
-
- 📦 15-second segment: ~9 seconds (1.88 MB/s)
|
|
680
|
-
- ⚠️ Cuts at keyframes (may be ±2-5 seconds off)
|
|
399
|
+
## Architecture
|
|
681
400
|
|
|
682
|
-
**
|
|
683
|
-
-
|
|
684
|
-
-
|
|
685
|
-
-
|
|
401
|
+
- **Client** - Main interface for all operations
|
|
402
|
+
- **Options** - Configuration management
|
|
403
|
+
- **VideoInfo** - Represents video metadata
|
|
404
|
+
- **Downloader** - Handles video downloads
|
|
405
|
+
- **YtdlpWrapper** - Wrapper for yt-dlp backend (primary download engine)
|
|
686
406
|
|
|
687
407
|
## Development
|
|
688
408
|
|
|
689
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt
|
|
409
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt.
|
|
690
410
|
|
|
691
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release
|
|
411
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`.
|
|
692
412
|
|
|
693
413
|
## Contributing
|
|
694
414
|
|
|
@@ -700,4 +420,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
700
420
|
|
|
701
421
|
## Credits
|
|
702
422
|
|
|
703
|
-
Inspired by [youtube-dl](https://github.com/ytdl-org/youtube-dl) and [yt-dlp](https://github.com/yt-dlp/yt-dlp).
|
|
423
|
+
Inspired by [youtube-dl](https://github.com/ytdl-org/youtube-dl) and powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp).
|