| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- """
- [Module documentaion here]
- @author:[author], [year]
- """
- from PyQt5 import QtWidgets
- from PyQt5.QtCore import QSize
- from path import Path
- from PyQt5.QtGui import QIcon
- from PyQt5.QtWidgets import QMainWindow, QListWidgetItem, QTableWidgetItem, QFileDialog, QMessageBox
- from core.logging_ import Logger
- from core.models import MusicFolder, TrackTag, Track
- from core.repositories import MusicFolderRepository, TrackRepository, SessionTrackRepository, SessionRepository, \
- TrackTagRepository, TagRepository
- from ui.qt.dlg_meta_editor import DlgMetaEditor
- from ui.qt.dlg_playlist import DlgPlaylist
- from ui.qt.dlg_select_playlist import DlgSelectPlaylist
- from ui.qt.main_ui import Ui_mainWindow
- from ui.qt.widgets.explorertable import ExplorerTable
- from ui.qt.widgets.playlist_table import PlaylistTable
- logger = Logger.get()
- class MainWindow(QMainWindow):
- def __init__(self, settings=None):
- super().__init__()
- self.settings = settings or {}
- self.selected_playlist = None
- self.playing_queue = []
- self.selected_track = None # /!\ the selected track is not necessarily the one being played!
- self.createWidgets()
- def createWidgets(self):
- self.ui = Ui_mainWindow()
- self.ui.setupUi(self)
- # Stack and menus
- self.ui.stack.setCurrentIndex(0)
- menu_items = {
- 0: (':/img/rsc/dance.png', 'Ma séance'),
- 1: (':/img/rsc/map.png', 'Explorer'),
- # 2: (':/img/rsc/calendar.png', 'Agenda'),
- 3: (':/img/rsc/settings.png', 'Paramètres'),
- }
- for i, item in menu_items.items():
- icon, lbl = item
- item = QListWidgetItem(QIcon(icon), lbl)
- item.index = i
- self.ui.menu.addItem(item)
- QtWidgets.qApp.focusChanged.connect(self.focus_changed)
- # Menu item clicked
- self.ui.menu.itemClicked.connect(self.menu_item_selected)
- # Page 1 - Homepage
- self.ui.sessionPlaylist.trackDoubleClicked.connect(self.play_playlist)
- self.ui.sessionBtnChange.clicked.connect(self.selectPlaylist)
- self.ui.btnSessionStart.clicked.connect(self.play_playlist)
- # Page 3 - explorer
- self.ui.explorerTable.populate()
- self.ui.explorerTable.trackSelected.connect(self.newTrackSelected)
- self.ui.explorerTable.trackDoubleClicked.connect(self.play_track)
- self.ui.btnExplorerRefresh.clicked.connect(self.refresh_explorer_tree)
- self.ui.explorerLineSearch.editingFinished.connect(self.explorerFiltersChanged)
- self.ui.explorerLineSearch.textChanged.connect(self.explorerFiltersChanged) # when search bar is cleared
- self.ui.explorerBtnSearch.clicked.connect(self.explorerFiltersChanged)
- self.populate_explorer_filter_tags()
- self.ui.explorerFilterTags.currentIndexChanged.connect(self.explorerFiltersChanged)
- self.ui.explorerTrackEdit.clicked.connect(self.showMetaEditor)
- self.ui.lineSearchTags.textChanged.connect(self.ui.explorerTrackTagsTable.filter)
- self.ui.explorerTrackTagsTable.tagChecked.connect(self.addTrackTags)
- self.ui.explorerTrackTagsTable.tagUnchecked.connect(self.removeTrackTags)
- self.ui.explorerTrackMetaStack.setCurrentIndex(0)
- self.ui.btnPlaySelectedTrack.clicked.connect(self.playSelectedTrack)
- self.ui.btnSelectPlaylist.clicked.connect(self.selectPlaylist)
- self.ui.explorerAddToPlaylist.clicked.connect(self.add_to_playlist)
- self.ui.explorerPlaylist.droppedEvent.connect(self.add_to_playlist)
- self.ui.explorerPlaylist.trackSelected.connect(self.newTrackSelected)
- self.ui.explorerPlaylist.trackDoubleClicked.connect(self.play_playlist)
- self.ui.btnPlaylistMoveToTop.clicked.connect(self.ui.explorerPlaylist.move_selected_to_top)
- self.ui.btnPlaylistMoveUp.clicked.connect(self.ui.explorerPlaylist.move_selected_up)
- self.ui.btnPlaylistMoveDown.clicked.connect(self.ui.explorerPlaylist.move_selected_down)
- self.ui.btnPlaylistMoveToBottom.clicked.connect(self.ui.explorerPlaylist.move_selected_to_bottom)
- self.ui.btnPlaylistRemove.clicked.connect(self.remove_from_playlist)
- # Page 5 - settings
- self.ui.musicFoldersAddButton.clicked.connect(self.ui.settingsMusicFoldersTable.add_music_folder)
- self.ui.musicFoldersRemoveButton.clicked.connect(self.ui.settingsMusicFoldersTable.remove_music_folder)
- self.ui.settingsMusicFoldersTable.populate()
- self.ui.tagsTableAddButton.clicked.connect(self.addTag)
- self.ui.tableTagsRemoveButton.clicked.connect(self.removeTag)
- self.ui.settingsTagsTableWidget.selectable = False
- self.ui.settingsTagsTableWidget.populate()
- self.ui.settingsTagsTableWidget.contentChanged.connect(self.ui.explorerTrackTagsTable.populate)
- # vlc frame
- self.ui.vlcFrame.trackStarted.connect(self.vlcTrackStarted)
- self.ui.vlcFrame.playlistEnded.connect(self.vlcPlaylistEnded)
- # Apply settings
- if self.settings:
- self.ui.vlcFrame.set_volume(int(self.settings['volume']))
- self.ui.vlcFrame.set_muted(self.settings['muted'])
- playlist_id = self.settings['playlist']
- if playlist_id is not None and playlist_id > 0:
- playlist_repo = SessionRepository()
- playlist = playlist_repo.get_by_id(playlist_id)
- self.loadPlaylist(playlist)
- def focus_changed(self, old, new):
- if old is self.ui.explorerTrackNotepad:
- self.saveTrackNotes()
- def menu_item_selected(self, e):
- self.ui.stack.setCurrentIndex(e.index)
- def indexation_started(self):
- self.ui.statusbar.setStatusTip("Indexation en cours...")
- def indexation_ended(self):
- self.ui.statusbar.setStatusTip("Indexation terminée.")
- def refresh_explorer_tree(self, tracks=None):
- if tracks:
- self.ui.explorerTable.update_tracks(tracks)
- else:
- self.ui.explorerTable.populate()
- self.ui.explorerLineSearch.clear()
- def newTrackSelected(self, track=None):
- sender = self.sender()
- self.selected_track = None
- self.ui.explorerTrackMetaStack.setCurrentIndex(0)
- self.ui.btnPlaySelectedTrack.setEnabled(False)
- self.ui.explorerAddToPlaylist.setEnabled(False)
- self.ui.btnPlaylistRemove.setEnabled(False)
- self.ui.explorerTrackNotepad.setText("")
- self.ui.frameMissingFileWarning.setVisible(False)
- if not track:
- return
- self.selected_track = track
- # track infos
- self.update_meta()
- self.ui.explorerTrackNotepad.setHtml(track.note)
- self.ui.explorerTrackTagsTable.populate(track)
- self.ui.explorerTrackMetaStack.setCurrentIndex(1)
- # Commands
- if self.selected_track.status == Track.STATUS_UNAVAILABLE:
- self.ui.frameMissingFileWarning.setVisible(True)
- else:
- self.ui.btnPlaySelectedTrack.setEnabled(True)
- if type(sender) is ExplorerTable:
- self.ui.explorerAddToPlaylist.setEnabled(True)
- elif type(sender) is PlaylistTable:
- self.ui.btnPlaylistRemove.setEnabled(True)
- else:
- raise RuntimeError("Unknown sender")
- self.ui.explorerTable.viewport().repaint()
- self.ui.explorerPlaylist.viewport().repaint()
- self.ui.sessionPlaylist.viewport().repaint()
- def update_meta(self):
- if self.selected_track:
- title, artist, album, track_num = self.selected_track.title, \
- self.selected_track.artist, \
- self.selected_track.album, \
- self.selected_track.track_num
- else:
- title, artist, album, track_num = "", "", "", ""
- self.ui.explorerLblTrackTitle.setText(title)
- self.ui.explorerLblTrackArtist.setText(artist)
- self.ui.explorerLblTrackAlbum.setText(album)
- self.ui.explorerLblTrackNumber.setText(
- str(track_num if track_num is not None else "")
- )
- if self.selected_track:
- # refresh tables
- self.refresh_explorer_tree([self.selected_track])
- if self.selected_playlist:
- self.ui.explorerPlaylist.update()
- self.ui.sessionPlaylist.update()
- def populate_explorer_filter_tags(self):
- tag_repo = TagRepository()
- self.ui.explorerFilterTags.clear()
- self.ui.explorerFilterTags.addItem("Toutes les étiquettes", 0)
- self.ui.explorerFilterTags.setCurrentIndex(0)
- for tag in tag_repo.get_all():
- self.ui.explorerFilterTags.addItem(tag.label, tag.id)
- def addTag(self):
- self.ui.settingsTagsTableWidget.add()
- def removeTag(self):
- if QMessageBox.question(self, "Confirmer", "Êtes-vous sûr(e) de vouloir supprimer cette étiquette?") != QMessageBox.Yes:
- return
- self.ui.settingsTagsTableWidget.removeSelected()
- def playSelectedTrack(self):
- if self.selected_track:
- self.play_track(self.selected_track)
- def play_track(self, track):
- if not Path(track.path).exists():
- return
- logger.info("Start playing: %s" % track)
- self.ui.vlcFrame.load_track(track)
- self.ui.vlcFrame.play()
- def showMetaEditor(self):
- if not self.selected_track:
- return
- r = DlgMetaEditor.edit(self, self.selected_track)
- if r:
- self.update_meta()
- def createOrEditPlaylist(self):
- r = DlgPlaylist.edit(self)
- def selectPlaylist(self):
- playlist = DlgSelectPlaylist.select(self)
- if playlist:
- self.loadPlaylist(playlist)
- def loadPlaylist(self, playlist):
- # home page
- self.ui.sessionPlaylist.setEnabled(True)
- self.ui.frameNotes.setEnabled(True)
- self.ui.sessionLblTitle.setText(playlist.name)
- self.ui.sessionPlaylist.populate(playlist)
- self.ui.frameNotes.set_playlist(playlist)
- # explorer page
- self.ui.explorerPlaylist.setEnabled(True)
- self.ui.explorerLblPlaylistTitle.setText(playlist.name)
- self.ui.explorerPlaylist.populate(playlist)
- self.selected_playlist = playlist
- def playlistItemDropped(self, event):
- if event.source() == ExplorerTable:
- self.add_to_playlist()
- def add_to_playlist(self):
- track = self.ui.explorerTable.selected_track()
- if track is None:
- return
- playlist = self.ui.explorerPlaylist.playlist
- if playlist is None:
- return
- track_repo = TrackRepository()
- track_repo.add_to_session(
- track.id,
- playlist.id
- )
- self.ui.explorerPlaylist.update()
- self.ui.sessionPlaylist.update()
- def remove_from_playlist(self):
- session_track = self.ui.explorerPlaylist.selected_session_track()
- if session_track is None:
- return
- session_track_repo = SessionTrackRepository()
- session_track_repo.delete(session_track, True)
- self.ui.explorerPlaylist.update()
- self.ui.sessionPlaylist.update()
- def play_playlist(self, track=None):
- if track.status == Track.STATUS_UNAVAILABLE:
- track = None
- playlist = self.selected_playlist
- track_repo = TrackRepository()
- tracks = track_repo.get_by_session_id(playlist.id)
- tracks = [t for t in tracks if t.status != Track.STATUS_UNAVAILABLE]
- if not tracks:
- return
- start_at = tracks.index(track) if track else 0
- logger.info("Start playing playlist: %s from index %s" % (playlist, start_at))
- self.ui.vlcFrame.load_playlist(playlist, tracks, start_at)
- self.ui.vlcFrame.play()
- def vlcTrackStarted(self, track):
- if self.selected_playlist:
- self.ui.explorerPlaylist.set_is_playing(track)
- self.ui.sessionPlaylist.set_is_playing(track)
- else:
- self.ui.explorerPlaylist.set_is_playing(None)
- self.ui.sessionPlaylist.set_is_playing(None)
- def vlcPlaylistEnded(self):
- self.ui.explorerPlaylist.set_is_playing(None)
- self.ui.sessionPlaylist.set_is_playing(None)
- def addTrackTags(self, tag_id):
- track_id = self.selected_track.id
- track_tag_repo = TrackTagRepository()
- tt = TrackTag(track_id=track_id, tag_id=tag_id)
- track_tag_repo.create(tt)
- track_tag_repo.commit()
- def removeTrackTags(self, tag_id):
- track_id = self.selected_track.id
- track_tag_repo = TrackTagRepository()
- track_tag_repo.query().filter(TrackTag.track_id == track_id).filter(TrackTag.tag_id == tag_id).delete()
- track_tag_repo.commit()
- def saveTrackNotes(self):
- if not self.selected_track:
- return
- note = self.ui.explorerTrackNotepad.toHtml()
- track_repo = TrackRepository()
- self.selected_track.note = note
- track_repo.commit()
- def explorerFiltersChanged(self):
- searchText = self.ui.explorerLineSearch.text()
- tag_id = int(self.ui.explorerFilterTags.currentData())
- self.ui.explorerTable.filterBy(tag_id, searchText)
- def filesIndexed(self, tracks):
- self.statusBar().showMessage(f"{len(tracks)} fichiers indexés", 3000)
- self.refresh_explorer_tree(tracks)
- def musicFolderStatusChanged(self, music_folder_id):
- self.ui.settingsMusicFoldersTable.populate()
- def currentSettings(self):
- volume = self.ui.vlcFrame.volume
- playlist_id = self.selected_playlist.id if self.selected_playlist else None
- muted = self.ui.vlcFrame.is_muted
- return {
- "playlist": playlist_id,
- "volume": volume,
- "muted": muted,
- }
- def __del__(self):
- if self.qdb.isOpen():
- self.qdb.close()
|