Convert to GUI-only application
- Remove all CLI/TUI functionality and command line arguments - Update README to reflect GUI-only nature - Simplify main() function to launch GUI directly - Remove unused imports and display_stats function
This commit is contained in:
@@ -1,117 +1,57 @@
|
|||||||
# slskd Transfer Statistics
|
# slskd Transfer Statistics
|
||||||
|
|
||||||
A tool to analyze upload and download statistics from your slskd transfers database with both command-line and GUI interfaces.
|
A GUI tool to analyze upload and download statistics from your slskd transfers database.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Analyzes uploads and downloads stored in the transfers.db database(s)
|
- Analyzes uploads and downloads stored in the transfers.db database(s)
|
||||||
- Automatically finds and combines data from multiple database files
|
- Automatically finds and combines data from multiple database files
|
||||||
|
- Backwards compatible with both old and new database formats
|
||||||
- Calculates total transfers, data transferred, and unique users
|
- Calculates total transfers, data transferred, and unique users
|
||||||
- Shows average transfer speed and duration
|
- Shows average transfer speed and duration
|
||||||
- Lists top users by data transferred
|
- Lists top users by data transferred
|
||||||
- Shows statistics by file type
|
- Shows statistics by file type
|
||||||
- Filter statistics by date range
|
- Filter statistics by time period (All time, Last month, Last year)
|
||||||
- Graphical user interface for easier analysis
|
- User-friendly graphical interface with summary and detailed tables
|
||||||
- Maintains full command-line functionality
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Python 3.6+
|
- Python 3.6+
|
||||||
- SQLite3
|
- SQLite3
|
||||||
- PyQt5 (for GUI version)
|
- PyQt5
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Clone or download this repository to your local machine
|
1. Clone or download this repository to your local machine
|
||||||
2. Ensure Python 3 is installed
|
2. Ensure Python 3 and PyQt5 are installed
|
||||||
3. Place your `transfers.db` file in the same directory as the script, or specify database paths using the `--db` option
|
3. Place your `transfers.db` file in the same directory as the script, or use the file browser to select database files
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Command Line Interface
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Basic usage (uses transfers.db in current directory)
|
# Launch the GUI application
|
||||||
# Shows both upload and download stats by default
|
python3 slskd_stats_gui.py
|
||||||
./slskd_stats.py
|
|
||||||
|
|
||||||
# Show only upload stats
|
|
||||||
./slskd_stats.py --uploads
|
|
||||||
|
|
||||||
# Show only download stats
|
|
||||||
./slskd_stats.py --downloads
|
|
||||||
|
|
||||||
# Explicitly show both upload and download stats (same as default)
|
|
||||||
./slskd_stats.py --all
|
|
||||||
|
|
||||||
# Specify single database file
|
|
||||||
./slskd_stats.py --db /path/to/transfers.db
|
|
||||||
|
|
||||||
# Specify multiple database files
|
|
||||||
./slskd_stats.py --db /path/to/transfers.db --db /path/to/another-transfers.db
|
|
||||||
|
|
||||||
# Only show transfers from the last 30 days
|
|
||||||
./slskd_stats.py --days 30
|
|
||||||
|
|
||||||
# Show top 15 entries in each category
|
|
||||||
./slskd_stats.py --top 15
|
|
||||||
|
|
||||||
# Combine options
|
|
||||||
./slskd_stats.py --all --days 7 --top 20 --db /path/to/transfers.db
|
|
||||||
```
|
|
||||||
|
|
||||||
### GUI Interface
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Launch the GUI version
|
|
||||||
./slskd_stats_gui.py
|
|
||||||
|
|
||||||
# Launch GUI even when providing command line arguments
|
|
||||||
./slskd_stats_gui.py --gui
|
|
||||||
```
|
```
|
||||||
|
|
||||||
With the GUI, you can:
|
With the GUI, you can:
|
||||||
- Select one or more database files using the file browser
|
- Select one or more database files using the file browser
|
||||||
- Choose to show upload stats, download stats, or both
|
- Choose time period from dropdown (All time, Last month, Last year)
|
||||||
- Filter by time period (last X days)
|
|
||||||
- Set the number of top entries to display
|
- Set the number of top entries to display
|
||||||
- View statistics in a user-friendly tabbed interface
|
- View upload and download statistics side-by-side
|
||||||
|
- See summary statistics and detailed tables for users and file types
|
||||||
|
|
||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
```
|
The GUI displays:
|
||||||
=== UPLOAD STATISTICS ===
|
- **Summary sections** showing total transfers, data transferred, unique users, average speeds, and error rates
|
||||||
|
- **Top Users tables** showing users ranked by data transferred
|
||||||
|
- **Top File Types tables** showing file extensions ranked by data transferred
|
||||||
|
|
||||||
Total Uploads: 8583
|
## Database Compatibility
|
||||||
Total Data Uploaded: 241.97 GB
|
|
||||||
Unique Users: 650
|
|
||||||
Average Upload Speed: 8.50 MB/s
|
|
||||||
Average Upload Duration: 10.02 seconds
|
|
||||||
|
|
||||||
--- Top Users by Data Uploaded ---
|
This tool automatically detects and works with both:
|
||||||
1. username1: 279 files, 18.01 GB
|
- **Old format**: Text-based `State` column
|
||||||
2. username2: 494 files, 12.29 GB
|
- **New format**: Integer `State` + `StateDescription` columns
|
||||||
3. username3: 378 files, 11.05 GB
|
|
||||||
...
|
|
||||||
|
|
||||||
--- Top File Types ---
|
|
||||||
1. .flac: 8456 files, 241.00 GB
|
|
||||||
2. .mp3: 105 files, 830.71 MB
|
|
||||||
3. .m4a: 22 files, 165.58 MB
|
|
||||||
|
|
||||||
=== DOWNLOAD STATISTICS ===
|
|
||||||
|
|
||||||
Total Downloads: 357
|
|
||||||
Total Data Downloaded: 10.94 GB
|
|
||||||
Unique Users: 36
|
|
||||||
Average Download Speed: 2.03 MB/s
|
|
||||||
Average Download Duration: 26.21 seconds
|
|
||||||
|
|
||||||
--- Top Users by Data Downloaded ---
|
|
||||||
1. username1: 6 files, 1.45 GB
|
|
||||||
2. username2: 58 files, 1.33 GB
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
|
|||||||
+1
-110
@@ -3,10 +3,7 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# For GUI
|
# For GUI
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
@@ -191,48 +188,6 @@ def get_transfer_stats(db_paths, direction="Upload", days=None):
|
|||||||
|
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
def display_stats(stats, direction, top_n=10):
|
|
||||||
"""Display the statistics in a readable format for CLI"""
|
|
||||||
if not stats or stats["total_transfers"] == 0:
|
|
||||||
print(f"No {direction.lower()} data found for the specified period.")
|
|
||||||
return
|
|
||||||
|
|
||||||
output = []
|
|
||||||
output.append(f"\n=== {direction.upper()} STATISTICS ===\n")
|
|
||||||
|
|
||||||
output.append(f"Total {direction}s: {stats['total_transfers']}")
|
|
||||||
output.append(f"Total Data {direction}ed: {format_size(stats['total_bytes'])}")
|
|
||||||
output.append(f"Unique Users: {stats['unique_users']}")
|
|
||||||
output.append(f"Average {direction} Speed: {format_size(stats['avg_speed'])}/s")
|
|
||||||
output.append(f"Average {direction} Duration: {format_time(stats['avg_duration'])}")
|
|
||||||
|
|
||||||
# Top users by data transferred
|
|
||||||
output.append(f"\n--- Top Users by Data {direction}ed ---")
|
|
||||||
sorted_users = sorted(
|
|
||||||
stats["user_stats"].items(),
|
|
||||||
key=lambda x: x[1]["bytes"],
|
|
||||||
reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
for i, (username, data) in enumerate(sorted_users[:top_n], 1):
|
|
||||||
output.append(f"{i}. {username}: {data['count']} files, {format_size(data['bytes'])}")
|
|
||||||
|
|
||||||
# Top file types
|
|
||||||
output.append("\n--- Top File Types ---")
|
|
||||||
sorted_extensions = sorted(
|
|
||||||
stats["extension_stats"].items(),
|
|
||||||
key=lambda x: x[1]["bytes"],
|
|
||||||
reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
for i, (ext, data) in enumerate(sorted_extensions[:top_n], 1):
|
|
||||||
output.append(f"{i}. {ext}: {data['count']} files, {format_size(data['bytes'])}")
|
|
||||||
|
|
||||||
# Print all lines
|
|
||||||
for line in output:
|
|
||||||
print(line)
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -526,71 +481,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.downloadSummary.setText("No download data found for the specified period.")
|
self.downloadSummary.setText("No download data found for the specified period.")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Check if command line args were provided
|
# Launch GUI application
|
||||||
if len(sys.argv) > 1:
|
|
||||||
# Command line mode
|
|
||||||
parser = argparse.ArgumentParser(description="Analyze transfer statistics from slskd transfers database")
|
|
||||||
parser.add_argument("--db", action="append", help="Path to transfers.db file(s). Can be specified multiple times.")
|
|
||||||
parser.add_argument("--days", type=int, help="Only analyze transfers from the last X days")
|
|
||||||
parser.add_argument("--top", type=int, default=10, help="Show top N entries in each category")
|
|
||||||
parser.add_argument("--uploads", action="store_true", help="Show only upload statistics")
|
|
||||||
parser.add_argument("--downloads", action="store_true", help="Show only download statistics")
|
|
||||||
parser.add_argument("--all", action="store_true", help="Show both upload and download statistics (default)")
|
|
||||||
parser.add_argument("--gui", action="store_true", help="Launch the GUI instead of command line mode")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Check if GUI mode is requested
|
|
||||||
if args.gui:
|
|
||||||
# Launch GUI mode
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
window = MainWindow()
|
|
||||||
window.show()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
|
||||||
# Determine which db files to use
|
|
||||||
db_paths = []
|
|
||||||
if args.db:
|
|
||||||
# User specified database files
|
|
||||||
for db_path in args.db:
|
|
||||||
if os.path.exists(db_path):
|
|
||||||
db_paths.append(db_path)
|
|
||||||
else:
|
|
||||||
print(f"Warning: Database file not found: {db_path}")
|
|
||||||
else:
|
|
||||||
# Default: Only look for transfers.db in the current directory
|
|
||||||
if os.path.exists("transfers.db"):
|
|
||||||
db_paths.append("transfers.db")
|
|
||||||
else:
|
|
||||||
print("Default transfers.db not found in current directory.")
|
|
||||||
|
|
||||||
if not db_paths:
|
|
||||||
print("Error: No database files found. Please specify with --db option.")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"Using database file(s): {', '.join(db_paths)}")
|
|
||||||
|
|
||||||
# Default behavior is to show both uploads and downloads
|
|
||||||
# Only change from default if specific flags are set
|
|
||||||
if args.uploads and not args.downloads and not args.all:
|
|
||||||
show_uploads = True
|
|
||||||
show_downloads = False
|
|
||||||
elif args.downloads and not args.uploads and not args.all:
|
|
||||||
show_uploads = False
|
|
||||||
show_downloads = True
|
|
||||||
else:
|
|
||||||
# Default behavior or --all flag
|
|
||||||
show_uploads = True
|
|
||||||
show_downloads = True
|
|
||||||
|
|
||||||
if show_uploads:
|
|
||||||
upload_stats = get_transfer_stats(db_paths, "Upload", args.days)
|
|
||||||
display_stats(upload_stats, "Upload", args.top)
|
|
||||||
|
|
||||||
if show_downloads:
|
|
||||||
download_stats = get_transfer_stats(db_paths, "Download", args.days)
|
|
||||||
display_stats(download_stats, "Download", args.top)
|
|
||||||
else:
|
|
||||||
# No args provided, launch GUI
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
window = MainWindow()
|
window = MainWindow()
|
||||||
window.show()
|
window.show()
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user