def __init__(self, parent = None): QDialog.__init__(self, parent) self.previousChannel = None self.setupUI() if settings['firstRun']: self.initialSetup() self.mythDB = MythDB(settings['dbHost'], settings['dbUser'], settings['dbPassword']) self.mythControl = MythControl(self.mythDB) self.refreshShowList() self.setWindowTitle('Mythnimal') self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint) self.resize(1024, 600) self.mainMenu.focus() self.show()
class MainForm(QDialog): mythControl = None def __init__(self, parent = None): QDialog.__init__(self, parent) self.previousChannel = None self.setupUI() if settings['firstRun']: self.initialSetup() self.mythDB = MythDB(settings['dbHost'], settings['dbUser'], settings['dbPassword']) self.mythControl = MythControl(self.mythDB) self.refreshShowList() self.setWindowTitle('Mythnimal') self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint) self.resize(1024, 600) self.mainMenu.focus() self.show() def setupUI(self): self.tabLayout = QVBoxLayout(self) self.tabs = TabWidget() self.tabLayout.addWidget(self.tabs) self.mainMenuTab = self.tabs.createTab('Main Menu') self.mainMenuLayout = QVBoxLayout(self.mainMenuTab) self.mainMenu = MenuWidget() self.mainMenu.selected.connect(self.mainMenuSelected) self.mainMenu.exit.connect(self.close) self.mainMenu.add(SimpleMenuItem('Live TV')) self.mainMenu.add(SimpleMenuItem('Watch Recordings')) self.mainMenu.add(SimpleMenuItem('Settings')) self.mainMenuLayout.addWidget(self.mainMenu) self.createRecordingsTab() self.createSettingsTab() self.messageDialog = MessageDialog(self) def createRecordingsTab(self): self.recordingsTab = self.tabs.createTab('Recordings') self.columnLayout = QHBoxLayout(self.recordingsTab) self.showMenu = MenuWidget() self.showMenu.selected.connect(self.showSelected) self.showMenu.exit.connect(self.exitShowMenu) self.showMenu.selectionChanged.connect(self.filterByShow) self.columnLayout.addWidget(self.showMenu, 1) self.programMenu = MenuWidget() self.programMenu.selected.connect(self.programSelected) self.programMenu.exit.connect(self.exitProgramMenu) self.programMenu.selectionChanged.connect(self.displayProgramDetails) self.columnLayout.addWidget(self.programMenu, 1) self.programInfoLayout = QVBoxLayout() self.programThumbnail = self.wrappedLabel() self.programInfoLayout.addWidget(self.programThumbnail) self.programChannel = self.wrappedLabel() self.programInfoLayout.addWidget(self.programChannel) self.programTitle = self.wrappedLabel() self.programInfoLayout.addWidget(self.programTitle) self.programSubtitle = self.wrappedLabel() self.programInfoLayout.addWidget(self.programSubtitle) self.programStartTime = self.wrappedLabel() self.programInfoLayout.addWidget(self.programStartTime) self.programTime = self.wrappedLabel() self.programInfoLayout.addWidget(self.programTime) self.programDescription = self.wrappedLabel() self.programInfoLayout.addWidget(self.programDescription, 1) self.columnLayout.addLayout(self.programInfoLayout, 1) def createSettingsTab(self): self.settingsTab = self.tabs.createTab('Settings') self.settingsLayout = QVBoxLayout(self.settingsTab) self.settingsInputLayout = QHBoxLayout() self.settingsLayout.addLayout(self.settingsInputLayout) self.dbGroup = QGroupBox('DB/Filesystem') self.dbGroupLayout = QVBoxLayout() self.dbGroup.setLayout(self.dbGroupLayout) self.settingsInputLayout.addWidget(self.dbGroup) self.dbHostInput = QLineEdit() self.dbGroupLayout.addWidget(PairWidget('DB Hostname', self.dbHostInput)) self.dbUserInput = QLineEdit() self.dbGroupLayout.addWidget(PairWidget('DB Username', self.dbUserInput)) self.dbPasswordInput = QLineEdit() self.dbGroupLayout.addWidget(PairWidget('DB Password', self.dbPasswordInput)) self.fileDirInput = QLineEdit() self.dbGroupLayout.addWidget(PairWidget('Local Myth File Directory', self.fileDirInput)) self.miscGroup = QGroupBox('Miscellaneous') self.miscGroupLayout = QVBoxLayout() self.miscGroup.setLayout(self.miscGroupLayout) self.settingsInputLayout.addWidget(self.miscGroup) self.mpvInput = QLineEdit() self.miscGroupLayout.addWidget(PairWidget('MPV Command', self.mpvInput)) self.bufferTimeInput = QSpinBox() self.miscGroupLayout.addWidget(PairWidget('Buffer Time', self.bufferTimeInput)) self.settingsButtonLayout = QHBoxLayout() self.settingsLayout.addLayout(self.settingsButtonLayout) self.saveSettingsButton = QPushButton('Save') self.saveSettingsButton.clicked.connect(self.saveSettings) self.settingsButtonLayout.addWidget(self.saveSettingsButton) self.discardSettingsButton = QPushButton('Discard') self.discardSettingsButton.clicked.connect(self.discardSettings) self.settingsButtonLayout.addWidget(self.discardSettingsButton) def wrappedLabel(self): label = ScaledLabel() label.setWordWrap(True) return label def refreshShowList(self): self.showMenu.reset() newItem = SimpleMenuItem('[All]') newItem.id = '%' self.showMenu.add(newItem) self.showFilter = '%' shows = self.mythDB.showList() for i in shows: self.showMenu.add(SimpleMenuItem(i.title)) self.refreshProgramList() def refreshProgramList(self): self.programMenu.reset() programs = self.mythDB.programList(self.showFilter) for i in programs: self.programMenu.add(ProgramMenuItem(i)) def filterByShow(self, index): item = self.showMenu.selectedItem() self.showFilter = item.id self.refreshProgramList() def showSelected(self): self.programMenu.focus() self.displayProgramDetails() def exitProgramMenu(self): self.showMenu.focus() def exitShowMenu(self): self.tabs.setCurrentWidget(self.mainMenuTab) def displayProgramDetails(self): selected = self.programMenu.selectedItem() if selected is None: return details = self.mythDB.getProgram(selected.id) if details is None: self.refreshProgramList() return channel = self.mythDB.getChannel(details.chanid) filename = self.getFullPath(details.basename) filename += '.png' self.programThumbnail.setPixmap(QPixmap(filename).scaledToWidth(self.width() / 3)) if channel is not None: self.programChannel.setText(channel.channum + ' ' + channel.name) else: self.programChannel.setText('NA') self.programTitle.setText(details.title) self.programSubtitle.setText(details.subtitle) startTime = self.mythDB.fromUTC(details.starttime).strftime('%Y-%m-%d %I:%M %p') self.programStartTime.setText(startTime) self.programTime.setText(str(int((details.endtime - details.starttime).total_seconds() / 60)) + ' minutes') self.programDescription.setText(details.description) # Index is ignored def programSelected(self, index): self.startPlayer(self.programMenu.selectedItem().id, live = False) # TODO Needs to be reimplemented using MenuItem signals def mainMenuSelected(self, index): if index == 0: self.startLiveTV() elif index == 1: self.refreshShowList() self.tabs.setCurrentWidget(self.recordingsTab) elif index == 2: self.showSettingsTab() else: print 'Unimplemented main menu item selected' def populateSettings(self): self.dbHostInput.setText(settings['dbHost']) self.dbUserInput.setText(settings['dbUser']) self.dbPasswordInput.setText(settings['dbPassword']) self.fileDirInput.setText(settings['mythFileDir']) self.mpvInput.setText(settings['mpv']) self.bufferTimeInput.setValue(settings['bufferTime']) def showSettingsTab(self): self.populateSettings() self.tabs.setCurrentWidget(self.settingsTab) def saveSettings(self): settings['dbHost'] = str(self.dbHostInput.text()) settings['dbUser'] = str(self.dbUserInput.text()) settings['dbPassword'] = str(self.dbPasswordInput.text()) settings['mythFileDir'] = str(self.fileDirInput.text()) settings['mpv'] = str(self.mpvInput.text()) settings['bufferTime'] = self.bufferTimeInput.value() settings.save() if settings['firstRun']: self.initConfig.hide() self.tabs.setCurrentWidget(self.mainMenuTab) def discardSettings(self): self.tabs.setCurrentWidget(self.mainMenuTab) def closeEvent(self, event): settings.save() def resizeEvent(self, event): ScaledLabel.formHeight = event.size().height() def initialSetup(self): self.initConfig = QDialog() self.initConfig.setLayout(self.settingsLayout) self.populateSettings() self.initConfig.exec_() self.settingsTab.setLayout(self.settingsLayout) settings['firstRun'] = False def startLiveTV(self): self.messageDialog.showMessage('Buffering...') filename = self.mythControl.startLiveTV(qApp.processEvents) self.messageDialog.hide() self.startPlayer(filename, live = True) def changeChannel(self, channel): self.messageDialog.showMessage('Buffering...') self.previousChannel = self.mythControl.currentChannel filename = self.mythControl.changeChannel(channel, qApp.processEvents) # This is highly unlikely, but possible if filename is None: self.messageDialog.showMessageTimed('Channel change failed') self.messageDialog.hide() self.startPlayer(filename, live = True) def startPlayer(self, filename, live = False, startAtEnd = False): if filename is not None: playerX = self.x() + self.width() / 2 playerY = self.y() + self.height() / 2 self.player = Player(playerX, playerY, filename, self.mythDB, startAtEnd) self.player.finished.connect(self.activateWindow) if live: if self.previousChannel is None: self.previousChannel = self.mythControl.currentChannel self.player.previousChannel = self.previousChannel self.player.finished.connect(self.playerStopped) self.player.channelChange.connect(self.changeChannel) self.player.seekedPastStart.connect(self.playPreviousInChain) self.player.toggleRecording.connect(self.toggleRecording) self.player.currentChannel = self.mythControl.currentChannel def playerStopped(self, eof): if not eof: self.mythControl.stopLiveTV() self.activateWindow() else: # Go to the next live TV recording nextChain = None while nextChain == None: i, chain, currentChain = self.getCurrentChain() if i + 1 < len(chain): nextChain = chain[i + 1] else: print 'Waiting for next program to start' nextProgram = self.mythDB.getProgramByChain(nextChain) self.player.emitFinished = False self.player.end(eof = False) self.startPlayer(nextProgram.basename, live = True) def playPreviousInChain(self): i, chain, currentChain = self.getCurrentChain() if i > 0: nextProgram = self.mythDB.getProgramByChain(chain[i - 1]) self.player.emitFinished = False self.player.end(eof = False) self.startPlayer(nextProgram.basename, live = True, startAtEnd = True) def getCurrentChain(self): currentProgram = self.mythDB.getProgram(self.player.filename) chain = self.mythDB.getTVChain(self.mythControl.chain) for i, entry in enumerate(chain): if entry.chanid == currentProgram.chanid and entry.starttime == currentProgram.starttime: return i, chain, entry def toggleRecording(self): program = self.mythDB.getProgram(self.player.filename) self.mythControl.toggleRecording(program) if self.mythControl.recordCurrent: self.player.showMessage('Recording current program') else: self.player.showMessage('Not recording current program') def keyPressEvent(self, event): key = event.key() if self.programMenu.hasFocus(): if key == Qt.Key_M: self.showProgramMenu() def showProgramMenu(self): self.menuDialog = QDialog(self) menuLayout = QVBoxLayout(self.menuDialog) selected = self.mythDB.getProgram(self.programMenu.selectedItem().id) title = ScaledLabel(selected.title) menuLayout.addWidget(title) subtitle = ScaledLabel(selected.subtitle) menuLayout.addWidget(subtitle) programOptions = MenuWidget(self) programOptions.exit.connect(self.menuDialog.close) menuLayout.addWidget(programOptions) item = SimpleMenuItem('Delete') item.selected.connect(self.deleteSelected) programOptions.add(item) item = SimpleMenuItem('Delete and re-record') item.selected.connect(self.deleteAndRerecord) programOptions.add(item) self.menuDialog.exec_() self.menuDialog = None # For some reason not doing this results in segfaults def deleteSelected(self): self.deleteSelectedProgram(False) self.menuDialog.close() def deleteAndRerecord(self): self.deleteSelectedProgram(True) self.menuDialog.close() def deleteSelectedProgram(self, rerecord): selected = self.programMenu.selectedItem() selectedProgram = self.mythDB.getProgram(selected.id) self.mythControl.deleteProgram(selectedProgram, rerecord) self.programMenu.remove(selected) def getFullPath(self, basename): return os.path.join(settings['mythFileDir'], basename)