class VideoPlayer(QWidget): def __init__(self, aPath, parent=None): super(VideoPlayer, self).__init__(parent) self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAcceptDrops(True) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) self.mediaPlayer.setVolume(80) self.videoWidget = QVideoWidget(self) self.videoWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.videoWidget.setMinimumSize(QSize(640, 360)) self.lbl = QLineEdit('00:00:00') self.lbl.setReadOnly(True) self.lbl.setFixedWidth(70) self.lbl.setUpdatesEnabled(True) self.lbl.setStyleSheet(stylesheet(self)) self.elbl = QLineEdit('00:00:00') self.elbl.setReadOnly(True) self.elbl.setFixedWidth(70) self.elbl.setUpdatesEnabled(True) self.elbl.setStyleSheet(stylesheet(self)) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedWidth(32) self.playButton.setStyleSheet("background-color: black") self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setStyleSheet(stylesheet(self)) self.positionSlider.setRange(0, 100) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.sliderMoved.connect(self.handleLabel) self.positionSlider.setSingleStep(2) self.positionSlider.setPageStep(20) self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) self.clip = QApplication.clipboard() self.process = QProcess(self) self.process.readyRead.connect(self.dataReady) self.process.finished.connect(self.playFromURL) self.myurl = "" # channel list self.channelList = QListView(self) self.channelList.setMinimumSize(QSize(150, 0)) self.channelList.setMaximumSize(QSize(150, 4000)) self.channelList.setFrameShape(QFrame.Box) self.channelList.setObjectName("channelList") self.channelList.setStyleSheet("background-color: black; color: #585858;") self.channelList.setFocus() # for adding items to list must create a model self.model = QStandardItemModel() self.channelList.setModel(self.model) self.controlLayout = QHBoxLayout() self.controlLayout.setContentsMargins(5, 0, 5, 0) self.controlLayout.addWidget(self.playButton) self.controlLayout.addWidget(self.lbl) self.controlLayout.addWidget(self.positionSlider) self.controlLayout.addWidget(self.elbl) self.mainLayout = QHBoxLayout() # contains video and cotrol widgets to the left side self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.videoWidget) self.layout.addLayout(self.controlLayout) # adds channels list to the right self.mainLayout.addLayout(self.layout) self.mainLayout.addWidget(self.channelList) self.setLayout(self.mainLayout) self.myinfo = "©2020\nTIVOpy v1.0" self.widescreen = True #### shortcuts #### self.shortcut = QShortcut(QKeySequence("q"), self) self.shortcut.activated.connect(self.handleQuit) self.shortcut = QShortcut(QKeySequence("u"), self) self.shortcut.activated.connect(self.playFromURL) self.shortcut = QShortcut(QKeySequence(Qt.Key_Space), self) self.shortcut.activated.connect(self.play) self.shortcut = QShortcut(QKeySequence(Qt.Key_F), self) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) self.shortcut.activated.connect(self.exitFullscreen) self.shortcut.activated.connect(self.handleFullscreen) self.shortcut = QShortcut(QKeySequence("i"), self) self.shortcut.activated.connect(self.handleInfo) self.shortcut = QShortcut(QKeySequence("s"), self) self.shortcut.activated.connect(self.toggleSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) self.shortcut.activated.connect(self.forwardSlider) self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) self.shortcut.activated.connect(self.backSlider) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.positionChanged.connect(self.handleLabel) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.populateChannelList() self.selectChannel() self.initialPlay() def playFromURL(self): self.mediaPlayer.pause() self.myurl = self.clip.text() self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() print(self.myurl) def dataReady(self): self.myurl = str(self.process.readAll(), encoding='utf8').rstrip() ### self.myurl = self.myurl.partition("\n")[0] print(self.myurl) self.clip.setText(self.myurl) self.playFromURL() def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPause)) else: self.playButton.setIcon( self.style().standardIcon(QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) mtime = QTime(0, 0, 0, 0) mtime = mtime.addMSecs(self.mediaPlayer.duration()) self.elbl.setText(mtime.toString()) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) print("Error: ", self.mediaPlayer.errorString()) def handleQuit(self): self.mediaPlayer.stop() print("Goodbye ...") app.quit() def contextMenuRequested(self, point): menu = QMenu() actionURL = menu.addAction(QIcon.fromTheme("browser"), "URL from Clipboard (u)") menu.addSeparator() actionToggle = menu.addAction(QIcon.fromTheme("next"), "Show / Hide Channels (s)") actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"), "Fullscreen (f)") menu.addSeparator() actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "About (i)") menu.addSeparator() actionQuit = menu.addAction(QIcon.fromTheme("application-exit"), "Exit (q)") actionQuit.triggered.connect(self.handleQuit) actionFull.triggered.connect(self.handleFullscreen) actionInfo.triggered.connect(self.handleInfo) actionToggle.triggered.connect(self.toggleSlider) actionURL.triggered.connect(self.playFromURL) menu.exec_(self.mapToGlobal(point)) def wheelEvent(self, event): mscale = event.angleDelta().y() / 13 self.mediaPlayer.setVolume(self.mediaPlayer.volume() + mscale) print("Volume: " + str(self.mediaPlayer.volume())) def mouseDoubleClickEvent(self, event): if event.buttons() == Qt.LeftButton: self.handleFullscreen() def handleFullscreen(self): if self.windowState() and Qt.WindowFullScreen: self.showNormal() else: self.showFullScreen() def exitFullscreen(self): self.showNormal() def handleInfo(self): QMessageBox.about(self, "About", self.myinfo) def toggleSlider(self): if self.positionSlider.isVisible(): self.hideSlider() else: self.showSlider() def hideSlider(self): self.channelList.hide() self.playButton.hide() self.lbl.hide() self.positionSlider.hide() self.elbl.hide() def showSlider(self): self.channelList.show() self.playButton.show() self.lbl.show() self.positionSlider.show() self.elbl.show() self.channelList.setFocus() def forwardSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60) def backSlider(self): self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60) def volumeUp(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) print("Volume: " + str(self.mediaPlayer.volume())) def volumeDown(self): self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) print("Volume: " + str(self.mediaPlayer.volume())) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() elif event.mimeData().hasText(): event.accept() else: event.ignore() def dropEvent(self, event): print("drop") if event.mimeData().hasUrls(): url = event.mimeData().urls()[0].toString() print("url = ", url) self.mediaPlayer.stop() self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) self.playButton.setEnabled(True) self.mediaPlayer.play() elif event.mimeData().hasText(): mydrop = event.mimeData().text() print("generic url = ", mydrop) self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) self.playButton.setEnabled(True) self.mediaPlayer.play() self.hideSlider() def loadFilm(self, f): self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) self.playButton.setEnabled(True) self.mediaPlayer.play() def populateChannelList(self): # file must be in same directory as the script FILEPATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "canaletv.txt") # lines from file with "channel name" -- "link" channelArray = [] # split file by line and adding it to the array with open(FILEPATH) as f: for line in f: channelArray.append(line.rstrip()) # dictionary with key = channel name and value = link self.channelDict = dict(ch.split(" -- ") for ch in channelArray) for channel in self.channelDict.keys(): item = QStandardItem(channel) self.model.appendRow(item) def selectedItemBehavior(self, index): # gets the link for the selected channel and plays it itms = self.channelList.selectedIndexes() for it in itms: channel = it.data() link = self.channelDict[channel] self.mediaPlayer.setMedia(QMediaContent(QUrl(link))) self.play() def selectChannel(self): # selecting channel from sidebar calls selectedItemBehavior self.selModel = self.channelList.selectionModel() self.selModel.selectionChanged.connect(self.selectedItemBehavior) def initialPlay(self): # play somenting when app opens self.mediaPlayer.setMedia(QMediaContent(QUrl("https://vid.hls.protv.ro/proxhdn/proxhd_3_34/index.m3u8?1"))) self.play() def handleLabel(self): self.lbl.clear() mtime = QTime(0, 0, 0, 0) self.time = mtime.addMSecs(self.mediaPlayer.position()) self.lbl.setText(self.time.toString())
class AppWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setGeometry(100, 100, 550, 400) self.setUpMenu() self.setUpLayout() self.checkBoxConnect.stateChanged.connect(self.connect_disconnect) self.addButton.clicked.connect(self.add_contact) self.deleteButton.clicked.connect(self.delete_contact) self.sendButton.clicked.connect(self.send_message) self.contactsList.clicked.connect(self.select_contact) # self.messageField.drop.connect(self.add_file_to_message) # model -controller - view self.contact_list_model = StandardItemModelContacts(self) self.messages_list_model = StandardItemModelMessages(self) self.model = ClientModel(self.contact_list_model, self.messages_list_model) self.contactsList.setModel(self.contact_list_model) self.messagesList.setModel(self.messages_list_model) self.controller = ClientController(self.model) # signal-slot self.controller.auth_recieved.connect(self.authentification_recieved) self.controller.gotPersonal.connect(self.new_personal_message) # not connected self.connected = False # nobody selected self.currently_selected = '' def setUpMenu(self): fileMenu = self.menuBar().addMenu('File') quitAct = QAction('Quit', self) quitAct.triggered.connect(self.doQuit) fileMenu.addAction(quitAct) sendMenu = self.menuBar().addMenu('Send') sendFile = QAction('Send File', self) sendFile.triggered.connect(self.doSendFile) sendMenu.addAction(sendFile) def setUpLayout(self): hBoxLayout = QHBoxLayout() mainFrame = QFrame() mainFrame.setLayout(hBoxLayout) self.contact = QLineEdit() self.contact.setFont(QFont('Calibri', 14)) self.contact.setPlaceholderText('Add Contact Here') self.contact.setMinimumHeight(30) self.contact.setMaximumHeight(30) self.addButton = QPushButton('+') self.addButton.setMinimumHeight(30) self.addButton.setMaximumHeight(30) self.addButton.setMinimumWidth(30) self.addButton.setMaximumWidth(30) self.deleteButton = QPushButton('-') self.deleteButton.setMinimumHeight(30) self.deleteButton.setMaximumHeight(30) self.deleteButton.setMinimumWidth(30) self.deleteButton.setMaximumWidth(30) self.contactsList = QListView() self.contactsList.setFrameShape(QFrame.Box) spacer = QFrame() spacer.setMaximumWidth(5) self.nameLabel = QLabel('Username') self.nameLabel.setMinimumHeight(30) self.nameLabel.setMaximumHeight(30) self.nameLabel.setFont(QFont('Calibri', 14)) self.checkBoxConnect = QCheckBox() self.checkBoxConnect.setText('Connect') self.checkBoxConnect.setChecked(False) self.checkBoxConnect.setMaximumHeight(30) self.checkBoxConnect.setMinimumHeight(30) self.checkBoxConnect.setMaximumWidth(70) self.checkBoxConnect.setMinimumWidth(70) self.messagesList = QListView() self.messagesList.setIconSize(QSize(30, 30)) self.messagesList.setFrameShape(QFrame.Box) self.messageField = MessageField() self.messageField.setMinimumHeight(50) self.messageField.setMaximumHeight(50) self.sendButton = QPushButton() self.sendButton.setText('>>') self.sendButton.setMinimumHeight(50) self.sendButton.setMaximumHeight(50) self.sendButton.setMinimumWidth(50) self.sendButton.setMaximumWidth(50) contBox = QGridLayout() contBox.addWidget(self.contact, 0, 0) contBox.addWidget(self.addButton, 0, 1) contBox.addWidget(self.deleteButton, 0, 2) contBox.addWidget(self.contactsList, 1, 0, 2, 3) contBox.addWidget(spacer, 0, 3, 3, 1) contBox.addWidget(self.nameLabel, 0, 4) contBox.addWidget(self.checkBoxConnect, 0, 5, 1, 2) contBox.addWidget(self.messagesList, 1, 4, 1, 3) contBox.addWidget(self.messageField, 2, 4, 1, 2) contBox.addWidget(self.sendButton, 2, 6) contBox.setColumnStretch(0, 3) contBox.setColumnStretch(4, 6) groupBoxCont = QFrame() groupBoxCont.setLayout(contBox) self.setCentralWidget(groupBoxCont) def doQuit(self): self.close() def doSendFile(self): filename = QFileDialog.getOpenFileName(self, 'Open file', '/home')[0] self.messageField.file = filename self.messageField.appendPlainText(filename) def connect_disconnect(self): self.checkBoxConnect.setEnabled(False) if self.checkBoxConnect.isChecked(): self.authentification() else: self.user_disconnect() self.checkBoxConnect.setEnabled(True) # Log in dialog def authentification(self): #read config file d = conf.read_conf() #show Authorization dialog auth_dialog = AuthDialog(self.model, d['username'], d['hostname'], d['port'], parent=self) auth_dialog.accepted.connect(self.auth_dialog_accepted) auth_dialog.rejected.connect(self.auth_dialog_rejected) auth_dialog.show() def auth_dialog_accepted(self): self.checkBoxConnect.setEnabled(True) self.controller.run_client() def auth_dialog_rejected(self): self.checkBoxConnect.setChecked(False) self.checkBoxConnect.setEnabled(True) @pyqtSlot(bool) def authentification_recieved(self, ok): if ok: self.connected = True self.checkBoxConnect.setText('Connected') self.nameLabel.setText('{}:'.format(self.model.username)) self.model.contactlist.clear() self.model.personal_messages = [] self.model.server_messages = [] self.model.sent_messages = [] self.model.open_db() self.controller.ask_contact_list() else: self.checkBoxConnect.setChecked(False) def user_disconnect(self): if self.connected: conf.save_conf(username=self.model.username, hostname=self.model.host, port=str(self.model.port)) self.model.clear_data() self.controller.user_disconnect() self.contact.setText('') self.nameLabel.setText('') self.checkBoxConnect.setText('Connect') self.connected = False self.currently_selected = '' @pyqtSlot(str) def get_contact_list(self): pass def add_contact(self): name = self.contact.text() if name != '': self.controller.add_contact(name) self.contact.setText('') def delete_contact(self): name = self.contact.text() if name != '': self.controller.delete_contact(name) self.contact.setText('') @pyqtSlot(QMimeData) def add_file_to_message(self, mime): self.messageField.setPlainText(mime.text()) def send_message(self): sel_list = self.contactsList.selectionModel().selectedIndexes() if len(sel_list) > 0: contact = self.model.contactlist.contacts[sel_list[0].row()] if self.messageField.file != '': self.controller.send_file(contact.name, self.messageField.file) self.messageField.file = '' else: self.controller.personal_message( contact.name, self.messageField.toPlainText()) self.messageField.clear() self.model.update_messages_for_contact(contact.name) else: pass @pyqtSlot(QModelIndex) def select_contact(self, modelindex): item = self.contact_list_model.data(modelindex, role=Qt.DisplayRole) contact_name = self.model.contactlist.contacts_name[modelindex.row()] self.contact.setText(contact_name) self.show_messages_for_contact(contact_name) self.contactsList.setCurrentIndex(modelindex) self.currently_selected = contact_name @pyqtSlot(str) def new_personal_message(self, sender): self.model.new_message_increase(sender, True) # sel_list = self.listViewContacts.selectionModel().selectedIndexes() if sender == self.currently_selected: self.show_messages_for_contact(self.currently_selected) @pyqtSlot(str) def show_messages_for_contact(self, contact_name): self.model.update_messages_for_contact(contact_name) self.model.new_message_increase(contact_name, False) self.messagesList.scrollToBottom()