Compare commits
4 Commits
d4f542cc29
...
0e3e30391b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e3e30391b | ||
|
|
246b0d4915 | ||
|
|
fcf4ba3eb9 | ||
|
|
a7d9252619 |
@ -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})")
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user