Updated script
This commit is contained in:
parent
47cc5039b8
commit
80255b2012
11 changed files with 1562 additions and 286 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
|
# User configuration file (contains personal settings)
|
||||||
|
config.json
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
.env
|
||||||
archive
|
archive
|
||||||
|
|
@ -8,4 +11,6 @@ subprocess_time.py
|
||||||
env2/**
|
env2/**
|
||||||
venv3/**
|
venv3/**
|
||||||
.gitignore
|
.gitignore
|
||||||
bin/**
|
bin/**
|
||||||
|
\n+# Ignore any virtual environment directories starting with 'venv' (venv, venv3, venv314, etc.)
|
||||||
|
venv*/
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
3.14.3
|
||||||
267
IMPROVEMENTS.md
Normal file
267
IMPROVEMENTS.md
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
# Twitch Archive - Code Improvements
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This document outlines the improvements made to make the `twitch-archive.py` script more user-friendly for programmers who aren't familiar with Python.
|
||||||
|
|
||||||
|
## Key Improvements
|
||||||
|
|
||||||
|
### 1. **Better Code Organization**
|
||||||
|
- **Module-level docstring**: Added comprehensive documentation at the top explaining what the script does
|
||||||
|
- **Constants section**: All magic values and API endpoints moved to well-named constants at the top
|
||||||
|
- **Logical grouping**: Code is now organized into clear sections with visual separators
|
||||||
|
|
||||||
|
### 2. **Enhanced Documentation**
|
||||||
|
- **Type hints**: Added type annotations to all methods (e.g., `def run(self) -> None:`)
|
||||||
|
- **Docstrings**: Every method now has detailed documentation explaining:
|
||||||
|
- What it does
|
||||||
|
- What parameters it accepts
|
||||||
|
- What it returns
|
||||||
|
- Potential errors/exceptions
|
||||||
|
- **Inline comments**: Added explanatory comments throughout the code
|
||||||
|
|
||||||
|
### 3. **Improved Method Names**
|
||||||
|
- Old: `sendNotif()` → New: `send_notification()` (more descriptive)
|
||||||
|
- Old: `get_OS()` → New: `_detect_operating_system()` (clearer purpose)
|
||||||
|
- Old: `correct_user()` → New: `_validate_username()` (describes action)
|
||||||
|
- Added underscore prefix to private methods (Python convention)
|
||||||
|
|
||||||
|
### 4. **Modular Design**
|
||||||
|
The massive `loopcheck()` method was broken down into smaller, focused methods:
|
||||||
|
|
||||||
|
- `_is_stream_already_processed()` - Check if stream was already recorded
|
||||||
|
- `_mark_stream_as_processed()` - Log stream to prevent duplicates
|
||||||
|
- `_record_livestream()` - Handle stream recording with streamlink
|
||||||
|
- `_process_raw_stream()` - Convert .ts files with ffmpeg
|
||||||
|
- `_download_vod()` - Download VOD with TwitchDownloaderCLI
|
||||||
|
- `_download_and_render_chat()` - Download and render chat logs
|
||||||
|
- `_save_metadata()` - Save stream metadata
|
||||||
|
- `_upload_to_cloud()` - Upload to cloud storage with rclone
|
||||||
|
- `_delete_local_files()` - Clean up local files after upload
|
||||||
|
|
||||||
|
### 5. **Better Error Handling**
|
||||||
|
- **Specific exceptions**: Catch and handle specific exception types
|
||||||
|
- **User-friendly messages**: Error messages now explain what went wrong and how to fix it
|
||||||
|
- **Graceful degradation**: Script continues running even when non-critical operations fail
|
||||||
|
- **Visual feedback**: Uses colored output (✓, ✗, ⚠) to indicate status
|
||||||
|
|
||||||
|
### 6. **Improved User Feedback**
|
||||||
|
|
||||||
|
#### Before:
|
||||||
|
```
|
||||||
|
Configuration:
|
||||||
|
Root path: E:\dev\Twitch-Archive-2\archive
|
||||||
|
Refresh rate: 60.0
|
||||||
|
Email notifications: Enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
#### After:
|
||||||
|
```
|
||||||
|
============================================================
|
||||||
|
TWITCH ARCHIVE - Configuration Summary
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
Streamer: vinesauce
|
||||||
|
Quality: best
|
||||||
|
Storage: E:\dev\Twitch-Archive-2\archive
|
||||||
|
Refresh rate: 60s
|
||||||
|
|
||||||
|
Email notifications: Enabled ✓
|
||||||
|
Metadata download: Enabled ✓
|
||||||
|
VOD download: Enabled ✓
|
||||||
|
Chat download & render: Enabled ✓
|
||||||
|
Cloud upload: Enabled ✓
|
||||||
|
|
||||||
|
✓ Files will be preserved locally
|
||||||
|
============================================================
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. **Constants for Magic Values**
|
||||||
|
```python
|
||||||
|
# Before: Scattered throughout code
|
||||||
|
response = requests.post('https://gql.twitch.tv/gql', ...)
|
||||||
|
|
||||||
|
# After: Named constants at top
|
||||||
|
TWITCH_GQL_URL = "https://gql.twitch.tv/gql"
|
||||||
|
response = requests.post(TWITCH_GQL_URL, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. **Cleaner Configuration Loading**
|
||||||
|
- Uses `DEFAULT_CONFIG` dictionary instead of inline defaults
|
||||||
|
- Better error messages when config.json is missing or invalid
|
||||||
|
- Filters comment fields more elegantly
|
||||||
|
- Validates JSON syntax and provides helpful error messages
|
||||||
|
|
||||||
|
### 9. **Path Handling Improvements**
|
||||||
|
- Uses `pathlib.Path` consistently for cross-platform compatibility
|
||||||
|
- Centralized path initialization in `_initialize_paths()` method
|
||||||
|
- All paths are absolute to avoid confusion
|
||||||
|
|
||||||
|
### 10. **Better Help Text**
|
||||||
|
The command-line help is now formatted with colors and clear sections:
|
||||||
|
```
|
||||||
|
============================================================
|
||||||
|
TWITCH ARCHIVE - Automated Stream Recording & Archiving
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
python twitch-archive.py [OPTIONS]
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-h, --help Display this help information
|
||||||
|
-u, --username <name> Twitch channel username to monitor
|
||||||
|
...
|
||||||
|
|
||||||
|
TIPS:
|
||||||
|
• Configure settings in config.json
|
||||||
|
• Set up API credentials in .env file
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11. **Safer File Operations**
|
||||||
|
- Checks if files exist before attempting to delete them
|
||||||
|
- Groups all file deletion in one method for easier tracking
|
||||||
|
- Prevents deletion if upload fails (data safety)
|
||||||
|
|
||||||
|
### 12. **Code Readability Enhancements**
|
||||||
|
- Consistent indentation and spacing
|
||||||
|
- Logical variable names (e.g., `filename_base` instead of `live_raw_filename`)
|
||||||
|
- Removed redundant code (e.g., duplicate API calls)
|
||||||
|
- Consistent string formatting (f-strings everywhere)
|
||||||
|
|
||||||
|
## How These Improvements Help Non-Python Programmers
|
||||||
|
|
||||||
|
1. **Clearer Intent**: Type hints and docstrings make it obvious what each function does without needing to read the implementation
|
||||||
|
|
||||||
|
2. **Easier Debugging**: Modular functions mean you can test individual pieces separately
|
||||||
|
|
||||||
|
3. **Better Error Messages**: Instead of cryptic Python errors, users get helpful messages like:
|
||||||
|
```
|
||||||
|
✗ ERROR: Twitch user "invaliduser" not found
|
||||||
|
→ Check the username in your config.json file
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Self-Documenting**: The code reads more like pseudocode with clear method names and constants
|
||||||
|
|
||||||
|
5. **Standard Conventions**: Follows PEP 8 (Python style guide) making it easier to understand for anyone familiar with coding standards
|
||||||
|
|
||||||
|
6. **Visual Organization**: Section headers and consistent formatting make it easy to navigate
|
||||||
|
|
||||||
|
7. **Extensibility**: Each feature is isolated, making it easy to add new features or modify existing ones
|
||||||
|
|
||||||
|
## Maintenance Benefits
|
||||||
|
|
||||||
|
- **Easier Updates**: Modular design means changing one feature doesn't affect others
|
||||||
|
- **Testable**: Each method can be unit tested independently
|
||||||
|
- **Understandable**: Future developers can quickly understand what each part does
|
||||||
|
- **Documented Decisions**: Docstrings explain *why* things are done a certain way
|
||||||
|
|
||||||
|
## Example: Before vs After
|
||||||
|
|
||||||
|
### Before (Complex loopcheck):
|
||||||
|
```python
|
||||||
|
def loopcheck(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
is_live = self.check_user()['data']['user']['stream']
|
||||||
|
if is_live is not None:
|
||||||
|
is_live_ready = self.check_user()['data']['user']['stream']['title']
|
||||||
|
if is_live_ready is not None:
|
||||||
|
bin_path = str(pathlib.Path(__file__).parent.resolve())+"/bin"
|
||||||
|
live_date = datetime.strptime(is_live["createdAt"],'%Y-%m-%dT%H:%M:%SZ').replace(...)
|
||||||
|
# ... 200+ more lines of mixed logic ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### After (Clean and modular):
|
||||||
|
```python
|
||||||
|
def loopcheck(self) -> None:
|
||||||
|
"""
|
||||||
|
Main monitoring loop.
|
||||||
|
|
||||||
|
Continuously checks if the streamer is live, and when they are:
|
||||||
|
1. Records the live stream
|
||||||
|
2. Downloads the VOD
|
||||||
|
3. Downloads and renders chat
|
||||||
|
4. Uploads everything to cloud storage (if enabled)
|
||||||
|
5. Optionally deletes local files after upload
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
response = self._check_stream_status()
|
||||||
|
is_live = response['data']['user']['stream']
|
||||||
|
|
||||||
|
if is_live is None:
|
||||||
|
time.sleep(self.refresh)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Each step is a well-named method
|
||||||
|
stream_id = self._create_stream_id(is_live)
|
||||||
|
if self._is_stream_already_processed(stream_id):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._record_livestream(...)
|
||||||
|
self._process_raw_stream(...)
|
||||||
|
self._download_vod(...)
|
||||||
|
# ... clear logical flow ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backward Compatibility
|
||||||
|
|
||||||
|
All improvements maintain backward compatibility:
|
||||||
|
- Same configuration file format
|
||||||
|
- Same command-line arguments
|
||||||
|
- Same file output structure
|
||||||
|
- Same external tool dependencies
|
||||||
|
|
||||||
|
## Testing Recommendations
|
||||||
|
|
||||||
|
After these improvements, test:
|
||||||
|
1. ✓ Configuration loading (valid and invalid config.json)
|
||||||
|
2. ✓ Username validation
|
||||||
|
3. ✓ Live stream recording
|
||||||
|
4. ✓ VOD downloading
|
||||||
|
5. ✓ Chat downloading
|
||||||
|
6. ✓ Cloud upload
|
||||||
|
7. ✓ File deletion safety
|
||||||
|
8. ✓ Error recovery
|
||||||
|
|
||||||
|
## Future Enhancement Opportunities
|
||||||
|
|
||||||
|
Now that the code is more maintainable, future enhancements could include:
|
||||||
|
- Configuration validation with schemas
|
||||||
|
- Logging to file instead of print statements
|
||||||
|
- Progress bars for downloads
|
||||||
|
- Multi-channel monitoring
|
||||||
|
- Web interface for configuration
|
||||||
|
- Database for tracking streams
|
||||||
|
- Automated testing suite
|
||||||
|
|
||||||
|
## Streamlink Compatibility Update (February 2026)
|
||||||
|
|
||||||
|
### Deprecated Options Removed
|
||||||
|
Updated the script to work with streamlink 5.0+ by removing deprecated command-line options:
|
||||||
|
|
||||||
|
1. **`--twitch-disable-reruns`** - This option has been completely removed from streamlink
|
||||||
|
- The script now works without this option
|
||||||
|
- Twitch's rerun detection is handled differently in newer versions
|
||||||
|
|
||||||
|
2. **`--twitch-proxy-playlist`** - The ttvlol ad-blocking proxy option has been removed
|
||||||
|
- If `streamlink_ttvlol` is enabled in config, the script will show a warning
|
||||||
|
- Users should disable this option or use alternative ad-blocking methods
|
||||||
|
- Consider using Twitch Turbo subscription for ad-free viewing
|
||||||
|
|
||||||
|
3. **`--hls-segment-threads`** - Renamed to `--stream-segment-threads`
|
||||||
|
- The script already uses the correct new option name
|
||||||
|
- This applies to all segmented stream types (HLS, DASH, etc.)
|
||||||
|
- Valid values: 1-10 threads (default: 1)
|
||||||
|
|
||||||
|
### What You Need to Do
|
||||||
|
1. Update streamlink to the latest version:
|
||||||
|
```bash
|
||||||
|
pip install --upgrade streamlink
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Update your config.json:
|
||||||
|
- Set `streamlink_ttvlol` to `0` if you were using ad-blocking
|
||||||
|
- The other settings remain the same
|
||||||
|
|
||||||
|
3. Run the script normally - it will work with the latest streamlink version
|
||||||
|
|
@ -18,7 +18,7 @@ CLIENT-ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
CLIENT-SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
CLIENT-SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
OAUTH-PRIVATE-TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # optional to record without ADS or download sub-only VODS
|
OAUTH-PRIVATE-TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # optional to record without ADS or download sub-only VODS
|
||||||
```
|
```
|
||||||
8. if you want to enable/disable more available options, edit `twitch-archive.py`
|
8. Copy `config.sample.json` to `config.json` and edit it with your settings (username, quality, paths, etc.)
|
||||||
9. run `Python twitch-archive.py` or for multiple streamers `Python twitch-archive.py -u streamer`
|
9. run `Python twitch-archive.py` or for multiple streamers `Python twitch-archive.py -u streamer`
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
BIN
bin/TwitchDownloaderCLI
(Stored with Git LFS)
BIN
bin/TwitchDownloaderCLI
(Stored with Git LFS)
Binary file not shown.
BIN
bin/TwitchDownloaderCLI.exe
(Stored with Git LFS)
BIN
bin/TwitchDownloaderCLI.exe
(Stored with Git LFS)
Binary file not shown.
51
config.sample.json
Normal file
51
config.sample.json
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"_comment": "Copy this file to config.json and edit with your settings",
|
||||||
|
|
||||||
|
"username": "your_twitch_username",
|
||||||
|
"_username_comment": "Twitch streamer username to monitor and archive",
|
||||||
|
|
||||||
|
"quality": "best",
|
||||||
|
"_quality_comment": "Quality options: best/source, high/720p, medium/540p, low/360p, audio_only",
|
||||||
|
|
||||||
|
"root_path": "archive",
|
||||||
|
"_root_path_comment": "Path where this script saves everything (livestream, VODs, chat, metadata)",
|
||||||
|
|
||||||
|
"rclone_path": "remote:path/to/streams",
|
||||||
|
"_rclone_path_comment": "Path to rclone remote storage (e.g., MyDrive:Backups/streams)",
|
||||||
|
|
||||||
|
"refresh": 60.0,
|
||||||
|
"_refresh_comment": "Time between checking in seconds (5.0 is recommended), avoid less than 1.0",
|
||||||
|
|
||||||
|
"streamlink_ttvlol": 0,
|
||||||
|
"_streamlink_ttvlol_comment": "0 = disable, 1 = enable blocking ads with ttvlol (DEPRECATED: --twitch-proxy-playlist removed in newer streamlink versions)",
|
||||||
|
|
||||||
|
"notifications": 0,
|
||||||
|
"_notifications_comment": "0 = disable, 1 = enable email notifications",
|
||||||
|
|
||||||
|
"downloadMETADATA": 1,
|
||||||
|
"_downloadMETADATA_comment": "0 = disable, 1 = enable metadata downloading",
|
||||||
|
|
||||||
|
"downloadVOD": 1,
|
||||||
|
"_downloadVOD_comment": "0 = disable, 1 = enable VOD downloading after stream finished",
|
||||||
|
|
||||||
|
"downloadCHAT": 1,
|
||||||
|
"_downloadCHAT_comment": "0 = disable, 1 = enable chat downloading and rendering",
|
||||||
|
|
||||||
|
"uploadCloud": 1,
|
||||||
|
"_uploadCloud_comment": "0 = disable, 1 = enable upload to remote cloud",
|
||||||
|
|
||||||
|
"deleteFiles": 0,
|
||||||
|
"_deleteFiles_comment": "0 = disable, 1 = enable deleting files after upload (BE CAREFUL WITH THIS OPTION)",
|
||||||
|
|
||||||
|
"onlyRaw": 0,
|
||||||
|
"_onlyRaw_comment": "0 = convert ts files to mp3/mp4, 1 = keep only raw ts files for recording",
|
||||||
|
|
||||||
|
"cleanRaw": 1,
|
||||||
|
"_cleanRaw_comment": "0 = keep raw .ts files, 1 = delete raw .ts files after processing",
|
||||||
|
|
||||||
|
"hls_segments": 3,
|
||||||
|
"_hls_segments_comment": "Number of threads for live stream downloading (1-10, recommended 2-3)",
|
||||||
|
|
||||||
|
"hls_segmentsVOD": 10,
|
||||||
|
"_hls_segmentsVOD_comment": "Number of threads for VOD downloading (1-10)"
|
||||||
|
}
|
||||||
23
loopstart.bat
Normal file
23
loopstart.bat
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
rem @echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
rem Set the path to your virtual environment
|
||||||
|
set VENV_PATH=.\venv314
|
||||||
|
rem Activate the virtual environment
|
||||||
|
call "%VENV_PATH%\Scripts\activate.bat"
|
||||||
|
rem pyenv-venv activate twitcharchive
|
||||||
|
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
:loop
|
||||||
|
|
||||||
|
rem Run the desired command in the virtual environment
|
||||||
|
python twitch-archive.py -u %1
|
||||||
|
|
||||||
|
@REM rem if the program exits with a non-zero error code, go back to the beginning of the loop
|
||||||
|
@REM if %errorlevel% neq 0 (
|
||||||
|
goto loop
|
||||||
|
@REM )
|
||||||
|
|
||||||
|
rem Deactivate the virtual environment
|
||||||
|
call "%VENV_PATH%\Scripts\deactivate.bat"
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
python-dotenv==0.21.0
|
python-dotenv==1.0.1
|
||||||
pytz==2022.6
|
pytz==2024.2
|
||||||
requests==2.28.1
|
requests==2.32.3
|
||||||
streamlink==5.1.0
|
streamlink==8.2.0
|
||||||
|
|
@ -2,22 +2,15 @@ rem @echo off
|
||||||
setlocal
|
setlocal
|
||||||
|
|
||||||
rem Set the path to your virtual environment
|
rem Set the path to your virtual environment
|
||||||
set VENV_PATH=.\venv3
|
set VENV_PATH=.\venv314
|
||||||
rem Activate the virtual environment
|
rem Activate the virtual environment
|
||||||
call "%VENV_PATH%\Scripts\activate.bat"
|
call "%VENV_PATH%\Scripts\activate.bat"
|
||||||
rem pyenv-venv activate twitcharchive
|
rem pyenv-venv activate twitcharchive
|
||||||
|
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
:loop
|
|
||||||
|
|
||||||
rem Run the desired command in the virtual environment
|
rem Run the desired command in the virtual environment
|
||||||
python twitch-archive.py -u %1
|
python twitch-archive.py -u %1
|
||||||
|
|
||||||
@REM rem if the program exits with a non-zero error code, go back to the beginning of the loop
|
|
||||||
@REM if %errorlevel% neq 0 (
|
|
||||||
goto loop
|
|
||||||
@REM )
|
|
||||||
|
|
||||||
rem Deactivate the virtual environment
|
rem Deactivate the virtual environment
|
||||||
call "%VENV_PATH%\Scripts\deactivate.bat"
|
call "%VENV_PATH%\Scripts\deactivate.bat"
|
||||||
|
|
|
||||||
1484
twitch-archive.py
1484
twitch-archive.py
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue