subxx 0.3.0__tar.gz

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.
subxx-0.3.0/!README.md ADDED
@@ -0,0 +1,853 @@
1
+ # subxx
2
+
3
+ **YouTube transcript / subtitle fetching toolkit for Python** - Download, extract, and process subtitles from video URLs with a simple CLI or HTTP API.
4
+
5
+ [![Version](https://img.shields.io/badge/version-0.3.0-blue.svg)](https://gist.github.com/cprima/1ec077cb315295e349ee61dccf13f6b2)
6
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
7
+ [![License: CC BY 4.0](https://img.shields.io/badge/License-CC%20BY%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by/4.0/)
8
+ [![Development Status](https://img.shields.io/badge/status-alpha-orange.svg)](https://github.com/cprima/subxx)
9
+
10
+ ---
11
+
12
+ ## Features
13
+
14
+ - **Download YouTube subtitles** from videos and channels (powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp))
15
+ - **Multiple output formats**: SRT, VTT, TXT, Markdown, PDF
16
+ - **Text extraction** with automatic subtitle cleanup and optional timestamp markers
17
+ - **Language selection**: Download specific languages or all available subtitles
18
+ - **Batch processing**: Process multiple URLs from a file
19
+ - **Configuration files**: Project and global settings via TOML
20
+ - **HTTP API**: Optional FastAPI server for programmatic access
21
+ - **Dry-run mode**: Preview operations without downloading
22
+ - **Filename sanitization**: Safe, nospace, or slugify modes
23
+
24
+ ---
25
+
26
+ ## Table of Contents
27
+
28
+ - [Installation](#installation)
29
+ - [Quick Start](#quick-start)
30
+ - [Usage](#usage)
31
+ - [List Available Subtitles](#list-available-subtitles)
32
+ - [Download Subtitles](#download-subtitles)
33
+ - [Text Extraction](#text-extraction)
34
+ - [Batch Processing](#batch-processing)
35
+ - [Extract from Files](#extract-from-files)
36
+ - [Configuration](#configuration)
37
+ - [Makefile Shortcuts](#makefile-shortcuts)
38
+ - [HTTP API](#http-api)
39
+ - [Development](#development)
40
+ - [Testing](#testing)
41
+ - [License](#license)
42
+
43
+ ---
44
+
45
+ ## Installation
46
+
47
+ ### Requirements
48
+
49
+ - Python 3.9 or higher
50
+ - [uv](https://github.com/astral-sh/uv) package manager (recommended)
51
+
52
+ ### Install with uv (recommended)
53
+
54
+ ```bash
55
+ # Clone or download the project
56
+ git clone https://gist.github.com/cprima/subxx
57
+ cd subxx
58
+
59
+ # Install core dependencies
60
+ uv sync
61
+
62
+ # Install with optional features
63
+ uv sync --extra extract # Text extraction (txt/md/pdf)
64
+ uv sync --extra api # HTTP API server
65
+ uv sync --extra dev # Development tools (pytest)
66
+
67
+ # Install all features
68
+ uv sync --extra extract --extra api --extra dev
69
+ ```
70
+
71
+ ### Using Make (Windows)
72
+
73
+ ```bash
74
+ make install # Core dependencies
75
+ make install-all # All dependencies (extract + api + dev)
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Quick Start
81
+
82
+ ### Basic Usage
83
+
84
+ ```bash
85
+ # List available subtitles
86
+ uv run python __main__.py list https://youtu.be/VIDEO_ID
87
+
88
+ # Download English subtitle (SRT format, default)
89
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID
90
+
91
+ # Extract to plain text
92
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID --txt
93
+
94
+ # Extract to Markdown with 5-minute timestamps
95
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID --md -t 300
96
+
97
+ # Extract to PDF
98
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID --pdf
99
+ ```
100
+
101
+ ### With Makefile
102
+
103
+ ```bash
104
+ # Quick Markdown extraction (just paste video ID)
105
+ make md VIDEO_ID=dQw4w9WgXcQ
106
+
107
+ # With timestamps
108
+ make md VIDEO_ID=dQw4w9WgXcQ TIMESTAMPS=300
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Usage
114
+
115
+ ### List Available Subtitles
116
+
117
+ Preview available subtitle languages without downloading:
118
+
119
+ ```bash
120
+ uv run python __main__.py list https://youtu.be/VIDEO_ID
121
+ ```
122
+
123
+ **Output:**
124
+ ```
125
+ 📹 Video: Example Video Title
126
+ 🕒 Duration: 12:34
127
+
128
+ ✅ Manual subtitles:
129
+ - en
130
+ - es
131
+
132
+ 🤖 Auto-generated subtitles:
133
+ - en, de, fr, ja, ko, pt, ru, zh-Hans, ...
134
+ ```
135
+
136
+ **Options:**
137
+ - `-v, --verbose` - Debug output
138
+ - `-q, --quiet` - Errors only
139
+
140
+ ---
141
+
142
+ ### Download Subtitles
143
+
144
+ #### Format Selection
145
+
146
+ Download subtitle files in SRT or VTT format:
147
+
148
+ ```bash
149
+ # Download SRT (default)
150
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID
151
+
152
+ # Download VTT
153
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID --vtt
154
+
155
+ # Using --fmt flag
156
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -f srt
157
+ ```
158
+
159
+ **Behavior**: Subtitle files (SRT/VTT) are downloaded and kept on disk.
160
+
161
+ #### Language Selection
162
+
163
+ ```bash
164
+ # Download English (default)
165
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID
166
+
167
+ # Download specific language
168
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -l de
169
+
170
+ # Download multiple languages
171
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -l "en,de,fr"
172
+
173
+ # Download all available languages
174
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -l all
175
+ ```
176
+
177
+ #### Output Directory
178
+
179
+ ```bash
180
+ # Save to specific directory
181
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -o ~/Downloads/subs
182
+
183
+ # Use current directory (default)
184
+ uv run python __main__.py subs https://youtu.be/VIDEO_ID -o .
185
+ ```
186
+
187
+ #### Filename Sanitization
188
+
189
+ ```bash
190
+ # Safe mode: Remove unsafe characters, keep spaces (default)
191
+ uv run python __main__.py subs URL --sanitize safe
192
+
193
+ # No spaces: Replace spaces with underscores
194
+ uv run python __main__.py subs URL --sanitize nospaces
195
+
196
+ # Slugify: Lowercase, hyphens, URL-safe
197
+ uv run python __main__.py subs URL --sanitize slugify
198
+ ```
199
+
200
+ **Examples:**
201
+ - `safe`: `"My Video Title.srt"` → `"My Video Title.srt"`
202
+ - `nospaces`: `"My Video Title.srt"` → `"My_Video_Title.srt"`
203
+ - `slugify`: `"My Video Title.srt"` → `"my-video-title.srt"`
204
+
205
+ #### Overwrite Handling
206
+
207
+ ```bash
208
+ # Prompt before overwriting (default)
209
+ uv run python __main__.py subs URL
210
+
211
+ # Force overwrite without prompting
212
+ uv run python __main__.py subs URL --force
213
+
214
+ # Skip existing files
215
+ uv run python __main__.py subs URL --skip-existing
216
+ ```
217
+
218
+ #### Auto-Generated Subtitles
219
+
220
+ ```bash
221
+ # Include auto-generated subtitles (default)
222
+ uv run python __main__.py subs URL --auto
223
+
224
+ # Only manual subtitles
225
+ uv run python __main__.py subs URL --no-auto
226
+ ```
227
+
228
+ #### Dry Run
229
+
230
+ Preview what would be downloaded without actually downloading:
231
+
232
+ ```bash
233
+ uv run python __main__.py subs URL --dry-run
234
+ ```
235
+
236
+ **Output:**
237
+ ```
238
+ [DRY RUN] Would download subtitle: en
239
+ ```
240
+
241
+ ---
242
+
243
+ ### Text Extraction
244
+
245
+ Extract clean, readable text from subtitles by automatically removing timestamps and formatting.
246
+
247
+ **Key behavior**: When using text formats (txt/md/pdf), subxx:
248
+ 1. Downloads the subtitle as SRT
249
+ 2. Extracts the text content
250
+ 3. **Automatically deletes the SRT file**
251
+
252
+ #### Plain Text
253
+
254
+ ```bash
255
+ # Extract to plain text
256
+ uv run python __main__.py subs URL --txt
257
+ ```
258
+
259
+ **Output**: `Video_Title.VIDEO_ID.en.txt`
260
+
261
+ **Example content:**
262
+ ```
263
+ Hello world.
264
+ This is a subtitle.
265
+ Welcome to the video.
266
+ ```
267
+
268
+ #### Markdown
269
+
270
+ ```bash
271
+ # Extract to Markdown
272
+ uv run python __main__.py subs URL --md
273
+
274
+ # Markdown with timestamp markers every 5 minutes
275
+ uv run python __main__.py subs URL --md -t 300
276
+
277
+ # Markdown with timestamp markers every 30 seconds
278
+ uv run python __main__.py subs URL --md -t 30
279
+ ```
280
+
281
+ **Output**: `Video_Title.VIDEO_ID.en.md`
282
+
283
+ **Example content (with timestamps):**
284
+ ```markdown
285
+ ## [0:00]
286
+
287
+ Hello world.
288
+ This is a subtitle.
289
+
290
+ ## [5:00]
291
+
292
+ Welcome to the next section.
293
+ More content here.
294
+
295
+ ## [10:00]
296
+
297
+ Final section of the video.
298
+ ```
299
+
300
+ #### PDF
301
+
302
+ ```bash
303
+ # Extract to PDF
304
+ uv run python __main__.py subs URL --pdf
305
+
306
+ # PDF with timestamp markers
307
+ uv run python __main__.py subs URL --pdf -t 300
308
+ ```
309
+
310
+ **Output**: `Video_Title.VIDEO_ID.en.pdf`
311
+
312
+ **Requirements**: Install extraction dependencies:
313
+ ```bash
314
+ uv sync --extra extract
315
+ ```
316
+
317
+ #### Timestamp Intervals
318
+
319
+ Add timestamp markers at regular intervals for long-form content:
320
+
321
+ ```bash
322
+ # Every 5 minutes (300 seconds)
323
+ uv run python __main__.py subs URL --md -t 300
324
+
325
+ # Every 30 seconds
326
+ uv run python __main__.py subs URL --txt -t 30
327
+
328
+ # Every 10 minutes
329
+ uv run python __main__.py subs URL --pdf -t 600
330
+ ```
331
+
332
+ **Format**: Timestamps appear as `## [0:00]`, `## [5:00]`, `## [10:00]`, etc.
333
+
334
+ ---
335
+
336
+ ### Batch Processing
337
+
338
+ Download subtitles for multiple URLs from a file:
339
+
340
+ ```bash
341
+ # Create URLs file (one URL per line)
342
+ cat > urls.txt << EOF
343
+ https://youtu.be/VIDEO_ID_1
344
+ https://youtu.be/VIDEO_ID_2
345
+ # This is a comment
346
+ https://youtu.be/VIDEO_ID_3
347
+ EOF
348
+
349
+ # Process all URLs
350
+ uv run python __main__.py batch urls.txt
351
+
352
+ # With options
353
+ uv run python __main__.py batch urls.txt -l "en,de" -f srt -o ~/subs
354
+ ```
355
+
356
+ **Options:**
357
+ - `-l, --langs` - Language codes (default: en)
358
+ - `-f, --fmt` - Output format (default: srt)
359
+ - `-o, --output-dir` - Output directory (default: .)
360
+ - `--sanitize` - Filename sanitization mode (default: safe)
361
+ - `-v, --verbose` - Verbose output
362
+ - `-q, --quiet` - Quiet mode
363
+
364
+ **URL File Format** (yt-dlp standard):
365
+ - One URL per line
366
+ - Lines starting with `#` are comments
367
+ - Empty lines are ignored
368
+
369
+ ---
370
+
371
+ ### Extract from Files
372
+
373
+ Extract text from existing subtitle files:
374
+
375
+ ```bash
376
+ # Extract SRT to plain text
377
+ uv run python __main__.py extract video.srt
378
+
379
+ # Extract to Markdown
380
+ uv run python __main__.py extract video.srt -f md
381
+
382
+ # Extract to PDF
383
+ uv run python __main__.py extract video.srt -f pdf
384
+
385
+ # With timestamp markers every 5 minutes
386
+ uv run python __main__.py extract video.srt -f md -t 300
387
+
388
+ # Specify output file
389
+ uv run python __main__.py extract video.srt -o output.txt
390
+
391
+ # Force overwrite
392
+ uv run python __main__.py extract video.srt --force
393
+ ```
394
+
395
+ **Supported input formats**: SRT, VTT
396
+
397
+ ---
398
+
399
+ ## Configuration
400
+
401
+ ### Config File Locations
402
+
403
+ Configuration files are loaded in priority order:
404
+
405
+ 1. `./.subxx.toml` (project-specific, current directory)
406
+ 2. `~/.subxx.toml` (user global, home directory)
407
+
408
+ ### Priority Chain
409
+
410
+ Settings are resolved in this order (highest to lowest):
411
+
412
+ 1. **CLI flags** (e.g., `--langs en`, `--fmt srt`)
413
+ 2. **Config file** (`.subxx.toml`)
414
+ 3. **Hardcoded defaults**
415
+
416
+ ### Example Configuration
417
+
418
+ Copy `.subxx.toml.example` to `.subxx.toml` or `~/.subxx.toml`:
419
+
420
+ ```bash
421
+ cp .subxx.toml.example ~/.subxx.toml
422
+ ```
423
+
424
+ **Example config:**
425
+
426
+ ```toml
427
+ [defaults]
428
+ # Language codes (comma-separated or "all")
429
+ langs = "en"
430
+
431
+ # Output format: srt, vtt, txt, md, pdf
432
+ fmt = "md"
433
+
434
+ # Include auto-generated subtitles
435
+ auto = true
436
+
437
+ # Output directory (supports ~)
438
+ output_dir = "~/Downloads/subtitles"
439
+
440
+ # Filename sanitization: safe, nospaces, slugify
441
+ sanitize = "safe"
442
+
443
+ # Timestamp interval (seconds) for txt/md/pdf
444
+ timestamps = 300 # 5-minute intervals
445
+
446
+ [logging]
447
+ # Log level: DEBUG, INFO, WARNING, ERROR
448
+ level = "INFO"
449
+
450
+ # Log file (optional)
451
+ log_file = "~/.subxx/subxx.log"
452
+ ```
453
+
454
+ ### Use Case Configurations
455
+
456
+ **Configuration 1: Download SRT files to dedicated directory**
457
+ ```toml
458
+ [defaults]
459
+ langs = "en"
460
+ fmt = "srt"
461
+ output_dir = "~/Downloads/subtitles"
462
+ ```
463
+
464
+ **Configuration 2: Auto-extract to Markdown with timestamps**
465
+ ```toml
466
+ [defaults]
467
+ langs = "en"
468
+ fmt = "md"
469
+ timestamps = 300
470
+ output_dir = "~/Documents/transcripts"
471
+ ```
472
+
473
+ **Configuration 3: Multiple languages, plain text**
474
+ ```toml
475
+ [defaults]
476
+ langs = "en,de,fr"
477
+ fmt = "txt"
478
+ sanitize = "slugify"
479
+ output_dir = "./subtitles"
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Makefile Shortcuts
485
+
486
+ ### Available Targets
487
+
488
+ ```bash
489
+ # Installation
490
+ make install # Core dependencies
491
+ make install-all # All dependencies (extract + api + dev)
492
+
493
+ # Testing
494
+ make test # Run all tests
495
+ make test-unit # Unit tests only
496
+ make test-integration # Integration tests only
497
+ make test-coverage # Tests with coverage report
498
+
499
+ # Usage
500
+ make list VIDEO_URL=https://youtu.be/VIDEO_ID
501
+ make subs VIDEO_URL=https://youtu.be/VIDEO_ID
502
+ make md VIDEO_ID=VIDEO_ID # Quick Markdown extraction
503
+ make md VIDEO_ID=VIDEO_ID TIMESTAMPS=300 # With timestamps
504
+
505
+ # Utilities
506
+ make version # Show version
507
+ make clean # Clean cache files
508
+ make clean-all # Clean everything including .venv
509
+ ```
510
+
511
+ ### Examples
512
+
513
+ ```bash
514
+ # Quick Markdown extraction (just paste video ID)
515
+ make md VIDEO_ID=dQw4w9WgXcQ
516
+
517
+ # With 5-minute timestamps
518
+ make md VIDEO_ID=lHuxDMMkGJ8 TIMESTAMPS=300
519
+
520
+ # List subtitles
521
+ make list VIDEO_URL=https://youtu.be/dQw4w9WgXcQ
522
+
523
+ # Download with languages
524
+ make subs VIDEO_URL=https://youtu.be/dQw4w9WgXcQ LANGS=en,de
525
+ ```
526
+
527
+ ---
528
+
529
+ ## HTTP API
530
+
531
+ Start an HTTP API server for programmatic access (requires API dependencies):
532
+
533
+ ### Installation
534
+
535
+ ```bash
536
+ # Install API dependencies
537
+ uv sync --extra api
538
+
539
+ # Or with Make
540
+ make install-api
541
+ ```
542
+
543
+ ### Start Server
544
+
545
+ ```bash
546
+ # Start on localhost:8000 (default)
547
+ uv run python __main__.py serve
548
+
549
+ # Custom host/port
550
+ uv run python __main__.py serve --host 127.0.0.1 --port 8080
551
+ ```
552
+
553
+ **Security Warning**: The API has NO authentication and should ONLY run on localhost (127.0.0.1).
554
+
555
+ ### API Endpoints
556
+
557
+ #### POST /subs
558
+
559
+ Fetch subtitles and return content directly.
560
+
561
+ **Request:**
562
+ ```json
563
+ {
564
+ "url": "https://youtu.be/VIDEO_ID",
565
+ "langs": "en",
566
+ "fmt": "srt",
567
+ "auto": true,
568
+ "sanitize": "safe"
569
+ }
570
+ ```
571
+
572
+ **Response:** Subtitle file content as plain text.
573
+
574
+ **Example:**
575
+ ```bash
576
+ curl -X POST http://127.0.0.1:8000/subs \
577
+ -H "Content-Type: application/json" \
578
+ -d '{
579
+ "url": "https://youtu.be/dQw4w9WgXcQ",
580
+ "langs": "en",
581
+ "fmt": "srt"
582
+ }'
583
+ ```
584
+
585
+ #### GET /health
586
+
587
+ Health check endpoint.
588
+
589
+ **Response:**
590
+ ```json
591
+ {
592
+ "status": "ok",
593
+ "service": "subxx"
594
+ }
595
+ ```
596
+
597
+ ### API Documentation
598
+
599
+ Interactive API docs available at:
600
+ - Swagger UI: `http://127.0.0.1:8000/docs`
601
+ - ReDoc: `http://127.0.0.1:8000/redoc`
602
+
603
+ ---
604
+
605
+ ## Development
606
+
607
+ ### Setup Development Environment
608
+
609
+ ```bash
610
+ # Clone repository
611
+ git clone https://gist.github.com/cprima/subxx
612
+ cd subxx
613
+
614
+ # Install all dependencies (core + extract + api + dev)
615
+ uv sync --extra extract --extra api --extra dev
616
+
617
+ # Or with Make
618
+ make install-all
619
+ ```
620
+
621
+ ### Project Structure
622
+
623
+ ```
624
+ subxx/
625
+ ├── __main__.py # CLI entry point (Typer commands)
626
+ ├── subxx.py # Core library functions
627
+ ├── test_subxx.py # Test suite (pytest)
628
+ ├── conftest.py # Pytest configuration
629
+ ├── pyproject.toml # Project metadata and dependencies
630
+ ├── Makefile # Build and test automation
631
+ ├── .subxx.toml.example # Example configuration file
632
+ └── !README.md # This file
633
+ ```
634
+
635
+ ### Key Components
636
+
637
+ - **`subxx.py`**: Core library
638
+ - `fetch_subs()` - Download subtitles
639
+ - `extract_text()` - Extract text from subtitles
640
+ - `load_config()` - Configuration management
641
+ - Helper functions for parsing, sanitization, logging
642
+
643
+ - **`__main__.py`**: CLI application
644
+ - `list` - List available subtitles
645
+ - `subs` - Download subtitles
646
+ - `batch` - Batch processing
647
+ - `extract` - Extract from files
648
+ - `serve` - HTTP API server
649
+ - `version` - Version information
650
+
651
+ ---
652
+
653
+ ## Testing
654
+
655
+ ### Run Tests
656
+
657
+ ```bash
658
+ # All tests
659
+ make test
660
+
661
+ # Unit tests only (fast, no network)
662
+ make test-unit
663
+
664
+ # Integration tests only
665
+ make test-integration
666
+
667
+ # With coverage report
668
+ make test-coverage
669
+
670
+ # Verbose output
671
+ make test-verbose
672
+ ```
673
+
674
+ ### Test Categories
675
+
676
+ - **Unit tests** (`@pytest.mark.unit`): No external dependencies, mocked I/O
677
+ - **Integration tests** (`@pytest.mark.integration`): May use files/network
678
+ - **E2E tests** (`@pytest.mark.e2e`): Real YouTube API, requires internet
679
+ - **Slow tests** (`@pytest.mark.slow`): Network I/O, real downloads
680
+
681
+ ### Running Specific Test Categories
682
+
683
+ ```bash
684
+ # Run all tests except e2e (fast, for CI)
685
+ pytest -m "not e2e"
686
+
687
+ # Run only e2e tests (slow, requires internet)
688
+ pytest -m e2e
689
+
690
+ # Run unit tests only
691
+ pytest -m unit
692
+ ```
693
+
694
+ ### Test Coverage
695
+
696
+ Current coverage: **~50 tests** (unit, integration, and e2e)
697
+
698
+ Key areas tested:
699
+ - Configuration loading and defaults
700
+ - Language parsing
701
+ - Filename sanitization
702
+ - Text extraction (txt/md/pdf)
703
+ - Timestamp markers
704
+ - CLI commands
705
+ - Overwrite protection
706
+ - Real YouTube subtitle download (e2e)
707
+
708
+ ---
709
+
710
+ ## Exit Codes
711
+
712
+ - `0` - Success
713
+ - `1` - User cancelled
714
+ - `2` - No subtitles available
715
+ - `3` - Network error
716
+ - `4` - Invalid URL
717
+ - `5` - Configuration error
718
+ - `6` - File error
719
+
720
+ ---
721
+
722
+ ## Troubleshooting
723
+
724
+ ### Missing Dependencies for Text Extraction
725
+
726
+ **Error:**
727
+ ```
728
+ ❌ Error: Missing dependencies for text extraction
729
+ ```
730
+
731
+ **Solution:**
732
+ ```bash
733
+ uv sync --extra extract
734
+ ```
735
+
736
+ ### Missing Dependencies for API
737
+
738
+ **Error:**
739
+ ```
740
+ ❌ Error: API dependencies not installed
741
+ ```
742
+
743
+ **Solution:**
744
+ ```bash
745
+ uv sync --extra api
746
+ ```
747
+
748
+ ### Windows Console Encoding Issues
749
+
750
+ If you see encoding errors on Windows, the tool automatically attempts to reconfigure stdout/stderr to UTF-8. If issues persist, use:
751
+
752
+ ```bash
753
+ # Set console to UTF-8
754
+ chcp 65001
755
+ ```
756
+
757
+ ### yt-dlp Network Errors
758
+
759
+ If downloads fail with network errors:
760
+
761
+ 1. Update yt-dlp:
762
+ ```bash
763
+ uv sync --upgrade
764
+ ```
765
+
766
+ 2. Check firewall/proxy settings
767
+
768
+ 3. Try with `--verbose` for debug output:
769
+ ```bash
770
+ uv run python __main__.py subs URL --verbose
771
+ ```
772
+
773
+ ---
774
+
775
+ ## Roadmap
776
+
777
+ Future enhancements planned:
778
+
779
+ - [ ] Progress bars for downloads
780
+ - [ ] Retry logic for network failures
781
+ - [ ] Subtitle merging/combining
782
+ - [ ] Translation support
783
+ - [ ] Docker container
784
+ - [ ] GitHub Actions CI/CD
785
+ - [ ] Published package on PyPI
786
+ - [ ] SRT/VTT format conversion
787
+ - [ ] Subtitle editing/manipulation
788
+
789
+ ---
790
+
791
+ ## Contributing
792
+
793
+ Contributions welcome! This is an alpha project under active development.
794
+
795
+ ### How to Contribute
796
+
797
+ 1. Fork the repository
798
+ 2. Create a feature branch
799
+ 3. Make your changes
800
+ 4. Add tests for new functionality
801
+ 5. Ensure all tests pass: `make test`
802
+ 6. Submit a pull request
803
+
804
+ ### Guidelines
805
+
806
+ - Follow existing code style
807
+ - Add docstrings for new functions
808
+ - Update tests for changes
809
+ - Update README for new features
810
+ - Keep commits focused and atomic
811
+
812
+ ---
813
+
814
+ ## License
815
+
816
+ This project is licensed under **CC BY 4.0** (Creative Commons Attribution 4.0 International).
817
+
818
+ You are free to:
819
+ - **Share** - Copy and redistribute the material
820
+ - **Adapt** - Remix, transform, and build upon the material
821
+
822
+ Under the following terms:
823
+ - **Attribution** - You must give appropriate credit
824
+
825
+ See [LICENSE](https://creativecommons.org/licenses/by/4.0/) for full details.
826
+
827
+ ---
828
+
829
+ ## Credits
830
+
831
+ - Built with [yt-dlp](https://github.com/yt-dlp/yt-dlp) for video subtitle extraction
832
+ - CLI powered by [Typer](https://typer.tiangolo.com/)
833
+ - API built with [FastAPI](https://fastapi.tiangolo.com/)
834
+ - Text extraction using [srt](https://github.com/cdown/srt) and [fpdf2](https://github.com/py-pdf/fpdf2)
835
+
836
+ ---
837
+
838
+ ## Author
839
+
840
+ **Christian Prior-Mamulyan**
841
+ - Email: cprior@gmail.com
842
+ - GitHub: [@cprima](https://github.com/cprima)
843
+
844
+ ---
845
+
846
+ ## Support
847
+
848
+ - Report issues: [GitHub Issues](https://gist.github.com/cprima/subxx/issues)
849
+ - Documentation: [GitHub Gist](https://gist.github.com/cprima/subxx)
850
+
851
+ ---
852
+
853
+ **subxx** - Simple, powerful YouTube transcript / subtitle fetching for Python.