Compare commits

..

No commits in common. "125a44c6452887c4a8a2ab0352fa890a7427709e" and "2fbf829eedd9035f23cbf31655b871e5bc4ad227" have entirely different histories.

7 changed files with 26 additions and 93 deletions

View File

@ -38,13 +38,6 @@ class Config(object):
MILLISECOND_SIGFIGS = 0 MILLISECOND_SIGFIGS = 0
MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_dev" # noqa E501 MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_dev" # noqa E501
NORMALISE_ON_IMPORT = True NORMALISE_ON_IMPORT = True
NOTE_COLOURS = {
'track': "#ffff00",
'request': "#7cf000",
'wrap': "#fffacd",
'this month then': "#c256c2",
'story': "#dda0dd",
}
ROOT = os.environ.get('ROOT') or "/home/kae/music" ROOT = os.environ.get('ROOT') or "/home/kae/music"
TESTMODE = True TESTMODE = True
TIMER_MS = 500 TIMER_MS = 500

View File

@ -106,7 +106,7 @@ class Playdates(Base):
pd.lastplayed = datetime.now() pd.lastplayed = datetime.now()
pd.track_id = track.id pd.track_id = track.id
session.add(pd) session.add(pd)
track.update_lastplayed(session, track.id) track.update_lastplayed()
session.commit() session.commit()
@staticmethod @staticmethod
@ -596,11 +596,8 @@ class Tracks(Base):
return session.query(Tracks).filter( return session.query(Tracks).filter(
Tracks.id == id).one() Tracks.id == id).one()
@staticmethod def update_lastplayed(self):
def update_lastplayed(session, track_id): self.lastplayed = datetime.now()
track = session.query(Tracks).filter(Tracks.id == track_id).one()
track.lastplayed = datetime.now()
session.commit()
@staticmethod @staticmethod
def update_artist(session, track_id, artist): def update_artist(session, track_id, artist):

View File

@ -166,7 +166,6 @@ class Window(QMainWindow, Ui_MainWindow):
def connect_signals_slots(self): def connect_signals_slots(self):
self.actionAdd_file.triggered.connect(self.add_file) self.actionAdd_file.triggered.connect(self.add_file)
self.actionAdd_note.triggered.connect(self.insert_note)
self.action_Clear_selection.triggered.connect(self.clear_selection) self.action_Clear_selection.triggered.connect(self.clear_selection)
self.actionClosePlaylist.triggered.connect(self.close_playlist_tab) self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
self.actionExport_playlist.triggered.connect(self.export_playlist_tab) self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
@ -197,7 +196,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.btnSongInfo.clicked.connect(self.song_info_search) self.btnSongInfo.clicked.connect(self.song_info_search)
self.btnStop.clicked.connect(self.stop) self.btnStop.clicked.connect(self.stop)
self.spnVolume.valueChanged.connect(self.change_volume) self.spnVolume.valueChanged.connect(self.change_volume)
self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
self.timer.timeout.connect(self.tick) self.timer.timeout.connect(self.tick)
@ -229,15 +227,6 @@ class Window(QMainWindow, Ui_MainWindow):
index = self.tabPlaylist.currentIndex() index = self.tabPlaylist.currentIndex()
self.tabPlaylist.removeTab(index) self.tabPlaylist.removeTab(index)
def close_tab(self, index):
if self.tabPlaylist.widget(index) == self.current_track_playlist_tab:
self.statusbar.showMessage("Can't close current track playlist",
5000)
elif self.tabPlaylist.widget(index) == self.next_track_playlist_tab:
self.statusbar.showMessage("Can't close next track playlist", 5000)
else:
self.tabPlaylist.removeTab(index)
def create_note(self, session, text): def create_note(self, session, text):
""" """
Create note Create note
@ -430,9 +419,6 @@ class Window(QMainWindow, Ui_MainWindow):
# the playlistis opened. # the playlistis opened.
destination_visible_playlist_tab = None destination_visible_playlist_tab = None
for tab in range(self.tabPlaylist.count()): for tab in range(self.tabPlaylist.count()):
# Non-playlist tabs won't have ids
if not hasattr(self.tabPlaylist.widget(tab), 'id'):
continue
if self.tabPlaylist.widget(tab).id == dlg.plid: if self.tabPlaylist.widget(tab).id == dlg.plid:
destination_visible_playlist_tab = ( destination_visible_playlist_tab = (
self.tabPlaylist.widget(tab)) self.tabPlaylist.widget(tab))
@ -525,6 +511,7 @@ class Window(QMainWindow, Ui_MainWindow):
QColor(Config.COLOUR_NEXT_TAB)) QColor(Config.COLOUR_NEXT_TAB))
# Tell database to record it as played # Tell database to record it as played
self.current_track.update_lastplayed()
Playdates.add_playdate(session, self.current_track) Playdates.add_playdate(session, self.current_track)
self.disable_play_next_controls() self.disable_play_next_controls()

View File

@ -141,8 +141,6 @@ class PlaylistTab(QTableWidget):
self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN, self.setSpan(row, self.COL_NOTE, self.NOTE_ROW_SPAN,
self.NOTE_COL_SPAN) self.NOTE_COL_SPAN)
# Scroll to drop zone
self.scrollToItem(self.item(row, 1))
super().dropEvent(event) super().dropEvent(event)
DEBUG( DEBUG(
@ -1030,13 +1028,8 @@ class PlaylistTab(QTableWidget):
if row_time: if row_time:
next_start_time = row_time next_start_time = row_time
# Set colour # Set colour
note_colour = Config.COLOUR_NOTES_PLAYLIST
note_text = self.item(row, self.COL_TITLE).text()
for colour_token in Config.NOTE_COLOURS.keys():
if note_text.lower().startswith(colour_token.lower()):
note_colour = Config.NOTE_COLOURS[colour_token]
self._set_row_colour( self._set_row_colour(
row, QColor(note_colour) row, QColor(Config.COLOUR_NOTES_PLAYLIST)
) )
self._set_row_bold(row) self._set_row_bold(row)
@ -1051,10 +1044,6 @@ class PlaylistTab(QTableWidget):
# Set start time # Set start time
self._set_row_start_time( self._set_row_start_time(
row, self.current_track_start_time) row, self.current_track_start_time)
last_played_str = get_relative_date(
self.current_track_start_time)
self.item(row, self.COL_LAST_PLAYED).setText(
last_played_str)
# Calculate next_start_time # Calculate next_start_time
next_start_time = self._calculate_next_start_time( next_start_time = self._calculate_next_start_time(
session, row, self.current_track_start_time) session, row, self.current_track_start_time)

View File

@ -14,13 +14,11 @@ from mutagen.mp3 import MP3
from pydub import AudioSegment, effects from pydub import AudioSegment, effects
from tinytag import TinyTag from tinytag import TinyTag
# Globals (I know)
messages = []
def main(): def main():
"Main loop" "Main loop"
DEBUG("Starting") INFO("Starting")
# Parse command line # Parse command line
p = argparse.ArgumentParser() p = argparse.ArgumentParser()
@ -38,25 +36,25 @@ def main():
# Run as required # Run as required
if args.update: if args.update:
DEBUG("Updating database") INFO("Updating database")
with Session() as session: with Session() as session:
update_db(session) update_db(session)
elif args.full_update: elif args.full_update:
DEBUG("Full update of database") INFO("Full update of database")
with Session() as session: with Session() as session:
full_update_db(session) full_update_db(session)
elif args.fname: elif args.fname:
fname = os.path.realpath(args.fname) fname = os.path.realpath(args.fname)
with Session() as session: with Session() as session:
create_track_from_file(session, fname, interactive=True) create_track_from_file(session, fname, verbose=True)
else: else:
INFO("No action specified") INFO("No action specified")
DEBUG("Finished") INFO("Finished")
def create_track_from_file(session, path, interactive=False): def create_track_from_file(session, path, verbose=False):
""" """
Create track in database from passed path, or update database entry Create track in database from passed path, or update database entry
if path already in database. if path already in database.
@ -64,35 +62,23 @@ def create_track_from_file(session, path, interactive=False):
Return track. Return track.
""" """
if interactive: if verbose:
str = f"Importing {path}" str = f"Importing {path}"
INFO(str) INFO(str)
INFO("-" * len(str)) INFO("-" * len(str))
track = Tracks.get_or_create(session, path)
if verbose:
INFO("Get track info...") INFO("Get track info...")
t = get_music_info(path) t = get_music_info(path)
title = t['title'] track.title = t['title']
artist = t['artist'] track.artist = t['artist']
if interactive: if verbose:
INFO(f" Title: \"{title}\"") INFO(f" Title: \"{track.title}\"")
INFO(f" Artist: \"{artist}\"") INFO(f" Artist: \"{track.artist}\"")
# Check for duplicate
tracks = Tracks.search_titles(session, title)
if interactive and tracks:
print("Found the following possible matches:")
for track in tracks:
print(f'"{track.title}" by {track.artist}')
response = input("Continue [c] or abort [a]?")
if not response:
return
if response[0].lower() not in ['c', 'y']:
return
track = Tracks.get_or_create(session, path)
track.title = title
track.artist = artist
track.duration = int(round( track.duration = int(round(
t['duration'], Config.MILLISECOND_SIGFIGS) * 1000) t['duration'], Config.MILLISECOND_SIGFIGS) * 1000)
if interactive: if verbose:
INFO("Parse for start, fade and silence...") INFO("Parse for start, fade and silence...")
audio = get_audio_segment(path) audio = get_audio_segment(path)
track.start_gap = leading_silence(audio) track.start_gap = leading_silence(audio)
@ -104,7 +90,7 @@ def create_track_from_file(session, path, interactive=False):
session.commit() session.commit()
if Config.NORMALISE_ON_IMPORT: if Config.NORMALISE_ON_IMPORT:
if interactive: if verbose:
INFO("Normalise...") INFO("Normalise...")
# Check type # Check type
ftype = os.path.splitext(path)[1][1:] ftype = os.path.splitext(path)[1][1:]
@ -331,7 +317,8 @@ def update_db(session):
# is filename in database? # is filename in database?
track = Tracks.get_track_from_filename(session, os.path.basename(path)) track = Tracks.get_track_from_filename(session, os.path.basename(path))
if not track: if not track:
messages.append(f"Track missing from database: {path}") INFO(f"songdb.update_db: Adding to database: {path}")
create_track_from_file(session, path)
else: else:
# Check track info matches found track # Check track info matches found track
t = get_music_info(path) t = get_music_info(path)
@ -346,7 +333,7 @@ def update_db(session):
for path in list(db_paths - os_paths): for path in list(db_paths - os_paths):
# Manage tracks listed in database but where path is invalid # Manage tracks listed in database but where path is invalid
track = Tracks.get_track_from_path(session, path) track = Tracks.get_track_from_path(session, path)
messages.append(f"Remove from database: {path=} {track=}") INFO(f"songdb.update_db(): remove from database: {path=} {track=}")
# Remove references from Playdates # Remove references from Playdates
Playdates.remove_track(session, track.id) Playdates.remove_track(session, track.id)
@ -365,12 +352,6 @@ def update_db(session):
# Remove Track entry pointing to invalid path # Remove Track entry pointing to invalid path
Tracks.remove_path(session, path) Tracks.remove_path(session, path)
# Output messages (so if running via cron, these will get sent to
# user)
if messages:
print("Messages")
print("\n".join(messages))
def update_meta(session, track, artist=None, title=None): def update_meta(session, track, artist=None, title=None):
""" """

View File

@ -468,7 +468,7 @@ border: 1px solid rgb(85, 87, 83);</string>
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="tabsClosable"> <property name="tabsClosable">
<bool>true</bool> <bool>false</bool>
</property> </property>
<property name="movable"> <property name="movable">
<bool>true</bool> <bool>true</bool>
@ -770,7 +770,6 @@ border: 1px solid rgb(85, 87, 83);</string>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSearch_database"/> <addaction name="actionSearch_database"/>
<addaction name="actionAdd_file"/> <addaction name="actionAdd_file"/>
<addaction name="actionAdd_note"/>
<addaction name="action_Clear_selection"/> <addaction name="action_Clear_selection"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSelect_unplayed_tracks"/> <addaction name="actionSelect_unplayed_tracks"/>
@ -1005,14 +1004,6 @@ border: 1px solid rgb(85, 87, 83);</string>
<string>Select unplayed tracks</string> <string>Select unplayed tracks</string>
</property> </property>
</action> </action>
<action name="actionAdd_note">
<property name="text">
<string>Add note...</string>
</property>
<property name="shortcut">
<string>Ctrl+T</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -208,7 +208,7 @@ class Ui_MainWindow(object):
self.gridLayout_3.addWidget(self.frame_5, 1, 0, 1, 1) self.gridLayout_3.addWidget(self.frame_5, 1, 0, 1, 1)
self.tabPlaylist = QtWidgets.QTabWidget(self.centralwidget) self.tabPlaylist = QtWidgets.QTabWidget(self.centralwidget)
self.tabPlaylist.setDocumentMode(False) self.tabPlaylist.setDocumentMode(False)
self.tabPlaylist.setTabsClosable(True) self.tabPlaylist.setTabsClosable(False)
self.tabPlaylist.setMovable(True) self.tabPlaylist.setMovable(True)
self.tabPlaylist.setObjectName("tabPlaylist") self.tabPlaylist.setObjectName("tabPlaylist")
self.gridLayout_3.addWidget(self.tabPlaylist, 2, 0, 1, 1) self.gridLayout_3.addWidget(self.tabPlaylist, 2, 0, 1, 1)
@ -438,8 +438,6 @@ class Ui_MainWindow(object):
self.actionSelect_played_tracks.setObjectName("actionSelect_played_tracks") self.actionSelect_played_tracks.setObjectName("actionSelect_played_tracks")
self.actionSelect_unplayed_tracks = QtWidgets.QAction(MainWindow) self.actionSelect_unplayed_tracks = QtWidgets.QAction(MainWindow)
self.actionSelect_unplayed_tracks.setObjectName("actionSelect_unplayed_tracks") self.actionSelect_unplayed_tracks.setObjectName("actionSelect_unplayed_tracks")
self.actionAdd_note = QtWidgets.QAction(MainWindow)
self.actionAdd_note.setObjectName("actionAdd_note")
self.menuFile.addAction(self.actionE_xit) self.menuFile.addAction(self.actionE_xit)
self.menuPlaylist.addAction(self.actionNewPlaylist) self.menuPlaylist.addAction(self.actionNewPlaylist)
self.menuPlaylist.addAction(self.actionOpenPlaylist) self.menuPlaylist.addAction(self.actionOpenPlaylist)
@ -449,7 +447,6 @@ class Ui_MainWindow(object):
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSearch_database) self.menuPlaylist.addAction(self.actionSearch_database)
self.menuPlaylist.addAction(self.actionAdd_file) self.menuPlaylist.addAction(self.actionAdd_file)
self.menuPlaylist.addAction(self.actionAdd_note)
self.menuPlaylist.addAction(self.action_Clear_selection) self.menuPlaylist.addAction(self.action_Clear_selection)
self.menuPlaylist.addSeparator() self.menuPlaylist.addSeparator()
self.menuPlaylist.addAction(self.actionSelect_unplayed_tracks) self.menuPlaylist.addAction(self.actionSelect_unplayed_tracks)
@ -548,7 +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"))
self.actionAdd_note.setText(_translate("MainWindow", "Add note..."))
self.actionAdd_note.setShortcut(_translate("MainWindow", "Ctrl+T"))
from musicmuster import ElideLabel from musicmuster import ElideLabel
import icons_rc import icons_rc