Add Playlist Analytics Dashboard with charts for growth, top artists, and update frequency using matplotlib
This commit is contained in:
1 parent
1339365941
commit
7e7754f533
2 files changed
+126
-13
No files matched your search
+125
-13
@@ -15,19 +15,17 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# GUI imports
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QPushButton, QTextEdit, QLineEdit, QFormLayout,
|
||||
QDialog, QDialogButtonBox, QSystemTrayIcon, QMenu,
|
||||
QGroupBox, QCheckBox, QSpinBox, QComboBox, QMessageBox,
|
||||
QProgressBar, QSplitter, QFrame, QScrollArea, QTextBrowser, QTableWidget, QTableWidgetItem, QHeaderView, QListWidget, QListWidgetItem
|
||||
)
|
||||
from PySide6.QtCore import (
|
||||
Qt, QTimer, QThread, Signal, QSettings, QSize
|
||||
)
|
||||
from PySide6.QtGui import (
|
||||
QIcon, QAction, QFont, QPixmap, QPainter, QColor, QDesktopServices
|
||||
)
|
||||
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QTextEdit, QLineEdit, QLabel, QHBoxLayout, QDialog, QListWidget, QListWidgetItem, QTableWidget, QTableWidgetItem, QHeaderView, QCheckBox, QInputDialog, QMessageBox, QProgressBar, QSystemTrayIcon, QMenu, QAction, QComboBox, QGroupBox, QFormLayout, QSpinBox, QTextBrowser, QTabWidget
|
||||
from PySide6.QtCore import QTimer, Qt, QThread, Signal, QSettings, QUrl
|
||||
from PySide6.QtGui import QIcon, QDesktopServices, QFont
|
||||
import json
|
||||
import csv
|
||||
from urllib.parse import quote
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
# Import our existing functionality
|
||||
from main import scrape_recently_played, create_playlist_in_plex, PLEX_TOKEN, SERVER_IP, PLAYLIST_NAME
|
||||
@@ -309,6 +307,11 @@ class MainWindow(QMainWindow):
|
||||
self.stats_button.clicked.connect(self.show_statistics)
|
||||
status_layout.addWidget(self.stats_button)
|
||||
|
||||
# Analytics button
|
||||
self.analytics_button = QPushButton("Analytics")
|
||||
self.analytics_button.clicked.connect(self.show_analytics)
|
||||
status_layout.addWidget(self.analytics_button)
|
||||
|
||||
status_group.setLayout(status_layout)
|
||||
splitter.addWidget(status_group)
|
||||
|
||||
@@ -628,6 +631,115 @@ class MainWindow(QMainWindow):
|
||||
dialog.setLayout(layout)
|
||||
dialog.exec()
|
||||
|
||||
def show_analytics(self):
|
||||
"""Show analytics dashboard with charts"""
|
||||
import sqlite3
|
||||
import json
|
||||
from datetime import datetime
|
||||
from collections import Counter
|
||||
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("Playlist Analytics")
|
||||
dialog.setModal(True)
|
||||
dialog.resize(1000, 700)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
tab_widget = QTabWidget()
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect('playlist_history.db')
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT date, added_songs, missing_songs FROM history ORDER BY date')
|
||||
rows = c.fetchall()
|
||||
conn.close()
|
||||
|
||||
# Prepare data
|
||||
dates = []
|
||||
cumulative_added = 0
|
||||
cumulative_list = []
|
||||
artist_counter = Counter()
|
||||
update_freq = []
|
||||
|
||||
for date, added_json, missing_json in rows:
|
||||
dt = datetime.fromisoformat(date)
|
||||
dates.append(dt.strftime('%Y-%m-%d'))
|
||||
|
||||
added_songs = json.loads(added_json) if added_json else []
|
||||
cumulative_added += len(added_songs)
|
||||
cumulative_list.append(cumulative_added)
|
||||
update_freq.append(len(added_songs))
|
||||
|
||||
for song in added_songs:
|
||||
# Parse artist from "Title by Artist"
|
||||
if " by " in song:
|
||||
artist = song.split(" by ", 1)[1]
|
||||
artist_counter[artist] += 1
|
||||
|
||||
# Tab 1: Playlist Growth
|
||||
growth_tab = QWidget()
|
||||
growth_layout = QVBoxLayout()
|
||||
fig1 = Figure(figsize=(8, 6))
|
||||
ax1 = fig1.add_subplot(111)
|
||||
ax1.plot(dates, cumulative_list, marker='o')
|
||||
ax1.set_title('Playlist Growth Over Time')
|
||||
ax1.set_xlabel('Date')
|
||||
ax1.set_ylabel('Total Songs')
|
||||
ax1.tick_params(axis='x', rotation=45)
|
||||
canvas1 = FigureCanvas(fig1)
|
||||
growth_layout.addWidget(canvas1)
|
||||
growth_tab.setLayout(growth_layout)
|
||||
tab_widget.addTab(growth_tab, "Growth")
|
||||
|
||||
# Tab 2: Top Artists
|
||||
artists_tab = QWidget()
|
||||
artists_layout = QVBoxLayout()
|
||||
fig2 = Figure(figsize=(8, 6))
|
||||
ax2 = fig2.add_subplot(111)
|
||||
top_artists = artist_counter.most_common(10)
|
||||
if top_artists:
|
||||
artists, counts = zip(*top_artists)
|
||||
ax2.bar(artists, counts)
|
||||
ax2.set_title('Top 10 Artists')
|
||||
ax2.set_xlabel('Artist')
|
||||
ax2.set_ylabel('Songs Added')
|
||||
ax2.tick_params(axis='x', rotation=45)
|
||||
canvas2 = FigureCanvas(fig2)
|
||||
artists_layout.addWidget(canvas2)
|
||||
artists_tab.setLayout(artists_layout)
|
||||
tab_widget.addTab(artists_tab, "Top Artists")
|
||||
|
||||
# Tab 3: Update Frequency
|
||||
freq_tab = QWidget()
|
||||
freq_layout = QVBoxLayout()
|
||||
fig3 = Figure(figsize=(8, 6))
|
||||
ax3 = fig3.add_subplot(111)
|
||||
ax3.bar(dates, update_freq)
|
||||
ax3.set_title('Songs Added per Update')
|
||||
ax3.set_xlabel('Date')
|
||||
ax3.set_ylabel('Songs Added')
|
||||
ax3.tick_params(axis='x', rotation=45)
|
||||
canvas3 = FigureCanvas(fig3)
|
||||
freq_layout.addWidget(canvas3)
|
||||
freq_tab.setLayout(freq_layout)
|
||||
tab_widget.addTab(freq_tab, "Update Frequency")
|
||||
|
||||
except Exception as e:
|
||||
error_tab = QWidget()
|
||||
error_layout = QVBoxLayout()
|
||||
error_layout.addWidget(QLabel(f"Error loading analytics: {str(e)}"))
|
||||
error_tab.setLayout(error_layout)
|
||||
tab_widget.addTab(error_tab, "Error")
|
||||
|
||||
layout.addWidget(tab_widget)
|
||||
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
|
||||
buttons.rejected.connect(dialog.close)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
dialog.setLayout(layout)
|
||||
dialog.exec()
|
||||
|
||||
def show_history(self):
|
||||
"""Show the playlist history dialog"""
|
||||
import sqlite3
|
||||
|
||||
@@ -5,3 +5,4 @@ mutagen
|
||||
selenium
|
||||
webdriver-manager
|
||||
PySide6
|
||||
matplotlib
|
||||
Reference in new issue
Block a user