Compare commits

..

4 Commits

Author SHA1 Message Date
Keith Edmunds
0e3e30391b Don't grow window when track title too long
Use an elided text box, set wrapping and max height for label.

Fixes #26
2021-08-15 16:03:48 +01:00
Keith Edmunds
246b0d4915 Improve full database update sanity check 2021-08-15 13:04:30 +01:00
Keith Edmunds
fcf4ba3eb9 Implement full database scan 2021-08-15 12:52:50 +01:00
Keith Edmunds
a7d9252619 Move Fade button to right of Stop
Fixes #50
2021-08-15 11:22:35 +01:00
5 changed files with 143 additions and 37 deletions

View File

@ -463,6 +463,12 @@ class Tracks(Base):
return [a[0] for a in session.query(Tracks.path).all()] return [a[0] for a in session.query(Tracks.path).all()]
@staticmethod
def get_all_tracks(session):
"Return a list of all tracks"
return session.query(Tracks).all()
@classmethod @classmethod
def get_or_create(cls, session, path): def get_or_create(cls, session, path):
DEBUG(f"Tracks.get_or_create(path={path})") DEBUG(f"Tracks.get_or_create(path={path})")

View File

@ -10,11 +10,13 @@ from datetime import datetime, timedelta
from log import DEBUG, EXCEPTION from log import DEBUG, EXCEPTION
from PyQt5.QtCore import Qt, QTimer from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFontMetrics, QPainter
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QApplication, QApplication,
QDialog, QDialog,
QFileDialog, QFileDialog,
QInputDialog, QInputDialog,
QLabel,
QListWidgetItem, QListWidgetItem,
QMainWindow, QMainWindow,
) )
@ -32,6 +34,21 @@ from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist
from ui.main_window_ui import Ui_MainWindow from ui.main_window_ui import Ui_MainWindow
class ElideLabel(QLabel):
"""
From https://stackoverflow.com/questions/11446478/
pyside-pyqt-truncate-text-in-qlabel-based-on-minimumsize
"""
def paintEvent(self, event):
painter = QPainter(self)
metrics = QFontMetrics(self.font())
elided = metrics.elidedText(self.text(), Qt.ElideRight, self.width())
painter.drawText(self.rect(), self.alignment(), elided)
class Window(QMainWindow, Ui_MainWindow): class Window(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)

View File

@ -115,10 +115,75 @@ def create_track_from_file(session, path):
return track return track
def full_update_db(): def full_update_db(session):
"Rescan all entries in database" "Rescan all entries in database"
print("Full scan not yet implemented") def log(msg):
INFO(f"full_update_db(): {msg}")
def check_change(track_id, title, attribute, old, new):
if new > (old * 1.1) or new < (old * 0.9):
log(
"\n"
f"track[{track_id}] ({title}) "
f"{attribute} updated from {old} to {new}"
)
# Start with normal update to add new tracks and remove any missing
# files
log("update_db()")
update_db(session)
# Now update track length, silence and fade for every track in
# database
tracks = Tracks.get_all_tracks(session)
total_tracks = len(tracks)
log(f"Processing {total_tracks} tracks")
track_count = 0
for track in tracks:
track_count += 1
print(f"\rTrack {track_count} of {total_tracks}", end='')
# Sanity check
tag = get_music_info(track.path)
if not tag['title']:
log(f"track[{track.id}] {track.title=}: No tag title")
continue
if not tag['artist']:
log(f"track[{track.id}] {track.artist=}: No tag artist")
continue
# Update title and artist
if track.title != tag['title']:
track.title = tag['title']
if track.artist != tag['artist']:
track.artist = tag['artist']
# Update numbers; log if more than 10% different
duration = int(round(
tag['duration'], Config.MILLISECOND_SIGFIGS) * 1000)
check_change(track.id, track.title, "duration", track.duration,
duration)
track.duration = duration
audio = get_audio_segment(track.path)
start_gap = leading_silence(audio)
check_change(track.id, track.title, "start_gap", track.start_gap,
start_gap)
track.start_gap = start_gap
fade_at = fade_point(audio)
check_change(track.id, track.title, "fade_at", track.fade_at,
fade_at)
track.fade_at = fade_at
silence_at = trailing_silence(audio)
check_change(track.id, track.title, "silence_at", track.silence_at,
silence_at)
track.silence_at = silence_at
session.commit()
def get_audio_segment(path): def get_audio_segment(path):
@ -196,22 +261,6 @@ def fade_point(audio_segment, fade_threshold=0,
return int(trim_ms) return int(trim_ms)
# Current unused (1 June 2021)
# def rescan_database(session):
#
# tracks = Tracks.get_all_tracks(session)
# total_tracks = len(tracks)
# track_count = 0
# for track in tracks:
# track_count += 1
# print(f"Track {track_count} of {total_tracks}")
# audio = get_audio_segment(track.path)
# track.start_gap = leading_silence(audio)
# track.fade_at = fade_point(audio)
# track.silence_at = trailing_silence(audio)
# session.commit()
def trailing_silence(audio_segment, silence_threshold=-50.0, def trailing_silence(audio_segment, silence_threshold=-50.0,
chunk_size=Config.AUDIO_SEGMENT_CHUNK_SIZE): chunk_size=Config.AUDIO_SEGMENT_CHUNK_SIZE):
return fade_point(audio_segment, silence_threshold, chunk_size) return fade_point(audio_segment, silence_threshold, chunk_size)

View File

@ -149,6 +149,9 @@ border: 1px solid rgb(85, 87, 83);</string>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -166,10 +169,25 @@ border: 1px solid rgb(85, 87, 83);</string>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="hdrNextTrack"> <widget class="ElideLabel" name="hdrNextTrack">
<property name="minimumSize">
<size>
<width>0</width>
<height>39</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>39</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<family>Sans</family> <family>Sans</family>
@ -183,6 +201,9 @@ border: 1px solid rgb(85, 87, 83);</string>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -392,13 +413,13 @@ border: 1px solid rgb(85, 87, 83);</string>
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QPushButton" name="btnFade"> <widget class="QPushButton" name="btnStop">
<property name="text"> <property name="text">
<string>Fade</string> <string>Stop</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="icons.qrc"> <iconset resource="icons.qrc">
<normaloff>:/icons/fade</normaloff>:/icons/fade</iconset> <normaloff>:/icons/stopsign</normaloff>:/icons/stopsign</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -409,13 +430,13 @@ border: 1px solid rgb(85, 87, 83);</string>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="btnStop"> <widget class="QPushButton" name="btnFade">
<property name="text"> <property name="text">
<string>Stop</string> <string>Fade</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="icons.qrc"> <iconset resource="icons.qrc">
<normaloff>:/icons/stopsign</normaloff>:/icons/stopsign</iconset> <normaloff>:/icons/fade</normaloff>:/icons/fade</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -984,6 +1005,13 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</action> </action>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ElideLabel</class>
<extends>QLabel</extends>
<header>musicmuster</header>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="icons.qrc"/> <include location="icons.qrc"/>
</resources> </resources>

View File

@ -85,6 +85,7 @@ class Ui_MainWindow(object):
self.hdrPreviousTrack.setStyleSheet("background-color: #f8d7da;\n" self.hdrPreviousTrack.setStyleSheet("background-color: #f8d7da;\n"
"border: 1px solid rgb(85, 87, 83);") "border: 1px solid rgb(85, 87, 83);")
self.hdrPreviousTrack.setText("") self.hdrPreviousTrack.setText("")
self.hdrPreviousTrack.setWordWrap(True)
self.hdrPreviousTrack.setObjectName("hdrPreviousTrack") self.hdrPreviousTrack.setObjectName("hdrPreviousTrack")
self.verticalLayout.addWidget(self.hdrPreviousTrack) self.verticalLayout.addWidget(self.hdrPreviousTrack)
self.hdrCurrentTrack = QtWidgets.QLabel(self.centralwidget) self.hdrCurrentTrack = QtWidgets.QLabel(self.centralwidget)
@ -95,9 +96,12 @@ class Ui_MainWindow(object):
self.hdrCurrentTrack.setStyleSheet("background-color: #d4edda;\n" self.hdrCurrentTrack.setStyleSheet("background-color: #d4edda;\n"
"border: 1px solid rgb(85, 87, 83);") "border: 1px solid rgb(85, 87, 83);")
self.hdrCurrentTrack.setText("") self.hdrCurrentTrack.setText("")
self.hdrCurrentTrack.setWordWrap(True)
self.hdrCurrentTrack.setObjectName("hdrCurrentTrack") self.hdrCurrentTrack.setObjectName("hdrCurrentTrack")
self.verticalLayout.addWidget(self.hdrCurrentTrack) self.verticalLayout.addWidget(self.hdrCurrentTrack)
self.hdrNextTrack = QtWidgets.QLabel(self.centralwidget) self.hdrNextTrack = ElideLabel(self.centralwidget)
self.hdrNextTrack.setMinimumSize(QtCore.QSize(0, 39))
self.hdrNextTrack.setMaximumSize(QtCore.QSize(16777215, 39))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Sans") font.setFamily("Sans")
font.setPointSize(20) font.setPointSize(20)
@ -105,6 +109,7 @@ class Ui_MainWindow(object):
self.hdrNextTrack.setStyleSheet("background-color: #fff3cd;\n" self.hdrNextTrack.setStyleSheet("background-color: #fff3cd;\n"
"border: 1px solid rgb(85, 87, 83);") "border: 1px solid rgb(85, 87, 83);")
self.hdrNextTrack.setText("") self.hdrNextTrack.setText("")
self.hdrNextTrack.setWordWrap(True)
self.hdrNextTrack.setObjectName("hdrNextTrack") self.hdrNextTrack.setObjectName("hdrNextTrack")
self.verticalLayout.addWidget(self.hdrNextTrack) self.verticalLayout.addWidget(self.hdrNextTrack)
self.horizontalLayout_3.addLayout(self.verticalLayout) self.horizontalLayout_3.addLayout(self.verticalLayout)
@ -181,20 +186,20 @@ class Ui_MainWindow(object):
self.horizontalLayout.addWidget(self.btnSetNext) self.horizontalLayout.addWidget(self.btnSetNext)
spacerItem3 = QtWidgets.QSpacerItem(69, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem3 = QtWidgets.QSpacerItem(69, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem3) self.horizontalLayout.addItem(spacerItem3)
self.btnFade = QtWidgets.QPushButton(self.frame_5)
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btnFade.setIcon(icon6)
self.btnFade.setIconSize(QtCore.QSize(30, 30))
self.btnFade.setObjectName("btnFade")
self.horizontalLayout.addWidget(self.btnFade)
self.btnStop = QtWidgets.QPushButton(self.frame_5) self.btnStop = QtWidgets.QPushButton(self.frame_5)
icon7 = QtGui.QIcon() icon6 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(":/icons/stopsign"), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon6.addPixmap(QtGui.QPixmap(":/icons/stopsign"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btnStop.setIcon(icon7) self.btnStop.setIcon(icon6)
self.btnStop.setIconSize(QtCore.QSize(30, 30)) self.btnStop.setIconSize(QtCore.QSize(30, 30))
self.btnStop.setObjectName("btnStop") self.btnStop.setObjectName("btnStop")
self.horizontalLayout.addWidget(self.btnStop) self.horizontalLayout.addWidget(self.btnStop)
self.btnFade = QtWidgets.QPushButton(self.frame_5)
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.btnFade.setIcon(icon7)
self.btnFade.setIconSize(QtCore.QSize(30, 30))
self.btnFade.setObjectName("btnFade")
self.horizontalLayout.addWidget(self.btnFade)
self.spnVolume = QtWidgets.QSpinBox(self.frame_5) self.spnVolume = QtWidgets.QSpinBox(self.frame_5)
self.spnVolume.setMaximum(100) self.spnVolume.setMaximum(100)
self.spnVolume.setProperty("value", 100) self.spnVolume.setProperty("value", 100)
@ -486,8 +491,8 @@ class Ui_MainWindow(object):
self.btnAddFile.setText(_translate("MainWindow", "Add file")) self.btnAddFile.setText(_translate("MainWindow", "Add file"))
self.btnAddNote.setText(_translate("MainWindow", "Add note")) self.btnAddNote.setText(_translate("MainWindow", "Add note"))
self.btnSetNext.setText(_translate("MainWindow", "Set next")) self.btnSetNext.setText(_translate("MainWindow", "Set next"))
self.btnFade.setText(_translate("MainWindow", "Fade"))
self.btnStop.setText(_translate("MainWindow", "Stop")) self.btnStop.setText(_translate("MainWindow", "Stop"))
self.btnFade.setText(_translate("MainWindow", "Fade"))
self.label_2.setText(_translate("MainWindow", "Started at:")) self.label_2.setText(_translate("MainWindow", "Started at:"))
self.label_start_tod.setText(_translate("MainWindow", "00:00:00")) self.label_start_tod.setText(_translate("MainWindow", "00:00:00"))
self.label_3.setText(_translate("MainWindow", "Silent at:")) self.label_3.setText(_translate("MainWindow", "Silent at:"))
@ -540,4 +545,5 @@ class Ui_MainWindow(object):
self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K")) self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K"))
self.actionSelect_played_tracks.setText(_translate("MainWindow", "Select played tracks")) self.actionSelect_played_tracks.setText(_translate("MainWindow", "Select played tracks"))
self.actionSelect_unplayed_tracks.setText(_translate("MainWindow", "Select unplayed tracks")) self.actionSelect_unplayed_tracks.setText(_translate("MainWindow", "Select unplayed tracks"))
from musicmuster import ElideLabel
import icons_rc import icons_rc