├── LICENSE ├── PhononVideoPlayer.py ├── QT5_VideoPlayer.py ├── QT6_VideoPlayer.py ├── README.md ├── TV_LiveStream.py └── VideoSchneiden.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Axel Schneider 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PhononVideoPlayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | from PyQt4 import QtGui, QtCore 4 | from PyQt4.QtGui import QSizePolicy, QMenu, QFileDialog, QAction, QCursor 5 | from PyQt4.phonon import Phonon 6 | from PyQt4.Qt import QSize, QString, Qt, QIcon, QMessageBox 7 | 8 | class Window(QtGui.QWidget): 9 | def __init__(self): 10 | QtGui.QWidget.__init__(self) 11 | self.media = Phonon.MediaObject(self) 12 | ### video widget #### 13 | self.video = Phonon.VideoWidget(self) 14 | self.video.setMinimumSize(320,200) 15 | self.myfilename = "" 16 | self.connect(QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Space), self), QtCore.SIGNAL('activated()'), self.handlePlayButton) 17 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("o"), self), QtCore.SIGNAL('activated()'), self.handleButton) 18 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("q"), self), QtCore.SIGNAL('activated()'), self.handleQuit) 19 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("f"), self), QtCore.SIGNAL('activated()'), self.handleFullscreen) 20 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("s"), self), QtCore.SIGNAL('activated()'), self.toggleSlider) 21 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("i"), self), QtCore.SIGNAL('activated()'), self.handleInfo) 22 | 23 | ### context menu #### 24 | self.setContextMenuPolicy(Qt.CustomContextMenu) 25 | self.customContextMenuRequested.connect(self.popup2) 26 | 27 | ### seek slider ### 28 | self.slider = Phonon.SeekSlider(self.media) 29 | self.slider.setStyleSheet(stylesheet(self)) 30 | isize = QSize(16,16) 31 | self.slider.setFixedHeight(8) 32 | self.slider.setIconSize(isize) 33 | self.slider.hide() 34 | 35 | ### connection position to label ### 36 | self.media.isSeekable() 37 | 38 | ### layout ### 39 | layout = QtGui.QGridLayout(self) 40 | layout.setMargin(1) 41 | layout.addWidget(self.video, 0, 0, 1, 1) 42 | layout.addWidget(self.slider, 1, 0, 1, 1) 43 | 44 | self.setStyleSheet(stylesheet(self)) 45 | 46 | #self.createPopup() 47 | 48 | def handleButton(self): 49 | if self.media.state() == Phonon.PlayingState: 50 | self.media.stop() 51 | self.loadFile() 52 | else: 53 | self.loadFile() 54 | 55 | def handlePlayButton(self): 56 | if self.media.state() == Phonon.PlayingState: 57 | self.media.pause() 58 | else: 59 | self.media.play() 60 | 61 | def handleQuit(self): 62 | app.quit() 63 | 64 | def handleFullscreen(self): 65 | if self.windowState() & QtCore.Qt.WindowFullScreen: 66 | self.showNormal() 67 | else: 68 | self.showFullScreen() 69 | 70 | def wheelEvent(self,event): 71 | mwidth = self.frameGeometry().width() 72 | mheight = self.frameGeometry().height() 73 | mleft = self.frameGeometry().left() 74 | mtop = self.frameGeometry().top() 75 | mscale = event.delta() / 5 76 | self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.778) 77 | 78 | def loadpopup(self, pos): 79 | lmenu = QMenu() 80 | loadAction = lmenu.addAction("Video laden") 81 | action = lmenu.exec_(self.mapToGlobal(pos)) 82 | if action == loadAction: 83 | self.handleButton() 84 | 85 | def popup2(self, pos): 86 | contextmenu = QMenu() 87 | contextmenu.addAction("Play / Pause (SPACE)", self.handlePlayButton) 88 | contextmenu.addSeparator() 89 | contextmenu.addAction("Load Video (o)", self.handleButton) 90 | contextmenu.addAction("Toggle Slider (s)", self.toggleSlider) 91 | contextmenu.addSeparator() 92 | contextmenu.addAction("Fullscreen (f)", self.handleFullscreen) 93 | contextmenu.addAction("Information (i)", self.handleInfo) 94 | contextmenu.addSeparator() 95 | contextmenu.addAction("Exit (q)", self.handleQuit) 96 | contextmenu.exec_(QCursor.pos()) 97 | 98 | def toggleSlider(self): 99 | if self.slider.isVisible(): 100 | self.slider.hide() 101 | else: 102 | self.slider.show() 103 | # self.slider.setGeometry(10, self.frameGeometry().height() - 10, self.frameGeometry().width() - 20, 10) 104 | self.slider.setFocus() 105 | 106 | def handleInfo(self): 107 | msg = QMessageBox() 108 | #msg.setFixedSize(500, 300) 109 | #msg.setGeometry(100,100, 400, 200) 110 | msg.setIcon(QMessageBox.Information) 111 | msg.setText("Axel Schneider") 112 | msg.setInformativeText(unicode("2016")) 113 | msg.setWindowTitle("Phonon Player") 114 | msg.setDetailedText("use Mouse Wheel for Zoom") 115 | msg.setStandardButtons(QMessageBox.Ok) 116 | 117 | retval = msg.exec_() 118 | print "value of pressed message box button:", retval 119 | 120 | def loadFile(self): 121 | path = QtGui.QFileDialog.getOpenFileName(self, ("Video laden"), 122 | '/Axel_1/Filme', 123 | "Videos (*.mp4 *.ts *.avi *.mpeg *.mpg *.mkv)") 124 | if path: 125 | #self.myfilename = unicode(path) 126 | self.media.setCurrentSource(Phonon.MediaSource(path)) 127 | self.video.setScaleMode(1) 128 | self.video.setAspectRatio(1) 129 | self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self) 130 | Phonon.createPath(self.media, self.audio) 131 | Phonon.createPath(self.media, self.video) 132 | self.slider.hide() 133 | self.media.play() 134 | 135 | def mouseMoveEvent(self, event): 136 | if event.buttons() == Qt.LeftButton: 137 | self.move(event.globalPos() \ 138 | - QtCore.QPoint(self.frameGeometry().width() / 2, \ 139 | self.frameGeometry().height() / 2)) 140 | event.accept() 141 | 142 | def stylesheet(self): 143 | return """ 144 | QWidget 145 | { 146 | background: black; 147 | } 148 | Phonon--SeekSlider > QSlider::groove:horizontal 149 | { 150 | background: black; 151 | border: 1px solid #565656; 152 | height: 6px; 153 | } 154 | 155 | Phonon--SeekSlider > QSlider::sub-page:horizontal 156 | { 157 | background: blue; 158 | border: 1px solid #565656; 159 | height: 3px; 160 | } 161 | """ 162 | 163 | if __name__ == '__main__': 164 | 165 | import sys 166 | app = QtGui.QApplication(sys.argv) 167 | app.setApplicationName('Phonon Player') 168 | window = Window() 169 | window.setGeometry(0,0,720,404) 170 | #window.setWindowFlags(Qt.WindowStaysOnTopHint) 171 | window.setWindowFlags(Qt.Widget | Qt.FramelessWindowHint) 172 | window.show() 173 | sys.exit(app.exec_()) 174 | -------------------------------------------------------------------------------- /QT5_VideoPlayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from PyQt5.QtGui import QKeySequence, QIcon 5 | from PyQt5.QtCore import QDir, Qt, QUrl, QPoint, QTime, QProcess 6 | from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer 7 | from PyQt5.QtMultimediaWidgets import QVideoWidget 8 | from PyQt5.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLineEdit, 9 | QPushButton, QSlider, QMessageBox, QStyle, QVBoxLayout, 10 | QWidget, QShortcut, QMenu) 11 | import sys 12 | import subprocess 13 | #QT_DEBUG_PLUGINS 14 | 15 | class VideoPlayer(QWidget): 16 | 17 | def __init__(self, aPath, parent=None): 18 | super(VideoPlayer, self).__init__(parent) 19 | 20 | self.setAttribute( Qt.WA_NoSystemBackground, True ) 21 | self.setAcceptDrops(True) 22 | self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback) 23 | self.mediaPlayer.mediaStatusChanged.connect(self.printMediaData) 24 | self.mediaPlayer.setVolume(80) 25 | self.videoWidget = QVideoWidget(self) 26 | 27 | self.lbl = QLineEdit('00:00:00') 28 | self.lbl.setReadOnly(True) 29 | self.lbl.setFixedWidth(70) 30 | self.lbl.setUpdatesEnabled(True) 31 | self.lbl.setStyleSheet(stylesheet(self)) 32 | self.lbl.selectionChanged.connect(lambda: self.lbl.setSelection(0, 0)) 33 | 34 | self.elbl = QLineEdit('00:00:00') 35 | self.elbl.setReadOnly(True) 36 | self.elbl.setFixedWidth(70) 37 | self.elbl.setUpdatesEnabled(True) 38 | self.elbl.setStyleSheet(stylesheet(self)) 39 | self.elbl.selectionChanged.connect(lambda: self.elbl.setSelection(0, 0)) 40 | 41 | self.playButton = QPushButton() 42 | self.playButton.setEnabled(False) 43 | self.playButton.setFixedWidth(32) 44 | self.playButton.setStyleSheet("background-color: black") 45 | self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) 46 | self.playButton.clicked.connect(self.play) 47 | 48 | self.positionSlider = QSlider(Qt.Horizontal, self) 49 | self.positionSlider.setStyleSheet (stylesheet(self)) 50 | self.positionSlider.setRange(0, 100) 51 | self.positionSlider.sliderMoved.connect(self.setPosition) 52 | self.positionSlider.setSingleStep(2) 53 | self.positionSlider.setPageStep(20) 54 | self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True) 55 | 56 | self.clip = QApplication.clipboard() 57 | self.process = QProcess(self) 58 | self.process.readyRead.connect(self.dataReady) 59 | self.process.finished.connect(self.playFromURL) 60 | 61 | self.myurl = "" 62 | 63 | controlLayout = QHBoxLayout() 64 | controlLayout.setContentsMargins(5, 0, 5, 0) 65 | controlLayout.addWidget(self.playButton) 66 | controlLayout.addWidget(self.lbl) 67 | controlLayout.addWidget(self.positionSlider) 68 | controlLayout.addWidget(self.elbl) 69 | 70 | layout = QVBoxLayout() 71 | layout.setContentsMargins(0, 0, 0, 0) 72 | layout.addWidget(self.videoWidget) 73 | layout.addLayout(controlLayout) 74 | 75 | self.setLayout(layout) 76 | 77 | self.myinfo = "©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" + \ 78 | "LEFT = < 1 Minute\nRIGHT = > 1 Minute\n" + \ 79 | "SHIFT+LEFT = < 10 Minutes\nSHIFT+RIGHT = > 10 Minutes" 80 | 81 | self.widescreen = True 82 | 83 | #### shortcuts #### 84 | self.shortcut = QShortcut(QKeySequence("q"), self) 85 | self.shortcut.activated.connect(self.handleQuit) 86 | self.shortcut = QShortcut(QKeySequence("u"), self) 87 | self.shortcut.activated.connect(self.playFromURL) 88 | 89 | self.shortcut = QShortcut(QKeySequence("y"), self) 90 | self.shortcut.activated.connect(self.getYTUrl) 91 | 92 | self.shortcut = QShortcut(QKeySequence("o"), self) 93 | self.shortcut.activated.connect(self.openFile) 94 | self.shortcut = QShortcut(QKeySequence(" "), self) 95 | self.shortcut.activated.connect(self.play) 96 | self.shortcut = QShortcut(QKeySequence("f"), self) 97 | self.shortcut.activated.connect(self.handleFullscreen) 98 | self.shortcut = QShortcut(QKeySequence("i"), self) 99 | self.shortcut.activated.connect(self.handleInfo) 100 | self.shortcut = QShortcut(QKeySequence("s"), self) 101 | self.shortcut.activated.connect(self.toggleSlider) 102 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self) 103 | self.shortcut.activated.connect(self.forwardSlider) 104 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self) 105 | self.shortcut.activated.connect(self.backSlider) 106 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) 107 | self.shortcut.activated.connect(self.volumeUp) 108 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) 109 | self.shortcut.activated.connect(self.volumeDown) 110 | self.shortcut = QShortcut(QKeySequence(Qt.ShiftModifier + Qt.Key_Right) , self) 111 | self.shortcut.activated.connect(self.forwardSlider10) 112 | self.shortcut = QShortcut(QKeySequence(Qt.ShiftModifier + Qt.Key_Left) , self) 113 | self.shortcut.activated.connect(self.backSlider10) 114 | 115 | self.mediaPlayer.setVideoOutput(self.videoWidget) 116 | self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) 117 | self.mediaPlayer.positionChanged.connect(self.positionChanged) 118 | self.mediaPlayer.durationChanged.connect(self.durationChanged) 119 | self.mediaPlayer.error.connect(self.handleError) 120 | 121 | print("QT5 Player started") 122 | print("press 'o' to open file (see context menu for more)") 123 | self.suspend_screensaver() 124 | 125 | def mouseDoubleClickEvent(self, event): 126 | self.handleFullscreen() 127 | 128 | def playFromURL(self): 129 | self.mediaPlayer.pause() 130 | self.myurl = self.clip.text() 131 | self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl))) 132 | self.playButton.setEnabled(True) 133 | self.mediaPlayer.play() 134 | self.hideSlider() 135 | print(self.myurl) 136 | 137 | def getYTUrl(self): 138 | cmd = "youtube-dl -g -f best " + self.clip.text() 139 | print("grabbing YouTube URL") 140 | self.process.start(cmd) 141 | 142 | def dataReady(self): 143 | self.myurl = str(self.process.readAll(), encoding = 'utf8').rstrip() ### 144 | self.myurl = self.myurl.partition("\n")[0] 145 | print(self.myurl) 146 | self.clip.setText(self.myurl) 147 | self.playFromURL() 148 | 149 | def suspend_screensaver(self): 150 | 'suspend linux screensaver' 151 | proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled false', shell=True) 152 | proc.wait() 153 | 154 | def resume_screensaver(self): 155 | 'resume linux screensaver' 156 | proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled true', shell=True) 157 | proc.wait() 158 | 159 | def openFile(self): 160 | fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", 161 | QDir.homePath() + "/Videos", "Media (*.webm *.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v *.3gp *.mp3 *.m4a *.wav *.ogg *.flac *.m3u *.m3u8)") 162 | 163 | if fileName != '': 164 | self.loadFilm(fileName) 165 | print("File loaded") 166 | 167 | def play(self): 168 | if self.mediaPlayer.state() == QMediaPlayer.PlayingState: 169 | self.mediaPlayer.pause() 170 | else: 171 | self.mediaPlayer.play() 172 | 173 | def mediaStateChanged(self, state): 174 | if self.mediaPlayer.state() == QMediaPlayer.PlayingState: 175 | self.playButton.setIcon( 176 | self.style().standardIcon(QStyle.SP_MediaPause)) 177 | else: 178 | self.playButton.setIcon( 179 | self.style().standardIcon(QStyle.SP_MediaPlay)) 180 | 181 | def positionChanged(self, position): 182 | self.positionSlider.setValue(position) 183 | mtime = QTime(0,0,0,0) 184 | mtime = mtime.addMSecs(self.mediaPlayer.position()) 185 | self.lbl.setText(mtime.toString()) 186 | 187 | def durationChanged(self, duration): 188 | self.positionSlider.setRange(0, duration) 189 | mtime = QTime(0,0,0,0) 190 | mtime = mtime.addMSecs(self.mediaPlayer.duration()) 191 | self.elbl.setText(mtime.toString()) 192 | 193 | def setPosition(self, position): 194 | self.mediaPlayer.setPosition(position) 195 | 196 | def handleError(self): 197 | self.playButton.setEnabled(False) 198 | print("Error: ", self.mediaPlayer.errorString()) 199 | 200 | def handleQuit(self): 201 | self.mediaPlayer.stop() 202 | self.resume_screensaver() 203 | print("Goodbye ...") 204 | app.quit() 205 | 206 | def contextMenuRequested(self,point): 207 | menu = QMenu() 208 | actionFile = menu.addAction(QIcon.fromTheme("video-x-generic"),"open File (o)") 209 | actionclipboard = menu.addSeparator() 210 | actionURL = menu.addAction(QIcon.fromTheme("browser"),"URL from Clipboard (u)") 211 | actionclipboard = menu.addSeparator() 212 | actionYTurl = menu.addAction(QIcon.fromTheme("youtube"), "URL from YouTube (y)") 213 | actionclipboard = menu.addSeparator() 214 | actionToggle = menu.addAction(QIcon.fromTheme("next"),"show / hide Slider (s)") 215 | actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"),"Fullscreen (f)") 216 | action169 = menu.addAction(QIcon.fromTheme("tv-symbolic"),"16 : 9") 217 | action43 = menu.addAction(QIcon.fromTheme("tv-symbolic"),"4 : 3") 218 | actionSep = menu.addSeparator() 219 | actionInfo = menu.addAction(QIcon.fromTheme("help-about"),"Info (i)") 220 | action5 = menu.addSeparator() 221 | actionQuit = menu.addAction(QIcon.fromTheme("application-exit"),"Exit (q)") 222 | 223 | actionFile.triggered.connect(self.openFile) 224 | actionQuit.triggered.connect(self.handleQuit) 225 | actionFull.triggered.connect(self.handleFullscreen) 226 | actionInfo.triggered.connect(self.handleInfo) 227 | actionToggle.triggered.connect(self.toggleSlider) 228 | actionURL.triggered.connect(self.playFromURL) 229 | actionYTurl.triggered.connect(self.getYTUrl) 230 | action169.triggered.connect(self.screen169) 231 | action43.triggered.connect(self.screen43) 232 | menu.exec_(self.mapToGlobal(point)) 233 | 234 | def wheelEvent(self,event): 235 | mwidth = self.frameGeometry().width() 236 | mleft = self.frameGeometry().left() 237 | mtop = self.frameGeometry().top() 238 | mscale = event.angleDelta().y() / 5 239 | if self.widescreen == True: 240 | self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.778)) 241 | else: 242 | self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.33)) 243 | 244 | 245 | def screen169(self): 246 | self.widescreen = True 247 | mwidth = self.frameGeometry().width() 248 | mleft = self.frameGeometry().left() 249 | mtop = self.frameGeometry().top() 250 | mratio = 1.778 251 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) 252 | 253 | def screen43(self): 254 | self.widescreen = False 255 | mwidth = self.frameGeometry().width() 256 | mleft = self.frameGeometry().left() 257 | mtop = self.frameGeometry().top() 258 | mratio = 1.33 259 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) 260 | 261 | def handleFullscreen(self): 262 | if self.windowState() & Qt.WindowFullScreen: 263 | QApplication.setOverrideCursor(Qt.ArrowCursor) 264 | self.showNormal() 265 | print("no Fullscreen") 266 | else: 267 | self.showFullScreen() 268 | QApplication.setOverrideCursor(Qt.BlankCursor) 269 | print("Fullscreen entered") 270 | 271 | def handleInfo(self): 272 | msg = QMessageBox.about(self, "QT5 Player", self.myinfo) 273 | 274 | def toggleSlider(self): 275 | if self.positionSlider.isVisible(): 276 | self.hideSlider() 277 | else: 278 | self.showSlider() 279 | 280 | def hideSlider(self): 281 | self.playButton.hide() 282 | self.lbl.hide() 283 | self.positionSlider.hide() 284 | self.elbl.hide() 285 | mwidth = self.frameGeometry().width() 286 | mleft = self.frameGeometry().left() 287 | mtop = self.frameGeometry().top() 288 | if self.widescreen == True: 289 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.778)) 290 | else: 291 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) 292 | 293 | def showSlider(self): 294 | self.playButton.show() 295 | self.lbl.show() 296 | self.positionSlider.show() 297 | self.elbl.show() 298 | mwidth = self.frameGeometry().width() 299 | mleft = self.frameGeometry().left() 300 | mtop = self.frameGeometry().top() 301 | if self.widescreen == True: 302 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.55)) 303 | else: 304 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) 305 | 306 | def forwardSlider(self): 307 | self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000*60) 308 | 309 | def forwardSlider10(self): 310 | self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000*60) 311 | 312 | def backSlider(self): 313 | self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000*60) 314 | 315 | def backSlider10(self): 316 | self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000*60) 317 | 318 | def volumeUp(self): 319 | self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) 320 | print("Volume: " + str(self.mediaPlayer.volume())) 321 | 322 | def volumeDown(self): 323 | self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) 324 | print("Volume: " + str(self.mediaPlayer.volume())) 325 | 326 | def mousePressEvent(self, evt): 327 | self.oldPos = evt.globalPos() 328 | 329 | def mouseMoveEvent(self, evt): 330 | delta = QPoint(evt.globalPos() - self.oldPos) 331 | self.move(self.x() + delta.x(), self.y() + delta.y()) 332 | self.oldPos = evt.globalPos() 333 | 334 | 335 | def dragEnterEvent(self, event): 336 | if event.mimeData().hasUrls(): 337 | event.accept() 338 | elif event.mimeData().hasText(): 339 | event.accept() 340 | else: 341 | event.ignore() 342 | 343 | def dropEvent(self, event): 344 | print("drop") 345 | if event.mimeData().hasUrls(): 346 | url = event.mimeData().urls()[0].toString() 347 | print("url = ", url) 348 | self.mediaPlayer.stop() 349 | self.mediaPlayer.setMedia(QMediaContent(QUrl(url))) 350 | self.playButton.setEnabled(True) 351 | self.mediaPlayer.play() 352 | elif event.mimeData().hasText(): 353 | mydrop = event.mimeData().text() 354 | ### YouTube url 355 | if "youtube" in mydrop: 356 | print("is YouTube", mydrop) 357 | self.clip.setText(mydrop) 358 | self.getYTUrl() 359 | else: 360 | ### normal url 361 | print("generic url = ", mydrop) 362 | self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop))) 363 | self.playButton.setEnabled(True) 364 | self.mediaPlayer.play() 365 | self.hideSlider() 366 | 367 | def loadFilm(self, f): 368 | self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f))) 369 | self.playButton.setEnabled(True) 370 | self.mediaPlayer.play() 371 | 372 | def printMediaData(self): 373 | if self.mediaPlayer.mediaStatus() == 6: 374 | if self.mediaPlayer.isMetaDataAvailable(): 375 | res = str(self.mediaPlayer.metaData("Resolution")).partition("PyQt5.QtCore.QSize(")[2].replace(", ", "x").replace(")", "") 376 | print("%s%s" % ("Video Resolution = ",res)) 377 | if int(res.partition("x")[0]) / int(res.partition("x")[2]) < 1.5: 378 | self.screen43() 379 | else: 380 | self.screen169() 381 | else: 382 | print("no metaData available") 383 | 384 | def openFileAtStart(self, filelist): 385 | matching = [s for s in filelist if ".myformat" in s] 386 | if len(matching) > 0: 387 | self.loadFilm(matching) 388 | 389 | ##################### end ################################## 390 | 391 | def stylesheet(self): 392 | return """ 393 | 394 | QSlider::handle:horizontal 395 | { 396 | background: transparent; 397 | width: 8px; 398 | } 399 | 400 | QSlider::groove:horizontal { 401 | border: 1px solid #444444; 402 | height: 8px; 403 | background: qlineargradient(y1: 0, y2: 1, 404 | stop: 0 #2e3436, stop: 1.0 #000000); 405 | } 406 | 407 | QSlider::sub-page:horizontal { 408 | background: qlineargradient( y1: 0, y2: 1, 409 | stop: 0 #729fcf, stop: 1 #2a82da); 410 | border: 1px solid #777; 411 | height: 8px; 412 | } 413 | 414 | QSlider::handle:horizontal:hover { 415 | background: #2a82da; 416 | height: 8px; 417 | width: 18px; 418 | border: 1px solid #2e3436; 419 | } 420 | 421 | QSlider::sub-page:horizontal:disabled { 422 | background: #bbbbbb; 423 | border-color: #999999; 424 | } 425 | 426 | QSlider::add-page:horizontal:disabled { 427 | background: #2a82da; 428 | border-color: #999999; 429 | } 430 | 431 | QSlider::handle:horizontal:disabled { 432 | background: #2a82da; 433 | } 434 | 435 | QLineEdit 436 | { 437 | background: black; 438 | color: #585858; 439 | border: 0px solid #076100; 440 | font-size: 8pt; 441 | font-weight: bold; 442 | } 443 | """ 444 | 445 | if __name__ == '__main__': 446 | 447 | app = QApplication(sys.argv) 448 | player = VideoPlayer('') 449 | player.setAcceptDrops(True) 450 | player.setWindowTitle("QT5 Player") 451 | player.setWindowIcon(QIcon.fromTheme("multimedia-video-player")) 452 | player.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) 453 | player.setGeometry(100, 300, 600, 380) 454 | player.setContextMenuPolicy(Qt.CustomContextMenu); 455 | player.customContextMenuRequested[QPoint].connect(player.contextMenuRequested) 456 | player.hideSlider() 457 | player.show() 458 | player.widescreen = True 459 | if len(sys.argv) > 1: 460 | print(sys.argv[1]) 461 | if sys.argv[1].startswith("http"): 462 | player.myurl = sys.argv[1] 463 | player.playFromURL() 464 | else: 465 | player.loadFilm(sys.argv[1]) 466 | sys.exit(app.exec_()) 467 | -------------------------------------------------------------------------------- /QT6_VideoPlayer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from PyQt6.QtGui import QKeySequence, QIcon, QShortcut, QDrag 5 | from PyQt6.QtCore import QDir, Qt, QUrl, QPoint, QTime, QProcess, QRect, QEvent 6 | from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput 7 | from PyQt6.QtMultimediaWidgets import QVideoWidget 8 | from PyQt6.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLineEdit, 9 | QPushButton, QSlider, QMessageBox, QStyle, QVBoxLayout, 10 | QWidget, QMenu) 11 | import sys 12 | import subprocess 13 | #QT_DEBUG_PLUGINS 14 | 15 | class VideoPlayer(QWidget): 16 | 17 | def __init__(self, aPath, parent=None): 18 | super(VideoPlayer, self).__init__(parent) 19 | 20 | self.setAttribute( Qt.WidgetAttribute.WA_NoSystemBackground, True ) 21 | self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) 22 | self.customContextMenuRequested[QPoint].connect(self.contextMenuRequested) 23 | self.setAcceptDrops(True) 24 | self.mediaPlayer = QMediaPlayer() 25 | self.mediaPlayer.mediaStatusChanged.connect(self.printMediaData) 26 | self.audioOutput = QAudioOutput() 27 | self.mediaPlayer.setAudioOutput(self.audioOutput) 28 | self.videoWidget = QVideoWidget(self) 29 | self.audioOutput.setVolume(0.8) 30 | 31 | self.lbl = QLineEdit('00:00:00') 32 | self.lbl.setReadOnly(True) 33 | self.lbl.setFixedWidth(70) 34 | self.lbl.setUpdatesEnabled(True) 35 | self.lbl.setStyleSheet(stylesheet(self)) 36 | self.lbl.selectionChanged.connect(lambda: self.lbl.setSelection(0, 0)) 37 | 38 | self.elbl = QLineEdit('00:00:00') 39 | self.elbl.setReadOnly(True) 40 | self.elbl.setFixedWidth(70) 41 | self.elbl.setUpdatesEnabled(True) 42 | self.elbl.setStyleSheet(stylesheet(self)) 43 | self.elbl.selectionChanged.connect(lambda: self.elbl.setSelection(0, 0)) 44 | 45 | self.playButton = QPushButton() 46 | self.playButton.setEnabled(False) 47 | self.playButton.setFixedWidth(32) 48 | self.playButton.setStyleSheet("background-color: black") 49 | 50 | self.playIcon = getattr(QStyle.StandardPixmap, "SP_MediaPlay") 51 | self.pauseIcon = getattr(QStyle.StandardPixmap, "SP_MediaPause") 52 | self.playButton.setIcon(self.style().standardIcon(self.playIcon)) 53 | self.playButton.clicked.connect(self.play) 54 | 55 | self.positionSlider = QSlider(Qt.Orientation.Horizontal, self) 56 | self.positionSlider.setStyleSheet (stylesheet(self)) 57 | self.positionSlider.setRange(0, 100) 58 | self.positionSlider.sliderMoved.connect(self.setPosition) 59 | self.positionSlider.setSingleStep(2) 60 | self.positionSlider.setPageStep(20) 61 | self.positionSlider.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) 62 | 63 | self.clip = QApplication.clipboard() 64 | self.process = QProcess(self) 65 | self.process.readyRead.connect(self.dataReady) 66 | self.process.finished.connect(self.playFromURL) 67 | 68 | self.myurl = "" 69 | self.fullscreen = False 70 | self.rect = QRect() 71 | 72 | controlLayout = QHBoxLayout() 73 | controlLayout.setContentsMargins(5, 0, 5, 0) 74 | controlLayout.addWidget(self.playButton) 75 | controlLayout.addWidget(self.lbl) 76 | controlLayout.addWidget(self.positionSlider) 77 | controlLayout.addWidget(self.elbl) 78 | 79 | layout = QVBoxLayout() 80 | layout.setContentsMargins(0, 0, 0, 0) 81 | layout.addWidget(self.videoWidget) 82 | layout.addLayout(controlLayout) 83 | 84 | self.setLayout(layout) 85 | 86 | self.myinfo = "©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" + \ 87 | "LEFT = < 1 Minute\nRIGHT = > 1 Minute\n" + \ 88 | "SHIFT+LEFT = < 10 Minutes\nSHIFT+RIGHT = > 10 Minutes" 89 | 90 | self.widescreen = True 91 | 92 | #### shortcuts #### 93 | self.shortcut = QShortcut(QKeySequence("q"), self) 94 | self.shortcut.activated.connect(self.handleQuit) 95 | self.shortcut = QShortcut(QKeySequence("u"), self) 96 | self.shortcut.activated.connect(self.playFromURL) 97 | 98 | self.shortcut = QShortcut(QKeySequence("y"), self) 99 | self.shortcut.activated.connect(self.getYTUrl) 100 | 101 | self.shortcut = QShortcut(QKeySequence("o"), self) 102 | self.shortcut.activated.connect(self.openFile) 103 | self.shortcut = QShortcut(QKeySequence(" "), self) 104 | self.shortcut.activated.connect(self.play) 105 | self.shortcut = QShortcut(QKeySequence("f"), self) 106 | self.shortcut.activated.connect(self.handleFullscreen) 107 | self.shortcut = QShortcut(QKeySequence("i"), self) 108 | self.shortcut.activated.connect(self.handleInfo) 109 | self.shortcut = QShortcut(QKeySequence("s"), self) 110 | self.shortcut.activated.connect(self.toggleSlider) 111 | self.shortcut = QShortcut(QKeySequence(Qt.Key.Key_Right), self) 112 | self.shortcut.activated.connect(self.forwardSlider) 113 | self.shortcut = QShortcut(QKeySequence(Qt.Key.Key_Left), self) 114 | self.shortcut.activated.connect(self.backSlider) 115 | self.shortcut = QShortcut(QKeySequence(Qt.Key.Key_Up), self) 116 | self.shortcut.activated.connect(self.volumeUp) 117 | self.shortcut = QShortcut(QKeySequence(Qt.Key.Key_Down), self) 118 | self.shortcut.activated.connect(self.volumeDown) 119 | self.shortcut = QShortcut(QKeySequence(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Right) , self) 120 | self.shortcut.activated.connect(self.forwardSlider10) 121 | self.shortcut = QShortcut(QKeySequence(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Left) , self) 122 | self.shortcut.activated.connect(self.backSlider10) 123 | 124 | self.mediaPlayer.setVideoOutput(self.videoWidget) 125 | self.mediaPlayer.playbackStateChanged.connect(self.mediaStateChanged) 126 | self.mediaPlayer.positionChanged.connect(self.positionChanged) 127 | self.mediaPlayer.durationChanged.connect(self.durationChanged) 128 | self.mediaPlayer.errorChanged.connect(self.handleError) 129 | self.setAttribute(Qt.WidgetAttribute.WA_Hover) 130 | 131 | print("QT6 Player started") 132 | print("press 'o' to open file (see context menu for more)") 133 | self.suspend_screensaver() 134 | 135 | def event(self, event): 136 | if event.type() == 127: 137 | self.showSlider() 138 | elif event.type() == 128: 139 | self.hideSlider() 140 | return super().event(event) 141 | 142 | 143 | def mouseDoubleClickEvent(self, event): 144 | self.handleFullscreen() 145 | 146 | def playFromURL(self): 147 | self.mediaPlayer.pause() 148 | self.myurl = self.clip.text() 149 | self.mediaPlayer.setSource(QUrl(self.myurl)) 150 | self.playButton.setEnabled(True) 151 | self.mediaPlayer.play() 152 | self.hideSlider() 153 | print(self.myurl) 154 | 155 | def getYTUrl(self): 156 | cmd = f"yt-dlp -g -f worst {self.clip.text()}" 157 | print(f"grabbing YouTube URL\n{cmd}") 158 | #self.process.start(cmd) 159 | self.myurl = subprocess.check_output(cmd, shell=True).decode() 160 | self.myurl = self.myurl.partition("\n")[0] 161 | print(self.myurl) 162 | self.clip.setText(self.myurl) 163 | self.playFromURL() 164 | 165 | def dataReady(self): 166 | self.myurl = str(self.process.readAll(), encoding = 'utf8').rstrip() ### 167 | self.myurl = self.myurl.partition("\n")[0] 168 | print(self.myurl) 169 | self.clip.setText(self.myurl) 170 | self.playFromURL() 171 | 172 | def suspend_screensaver(self): 173 | 'suspend linux screensaver' 174 | proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled false', shell=True) 175 | proc.wait() 176 | 177 | def resume_screensaver(self): 178 | 'resume linux screensaver' 179 | proc = subprocess.Popen('gsettings set org.gnome.desktop.screensaver idle-activation-enabled true', shell=True) 180 | proc.wait() 181 | 182 | def openFile(self): 183 | fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie", 184 | QDir.homePath() + "/Videos", "Media (*.webm *.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v *.3gp *.mp3 *.m4a *.wav *.ogg *.flac *.m3u *.m3u8)") 185 | 186 | if fileName != '': 187 | self.loadFilm(fileName) 188 | print("File loaded") 189 | 190 | def play(self): 191 | if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState: 192 | self.mediaPlayer.pause() 193 | else: 194 | self.mediaPlayer.play() 195 | 196 | def mediaStateChanged(self, state): 197 | if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState: 198 | self.playButton.setIcon(self.style().standardIcon(self.playIcon)) 199 | else: 200 | self.playButton.setIcon(self.style().standardIcon(self.pauseIcon)) 201 | 202 | def positionChanged(self, position): 203 | self.positionSlider.setValue(position) 204 | mtime = QTime(0,0,0,0) 205 | mtime = mtime.addMSecs(self.mediaPlayer.position()) 206 | self.lbl.setText(mtime.toString()) 207 | 208 | def durationChanged(self, duration): 209 | self.positionSlider.setRange(0, duration) 210 | mtime = QTime(0,0,0,0) 211 | mtime = mtime.addMSecs(self.mediaPlayer.duration()) 212 | self.elbl.setText(mtime.toString()) 213 | 214 | def setPosition(self, position): 215 | self.mediaPlayer.setPosition(position) 216 | 217 | def handleError(self): 218 | self.playButton.setEnabled(False) 219 | print("Error: ", self.mediaPlayer.errorString()) 220 | self.errorbox(self.mediaPlayer.errorString()) 221 | 222 | def errorbox(self, message): 223 | msg = QMessageBox(QMessageBox.Icon.Information, "Error", message, QMessageBox.StandardButton.Ok) 224 | msg.exec() 225 | 226 | def handleQuit(self): 227 | self.mediaPlayer.stop() 228 | self.resume_screensaver() 229 | print("Goodbye ...") 230 | app.quit() 231 | 232 | def contextMenuRequested(self,point): 233 | menu = QMenu() 234 | actionFile = menu.addAction(QIcon.fromTheme("video-x-generic"),"open File (o)") 235 | actionclipboard = menu.addSeparator() 236 | actionURL = menu.addAction(QIcon.fromTheme("browser"),"URL from Clipboard (u)") 237 | actionclipboard = menu.addSeparator() 238 | actionYTurl = menu.addAction(QIcon.fromTheme("youtube"), "URL from YouTube (y)") 239 | actionclipboard = menu.addSeparator() 240 | actionToggle = menu.addAction(QIcon.fromTheme("next"),"show / hide Slider (s)") 241 | actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"),"Fullscreen (f)") 242 | action169 = menu.addAction(QIcon.fromTheme("tv-symbolic"),"16 : 9") 243 | action43 = menu.addAction(QIcon.fromTheme("tv-symbolic"),"4 : 3") 244 | actionSep = menu.addSeparator() 245 | actionInfo = menu.addAction(QIcon.fromTheme("help-about"),"Info (i)") 246 | action5 = menu.addSeparator() 247 | actionQuit = menu.addAction(QIcon.fromTheme("application-exit"),"Exit (q)") 248 | 249 | actionFile.triggered.connect(self.openFile) 250 | actionQuit.triggered.connect(self.handleQuit) 251 | actionFull.triggered.connect(self.handleFullscreen) 252 | actionInfo.triggered.connect(self.handleInfo) 253 | actionToggle.triggered.connect(self.toggleSlider) 254 | actionURL.triggered.connect(self.playFromURL) 255 | actionYTurl.triggered.connect(self.getYTUrl) 256 | action169.triggered.connect(self.screen169) 257 | action43.triggered.connect(self.screen43) 258 | menu.exec(self.mapToGlobal(point)) 259 | 260 | def wheelEvent(self,event): 261 | mwidth = self.frameGeometry().width() 262 | mleft = self.frameGeometry().left() 263 | mtop = self.frameGeometry().top() 264 | mscale = round(event.angleDelta().y() / 5) 265 | if self.widescreen == True: 266 | self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.778)) 267 | else: 268 | self.setGeometry(mleft, mtop, mwidth + mscale, round((mwidth + mscale) / 1.33)) 269 | 270 | def screen169(self): 271 | self.widescreen = True 272 | mwidth = self.frameGeometry().width() 273 | mleft = self.frameGeometry().left() 274 | mtop = self.frameGeometry().top() 275 | mratio = 1.778 276 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) 277 | 278 | def screen43(self): 279 | self.widescreen = False 280 | mwidth = self.frameGeometry().width() 281 | mleft = self.frameGeometry().left() 282 | mtop = self.frameGeometry().top() 283 | mratio = 1.33 284 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio)) 285 | 286 | def handleFullscreen(self): 287 | if self.fullscreen == True: 288 | self.showNormal() 289 | self.setGeometry(self.rect) 290 | QApplication.setOverrideCursor(Qt.CursorShape.BlankCursor) 291 | self.fullscreen = False 292 | print("Fullscreen aus") 293 | else: 294 | self.rect = self.geometry() 295 | self.showFullScreen() 296 | QApplication.setOverrideCursor(Qt.CursorShape.ArrowCursor) 297 | self.fullscreen = True 298 | print("Fullscreen an") 299 | self.handleCursor() 300 | 301 | def handleCursor(self): 302 | if QApplication.overrideCursor() == Qt.CursorShape.ArrowCursor: 303 | QApplication.setOverrideCursor(Qt.CursorShape.BlankCursor) 304 | else: 305 | QApplication.setOverrideCursor(Qt.CursorShape.ArrowCursor) 306 | 307 | def handleInfo(self): 308 | msg = QMessageBox.about(self, "QT5 Player", self.myinfo) 309 | 310 | def toggleSlider(self): 311 | if self.positionSlider.isVisible(): 312 | self.hideSlider() 313 | else: 314 | self.showSlider() 315 | 316 | def hideSlider(self): 317 | self.playButton.hide() 318 | self.lbl.hide() 319 | self.positionSlider.hide() 320 | self.elbl.hide() 321 | mwidth = self.frameGeometry().width() 322 | mleft = self.frameGeometry().left() 323 | mtop = self.frameGeometry().top() 324 | if self.widescreen == True: 325 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.778)) 326 | else: 327 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) 328 | 329 | def showSlider(self): 330 | self.playButton.show() 331 | self.lbl.show() 332 | self.positionSlider.show() 333 | self.elbl.show() 334 | mwidth = self.frameGeometry().width() 335 | mleft = self.frameGeometry().left() 336 | mtop = self.frameGeometry().top() 337 | if self.widescreen == True: 338 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.55)) 339 | else: 340 | self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33)) 341 | 342 | def forwardSlider(self): 343 | self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000*60) 344 | 345 | def forwardSlider10(self): 346 | self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000*60) 347 | 348 | def backSlider(self): 349 | self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000*60) 350 | 351 | def backSlider10(self): 352 | self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000*60) 353 | 354 | def volumeUp(self): 355 | self.audioOutput.setVolume(self.audioOutput.volume() + 0.05) 356 | print(f"Volume: {self.audioOutput.volume():.2f}") 357 | 358 | def volumeDown(self): 359 | self.audioOutput.setVolume(self.audioOutput.volume() - 0.05) 360 | print(f"Volume: {self.audioOutput.volume():.2f}") 361 | 362 | def mousePressEvent(self, evt): 363 | self.oldPos = evt.position() 364 | 365 | def mouseMoveEvent(self, evt): 366 | delta = evt.position() - self.oldPos 367 | self.move(int(self.x() + delta.x()), int(self.y() + delta.y())) 368 | 369 | def dragEnterEvent(self, event): 370 | print("drag", event.mimeData()) 371 | if event.mimeData().hasUrls(): 372 | event.accept() 373 | elif event.mimeData().hasText(): 374 | event.accept() 375 | else: 376 | event.ignore() 377 | 378 | def dropEvent(self, event): 379 | print("drop") 380 | if event.mimeData().hasUrls(): 381 | url = event.mimeData().urls()[0].toString().rstrip() 382 | print("url = ", url) 383 | self.mediaPlayer.stop() 384 | self.mediaPlayer.setSource(QUrl(url)) 385 | self.playButton.setEnabled(True) 386 | self.mediaPlayer.play() 387 | elif event.mimeData().hasText(): 388 | mydrop = event.mimeData().text().rstrip() 389 | ### YouTube url 390 | if "youtube" in mydrop: 391 | print("is YouTube", mydrop) 392 | self.clip.setText(mydrop) 393 | self.getYTUrl() 394 | else: 395 | ### normal url 396 | print("generic url = ", mydrop) 397 | self.mediaPlayer.setSource(QUrl(mydrop)) 398 | self.playButton.setEnabled(True) 399 | self.mediaPlayer.play() 400 | self.hideSlider() 401 | 402 | def loadFilm(self, f): 403 | self.mediaPlayer.setSource(QUrl.fromLocalFile(f)) 404 | self.playButton.setEnabled(True) 405 | self.mediaPlayer.play() 406 | 407 | def printMediaData(self): 408 | if self.mediaPlayer.mediaStatus() == 6: 409 | if self.mediaPlayer.isMetaDataAvailable(): 410 | res = str(self.mediaPlayer.metaData("Resolution")).partition("PyQt6.QtCore.QSize(")[2].replace(", ", "x").replace(")", "") 411 | print("%s%s" % ("Video Resolution = ",res)) 412 | if res: 413 | v = round(int(res.partition("x")[0]) / int(res.partition("x")[2])) 414 | if v < 1.5: 415 | self.screen43() 416 | else: 417 | self.screen169() 418 | else: 419 | print("no metaData available") 420 | 421 | def openFileAtStart(self, filelist): 422 | matching = [s for s in filelist if ".myformat" in s] 423 | if len(matching) > 0: 424 | self.loadFilm(matching) 425 | 426 | ##################### end ################################## 427 | 428 | def stylesheet(self): 429 | return """ 430 | 431 | QSlider::handle:horizontal 432 | { 433 | background: transparent; 434 | width: 8px; 435 | } 436 | 437 | QSlider::groove:horizontal { 438 | border: 1px solid #444444; 439 | height: 8px; 440 | background: qlineargradient(y1: 0, y2: 1, 441 | stop: 0 #2e3436, stop: 1.0 #000000); 442 | } 443 | 444 | QSlider::sub-page:horizontal { 445 | background: qlineargradient( y1: 0, y2: 1, 446 | stop: 0 #729fcf, stop: 1 #2a82da); 447 | border: 1px solid #777; 448 | height: 8px; 449 | } 450 | 451 | QSlider::handle:horizontal:hover { 452 | background: #2a82da; 453 | height: 8px; 454 | width: 18px; 455 | border: 1px solid #2e3436; 456 | } 457 | 458 | QSlider::sub-page:horizontal:disabled { 459 | background: #bbbbbb; 460 | border-color: #999999; 461 | } 462 | 463 | QSlider::add-page:horizontal:disabled { 464 | background: #2a82da; 465 | border-color: #999999; 466 | } 467 | 468 | QSlider::handle:horizontal:disabled { 469 | background: #2a82da; 470 | } 471 | 472 | QLineEdit 473 | { 474 | background: black; 475 | color: #585858; 476 | border: 0px solid #076100; 477 | font-size: 8pt; 478 | font-weight: bold; 479 | } 480 | """ 481 | 482 | 483 | if __name__ == '__main__': 484 | app = QApplication(sys.argv) 485 | player = VideoPlayer('') 486 | player.setWindowTitle("QT6 Player") 487 | player.setWindowIcon(QIcon.fromTheme("multimedia-video-player")) 488 | player.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint) 489 | player.setGeometry(100, 50, 500, 280) 490 | 491 | player.hideSlider() 492 | player.show() 493 | player.widescreen = True 494 | if len(sys.argv) > 1: 495 | print(sys.argv[1]) 496 | if sys.argv[1].startswith("http"): 497 | player.myurl = sys.argv[1] 498 | player.playFromURL() 499 | else: 500 | player.loadFilm(sys.argv[1]) 501 | sys.exit(app.exec()) 502 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhononVideoPlayer 2 | VideoPlayer (Qt4) 3 | 4 | # VideoSchneiden 5 | cut Video (Qt4) 6 | 7 | # QT5_Videoplayer 8 | VideoPlayer (Qt5) 9 | 10 | press 'o' to open a video file or right mouse click for contextmenu 11 | 12 | ##creating an executable on Linux: 13 | ``` 14 | pyinstaller QT5_VideoPlayer.py 15 | ``` 16 | when errors about missing Qt5 Files use: 17 | ``` 18 | pyinstaller -y --distpath="." -p "/usr/lib/python3/dist-packages/PyQt5/" QT5_VideoPlayer.py 19 | ``` 20 | [Download 32 bit compiled Linux App](https://www.dropbox.com/s/66lw4rithsk1789/QT5_VideoPlayer.zip?dl=1) 21 | 22 | [Download 64 bit compiled Linux App](https://www.dropbox.com/s/0yxfsgd652b1o7b/QT5_VideoPlayer_64bit.tar.gz?dl=1) 23 | 24 | # TV_Livestream 25 | German TV Livestrems 26 | (Live Streams der öffentlich rechtlichen Fernsehanstalten + ORF) 27 | 28 | [Download 32 bit Linux App](https://www.dropbox.com/s/xneo85waxtz1r09/TV_LiveStream_32bit.tar.gz?dl=1) 29 | 30 | There is a new [Version with user lists and recording](https://github.com/Axel-Erfurt/LiveStream-TVPlayer) 31 | -------------------------------------------------------------------------------- /TV_LiveStream.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | from PyQt5.QtGui import QPalette, QKeySequence, QIcon 4 | from PyQt5 import QtCore, QtWidgets 5 | from PyQt5.QtCore import Qt, QUrl, QSize, QPoint, QTime 6 | from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer 7 | from PyQt5.QtMultimediaWidgets import QVideoWidget 8 | from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QSizePolicy, QMessageBox, QStyle, QVBoxLayout, 9 | QWidget, QShortcut) 10 | import os 11 | 12 | class VideoPlayer(QWidget): 13 | 14 | def __init__(self): 15 | super(VideoPlayer, self).__init__() 16 | 17 | self.setAttribute( Qt.WA_NoSystemBackground, True ) 18 | 19 | self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) 20 | self.mediaPlayer.setVolume(80) 21 | self.videoWidget = QVideoWidget(self) 22 | self.videoWidget.setAspectRatioMode(0) 23 | 24 | layout = QVBoxLayout() 25 | layout.setContentsMargins(0, 0, 0, 0) 26 | layout.addWidget(self.videoWidget) 27 | 28 | self.setLayout(layout) 29 | 30 | self.myinfo = "TV-Livestream\n©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" 31 | 32 | self.widescreen = True 33 | 34 | #### shortcuts #### 35 | self.shortcut = QShortcut(QKeySequence("q"), self) 36 | self.shortcut.activated.connect(self.handleQuit) 37 | self.shortcut = QShortcut(QKeySequence(" "), self) 38 | self.shortcut.activated.connect(self.play) 39 | self.shortcut = QShortcut(QKeySequence("f"), self) 40 | self.shortcut.activated.connect(self.handleFullscreen) 41 | self.shortcut = QShortcut(QKeySequence("i"), self) 42 | self.shortcut.activated.connect(self.handleInfo) 43 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Up), self) 44 | self.shortcut.activated.connect(self.volumeUp) 45 | self.shortcut = QShortcut(QKeySequence(Qt.Key_Down), self) 46 | self.shortcut.activated.connect(self.volumeDown) 47 | 48 | self.mediaPlayer.setVideoOutput(self.videoWidget) 49 | self.mediaPlayer.error.connect(self.handleError) 50 | 51 | print("QT5 Player started") 52 | 53 | def play(self): 54 | if self.mediaPlayer.state() == QMediaPlayer.PlayingState: 55 | self.mediaPlayer.pause() 56 | else: 57 | self.mediaPlayer.play() 58 | 59 | def positionChanged(self, position): 60 | self.positionSlider.setValue(position) 61 | 62 | 63 | def setPosition(self, position): 64 | self.mediaPlayer.setPosition(position) 65 | 66 | def handleError(self): 67 | print("Error: " + self.mediaPlayer.errorString()) 68 | 69 | def handleQuit(self): 70 | self.mediaPlayer.stop() 71 | print("Goodbye ...") 72 | app.quit() 73 | 74 | def contextMenuRequested(self,point): 75 | menu = QtWidgets.QMenu() 76 | actionARD = menu.addAction("ARD") 77 | actionZDF = menu.addAction("ZDF") 78 | actionMDR = menu.addAction("MDR") 79 | actionHR = menu.addAction("HR") 80 | actionRBB = menu.addAction("RBB") 81 | actionBR = menu.addAction("BR") 82 | actionSR = menu.addAction("SR") 83 | actionNDR = menu.addAction("NDR") 84 | actionWDR = menu.addAction("WDR") 85 | actionARTE = menu.addAction("ARTE") 86 | actionNeo = menu.addAction("ZDF Neo") 87 | actionZDFInfo = menu.addAction("ZDF Info") 88 | actionAlpha = menu.addAction("alpha") 89 | actionMDRPlus = menu.addAction("MDR +") 90 | actionSep = menu.addSeparator() 91 | actionORF1 = menu.addAction("ORF 1") 92 | actionORF2 = menu.addAction("ORF 2") 93 | actionORF3 = menu.addAction("ORF 3") 94 | 95 | actionsep2 = menu.addSeparator() 96 | actionFull = menu.addAction("Fullscreen (f)") 97 | action169 = menu.addAction("16 : 9") 98 | action43 = menu.addAction("4 : 3") 99 | actionSep = menu.addSeparator() 100 | actionInfo = menu.addAction("Info (i)") 101 | action5 = menu.addSeparator() 102 | actionQuit = menu.addAction("Exit (q)") 103 | 104 | actionQuit.triggered.connect(self.handleQuit) 105 | actionFull.triggered.connect(self.handleFullscreen) 106 | actionInfo.triggered.connect(self.handleInfo) 107 | 108 | actionARD.triggered.connect(self.handleARD) 109 | actionZDF.triggered.connect(self.handleZDF) 110 | actionMDR.triggered.connect(self.handleMDR) 111 | actionZDFInfo.triggered.connect(self.handleZDFInfo) 112 | actionHR.triggered.connect(self.handleHR) 113 | actionARTE.triggered.connect(self.handleARTE) 114 | actionRBB.triggered.connect(self.handleRBB) 115 | actionBR.triggered.connect(self.handleBR) 116 | actionSR.triggered.connect(self.handleSR) 117 | actionAlpha.triggered.connect(self.handleAlpha) 118 | actionNDR.triggered.connect(self.handleNDR) 119 | actionWDR.triggered.connect(self.handleWDR) 120 | actionNeo.triggered.connect(self.handleNeo) 121 | actionMDRPlus.triggered.connect(self.handleMDRPlus) 122 | actionORF1.triggered.connect(self.handleORF1) 123 | actionORF2.triggered.connect(self.handleORF2) 124 | actionORF3.triggered.connect(self.handleORF3) 125 | action169.triggered.connect(self.screen169) 126 | action43.triggered.connect(self.screen43) 127 | 128 | menu.exec_(self.mapToGlobal(point)) 129 | 130 | def wheelEvent(self,event): 131 | mwidth = self.frameGeometry().width() 132 | mheight = self.frameGeometry().height() 133 | mleft = self.frameGeometry().left() 134 | mtop = self.frameGeometry().top() 135 | mscale = event.angleDelta().y() / 5 136 | if self.widescreen == True: 137 | self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.778) 138 | else: 139 | self.setGeometry(mleft, mtop, mwidth + mscale, (mwidth + mscale) / 1.33) 140 | 141 | def handleFullscreen(self): 142 | if self.windowState() & QtCore.Qt.WindowFullScreen: 143 | self.showNormal() 144 | print("no Fullscreen") 145 | else: 146 | self.showFullScreen() 147 | print("Fullscreen entered") 148 | 149 | def handleInfo(self): 150 | msg = QMessageBox() 151 | msg.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SplashScreen) 152 | msg.setGeometry(self.frameGeometry().left() + 30, self.frameGeometry().top() + 30, 300, 400) 153 | msg.setIcon(QMessageBox.Information) 154 | msg.setText("QT5 Player") 155 | msg.setInformativeText(self.myinfo) 156 | msg.setStandardButtons(QMessageBox.Close) 157 | msg.exec() 158 | 159 | def volumeUp(self): 160 | self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10) 161 | print("Volume: " + str(self.mediaPlayer.volume())) 162 | 163 | def volumeDown(self): 164 | self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10) 165 | print("Volume: " + str(self.mediaPlayer.volume())) 166 | 167 | def mouseMoveEvent(self, event): 168 | if event.buttons() == Qt.LeftButton: 169 | self.move(event.globalPos() \ 170 | - QPoint(self.frameGeometry().width() / 2, \ 171 | self.frameGeometry().height() / 2)) 172 | event.accept() 173 | 174 | def screen169(self): 175 | self.widescreen = True 176 | mwidth = self.frameGeometry().width() 177 | mheight = self.frameGeometry().height() 178 | mleft = self.frameGeometry().left() 179 | mtop = self.frameGeometry().top() 180 | mratio = 1.778 181 | self.setGeometry(mleft, mtop, mwidth, mwidth / mratio) 182 | 183 | def screen43(self): 184 | self.widescreen = False 185 | mwidth = self.frameGeometry().width() 186 | mheight = self.frameGeometry().height() 187 | mleft = self.frameGeometry().left() 188 | mtop = self.frameGeometry().top() 189 | mratio = 1.33 190 | self.setGeometry(mleft, mtop, mwidth, mwidth / mratio) 191 | ############################### TV ################################ 192 | def handleARD(self): 193 | myurl = "http://daserste_live-lh.akamaihd.net/i/daserste_de@91204/master.m3u8" 194 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 195 | self.mediaPlayer.play() 196 | 197 | def handleZDF(self): 198 | myurl = "http://zdf1314-lh.akamaihd.net/i/de14_v1@392878/master.m3u8" 199 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 200 | self.mediaPlayer.play() 201 | 202 | def handleMDR(self): 203 | myurl = "http://mdr_th_hls-lh.akamaihd.net/i/livetvmdrthueringen_de@106903/master.m3u8" 204 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 205 | self.mediaPlayer.play() 206 | 207 | def handleRBB(self): 208 | myurl = "http://rbb_live-lh.akamaihd.net/i/rbb_brandenburg@107638/master.m3u8" 209 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 210 | self.mediaPlayer.play() 211 | 212 | def handleHR(self): 213 | myurl = "http://live1_hr-lh.akamaihd.net/i/hr_fernsehen@75910/master.m3u8" 214 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 215 | self.mediaPlayer.play() 216 | 217 | def handleBR(self): 218 | myurl = "http://livestreams.br.de/i/bfsnord_germany@119898/master.m3u8" 219 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 220 | self.mediaPlayer.play() 221 | 222 | def handleSR(self): 223 | myurl = "http://livestream.sr-online.de/live.m3u8" 224 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 225 | self.mediaPlayer.play() 226 | 227 | def handleNDR(self): 228 | myurl = "http://ndr_fs-lh.akamaihd.net/i/ndrfs_nds@119224/master.m3u8" 229 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 230 | self.mediaPlayer.play() 231 | 232 | def handleWDR(self): 233 | myurl = "http://wdr_fs_geo-lh.akamaihd.net/i/wdrfs_geogeblockt@112044/index_2692_av-b.m3u8" 234 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 235 | self.mediaPlayer.play() 236 | 237 | def handleZDFInfo(self): 238 | myurl = "http://zdf1112-lh.akamaihd.net/i/de12_v1@392882/master.m3u8" 239 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 240 | self.mediaPlayer.play() 241 | 242 | def handleNeo(self): 243 | myurl = "http://zdf1314-lh.akamaihd.net/i/de13_v1@392877/master.m3u8" 244 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 245 | self.mediaPlayer.play() 246 | 247 | def handleMDRPlus(self): 248 | myurl = "http://liveevent1.mdr.de/i/livetvmdrevent1_ww@106904/index_1106_av-b.m3u8" #?sd=10&rebase=on 249 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 250 | self.mediaPlayer.play() 251 | 252 | def handleAlpha(self): 253 | myurl = "http://livestreams.br.de/i/bralpha_germany@119899/master.m3u8" 254 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 255 | self.mediaPlayer.play() 256 | 257 | def handleARTE(self): 258 | myurl = "http://artelive-lh.akamaihd.net/i/artelive_de@393591/master.m3u8" 259 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 260 | self.mediaPlayer.play() 261 | 262 | def handleORF1(self): 263 | myurl = "http://apasfiisl.apa.at/ipad/orf1_q4a/orf.sdp/playlist.m3u8" 264 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 265 | self.mediaPlayer.play() 266 | 267 | def handleORF2(self): 268 | myurl = "http://apasfiisl.apa.at/ipad/orf2_q4a/orf.sdp/playlist.m3u8" 269 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 270 | self.mediaPlayer.play() 271 | 272 | def handleORF3(self): 273 | myurl = "http://apasfiisl.apa.at/ipad/orf3_q4a/orf.sdp/playlist.m3u8" 274 | self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl))) 275 | self.mediaPlayer.play() 276 | 277 | ############################### Ende TV ################################ 278 | 279 | if __name__ == '__main__': 280 | 281 | import sys 282 | app = QApplication(sys.argv) 283 | 284 | player = VideoPlayer() 285 | player.setAcceptDrops(True) 286 | player.setWindowTitle("QT5 Player") 287 | player.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) 288 | player.setGeometry(0, 0, 720, 720/1.778) 289 | player.setContextMenuPolicy(QtCore.Qt.CustomContextMenu); 290 | player.customContextMenuRequested[QtCore.QPoint].connect(player.contextMenuRequested) 291 | # player.handleARD() 292 | player.show() 293 | sys.exit(app.exec_()) 294 | -------------------------------------------------------------------------------- /VideoSchneiden.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | from PyQt4 import QtGui, QtCore 3 | from PyQt4.QtGui import QSizePolicy, QListWidget, QListWidgetItem, \ 4 | QMenu, QTableWidget, QFileDialog, QCursor 5 | from PyQt4.phonon import Phonon 6 | from PyQt4.Qt import QSize, QString, Qt, QStatusBar, QIcon, QImage, QGraphicsOpacityEffect, QMessageBox 7 | from time import time 8 | import datetime 9 | import os, subprocess 10 | #from moviepy.editor import * 11 | from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip 12 | import time 13 | import numpy as np 14 | 15 | class Window(QtGui.QWidget): 16 | def __init__(self): 17 | QtGui.QWidget.__init__(self) 18 | self.media = Phonon.MediaObject(self) 19 | ### video widget #### 20 | self.video = Phonon.VideoWidget(self) 21 | self.video.setMinimumSize(320,200) 22 | self.videoCuts = [] 23 | self.myfilename = "" 24 | self.extension = "" 25 | self.t1 = "" 26 | self.t2 = "" 27 | self.t3 = "" 28 | self.t4 = "" 29 | self.t5 = "" 30 | self.t6 = "" 31 | 32 | ### open button ### 33 | self.button = QtGui.QPushButton('Choose Video', self) 34 | self.button.setFixedWidth(90) 35 | self.button.clicked.connect(self.handleButton) 36 | self.button.setStyleSheet(stylesheet(self)) 37 | 38 | ### context menu #### 39 | self.setContextMenuPolicy(Qt.CustomContextMenu) 40 | self.customContextMenuRequested.connect(self.popup2) 41 | 42 | ### play / pause button ### 43 | self.playbutton = QtGui.QPushButton('Play', self) 44 | self.playbutton.setFixedWidth(70) 45 | self.playbutton.clicked.connect(self.handlePlayButton) 46 | self.playbutton.setStyleSheet(stylesheet(self)) 47 | self.connect(QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Space), self), QtCore.SIGNAL('activated()'), self.handlePlayButton) 48 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("Ctrl+o"), self), QtCore.SIGNAL('activated()'), self.handleButton) 49 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("Ctrl+s"), self), QtCore.SIGNAL('activated()'), self.handleSaveVideo) 50 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("Ctrl+q"), self), QtCore.SIGNAL('activated()'), self.handleQuit) 51 | ### save button ### 52 | self.savebutton = QtGui.QPushButton('Save Video', self) 53 | self.savebutton.setFixedWidth(90) 54 | self.savebutton.clicked.connect(self.handleSaveVideo) 55 | self.savebutton.setStyleSheet(stylesheet(self)) 56 | 57 | ### seek slider ### 58 | self.slider = Phonon.SeekSlider(self.media) 59 | self.slider.setStyleSheet(stylesheet(self)) 60 | isize = QSize(16,16) 61 | self.slider.setIconSize(isize) 62 | self.slider.setFocus() 63 | # self.slider.connect(self.handleLabel) 64 | 65 | ### connection position to label ### 66 | self.media.isSeekable() 67 | self.media.tick.connect(self.handleLabel) 68 | self.media.seekableChanged.connect(self.handleLabel) 69 | #self.slider.wheel.connect(self.handleLabel) 70 | 71 | ### table view ### 72 | self.iconList = QListWidget() 73 | self.iconList.setAlternatingRowColors(True) 74 | self.iconList.setFixedWidth(200) 75 | self.iconList.setContextMenuPolicy(Qt.CustomContextMenu) 76 | self.iconList.setStyleSheet("QListWidget::item:selected:active { background: #7D8ED9; color:#FFFFFF; } ") 77 | self.iconList.setViewMode(0) 78 | self.iconList.setSelectionBehavior(1) 79 | self.iconList.setIconSize(QSize(80, 80/1.78)) 80 | self._hookListActions() 81 | self.iconList.customContextMenuRequested.connect(self._openListMenu) 82 | 83 | ### set start button ### 84 | self.startbutton = QtGui.QPushButton('set Start', self) 85 | self.startbutton.setFixedWidth(70) 86 | self.startbutton.clicked.connect(self.handleStartButton) 87 | self.startbutton.setStyleSheet(stylesheet(self)) 88 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("s"), self), QtCore.SIGNAL('activated()'), self.handleStartButton) 89 | 90 | ### set end button ### 91 | self.endbutton = QtGui.QPushButton('set End', self) 92 | self.endbutton.setFixedWidth(70) 93 | self.endbutton.clicked.connect(self.handleEndButton) 94 | self.endbutton.setStyleSheet(stylesheet(self)) 95 | self.connect(QtGui.QShortcut(QtGui.QKeySequence("e"), self), QtCore.SIGNAL('activated()'), self.handleEndButton) 96 | ### label ### 97 | self.mlabel = QtGui.QLabel('Frame', self) 98 | self.mlabel.setStyleSheet('QLabel \ 99 | {background-color: transparent; color: white;}\nQLabel{color: darkcyan; font-size: 12px; background-color: transparent; border-radius: 5px; padding: 6px; text-align: center;}\n QLabel:hover{color: red;}') 100 | #self.mlabel.setFixedWidth(80) 101 | 102 | ### layout ### 103 | layout = QtGui.QGridLayout(self) 104 | layout.addWidget(self.iconList, 0, 0, 1, 1) 105 | layout.addWidget(self.video, 0, 1, 1, 6) 106 | layout.addWidget(self.slider, 1, 1, 1, 6) 107 | layout.addWidget(self.button, 2, 0, 1, 1) 108 | layout.addWidget(self.savebutton, 2, 1, 1, 1) 109 | layout.addWidget(self.playbutton, 2, 3, 1, 1) 110 | layout.addWidget(self.startbutton, 2, 5, 1, 1) 111 | layout.addWidget(self.endbutton, 2, 6, 1, 1) 112 | layout.addWidget(self.mlabel, 2, 4, 1, 1) 113 | 114 | def popup2(self, pos): 115 | contextmenu = QMenu() 116 | contextmenu.addAction("Play / Pause (SPACE)", self.handlePlayButton) 117 | contextmenu.addSeparator() 118 | contextmenu.addAction("Load Video (Ctrl-O)", self.handleButton) 119 | contextmenu.addAction("Save Video (Ctrl-S)", self.handleSaveVideo) 120 | contextmenu.addSeparator() 121 | contextmenu.addAction("Info", self.handleInfo) 122 | contextmenu.addSeparator() 123 | contextmenu.addAction("Exit (q)", self.handleQuit) 124 | contextmenu.exec_(QCursor.pos()) 125 | 126 | def handleInfo(self): 127 | msg = QMessageBox() 128 | #msg.setFixedSize(500, 300) 129 | #msg.setGeometry(100,100, 400, 200) 130 | msg.setIcon(QMessageBox.Information) 131 | msg.setText("Axel Schneider") 132 | msg.setInformativeText(unicode(u"©2016")) 133 | msg.setWindowTitle("Cut Video") 134 | msg.setDetailedText("Python Qt4") 135 | msg.setStandardButtons(QMessageBox.Ok) 136 | 137 | retval = msg.exec_() 138 | print "value of pressed message box button:", retval 139 | 140 | def handleQuit(self): 141 | app.quit() 142 | 143 | def handleButton(self): 144 | if self.media.state() == Phonon.PlayingState: 145 | self.media.stop() 146 | else: 147 | path = QtGui.QFileDialog.getOpenFileName(self, ("Video laden"), 148 | '/Axel_1/Filme', 149 | "Videos (*.ts *.mp4)") 150 | if path: 151 | self.myfilename = unicode(path) #.encode("utf-8") 152 | window.setWindowTitle(self.myfilename.split("/")[-1]) 153 | self.extension = path.split(".")[1] 154 | print(self.extension) 155 | self.media.setCurrentSource(Phonon.MediaSource(path)) 156 | self.video.setScaleMode(1) 157 | self.video.setAspectRatio(1) 158 | self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self) 159 | Phonon.createPath(self.media, self.audio) 160 | Phonon.createPath(self.media, self.video) 161 | self.media.play() 162 | self.playbutton.setText('Pause') 163 | 164 | def handleSaveVideo(self): 165 | result = QFileDialog.getSaveFileName(self, ("Video speichern"), 166 | '/tmp/film.' + str(self.extension), 167 | "Videos (*.ts *.mp4)") 168 | if result: 169 | target = unicode(result) 170 | self.t1 = float(self.videoCuts[0]) 171 | self.t2 = float(self.videoCuts[1]) 172 | ffmpeg_extract_subclip(self.myfilename, self.t1, self.t2, targetname=target) 173 | window.setWindowTitle("Film gespeichert") 174 | self.purgeMarker() 175 | 176 | def handlePlayButton(self): 177 | if self.media.state() == Phonon.PlayingState: 178 | self.media.pause() 179 | self.playbutton.setText('Play') 180 | 181 | else: 182 | #print(self.iconList.count()) 183 | self.media.play() 184 | self.playbutton.setText('Pause') 185 | 186 | def handleStartButton(self): 187 | if self.iconList.count() < 2: 188 | rm = str(self.media.currentTime() / 100.00 / 10.00) 189 | item = QListWidgetItem() 190 | img = QImage(self.video.snapshot()) 191 | pix = QtGui.QPixmap.fromImage(img) 192 | item.setIcon(QIcon(pix)) 193 | item.setText("Start: " + rm) 194 | self.iconList.addItem(item) 195 | self.videoCuts.append(rm) 196 | else: 197 | return 198 | 199 | def handleEndButton(self): 200 | if self.iconList.count() < 2: 201 | rm = str(self.media.currentTime() / 100.00 / 10.00) 202 | item = QListWidgetItem() 203 | #item.setSizeHint(QSize(150, 40)) 204 | img = QImage(self.video.snapshot()) 205 | pix = QtGui.QPixmap.fromImage(img) 206 | item.setIcon(QIcon(pix)) 207 | item.setText("End: " + rm) 208 | self.iconList.addItem(item) 209 | self.videoCuts.append(rm) 210 | self.t3 = float(str(self.media.remainingTime())) 211 | print(self.t3) 212 | self.media.stop() 213 | self.playbutton.setText('Play') 214 | else: 215 | return 216 | 217 | def handleLabel(self): 218 | ms = self.media.currentTime() 219 | seconds=str((ms/1000)%60) 220 | minutes=str((ms/(1000*60))%60) 221 | hours=str((ms/(1000*60*60))%24) 222 | if int(seconds) < 10: 223 | seconds = "0" + seconds 224 | if int(minutes) < 10: 225 | minutes = "0" + minutes 226 | if int(hours) < 10: 227 | hours = "0" + hours 228 | s = hours + ":" + minutes + ":" + seconds 229 | self.mlabel.setText(s) 230 | 231 | def _hookListActions(self): 232 | #TOO bad-the list model -should be here... 233 | rmAction = QtGui.QAction(QtGui.QIcon('icons/close-x.png'), 'entfernen', self) 234 | rmAction.triggered.connect(self._removeMarker) 235 | rmAllAction = QtGui.QAction(QtGui.QIcon('icons/clear-all.png'), 'alle entfernen', self) 236 | rmAllAction.triggered.connect(self.purgeMarker) 237 | self.gotoAction = QtGui.QAction(QtGui.QIcon('icons/go-next.png'), 'zu dieser Position springen', self) 238 | self.gotoAction.triggered.connect(self._gotoFromMarker) 239 | 240 | #menus 241 | self._listMenu = QMenu() 242 | self._listMenu.addAction(self.gotoAction) 243 | self._listMenu.addSeparator() 244 | self._listMenu.addAction(rmAction) 245 | self._listMenu.addAction(rmAllAction) 246 | 247 | #---List widget context menu 248 | def _removeMarker(self,whatis): 249 | selectionList = self.iconList.selectedIndexes() 250 | if len(selectionList)==0: 251 | return 252 | item = selectionList[0] 253 | self.iconList.takeItem(item.row()) 254 | #self.videoCuts.remove[1]) 255 | 256 | def clearMarkerList(self): 257 | self.iconList.clear() 258 | 259 | #remove contents, remove file 260 | def purgeMarker(self): 261 | self.iconList.clear() 262 | self.videoCuts = [] 263 | 264 | def _gotoFromMarker(self,whatis): 265 | selectionList = self.iconList.selectedIndexes() 266 | if len(selectionList)==0: 267 | return 268 | item = selectionList[0] 269 | pos = item.data().toString().replace("Start: ", "").replace("End: ", "") 270 | #frame = pos.ToInt() 271 | #self.video.currentTime = 1589 272 | self.setWindowTitle(pos) 273 | 274 | def _openListMenu(self,position): 275 | selectionList = self.iconList.selectedIndexes() 276 | if len(selectionList)==0: 277 | return 278 | self._listMenu.exec_(self.iconList.viewport().mapToGlobal(position)) 279 | 280 | def stylesheet(self): 281 | return """ 282 | Phonon--SeekSlider > QSlider::groove:horizontal 283 | { 284 | border: 1px solid #bbb; 285 | background: white; 286 | height: 6px; 287 | border-radius: 4px; 288 | } 289 | 290 | Phonon--SeekSlider > QSlider::sub-page:horizontal 291 | { 292 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 293 | stop: 0 #66e, stop: 1 #bbf); 294 | background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1, 295 | stop: 0 #bbf, stop: 1 #55f); 296 | border: 1px solid #777; 297 | height: 6px; 298 | border-radius: 4px; 299 | } 300 | 301 | Phonon--SeekSlider > QSlider::add-page:horizontal 302 | { 303 | background: #fff; 304 | border: 1px solid #777; 305 | height: 6px; 306 | border-radius: 4px; 307 | } 308 | 309 | Phonon--SeekSlider > QSlider::handle:horizontal 310 | { 311 | background: qlineargradient(x1:0, y1:0, x2:1, y2:1, 312 | stop:0 #eee, stop:1 #ccc); 313 | border: 1px solid #777; 314 | width: 15px; 315 | margin-top: -2px; 316 | margin-bottom: -2px; 317 | border-radius: 4px; 318 | } 319 | 320 | Phonon--SeekSlider > QSlider::handle:horizontal:hover 321 | { 322 | background: qlineargradient(x1:0, y1:0, x2:1, y2:1, 323 | stop:0 #fff, stop:1 #ddd); 324 | border: 1px solid #444; 325 | border-radius: 4px; 326 | } 327 | 328 | Phonon--SeekSlider > QSlider::sub-page:horizontal:disabled 329 | { 330 | background: #bbb; 331 | border-color: #999; 332 | } 333 | 334 | Phonon--SeekSlider > QSlider::add-page:horizontal:disabled 335 | { 336 | background: #eee; 337 | border-color: #999; 338 | } 339 | 340 | Phonon--SeekSlider > QSlider::handle:horizontal:disabled 341 | { 342 | background: #eee; 343 | border: 1px solid #aaa; 344 | border-radius: 4px; 345 | } 346 | 347 | Phonon--SeekSlider > QSlider::hover 348 | { 349 | border-width: 2px; 350 | border-style: solid; 351 | border-color: blue; 352 | background: gold; 353 | border-radius: 8px; 354 | } 355 | 356 | QPushButton 357 | { 358 | font-size: 11px; 359 | border: 3px outset grey; 360 | border-radius: 4px; 361 | height: 24px; 362 | color: black; 363 | background-color: lightgrey; 364 | background-position: bottom-left; 365 | } 366 | 367 | QPushButton::hover 368 | { 369 | font-weight: bold; 370 | color: white; 371 | background-color: darkcyan; 372 | } 373 | 374 | """ 375 | if __name__ == '__main__': 376 | 377 | import sys 378 | app = QtGui.QApplication(sys.argv) 379 | app.setApplicationName('Cut_TS') 380 | window = Window() 381 | window.setWindowTitle('Cut Video') 382 | window.setGeometry(100,250,720,450) 383 | window.show() 384 | sys.exit(app.exec_()) 385 | --------------------------------------------------------------------------------