#!/usr/bin/env python3 import sys import datetime as dt from dataclasses import dataclass from PyQt6.QtWidgets import ( QApplication, QDialog, QLabel, QLineEdit, QListWidget, QVBoxLayout, QHBoxLayout, QPushButton, QListWidgetItem ) from PyQt6.QtCore import Qt, pyqtSignal @dataclass class TrackDTO: track_id: int artist: str bitrate: int duration: int # milliseconds fade_at: int intro: int | None path: str silence_at: int start_gap: int title: str lastplayed: dt.datetime | None # Placeholder external function to simulate search def search_titles(query: str) -> list[TrackDTO]: now = dt.datetime.now() dummy_tracks = [ TrackDTO(1, "Artist A", 320, 210000, 0, None, "", 0, 0, "Title One", now - dt.timedelta(days=2)), TrackDTO(2, "Artist B", 256, 185000, 0, None, "", 0, 0, "Another Title", now - dt.timedelta(days=30)), TrackDTO(3, "Artist C", 320, 240000, 0, None, "", 0, 0, "More Music", None), ] return [t for t in dummy_tracks if query.lower() in t.title.lower()] def format_duration(ms: int) -> str: minutes, seconds = divmod(ms // 1000, 60) return f"{minutes}:{seconds:02d}" def friendly_last_played(lastplayed: dt.datetime | None) -> str: if lastplayed is None: return "(Never)" now = dt.datetime.now() delta = now - lastplayed days = delta.days if days == 0: return "(Today)" elif days == 1: return "(Yesterday)" years, days_remain = divmod(days, 365) months, days_final = divmod(days_remain, 30) parts = [] if years: parts.append(f"{years}y") if months: parts.append(f"{months}m") if days_final: parts.append(f"{days_final}d") formatted = " ".join(parts) return f"({formatted} ago)" class TrackInsertDialog(QDialog): signal_insert_track = pyqtSignal(int, str) def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Insert Track") # Title input on one line self.title_label = QLabel("Title:") self.title_edit = QLineEdit() self.title_edit.textChanged.connect(self.update_list) title_layout = QHBoxLayout() title_layout.addWidget(self.title_label) title_layout.addWidget(self.title_edit) # Track list self.track_list = QListWidget() # Note input on one line self.note_label = QLabel("Note:") self.note_edit = QLineEdit() note_layout = QHBoxLayout() note_layout.addWidget(self.note_label) note_layout.addWidget(self.note_edit) # Buttons self.add_btn = QPushButton("Add") self.add_close_btn = QPushButton("Add and close") self.close_btn = QPushButton("Close") self.add_btn.clicked.connect(self.add_clicked) self.add_close_btn.clicked.connect(self.add_and_close_clicked) self.close_btn.clicked.connect(self.close) btn_layout = QHBoxLayout() btn_layout.addWidget(self.add_btn) btn_layout.addWidget(self.add_close_btn) btn_layout.addWidget(self.close_btn) # Main layout layout = QVBoxLayout() layout.addLayout(title_layout) layout.addWidget(self.track_list) layout.addLayout(note_layout) layout.addLayout(btn_layout) self.setLayout(layout) self.resize(600, 400) def update_list(self, text: str): self.track_list.clear() if text.strip() == "": # Do not search or populate list if input is empty return tracks = search_titles(text) for track in tracks: duration_str = format_duration(track.duration) last_played_str = friendly_last_played(track.lastplayed) item_str = f"{track.title} - {track.artist} [{duration_str}] {last_played_str}" item = QListWidgetItem(item_str) item.setData(Qt.ItemDataRole.UserRole, track.track_id) self.track_list.addItem(item) def get_selected_track_id(self) -> int | None: selected_items = self.track_list.selectedItems() if selected_items: return selected_items[0].data(Qt.ItemDataRole.UserRole) return None def add_clicked(self): track_id = self.get_selected_track_id() if track_id is not None: note_text = self.note_edit.text() self.signal_insert_track.emit(track_id, note_text) self.title_edit.clear() self.note_edit.clear() self.track_list.clear() self.title_edit.setFocus() def add_and_close_clicked(self): track_id = self.get_selected_track_id() if track_id is not None: note_text = self.note_edit.text() self.signal_insert_track.emit(track_id, note_text) self.accept() # Test harness (for quick testing) if __name__ == "__main__": app = QApplication(sys.argv) dialog = TrackInsertDialog() def print_inserted(track_id, note): print(f"Inserted track ID: {track_id}, Note: '{note}'") dialog.signal_insert_track.connect(print_inserted) dialog.exec()