youtube-rb 0.2.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +703 -0
- data/Rakefile +6 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/lib/youtube-rb/client.rb +160 -0
- data/lib/youtube-rb/downloader.rb +632 -0
- data/lib/youtube-rb/extractor.rb +425 -0
- data/lib/youtube-rb/options.rb +186 -0
- data/lib/youtube-rb/version.rb +3 -0
- data/lib/youtube-rb/video_info.rb +179 -0
- data/lib/youtube-rb/ytdlp_wrapper.rb +269 -0
- data/lib/youtube-rb.rb +69 -0
- data/spec/client_spec.rb +514 -0
- data/spec/download_with_mocks_spec.rb +216 -0
- data/spec/downloader_spec.rb +774 -0
- data/spec/fixtures/first_video_info.json +19 -0
- data/spec/fixtures/rickroll_full_info.json +73 -0
- data/spec/fixtures/rickroll_info.json +73 -0
- data/spec/fixtures/rickroll_segment_info.json +9 -0
- data/spec/integration/ytdlp_integration_spec.rb +109 -0
- data/spec/real_download_spec.rb +175 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/fixtures_helper.rb +109 -0
- data/spec/support/mocking_helper.rb +21 -0
- data/spec/support/webmock_helper.rb +132 -0
- data/spec/youtube_rb_spec.rb +200 -0
- data/spec/ytdlp_wrapper_spec.rb +178 -0
- data/youtube-rb.gemspec +39 -0
- metadata +229 -0
data/README.md
ADDED
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
# YoutubeRb
|
|
2
|
+
|
|
3
|
+
A **Ruby library** inspired by [youtube-dl](https://github.com/ytdl-org/youtube-dl) for downloading videos, extracting video segments, and fetching subtitles from YouTube and other video platforms.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔧 **yt-dlp Backend** - Reliable video downloads with full YouTube support
|
|
8
|
+
- 📹 Download full videos or audio-only
|
|
9
|
+
- ✂️ Extract video segments (10-60 seconds)
|
|
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.)
|
|
13
|
+
- 📊 Get detailed video information
|
|
14
|
+
- 🔧 Flexible configuration options
|
|
15
|
+
- 🌐 Support for cookies and authentication
|
|
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
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Add this line to your application's Gemfile:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
gem 'youtube-rb'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
And then execute:
|
|
52
|
+
|
|
53
|
+
$ bundle install
|
|
54
|
+
|
|
55
|
+
Or install it yourself as:
|
|
56
|
+
|
|
57
|
+
$ gem install youtube-rb
|
|
58
|
+
|
|
59
|
+
## Requirements
|
|
60
|
+
|
|
61
|
+
### Ruby Version
|
|
62
|
+
|
|
63
|
+
- Ruby >= 2.7.0
|
|
64
|
+
|
|
65
|
+
### External Tools
|
|
66
|
+
|
|
67
|
+
#### yt-dlp (Strongly Recommended)
|
|
68
|
+
|
|
69
|
+
For reliable downloads and to avoid 403 errors, install yt-dlp:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Using pip (recommended)
|
|
73
|
+
pip install -U yt-dlp
|
|
74
|
+
|
|
75
|
+
# Using pipx (isolated installation)
|
|
76
|
+
pipx install yt-dlp
|
|
77
|
+
|
|
78
|
+
# macOS with Homebrew
|
|
79
|
+
brew install yt-dlp
|
|
80
|
+
|
|
81
|
+
# Or download binary from:
|
|
82
|
+
# https://github.com/yt-dlp/yt-dlp/releases
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### FFmpeg (Optional)
|
|
86
|
+
|
|
87
|
+
Required only for:
|
|
88
|
+
- Audio extraction from video
|
|
89
|
+
- Segment extraction (10-60 second clips)
|
|
90
|
+
- Format conversion
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# macOS
|
|
94
|
+
brew install ffmpeg
|
|
95
|
+
|
|
96
|
+
# Ubuntu/Debian
|
|
97
|
+
sudo apt install ffmpeg
|
|
98
|
+
|
|
99
|
+
# Windows (with Chocolatey)
|
|
100
|
+
choco install ffmpeg
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Check Installation:**
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
client = YoutubeRb::Client.new
|
|
107
|
+
client.check_dependencies
|
|
108
|
+
# => { ffmpeg: true, ytdlp: true, ytdlp_version: "2024.01.13" }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Usage
|
|
112
|
+
|
|
113
|
+
### Quick Start
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
require 'youtube-rb'
|
|
117
|
+
|
|
118
|
+
# 1. Simple download (automatically uses yt-dlp if available)
|
|
119
|
+
YoutubeRb.download('https://www.youtube.com/watch?v=VIDEO_ID',
|
|
120
|
+
output_path: './downloads'
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# 2. Get video information
|
|
124
|
+
info = YoutubeRb.info('https://www.youtube.com/watch?v=jNQXAC9IVRw')
|
|
125
|
+
puts "Title: #{info.title}"
|
|
126
|
+
puts "Duration: #{info.duration_formatted}"
|
|
127
|
+
puts "Views: #{info.view_count}"
|
|
128
|
+
|
|
129
|
+
# 3. Download single segment (10-60 seconds by default)
|
|
130
|
+
# Requires yt-dlp to be installed
|
|
131
|
+
YoutubeRb.download_segment(
|
|
132
|
+
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
133
|
+
60, # start time in seconds
|
|
134
|
+
90, # end time in seconds
|
|
135
|
+
output_path: './segments'
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# 4. Download multiple segments (batch processing - OPTIMIZED!)
|
|
139
|
+
# Downloads video ONCE via yt-dlp, then extracts all segments locally
|
|
140
|
+
# This is 10-100x faster than downloading each segment separately
|
|
141
|
+
YoutubeRb.download_segments(
|
|
142
|
+
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
143
|
+
[
|
|
144
|
+
{ start: 0, end: 30 },
|
|
145
|
+
{ start: 60, end: 90 },
|
|
146
|
+
{ start: 120, end: 150 }
|
|
147
|
+
],
|
|
148
|
+
output_path: './segments'
|
|
149
|
+
)
|
|
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
|
+
```
|
|
176
|
+
|
|
177
|
+
### Fixing 403 Errors
|
|
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
|
+
```
|
|
186
|
+
|
|
187
|
+
**Option 2: Export cookies from browser**
|
|
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:
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
client = YoutubeRb::Client.new(
|
|
195
|
+
cookies_file: './youtube_cookies.txt',
|
|
196
|
+
use_ytdlp: true
|
|
197
|
+
)
|
|
198
|
+
client.download(url)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Common Configuration Options
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
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
|
+
output_path: './downloads',
|
|
218
|
+
output_template: '%(title)s-%(id)s.%(ext)s',
|
|
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
|
|
229
|
+
write_subtitles: true,
|
|
230
|
+
subtitle_langs: ['en', 'ru'],
|
|
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...'
|
|
244
|
+
)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Основные примеры
|
|
248
|
+
|
|
249
|
+
#### Создание клиента с настройками
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
require 'youtube-rb'
|
|
253
|
+
|
|
254
|
+
client = YoutubeRb::Client.new(
|
|
255
|
+
output_path: './downloads',
|
|
256
|
+
write_subtitles: true,
|
|
257
|
+
subtitle_langs: ['en', 'ru']
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Скачать видео
|
|
261
|
+
client.download('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### Скачивание сегментов видео (главная функция)
|
|
265
|
+
|
|
266
|
+
Скачивание определенных интервалов видео (10-60 секунд по умолчанию):
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
client = YoutubeRb::Client.new(output_path: './segments')
|
|
270
|
+
|
|
271
|
+
# Скачать 30-секундный сегмент начиная с 1:00
|
|
272
|
+
output_file = client.download_segment(
|
|
273
|
+
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
274
|
+
60, # начало в секундах
|
|
275
|
+
90 # конец в секундах
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# С указанием имени файла
|
|
279
|
+
client.download_segment(
|
|
280
|
+
'https://www.youtube.com/watch?v=VIDEO_ID',
|
|
281
|
+
120, 150,
|
|
282
|
+
output_file: './my_segment.mp4'
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Ограничения по умолчанию: сегмент должен быть от 10 до 60 секунд
|
|
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
|
+
# Настройка пользовательских ограничений длительности
|
|
292
|
+
client = YoutubeRb::Client.new(
|
|
293
|
+
output_path: './segments',
|
|
294
|
+
min_segment_duration: 5, # минимум 5 секунд
|
|
295
|
+
max_segment_duration: 300 # максимум 5 минут
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
client.download_segment(url, 0, 5) # ✓ Валидно с новыми настройками
|
|
299
|
+
client.download_segment(url, 0, 300) # ✓ Валидно (5 минут)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**⚡ Performance Note**: By default, segments use **fast mode** (10x faster).
|
|
303
|
+
Cuts may be off by a few seconds due to keyframe positions. For frame-accurate cuts:
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
# Fast mode (default) - 10x faster, cuts at keyframes
|
|
307
|
+
client = YoutubeRb::Client.new(segment_mode: :fast)
|
|
308
|
+
|
|
309
|
+
# Precise mode - frame-accurate but slow (re-encodes video)
|
|
310
|
+
client = YoutubeRb::Client.new(segment_mode: :precise)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
See [PERFORMANCE.md](PERFORMANCE.md) for detailed performance comparison and recommendations.
|
|
314
|
+
|
|
315
|
+
#### Пакетная загрузка сегментов (новое!)
|
|
316
|
+
|
|
317
|
+
Для загрузки нескольких сегментов из одного видео используйте `download_segments`:
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
client = YoutubeRb::Client.new(output_path: './segments')
|
|
321
|
+
|
|
322
|
+
url = 'https://www.youtube.com/watch?v=VIDEO_ID'
|
|
323
|
+
|
|
324
|
+
segments = [
|
|
325
|
+
{ start: 0, end: 30 }, # Первые 30 секунд
|
|
326
|
+
{ start: 60, end: 90 }, # 1:00 - 1:30
|
|
327
|
+
{ start: 120, end: 150 } # 2:00 - 2:30
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
# Загрузит все сегменты эффективно
|
|
331
|
+
output_files = client.download_segments(url, segments)
|
|
332
|
+
# => ["./segments/video-segment-0-30.mp4", "./segments/video-segment-60-90.mp4", ...]
|
|
333
|
+
|
|
334
|
+
puts "Downloaded #{output_files.size} segments"
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Преимущества пакетной загрузки:**
|
|
338
|
+
|
|
339
|
+
- **Оптимизация yt-dlp**: Видео скачивается через yt-dlp **один раз**, все сегменты вырезаются локально через FFmpeg
|
|
340
|
+
- **Быстрее в 10-100x**: Не нужно перекачивать видео для каждого сегмента
|
|
341
|
+
- **Экономия трафика**: Полное видео загружается один раз вместо N раз
|
|
342
|
+
- **Надежность**: Использует yt-dlp для обхода защиты YouTube, FFmpeg для быстрой нарезки
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
# С пользовательскими именами файлов
|
|
346
|
+
segments = [
|
|
347
|
+
{ start: 0, end: 30, output_file: './intro.mp4' },
|
|
348
|
+
{ start: 60, end: 90, output_file: './main.mp4' },
|
|
349
|
+
{ start: 300, end: 330, output_file: './outro.mp4' }
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
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
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Скачивание субтитров
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
client = YoutubeRb::Client.new(
|
|
368
|
+
output_path: './downloads',
|
|
369
|
+
write_subtitles: true,
|
|
370
|
+
subtitle_langs: ['en', 'ru']
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
# При скачивании сегмента субтитры автоматически обрезаются
|
|
374
|
+
client.download_segment(url, 60, 90)
|
|
375
|
+
# Создаст: video-segment-60-90.mp4 и video-segment-60-90.en.srt
|
|
376
|
+
|
|
377
|
+
# Скачать только субтитры (без видео)
|
|
378
|
+
client.download_subtitles(url, langs: ['en', 'ru'])
|
|
379
|
+
|
|
380
|
+
# Проверить доступные языки субтитров
|
|
381
|
+
info = client.info(url)
|
|
382
|
+
puts info.available_subtitle_languages.join(', ')
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### Извлечение аудио
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
# Извлечь аудио в MP3
|
|
389
|
+
client.extract_audio(url, format: 'mp3', quality: '192')
|
|
390
|
+
|
|
391
|
+
# Другие форматы
|
|
392
|
+
client.extract_audio(url, format: 'aac', quality: '128')
|
|
393
|
+
client.extract_audio(url, format: 'opus')
|
|
394
|
+
client.extract_audio(url, format: 'flac') # без потерь
|
|
395
|
+
|
|
396
|
+
# Или через настройки клиента
|
|
397
|
+
client = YoutubeRb::Client.new(
|
|
398
|
+
extract_audio: true,
|
|
399
|
+
audio_format: 'mp3',
|
|
400
|
+
audio_quality: '320'
|
|
401
|
+
)
|
|
402
|
+
client.download(url) # скачает только аудио
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### Получение информации о видео
|
|
406
|
+
|
|
407
|
+
```ruby
|
|
408
|
+
info = client.info('https://www.youtube.com/watch?v=VIDEO_ID')
|
|
409
|
+
|
|
410
|
+
puts info.title
|
|
411
|
+
puts info.description
|
|
412
|
+
puts info.duration_formatted # "01:23:45"
|
|
413
|
+
puts info.view_count
|
|
414
|
+
puts info.uploader
|
|
415
|
+
|
|
416
|
+
# Доступные форматы
|
|
417
|
+
info.available_formats.each do |format_id|
|
|
418
|
+
format = info.get_format(format_id)
|
|
419
|
+
puts "#{format[:format_id]}: #{format[:height]}p"
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Лучшее качество
|
|
423
|
+
best = info.best_format
|
|
424
|
+
video_only = info.best_video_format
|
|
425
|
+
audio_only = info.best_audio_format
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Настройки (Options)
|
|
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)
|
|
474
|
+
|
|
475
|
+
For age-restricted, private, member-only videos or to bypass 403 errors:
|
|
476
|
+
|
|
477
|
+
#### Method 1: Export cookies from browser (Most Reliable)
|
|
478
|
+
|
|
479
|
+
1. **Install browser extension to export cookies:**
|
|
480
|
+
- Chrome/Edge: [Get cookies.txt LOCALLY](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
|
|
481
|
+
- Firefox: [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
|
|
482
|
+
|
|
483
|
+
2. **Log into YouTube** in your browser
|
|
484
|
+
|
|
485
|
+
3. **Export cookies** from youtube.com (Netscape format)
|
|
486
|
+
|
|
487
|
+
4. **Use cookies in YoutubeRb:**
|
|
488
|
+
|
|
489
|
+
```ruby
|
|
490
|
+
# With yt-dlp backend (recommended - automatic cookie handling)
|
|
491
|
+
client = YoutubeRb::Client.new(
|
|
492
|
+
cookies_file: './youtube_cookies.txt',
|
|
493
|
+
use_ytdlp: true,
|
|
494
|
+
verbose: true
|
|
495
|
+
)
|
|
496
|
+
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
|
+
```
|
|
505
|
+
|
|
506
|
+
#### Method 2: Let yt-dlp extract cookies from browser (Easiest)
|
|
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)
|
|
528
|
+
- 🔒 **Keep your cookies file secure** - it contains your session data
|
|
529
|
+
- 🔄 **Cookies expire** - re-export if you get 403 errors again
|
|
530
|
+
- 💡 **Use yt-dlp backend** for best cookie handling
|
|
531
|
+
|
|
532
|
+
### Полный пример: скачивание нескольких сегментов
|
|
533
|
+
|
|
534
|
+
```ruby
|
|
535
|
+
require 'youtube-rb'
|
|
536
|
+
|
|
537
|
+
client = YoutubeRb::Client.new(
|
|
538
|
+
output_path: './highlights',
|
|
539
|
+
write_subtitles: true,
|
|
540
|
+
subtitle_langs: ['en'],
|
|
541
|
+
use_ytdlp: true, # рекомендуется для надежности
|
|
542
|
+
cache_full_video: true # кэширование для быстрой обработки
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
url = 'https://www.youtube.com/watch?v=VIDEO_ID'
|
|
546
|
+
|
|
547
|
+
# Вариант 1: Пакетная загрузка (рекомендуется, быстрее)
|
|
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
|
+
]
|
|
553
|
+
|
|
554
|
+
begin
|
|
555
|
+
output_files = client.download_segments(url, segments)
|
|
556
|
+
output_files.each_with_index do |file, i|
|
|
557
|
+
puts "✓ Segment #{i+1}: #{file}"
|
|
558
|
+
end
|
|
559
|
+
rescue => e
|
|
560
|
+
puts "✗ Error: #{e.message}"
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
# Вариант 2: По одному (если нужен контроль над каждым сегментом)
|
|
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
|
+
]
|
|
569
|
+
|
|
570
|
+
segments_old_way.each do |seg|
|
|
571
|
+
begin
|
|
572
|
+
output = client.download_segment(
|
|
573
|
+
url, seg[:start], seg[:end],
|
|
574
|
+
output_file: "./highlights/#{seg[:name]}.mp4"
|
|
575
|
+
)
|
|
576
|
+
puts "✓ #{seg[:name]}: #{output}"
|
|
577
|
+
rescue => e
|
|
578
|
+
puts "✗ #{seg[:name]}: #{e.message}"
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Обработка ошибок
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
begin
|
|
587
|
+
client = YoutubeRb::Client.new
|
|
588
|
+
output = client.download_segment(url, 60, 90)
|
|
589
|
+
puts "Success: #{output}"
|
|
590
|
+
rescue YoutubeRb::ExtractionError => e
|
|
591
|
+
puts "Не удалось извлечь данные: #{e.message}"
|
|
592
|
+
rescue YoutubeRb::DownloadError => e
|
|
593
|
+
puts "Ошибка загрузки: #{e.message}"
|
|
594
|
+
rescue => e
|
|
595
|
+
puts "Ошибка: #{e.message}"
|
|
596
|
+
end
|
|
597
|
+
```
|
|
598
|
+
|
|
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)
|
|
681
|
+
|
|
682
|
+
**Precise Mode (Optional):**
|
|
683
|
+
- 🎯 Frame-accurate cuts
|
|
684
|
+
- 🐌 15-second segment: ~79 seconds (187 KB/s)
|
|
685
|
+
- ⚙️ Requires re-encoding (CPU intensive)
|
|
686
|
+
|
|
687
|
+
## Development
|
|
688
|
+
|
|
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 that will allow you to experiment.
|
|
690
|
+
|
|
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`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
692
|
+
|
|
693
|
+
## Contributing
|
|
694
|
+
|
|
695
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Qew7/youtube-rb.
|
|
696
|
+
|
|
697
|
+
## License
|
|
698
|
+
|
|
699
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
700
|
+
|
|
701
|
+
## Credits
|
|
702
|
+
|
|
703
|
+
Inspired by [youtube-dl](https://github.com/ytdl-org/youtube-dl) and [yt-dlp](https://github.com/yt-dlp/yt-dlp).
|