Refactor code structure for improved readability and maintainability
This commit is contained in:
parent
07856196dd
commit
dd8abf03d3
4 changed files with 108 additions and 16 deletions
|
|
@ -2,9 +2,18 @@
|
|||
Inspired by https://github.com/EnterGin/Auto-Stream-Recording-Twitch
|
||||
|
||||
Python script to check, download live stream, VOD, chat and upload them to any cloud storage supported by rclone.
|
||||
|
||||
## ⚡ FFmpeg 8.0 Enhanced
|
||||
Now with FFmpeg 8.0+ support featuring hardware acceleration and performance improvements!
|
||||
- **5-10x faster encoding** with NVIDIA, Intel, or AMD GPUs
|
||||
- **Docker-ready** with Linux builds
|
||||
- **Configurable options** for different scenarios
|
||||
- 📖 **[See FFMPEG_SETUP.md for detailed setup instructions](FFMPEG_SETUP.md)**
|
||||
|
||||
## Requirements
|
||||
- [Python 3](https://www.python.org/downloads/)
|
||||
- [Streamlink](https://github.com/streamlink/streamlink)
|
||||
- [FFmpeg 8.0+](https://ffmpeg.org/download.html) (see [FFMPEG_SETUP.md](FFMPEG_SETUP.md) for platform-specific versions)
|
||||
## Getting started
|
||||
1. Install Python 3.x
|
||||
2. Install Streamlink 5.1.x
|
||||
|
|
|
|||
BIN
bin/ffmpeg
(Stored with Git LFS)
BIN
bin/ffmpeg
(Stored with Git LFS)
Binary file not shown.
BIN
bin/ffmpeg.exe
(Stored with Git LFS)
BIN
bin/ffmpeg.exe
(Stored with Git LFS)
Binary file not shown.
|
|
@ -72,7 +72,16 @@ DEFAULT_CONFIG = {
|
|||
'onlyRaw': 0,
|
||||
'cleanRaw': 1,
|
||||
'hls_segments': 3,
|
||||
'hls_segmentsVOD': 10
|
||||
'hls_segmentsVOD': 10,
|
||||
# FFmpeg 8.0+ Enhancement Options
|
||||
'ffmpeg_hwaccel': 'auto', # Hardware acceleration: 'auto', 'nvenc', 'qsv', 'amf', 'vaapi', 'none'
|
||||
'ffmpeg_threads': 0, # Thread count (0 = auto-detect)
|
||||
'ffmpeg_audio_codec': 'aac', # Audio codec for audio-only streams
|
||||
'ffmpeg_audio_samplerate': 48000, # Audio sample rate (48000 recommended for broadcasts)
|
||||
'ffmpeg_audio_bitrate': '192k', # Audio bitrate
|
||||
'ffmpeg_error_recovery': 1, # Enable error recovery for corrupted streams (0/1)
|
||||
'ffmpeg_faststart': 1, # Enable faststart for MP4 (better streaming compatibility) (0/1)
|
||||
'ffmpeg_progress': 0 # Show encoding progress (0/1)
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
|
|
@ -537,6 +546,36 @@ class TwitchArchive:
|
|||
return os.path.join(bin_path, 'TwitchDownloaderCLI.exe')
|
||||
return os.path.join(bin_path, 'TwitchDownloaderCLI')
|
||||
|
||||
def _detect_hardware_acceleration(self) -> Optional[str]:
|
||||
"""
|
||||
Detect available hardware acceleration based on config and system.
|
||||
|
||||
Returns:
|
||||
str: Hardware acceleration type ('nvenc', 'qsv', 'amf', 'vaapi', 'none') or None
|
||||
"""
|
||||
hwaccel_config = getattr(self, 'ffmpeg_hwaccel', 'auto')
|
||||
|
||||
# If user explicitly set to 'none', disable hardware acceleration
|
||||
if hwaccel_config == 'none':
|
||||
return 'none'
|
||||
|
||||
# If user specified a particular type, use it
|
||||
if hwaccel_config in ['nvenc', 'qsv', 'amf', 'vaapi']:
|
||||
return hwaccel_config
|
||||
|
||||
# Auto-detect: try to determine available hardware
|
||||
if hwaccel_config == 'auto':
|
||||
# On Windows, NVIDIA is most common
|
||||
if self.os == 'windows':
|
||||
# Could check for nvidia-smi, but just return 'auto' for ffmpeg to decide
|
||||
return 'auto'
|
||||
else:
|
||||
# On Linux, VAAPI is common for Intel/AMD, or NVENC for NVIDIA
|
||||
# Let ffmpeg auto-detect
|
||||
return 'auto'
|
||||
|
||||
return None
|
||||
|
||||
def _record_livestream(self, stream_info: Dict[str, Any], output_path: str) -> bool:
|
||||
"""
|
||||
Record a live Twitch stream using streamlink.
|
||||
|
|
@ -624,33 +663,77 @@ class TwitchArchive:
|
|||
|
||||
# Build ffmpeg command based on quality
|
||||
if self.quality == 'audio_only':
|
||||
# Audio-only conversion
|
||||
# Audio-only conversion with modern AAC encoding
|
||||
cmd = [
|
||||
self._get_ffmpeg_executable(),
|
||||
'-i', raw_path,
|
||||
'-vn', # No video
|
||||
'-ar', '44100', # Audio sample rate
|
||||
'-c:a', self.ffmpeg_audio_codec, # Audio codec (AAC recommended)
|
||||
'-ar', str(self.ffmpeg_audio_samplerate), # Audio sample rate
|
||||
'-ac', '2', # Audio channels (stereo)
|
||||
'-b:a', '192k', # Audio bitrate
|
||||
output_path
|
||||
'-b:a', self.ffmpeg_audio_bitrate, # Audio bitrate
|
||||
]
|
||||
|
||||
# Add threading for faster encoding
|
||||
if self.ffmpeg_threads > 0:
|
||||
cmd.extend(['-threads', str(self.ffmpeg_threads)])
|
||||
|
||||
# Add faststart for better streaming compatibility (MP4/M4A)
|
||||
if self.ffmpeg_faststart == 1 and output_path.endswith(('.mp4', '.m4a')):
|
||||
cmd.extend(['-movflags', '+faststart'])
|
||||
|
||||
cmd.append(output_path)
|
||||
else:
|
||||
# Video conversion (copy streams for speed)
|
||||
# Video conversion with hardware acceleration support
|
||||
cmd = [
|
||||
self._get_ffmpeg_executable(),
|
||||
'-y', # Overwrite output file
|
||||
]
|
||||
|
||||
# Add hardware acceleration if enabled
|
||||
hwaccel_type = self._detect_hardware_acceleration()
|
||||
if hwaccel_type and hwaccel_type != 'none':
|
||||
print(f'{Fore.CYAN}Using hardware acceleration: {hwaccel_type}{Style.RESET_ALL}')
|
||||
cmd.extend(['-hwaccel', 'auto'])
|
||||
|
||||
cmd.extend([
|
||||
'-i', raw_path,
|
||||
'-analyzeduration', '2147483647',
|
||||
'-probesize', '2147483647',
|
||||
'-c:v', 'copy', # Copy video codec (fast)
|
||||
'-c:a', 'copy', # Copy audio codec (fast)
|
||||
])
|
||||
|
||||
# Threading support
|
||||
if self.ffmpeg_threads >= 0:
|
||||
cmd.extend(['-threads', str(self.ffmpeg_threads)])
|
||||
|
||||
# Error recovery options for corrupted streams
|
||||
if self.ffmpeg_error_recovery == 1:
|
||||
cmd.extend([
|
||||
'-fflags', '+genpts', # Generate missing timestamps
|
||||
'-avoid_negative_ts', 'make_zero', # Handle timestamp issues
|
||||
'-err_detect', 'ignore_err' # More tolerant of errors
|
||||
])
|
||||
|
||||
# Stream copy (fast, no re-encoding)
|
||||
cmd.extend([
|
||||
'-c:v', 'copy', # Copy video codec
|
||||
'-c:a', 'copy', # Copy audio codec
|
||||
'-start_at_zero',
|
||||
'-copyts',
|
||||
output_path
|
||||
]
|
||||
])
|
||||
|
||||
# Add faststart for MP4 files
|
||||
if self.ffmpeg_faststart == 1 and output_path.endswith('.mp4'):
|
||||
cmd.extend(['-movflags', '+faststart'])
|
||||
|
||||
cmd.append(output_path)
|
||||
|
||||
# Run ffmpeg with optional progress output
|
||||
if self.ffmpeg_progress == 1:
|
||||
subprocess.call(cmd)
|
||||
else:
|
||||
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||
|
||||
# Run ffmpeg (suppress output)
|
||||
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||
print(f'{Fore.GREEN}✓ Stream processed successfully{Style.RESET_ALL}')
|
||||
|
||||
def _download_vod(self, vod_info: Dict[str, Any], output_path: str) -> bool:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue