Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>
This commit is contained in:
parent
b22a7d2e16
commit
53b90a3027
311
README.md
311
README.md
@ -1,248 +1,127 @@
|
|||||||
# 🎤 Karaoke Playlist Downloader
|
# 🎤 Karaoke Video Downloader
|
||||||
|
|
||||||
A Python-based Windows command-line tool that wraps `yt-dlp.exe` to batch-download karaoke videos from YouTube playlists.
|
A Python-based Windows CLI tool to download karaoke videos from YouTube channels/playlists using `yt-dlp.exe`, with advanced tracking, songlist prioritization, and flexible configuration.
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
- 🎵 **Channel & Playlist Downloads**: Download all videos from a YouTube channel or playlist
|
||||||
- 🚀 **Fast Batch Downloads**: Download entire YouTube playlists with a single command
|
- 📂 **Organized Storage**: Each channel gets its own folder in `downloads/`
|
||||||
- 📁 **Organized Storage**: Each playlist gets its own folder with proper naming
|
- 📝 **Robust Tracking**: Tracks all downloads, statuses, and formats in JSON
|
||||||
- 🔄 **Smart Skipping**: Avoid re-downloading videos you already have
|
- 🏆 **Songlist Prioritization**: Prioritize or restrict downloads to a custom songlist
|
||||||
- 📝 **Comprehensive Logging**: Detailed logs for each playlist download
|
- 🔄 **Batch Saving & Caching**: Efficient, minimizes API calls
|
||||||
- 🎵 **Multiple Formats**: Download as MP4 video or extract MP3 audio
|
- 🏷️ **ID3 Tagging**: Adds artist/title metadata to MP4 files
|
||||||
- 📊 **Progress Tracking**: Real-time progress updates and error handling
|
- 🧹 **Automatic Cleanup**: Removes extra yt-dlp files
|
||||||
|
- 📈 **Real-Time Progress**: Detailed console and log output
|
||||||
|
|
||||||
## 📋 Requirements
|
## 📋 Requirements
|
||||||
|
- **Windows 10/11**
|
||||||
- **Windows** (tested on Windows 10/11)
|
- **Python 3.7+**
|
||||||
- **Python 3.7+** (included in the project)
|
- **yt-dlp.exe** (in `downloader/`)
|
||||||
- **yt-dlp.exe** (included in `downloader/` folder)
|
- **mutagen** (for ID3 tagging, optional)
|
||||||
|
|
||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
### 1. Download a Single Playlist
|
### Download a Channel
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python download_karaoke.py https://www.youtube.com/playlist?list=YOUR_PLAYLIST_ID
|
python download_karaoke.py https://www.youtube.com/@SingKingKaraoke/videos
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Download Multiple Playlists
|
### Download from a List of Channels
|
||||||
|
|
||||||
Create a `playlists.txt` file with your playlist URLs (one per line):
|
|
||||||
|
|
||||||
```txt
|
|
||||||
https://www.youtube.com/playlist?list=PLAYLIST1_ID
|
|
||||||
https://www.youtube.com/playlist?list=PLAYLIST2_ID
|
|
||||||
https://www.youtube.com/playlist?list=PLAYLIST3_ID
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python download_karaoke.py --file playlists.txt
|
python download_karaoke.py --file channels.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📁 Project Structure
|
### Download Only Songlist Songs
|
||||||
|
```bash
|
||||||
|
python download_karaoke.py --songlist-only
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prioritize Songlist in Download Queue
|
||||||
|
```bash
|
||||||
|
python download_karaoke.py --songlist-priority
|
||||||
|
```
|
||||||
|
|
||||||
|
### Show Songlist Download Progress
|
||||||
|
```bash
|
||||||
|
python download_karaoke.py --songlist-status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Limit Number of Downloads
|
||||||
|
```bash
|
||||||
|
python download_karaoke.py --limit 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Override Resolution
|
||||||
|
```bash
|
||||||
|
python download_karaoke.py --resolution 1080p
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🧠 Songlist Integration
|
||||||
|
- Place your prioritized song list in `docs/songList.json` (see example format below).
|
||||||
|
- The tool will match and prioritize these songs across all available channel videos.
|
||||||
|
- Use `--songlist-only` to download only these songs, or `--songlist-priority` to prioritize them in the queue.
|
||||||
|
- Download progress for the songlist is tracked globally in `songlist_tracking.json`.
|
||||||
|
|
||||||
|
#### Example `docs/songList.json`
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{ "artist": "Taylor Swift", "title": "Cruel Summer" },
|
||||||
|
{ "artist": "Billie Eilish", "title": "Happier Than Ever" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ Tracking & Caching
|
||||||
|
- **karaoke_tracking.json**: Tracks all downloads, statuses, and formats
|
||||||
|
- **songlist_tracking.json**: Tracks global songlist download progress
|
||||||
|
- **channel_cache.json**: Caches channel video lists for performance
|
||||||
|
|
||||||
|
## 📂 Folder Structure
|
||||||
```
|
```
|
||||||
KaroakeVideoDownloader/
|
KaroakeVideoDownloader/
|
||||||
├── download_karaoke.py # Main script
|
├── download_karaoke.py # Main script
|
||||||
├── tracking_manager.py # Advanced tracking system
|
├── tracking_manager.py # Tracking logic
|
||||||
├── manage_tracking.py # Tracking management utility
|
├── manage_tracking.py # Tracking management utility
|
||||||
├── update_resolution.py # Resolution configuration utility
|
├── update_resolution.py # Resolution config utility
|
||||||
├── config.json # Configuration file
|
├── config.json # Main config
|
||||||
├── yt-dlp.exe # Downloader binary (in downloader/)
|
├── downloader/yt-dlp.exe # yt-dlp binary
|
||||||
├── playlists.txt # Sample playlist list
|
|
||||||
├── downloads/ # All video output
|
├── downloads/ # All video output
|
||||||
│ └── [playlist_name]/ # Folders per playlist
|
│ └── [ChannelName]/ # Per-channel folders
|
||||||
├── logs/
|
├── logs/ # Download logs
|
||||||
│ └── [playlist_name].log # Download logs
|
├── karaoke_tracking.json # Main tracking DB
|
||||||
└── karaoke_tracking.json # Advanced tracking database
|
├── songlist_tracking.json # Songlist tracking DB
|
||||||
|
├── docs/songList.json # Songlist for prioritization
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🎯 Usage Examples
|
## 🚦 CLI Options
|
||||||
|
- `--file <channels.txt>`: Download from a list of channels
|
||||||
### Basic Usage
|
- `--songlist-priority`: Prioritize songlist songs in download queue
|
||||||
|
- `--songlist-only`: Download only songs from the songlist
|
||||||
|
- `--songlist-status`: Show songlist download progress
|
||||||
|
- `--limit <N>`: Limit number of downloads
|
||||||
|
- `--resolution <720p|1080p|...>`: Override resolution
|
||||||
|
- `--status`: Show download/tracking status
|
||||||
|
|
||||||
|
## 📝 Example Usage
|
||||||
```bash
|
```bash
|
||||||
# Download a single playlist (720p MP4)
|
python download_karaoke.py https://www.youtube.com/@SingKingKaraoke/videos --songlist-priority --limit 10
|
||||||
python download_karaoke.py https://www.youtube.com/playlist?list=PLxxxxxxxx
|
python download_karaoke.py --file channels.txt --songlist-only
|
||||||
|
python download_karaoke.py --songlist-status
|
||||||
# Download with specific resolution
|
|
||||||
python download_karaoke.py --resolution 1080p https://www.youtube.com/playlist?list=PLxxxxxxxx
|
|
||||||
|
|
||||||
# Download from file
|
|
||||||
python download_karaoke.py --file playlists.txt
|
|
||||||
|
|
||||||
# Show download status and statistics
|
|
||||||
python download_karaoke.py --status
|
|
||||||
|
|
||||||
# Generate playlist report
|
|
||||||
python download_karaoke.py --report PLAYLIST_ID
|
|
||||||
|
|
||||||
# Clean up orphaned tracking entries
|
|
||||||
python download_karaoke.py --cleanup
|
|
||||||
|
|
||||||
# Show help
|
|
||||||
python download_karaoke.py --help
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tracking Management
|
## 🏷️ ID3 Tagging
|
||||||
|
- Adds artist/title/album/year/genre to MP4 files using mutagen (if installed)
|
||||||
|
|
||||||
```bash
|
## 🧹 Cleanup
|
||||||
# Show overall statistics
|
- Removes `.info.json` and `.meta` files after download
|
||||||
python manage_tracking.py --stats
|
|
||||||
|
|
||||||
# List all playlists
|
## 🧩 Configuration
|
||||||
python manage_tracking.py --list-playlists
|
- All options are in `config.json` (format, resolution, metadata, etc.)
|
||||||
|
- You can edit this file or use CLI flags to override
|
||||||
|
|
||||||
# Show playlist details
|
## 🐞 Troubleshooting
|
||||||
python manage_tracking.py --playlist PLAYLIST_ID
|
- Ensure `yt-dlp.exe` is in the `downloader/` folder
|
||||||
|
- Check `logs/` for error details
|
||||||
# Show failed songs
|
- Use `python check_resolution.py` to verify video quality
|
||||||
python manage_tracking.py --failed
|
|
||||||
|
|
||||||
# Show partial downloads
|
|
||||||
python manage_tracking.py --partial
|
|
||||||
|
|
||||||
# Clean up orphaned entries
|
|
||||||
python manage_tracking.py --cleanup
|
|
||||||
|
|
||||||
# Export database backup
|
|
||||||
python manage_tracking.py --export backup.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Resolution Management
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Show current resolution setting
|
|
||||||
python update_resolution.py --show
|
|
||||||
|
|
||||||
# Update to 1080p resolution
|
|
||||||
python update_resolution.py --resolution 1080p
|
|
||||||
|
|
||||||
# Update to 720p resolution (default)
|
|
||||||
python update_resolution.py --resolution 720p
|
|
||||||
```
|
|
||||||
|
|
||||||
### Advanced Features
|
|
||||||
|
|
||||||
The tool automatically:
|
|
||||||
- ✅ Creates organized folder structure
|
|
||||||
- ✅ Skips already downloaded videos
|
|
||||||
- ✅ Logs all activities
|
|
||||||
- ✅ Handles errors gracefully
|
|
||||||
- ✅ Shows real-time progress
|
|
||||||
- ✅ Extracts metadata and thumbnails
|
|
||||||
- ✅ Downloads subtitles when available
|
|
||||||
|
|
||||||
## 📊 Output Format
|
|
||||||
|
|
||||||
### Video Files
|
|
||||||
- **Format**: MP4 (720p by default, configurable)
|
|
||||||
- **Resolution**: 720p (upgradeable to 1080p, 1440p, 2160p)
|
|
||||||
- **Naming**: Original YouTube video title
|
|
||||||
- **Location**: `downloads/[playlist_name]/`
|
|
||||||
|
|
||||||
### Additional Files
|
|
||||||
- **Metadata**: JSON files with video info
|
|
||||||
- **Thumbnails**: Video thumbnails
|
|
||||||
- **Subtitles**: English SRT files (if available)
|
|
||||||
- **Logs**: Detailed download logs
|
|
||||||
|
|
||||||
## 🔧 Configuration
|
|
||||||
|
|
||||||
### Customizing Download Options
|
|
||||||
|
|
||||||
The script uses optimized yt-dlp settings for karaoke videos:
|
|
||||||
|
|
||||||
- **Format**: 720p MP4 by default (configurable via `config.json` or `--resolution`)
|
|
||||||
- **Resolution Options**: 480p, 720p, 1080p, 1440p, 2160p
|
|
||||||
- **Audio**: MP3 extraction as fallback
|
|
||||||
- **Metadata**: Full metadata embedding
|
|
||||||
- **Subtitles**: English SRT format
|
|
||||||
- **Error Handling**: Graceful error recovery
|
|
||||||
|
|
||||||
### Resolution Configuration
|
|
||||||
|
|
||||||
You can easily change the video resolution:
|
|
||||||
|
|
||||||
1. **Command Line**: Use `--resolution` flag
|
|
||||||
```bash
|
|
||||||
python download_karaoke.py --resolution 1080p https://www.youtube.com/playlist?list=XYZ
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Config File**: Edit `config.json` or use the utility
|
|
||||||
```bash
|
|
||||||
python update_resolution.py --resolution 1080p
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Supported Resolutions**: 480p, 720p, 1080p, 1440p, 2160p
|
|
||||||
|
|
||||||
### File Locations
|
|
||||||
|
|
||||||
- **Downloads**: `downloads/` folder
|
|
||||||
- **Logs**: `logs/` folder
|
|
||||||
- **Tracking**: `downloaded_videos.json`
|
|
||||||
|
|
||||||
## 🐛 Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
1. **yt-dlp.exe not found**
|
|
||||||
- Ensure `yt-dlp.exe` is in the `downloader/` folder
|
|
||||||
- Download from [yt-dlp releases](https://github.com/yt-dlp/yt-dlp/releases)
|
|
||||||
|
|
||||||
2. **Permission errors**
|
|
||||||
- Run as administrator if needed
|
|
||||||
- Check folder write permissions
|
|
||||||
|
|
||||||
3. **Network issues**
|
|
||||||
- Check internet connection
|
|
||||||
- Try again later (YouTube rate limiting)
|
|
||||||
|
|
||||||
4. **Playlist not found**
|
|
||||||
- Verify playlist URL is correct
|
|
||||||
- Ensure playlist is public
|
|
||||||
|
|
||||||
### Log Files
|
|
||||||
|
|
||||||
Check the log files in `logs/` for detailed error information:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# View latest log
|
|
||||||
type logs\playlist_name.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 Updating
|
|
||||||
|
|
||||||
### Update yt-dlp
|
|
||||||
|
|
||||||
Download the latest `yt-dlp.exe` from [GitHub releases](https://github.com/yt-dlp/yt-dlp/releases) and replace the file in `downloader/`.
|
|
||||||
|
|
||||||
### Update Script
|
|
||||||
|
|
||||||
The Python script is self-contained and doesn't require additional dependencies.
|
|
||||||
|
|
||||||
## 📝 License
|
|
||||||
|
|
||||||
This project is open source. Feel free to modify and distribute.
|
|
||||||
|
|
||||||
## 🤝 Contributing
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create a feature branch
|
|
||||||
3. Make your changes
|
|
||||||
4. Test thoroughly
|
|
||||||
5. Submit a pull request
|
|
||||||
|
|
||||||
## 🆘 Support
|
|
||||||
|
|
||||||
For issues and questions:
|
|
||||||
1. Check the troubleshooting section
|
|
||||||
2. Review log files for errors
|
|
||||||
3. Ensure all requirements are met
|
|
||||||
4. Try with a simple playlist first
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Happy Karaoke! 🎵**
|
**Happy Karaoke! 🎤**
|
||||||
108
docs/PRD.md
108
docs/PRD.md
@ -1,74 +1,110 @@
|
|||||||
|
|
||||||
# 🎤 Karaoke Playlist Downloader – PRD (v1.0)
|
# 🎤 Karaoke Video Downloader – PRD (v2.0)
|
||||||
|
|
||||||
## ✅ Overview
|
## ✅ Overview
|
||||||
A Python-based Windows command-line tool that wraps `yt-dlp.exe` to batch-download karaoke videos from YouTube playlists.
|
A Python-based Windows CLI tool to download karaoke videos from YouTube channels/playlists using `yt-dlp.exe`, with advanced tracking, songlist prioritization, and flexible configuration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📌 Goals
|
## 📋 Goals
|
||||||
- Quickly download full YouTube playlists containing karaoke videos.
|
- Download karaoke videos from YouTube channels or playlists.
|
||||||
- Organize downloads by playlist.
|
- Organize downloads by channel (or playlist) in subfolders.
|
||||||
- Avoid re-downloading the same videos.
|
- Avoid re-downloading the same videos (robust tracking).
|
||||||
|
- Prioritize and track a custom songlist across channels.
|
||||||
|
- Allow flexible, user-friendly configuration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧑💻 Target Users
|
## 🧑💻 Target Users
|
||||||
- Tech-savvy users, developers, or power users familiar with command-line tools.
|
- Karaoke DJs, home karaoke users, event hosts, or anyone needing offline karaoke video libraries.
|
||||||
- Use case: Karaoke DJs, home karaoke setups, offline playlist prep.
|
- Users comfortable with command-line tools.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙️ Platform & Stack
|
## ⚙️ Platform & Stack
|
||||||
- **Platform:** Windows
|
- **Platform:** Windows
|
||||||
- **Interface:** Command-line tool (CLI)
|
- **Interface:** Command-line (CLI)
|
||||||
- **Tech Stack:** Python + yt-dlp.exe
|
- **Tech Stack:** Python 3.7+, yt-dlp.exe, mutagen (for ID3 tagging)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📥 Input
|
## 📥 Input
|
||||||
- Accepts YouTube playlist URLs via command line.
|
- YouTube channel or playlist URLs (e.g. `https://www.youtube.com/@SingKingKaraoke/videos`)
|
||||||
- Optional: Accept a text file containing multiple playlist URLs (one per line).
|
- Optional: `channels.txt` file with multiple channel URLs (one per line)
|
||||||
|
- Optional: `docs/songList.json` for prioritized song downloads
|
||||||
|
|
||||||
### 🔹 Example Usage
|
### Example Usage
|
||||||
```bash
|
```bash
|
||||||
python download_karaoke.py https://www.youtube.com/playlist?list=XYZ
|
python download_karaoke.py https://www.youtube.com/@SingKingKaraoke/videos
|
||||||
python download_karaoke.py --file playlists.txt
|
python download_karaoke.py --file channels.txt
|
||||||
|
python download_karaoke.py --songlist-only
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📤 Output
|
## 📤 Output
|
||||||
- Downloads videos as **MP4** using `yt-dlp.exe`.
|
- MP4 files in `downloads/<ChannelName>/` subfolders
|
||||||
- Each playlist gets its own folder: `downloads/<playlist_name>/`
|
- All videos tracked in `karaoke_tracking.json`
|
||||||
- Filenames are preserved as per the original YouTube video title.
|
- Songlist progress tracked in `songlist_tracking.json`
|
||||||
|
- Logs in `logs/`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠️ Features
|
## 🛠️ Features
|
||||||
- ✅ Skips already downloaded videos (uses video ID log).
|
- ✅ Channel-based downloads (with per-channel folders)
|
||||||
- ✅ Logs each download to `logs/<playlist_name>.log`.
|
- ✅ Robust JSON tracking (downloaded, partial, failed, etc.)
|
||||||
- ✅ Shows progress and errors in the terminal.
|
- ✅ Batch saving and channel video caching for performance
|
||||||
- ✅ Lightweight and fast to execute.
|
- ✅ Configurable download resolution and yt-dlp options (`config.json`)
|
||||||
|
- ✅ Songlist integration: prioritize and track custom songlists
|
||||||
|
- ✅ Songlist-only mode: download only songs from the songlist
|
||||||
|
- ✅ Global songlist tracking to avoid duplicates across channels
|
||||||
|
- ✅ ID3 tagging for artist/title in MP4 files (mutagen)
|
||||||
|
- ✅ Real-time progress and detailed logging
|
||||||
|
- ✅ Automatic cleanup of extra yt-dlp files
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📁 Folder Structure (Suggested)
|
## 📂 Folder Structure
|
||||||
```
|
```
|
||||||
karaoke_downloader/
|
KaroakeVideoDownloader/
|
||||||
├── download_karaoke.py # main script
|
├── download_karaoke.py # Main script
|
||||||
├── yt-dlp.exe # downloader binary
|
├── tracking_manager.py # Tracking logic
|
||||||
├── playlists.txt # optional playlist list
|
├── manage_tracking.py # Tracking management utility
|
||||||
├── downloads/ # all video output
|
├── update_resolution.py # Resolution config utility
|
||||||
│ └── [playlist_name]/ # folders per playlist
|
├── config.json # Main config
|
||||||
└── logs/
|
├── downloader/yt-dlp.exe # yt-dlp binary
|
||||||
└── [playlist_name].log # download log
|
├── downloads/ # All video output
|
||||||
|
│ └── [ChannelName]/ # Per-channel folders
|
||||||
|
├── logs/ # Download logs
|
||||||
|
├── karaoke_tracking.json # Main tracking DB
|
||||||
|
├── songlist_tracking.json # Songlist tracking DB
|
||||||
|
├── docs/songList.json # Songlist for prioritization
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Future Enhancements (Optional)
|
## 🚦 CLI Options (Summary)
|
||||||
- [ ] `--audio` flag to extract MP3 only.
|
- `--file <channels.txt>`: Download from a list of channels
|
||||||
- [ ] Smart filename cleanup (`[Karaoke]` tag).
|
- `--songlist-priority`: Prioritize songlist songs in download queue
|
||||||
- [ ] Graceful skip of unavailable/private videos.
|
- `--songlist-only`: Download only songs from the songlist
|
||||||
- [ ] Retry logic for failed downloads.
|
- `--songlist-status`: Show songlist download progress
|
||||||
|
- `--limit <N>`: Limit number of downloads
|
||||||
|
- `--resolution <720p|1080p|...>`: Override resolution
|
||||||
|
- `--status`: Show download/tracking status
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Logic Highlights
|
||||||
|
- **Tracking:** All downloads, statuses, and formats are tracked in JSON files for reliability and deduplication.
|
||||||
|
- **Songlist:** Loads and normalizes `docs/songList.json`, matches against available videos, and prioritizes or restricts downloads accordingly.
|
||||||
|
- **Batch/Caching:** Channel video lists are cached to minimize API calls; tracking is batch-saved for performance.
|
||||||
|
- **ID3 Tagging:** Artist/title extracted from video title and embedded in MP4 files.
|
||||||
|
- **Cleanup:** Extra files from yt-dlp (e.g., `.info.json`) are automatically removed after download.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Future Enhancements
|
||||||
|
- [ ] Web UI for easier management
|
||||||
|
- [ ] More advanced song matching (fuzzy, multi-language)
|
||||||
|
- [ ] Download scheduling and retry logic
|
||||||
|
- [ ] More granular status reporting
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user