20 Commits

Author SHA1 Message Date
Alec a35c6841bc Add requirements.txt for easier dependency installation 2025-09-03 10:56:59 +02:00
Alec 9c0a4e0ff2 Fix popularity stats to use upload data instead of download data
- Change popularity stats to analyze upload records (Direction = 'Upload')
- This shows which of your shared files are most downloaded by others
- Update error messages and explanations to reflect upload-based analysis
- Remove "NEW" labels from README features
- Clarify that popularity shows download frequency of your uploads
2025-09-03 10:53:43 +02:00
Alec 7ebb1372f4 Fix popularity stats and enhance path parsing for download-based analysis
- Fix database format compatibility for popularity functions
- Change popularity metrics from uploads to downloads (tracks user demand)
- Implement enhanced left-to-right path parsing algorithm
- Add support for diverse library structures (/music/, \Artists\, etc.)
- Improve artist name removal from album titles
- Update UI labels to reflect download-based popularity
2025-09-01 12:38:33 +02:00
Alec cf197456de Add popularity statistics tab with artist and album rankings
- New Popularity Stats tab showing top artists and albums by upload count
- Interactive charts with truncated names and hover tooltips
- Smart album name cleaning to remove redundant artist prefixes
- Library format detection and user-friendly error messages
- Configurable top entries display (5-50, default 10)
- Read-only tables to prevent accidental data modification
- Centered charts with proper label spacing
- Removed mplcursors dependency for better compatibility
- Updated README with new features and screenshot
2025-07-26 11:26:55 +02:00
Alec e66d578a86 Add AI development disclaimer to README 2025-07-17 16:53:31 +02:00
Alec 6ad50a90f5 Add screenshots to README and remove redundant Example Output section 2025-07-17 16:51:31 +02:00
Alec 3563eb6832 Fix window resize behavior - content now scales properly
- Replace setMaximumHeight() with setMinimumHeight() for all tables and summaries
- Tables now expand/contract when window is resized instead of staying fixed
- Summary text boxes scale with window height changes
- Graph canvases set minimum height but can grow with window
- Proper responsive layout that adapts to different window sizes
- Better user experience with flexible content sizing
2025-07-17 16:31:47 +02:00
Alec e854deb1bc Center controls layout with separator in the middle
- Add stretch layouts on both sides to center the controls
- Separator (|) now positioned in the center of the window
- Database controls balanced on the left side of separator
- Analysis controls balanced on the right side of separator
- Symmetrical, professional layout with perfect centering
2025-07-17 16:28:33 +02:00
Alec 9b13720a15 Move database status label to bottom left for same-height controls
- Remove database status label from controls section
- Move database status label to bottom left of main window
- All controls now truly at same height (buttons and dropdown)
- Clean horizontal alignment between database and analysis controls
- Database status visible but doesn't interfere with control layout
- Increased label max width to 400px for better text display
2025-07-17 16:27:22 +02:00
Alec 8bee10df20 Align controls to same height with vertical separator
- Move analysis controls (period + button) to horizontal layout
- Add vertical separator (|) between database and analysis sections
- Align all controls at the same height for cleaner appearance
- Remove unnecessary nested vertical layouts
- Database controls on left, analysis controls on right
- Proper visual separation while maintaining compact layout
2025-07-17 16:25:35 +02:00
Alec 8e594387af Clean up UI: remove overrides, simplify controls, use proper labels
- Remove all font size and margin specifications to respect user's theme
- Remove Top N control (now fixed at 10 entries)
- Move time period selection next to analyze button in same row
- Use proper button labels: 'Add Database File' and 'Clear Database Files'
- Remove manual layout margins/spacing to use system defaults
- Simplify controls layout with database controls on left, analysis on right
- Let the operating system handle proper spacing and theming
2025-07-17 16:23:45 +02:00
Alec e95c125dff Consolidate controls into compact horizontal layout
- Combine database and filter sections into single horizontal row
- Reduce vertical space usage by ~60% for control area
- Use shorter button labels (Add DB, Clear) to save space
- Add visual separators between control sections
- Compact filter controls into inline layouts
- Make database path label more compact with word wrap
- Integrate analyze button into controls row
- Significantly increase space available for data display
2025-07-17 16:20:35 +02:00
Alec 74237b6429 Make UI more compact and efficient
- Reduce window minimum size to 900x700, default to 1000x750
- Decrease graph figure sizes from 12x4 to 10x3
- Add proper margins and spacing throughout all layouts
- Reduce summary text height from 120px to 90px
- Limit table heights to 150px with alternating row colors
- Adjust graph subplot margins for better space utilization
- Use smaller font size for summary text
- Improve overall visual density and information display
2025-07-17 16:17:56 +02:00
Alec e484bd6704 Fix line unpacking error in graph plotting
- Check plot() return values before accessing first element
- Handle cases where matplotlib returns None or empty results
- Fix total errors calculation in amounts graph
- Update both amounts and ratios graphs consistently
- Prevent 'cannot unpack none-iteralLine2D Object' error
2025-07-17 16:13:38 +02:00
Alec f02a5416e7 Fix tooltip index access for proper data display
- Add multiple methods to access data point index from mplcursors
- Use coordinate-based fallback when direct index access fails
- Show proper date, metric name, and formatted values in tooltips
- Add better error handling with detailed error messages
2025-07-17 16:08:30 +02:00
Alec 5fe67cf9a5 Add interactive time series graphs with hover tooltips
- Add Visual Stats tab with two interactive graphs
- Amounts graph: uploads, downloads, errors, new users over time
- Ratios graph: speeds and error rates with dynamic y-axes
- Interactive hover tooltips showing date and exact values
- Checkboxes to toggle metrics on/off
- Automatic y-axis adjustment when metrics are disabled
- Clean, modern graph styling with proper date formatting
- Support for all existing time period filters
2025-07-17 16:04:16 +02:00
Player6734 5373bd83a5 Delete .DS_Store 2025-07-17 15:57:46 +02:00
Alec 479593e010 Remove transfers.db from tracking and add .gitignore 2025-07-17 15:46:39 +02:00
Alec 0c86bcee18 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
2025-07-17 15:44:50 +02:00
Alec f21c75adb0 Update GUI with dropdown time periods and backwards compatibility
- Replace spinbox with dropdown for time periods (All time, Last month, Last year)
- Add backwards compatibility for both old and new database formats
- Detect database schema automatically and use appropriate queries
- Fix compatibility with newer transfers.db format (StateDescription vs State)
2025-07-17 15:43:44 +02:00
11 changed files with 1553 additions and 230 deletions
+2
View File
@@ -0,0 +1,2 @@
transfers.db
.DS_Store
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 Player6734
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

+75 -2
View File
@@ -1,2 +1,75 @@
# slskd-stats
A python script to see upload stats (kind of manual)
# slskd Transfer Statistics
A GUI tool to analyze upload and download statistics from your slskd transfers database.
## Features
- Analyzes uploads and downloads stored in the transfers.db database(s)
- 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
- Shows average transfer speed and duration
- Lists top users by data transferred
- Shows statistics by file type
- Filter statistics by time period (All time, Last month, Last year)
- Artist and album popularity statistics based on download frequency of your uploads
- Smart path parsing with enhanced library structure detection
- Intelligent album name cleaning (removes redundant artist names from folder names)
- User-friendly graphical interface with summary and detailed tables
## Requirements
- Python 3.6+
- SQLite3
- PyQt5
- matplotlib
## Installation
1. Clone or download this repository to your local machine
2. Install dependencies: `pip3 install PyQt5 matplotlib`
3. Place your `transfers.db` file in the same directory as the script, or use the file browser to select database files
## Usage
```bash
# Launch the GUI application
python3 slskd_stats_gui.py
```
With the GUI, you can:
- Select one or more database files using the file browser
- Choose time period from dropdown (All time, Last month, Last year)
- Set the number of top entries to display
- View upload and download statistics side-by-side
- See summary statistics and detailed tables for users and file types
- Visual time series graphs showing transfer trends over time
- Analyze artist and album popularity based on how often others download your files with interactive charts and tables
## Screenshots
### Summary View
![Summary View](Summary.png)
### Visual Stats with Time Series Graphs
![Visual Stats](Visual.png)
### Popularity Stats with Artist and Album Rankings
![Popularity Stats](Popularity.png)
## Database Compatibility
This tool automatically detects and works with both:
- **Old format**: Text-based `State` column
- **New format**: Integer `State` + `StateDescription` columns
## About
This tool is designed to work with the `transfers.db` SQLite database created by [slskd](https://github.com/slskd/slskd), a Soulseek client daemon. It helps you understand your sharing patterns and track transfer statistics.
*This project was developed with assistance from AI.*
## License
MIT
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

+2
View File
@@ -0,0 +1,2 @@
PyQt5>=5.15.0
matplotlib>=3.5.0
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

-207
View File
@@ -1,207 +0,0 @@
#!/usr/bin/env python3
"""
SLSKD Transfer Size Analyzer
A script I created to analyze SLSKD HTML and calculate accurate transfer statistics.
After experimenting with different approaches, I found that checking the button text
directly gives more reliable results than relying on CSS classes.
I also added automatic conversion between MB and GB to make large numbers more readable.
Usage:
python slskd_analyzer_with_gb.py <html_file>
"""
import re
import sys
import os
from bs4 import BeautifulSoup
def format_size(size_mb):
"""
Format file size in MB or GB depending on the size.
I added this function to make large transfer sizes more readable.
After dealing with multi-GB transfers, seeing something like "2458.7 MB"
is less intuitive than "2.4 GB".
"""
if size_mb >= 1024:
return f"{size_mb/1024:.2f} GB"
else:
return f"{size_mb:.1f} MB"
def analyze_html(html_content):
"""
Parse and analyze the SLSKD HTML content to extract transfer statistics.
I initially tried looking only at CSS classes, but found inconsistencies in how
the success/failure states were represented. Checking the actual button text with
"Completed, Succeeded" proved more reliable and worked across different versions.
"""
soup = BeautifulSoup(html_content, 'html.parser')
# Initialize statistics dictionary
stats = {
'successful_mb': 0,
'failed_mb': 0,
'total_mb': 0,
'successful_files': 0,
'failed_files': 0,
'flac_files': 0,
'mp3_files': 0,
'users': {}
}
# Process each transfer card (one per user)
# I structured it this way to make it easier to attribute transfers to users
transfer_cards = soup.find_all('div', class_='ui raised card transfer-card')
for card in transfer_cards:
# Extract the username from the header
header = card.find('div', class_='header')
username = header.text.strip() if header else "Unknown"
# Initialize user statistics if not already present
if username not in stats['users']:
stats['users'][username] = {
'successful_mb': 0,
'failed_mb': 0,
'total_mb': 0,
'successful_files': 0,
'failed_files': 0
}
# Process all file rows for this user
# I tried several approaches and found traversing the rows directly was most reliable
rows = card.find_all('tr')
for row in rows:
# Skip header rows - they have th elements
if row.find('th'):
continue
# Extract the relevant cells
filename_cell = row.find('td', class_='transferlist-filename')
progress_cell = row.find('td', class_='transferlist-progress')
size_cell = row.find('td', class_='transferlist-size')
# Skip if any required cell is missing
if not all([filename_cell, progress_cell, size_cell]):
continue
filename = filename_cell.text.strip()
button = progress_cell.find('button')
if not button:
continue
# Track file types - primarily interested in audio formats
if filename.lower().endswith('.flac'):
stats['flac_files'] += 1
elif filename.lower().endswith('.mp3'):
stats['mp3_files'] += 1
# Check success/failure status based on button text
# This was a key insight - looking for specific text patterns rather than
# relying on CSS classes which can vary across SLSKD versions/themes
button_text = button.text.strip()
is_success = 'Completed, Succeeded' in button_text
is_failed = 'Completed, Errored' in button_text
# Parse size information
# Format is typically "X.X/Y.Y MB" where X is transferred and Y is total
size_text = size_cell.text.strip()
size_match = re.search(r'(\d+(?:\.\d+)?)/(\d+(?:\.\d+)?)', size_text)
if not size_match:
continue
transferred = float(size_match.group(1))
total = float(size_match.group(2))
# Update statistics based on transfer status
if is_success:
stats['successful_mb'] += transferred
stats['successful_files'] += 1
stats['users'][username]['successful_mb'] += transferred
stats['users'][username]['successful_files'] += 1
elif is_failed:
# For failed transfers, I count the target size rather than the partial transfer
# This gives a better sense of what "should have" transferred
stats['failed_mb'] += total
stats['failed_files'] += 1
stats['users'][username]['failed_mb'] += total
stats['users'][username]['failed_files'] += 1
stats['total_mb'] += total
stats['users'][username]['total_mb'] += total
return stats
def print_report(stats):
"""
Format and print a comprehensive report of the transfer statistics.
I organized this to present the most relevant information first (overall stats),
followed by file type breakdowns and user-specific information.
For readability, I convert large values from MB to GB automatically.
"""
print("\n===== SLSKD TRANSFER STATISTICS =====")
print(f"\nOverall Statistics:")
print(f"Successfully transferred: {format_size(stats['successful_mb'])} ({stats['successful_files']} files)")
print(f"Failed transfers: {format_size(stats['failed_mb'])} ({stats['failed_files']} files)")
print(f"Total size of all files: {format_size(stats['total_mb'])} ({stats['successful_files'] + stats['failed_files']} files)")
if stats['total_mb'] > 0:
success_rate = (stats['successful_mb'] / stats['total_mb']) * 100
print(f"Success rate: {success_rate:.1f}%")
print(f"\nFile Type Statistics:")
print(f"FLAC files: {stats['flac_files']}")
print(f"MP3 files: {stats['mp3_files']}")
other_files = stats['successful_files'] + stats['failed_files'] - stats['flac_files'] - stats['mp3_files']
print(f"Other files: {other_files}")
# Top users by total volume
print("\nTop Users by Total Transfer Volume:")
sorted_users_total = sorted(stats['users'].items(), key=lambda x: x[1]['total_mb'], reverse=True)
for i, (username, user_stats) in enumerate(sorted_users_total[:5], 1):
print(f"{i}. {username}: {format_size(user_stats['total_mb'])} total")
# Top users by successful transfers
print("\nTop Users by Successful Transfers:")
sorted_users_success = sorted(stats['users'].items(), key=lambda x: x[1]['successful_mb'], reverse=True)
for i, (username, user_stats) in enumerate(sorted_users_success[:5], 1):
if user_stats['successful_mb'] > 0:
print(f"{i}. {username}: {format_size(user_stats['successful_mb'])} successful "
f"({user_stats['successful_files']} files)")
print("\n=====================================")
def main():
"""
Main entry point - handles command line arguments and file processing.
I kept the interface simple - just provide the HTML file path as an argument.
This makes it easy to analyze different snapshots over time.
"""
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <html_file>")
sys.exit(1)
html_file = sys.argv[1]
if not os.path.exists(html_file):
print(f"Error: File {html_file} does not exist")
sys.exit(1)
with open(html_file, 'r', encoding='utf-8') as f:
html_content = f.read()
stats = analyze_html(html_content)
print_report(stats)
if __name__ == "__main__":
main()
+1474
View File
File diff suppressed because it is too large Load Diff