I am trying to use PyQt4 and Phonon (on windows 8 64 bits) to play a song from the internet (streaming, ex: http://dr5huvbk6x9di.cloudfront.net/cloudfront_songs/file4.ogg)
To play a song from the filesystem is working, but when I try to play from the internet it doesn't. I read the documentation and it seems everything is fine. The error is a FatalError, so is hard to understand what is going on. Phonon can't play the song from the internet?
Another questions is that I read that phonon has been deprecated and we have PyQt5. So, which is the best way to do what I am trying to do.
Here is my code. It is a little bit messy because I just wanted to work, so I could understand and then make it better. Thank you
#!/usr/bin/env python
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.phonon import Phonon
class MainWindow(QtGui.QMainWindow):
def __init__(self, win_parent=None):
QtGui.QMainWindow.__init__(self, win_parent)
self.create_widgets()
def create_widgets(self):
# Widgets
self.label = QtGui.QLabel("ply music player")
self.fs_button = QtGui.QPushButton("FileSystem", self)
self.ws_button = QtGui.QPushButton("WebStream", self)
# Phonon actions
self.mediaObject = Phonon.MediaObject(self)
self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
Phonon.createPath(self.mediaObject, self.audioOutput)
# Connect signal
self.fs_button.clicked.connect(self.on_fs_clicked)
self.mediaObject.stateChanged.connect(self.handleStateChanged)
self.ws_button.clicked.connect(self.on_ws_clicked)
# Vertical layout (manages the layout automatically)
v_box = QtGui.QVBoxLayout()
v_box.addWidget(self.fs_button)
v_box.addWidget(self.ws_button)
# Create central widget, add layout and set
central_widget = QtGui.QWidget()
central_widget.setLayout(v_box)
self.setCentralWidget(central_widget)
def on_fs_clicked(self):
if self.mediaObject.state() == Phonon.PlayingState:
self.mediaObject.stop()
else:
files = QtGui.QFileDialog.getOpenFileNames(self, self.fs_button.text())
if files:
songs = []
for file in files:
songs.append(Phonon.MediaSource(file))
self.mediaObject.setQueue(songs)
self.mediaObject.play()
self.fs_button.setText("FileSystem")
def handleStateChanged(self, newstate, oldstate):
if newstate == Phonon.PlayingState:
self.fs_button.setText("Stop")
elif newstate == Phonon.StoppedState:
self.fs_button.setText("FileSystem")
elif newstate == Phonon.ErrorState:
source = self.mediaObject.currentSource().fileName()
print "ERROR: ", self.mediaObject.errorType()
print "ERROR: could not play:", source.toLocal8Bit().data()
def on_ws_clicked(self):
if self.mediaObject.state() == Phonon.PlayingState:
self.mediaObject.stop()
else:
song = "http://dr5huvbk6x9di.cloudfront.net/cloudfront_songs/file4.ogg"
self.mediaObject.setCurrentSource(Phonon.MediaSource(song))
print self.mediaObject.currentSource()
self.mediaObject.play()
self.ws_button.setText("WebStream")
if __name__ == "__main__":
ply = QtGui.QApplication(sys.argv)
ply.setApplicationName("Ply")
ply.setQuitOnLastWindowClosed(True)
main_window = MainWindow()
main_window.show()
sys.exit(ply.exec_())
The answer was installing codecs to play .ogg files. Thanks to #ekhumoro.
Related
I'm trying to play a media file. This is the example on the python-vlc repository:
import platform
import os
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
import vlc
class Player(QtWidgets.QMainWindow):
"""A simple Media Player using VLC and Qt
"""
def __init__(self, master=None):
QtWidgets.QMainWindow.__init__(self, master)
self.setWindowTitle("Media Player")
# Create a basic vlc instance
self.instance = vlc.Instance()
self.media = None
# Create an empty vlc media player
self.mediaplayer = self.instance.media_player_new()
self.create_ui()
self.is_paused = False
def create_ui(self):
"""Set up the user interface, signals & slots
"""
self.widget = QtWidgets.QWidget(self)
self.setCentralWidget(self.widget)
# In this widget, the video will be drawn
if platform.system() == "Darwin": # for MacOS
self.videoframe = QtWidgets.QMacCocoaViewContainer(0)
else:
self.videoframe = QtWidgets.QFrame()
self.palette = self.videoframe.palette()
self.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(0, 0, 0))
self.videoframe.setPalette(self.palette)
self.videoframe.setAutoFillBackground(True)
self.positionslider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
self.positionslider.setToolTip("Position")
self.positionslider.setMaximum(1000)
self.positionslider.sliderMoved.connect(self.set_position)
self.positionslider.sliderPressed.connect(self.set_position)
self.hbuttonbox = QtWidgets.QHBoxLayout()
self.playbutton = QtWidgets.QPushButton("Play")
self.hbuttonbox.addWidget(self.playbutton)
self.playbutton.clicked.connect(self.play_pause)
self.stopbutton = QtWidgets.QPushButton("Stop")
self.hbuttonbox.addWidget(self.stopbutton)
self.stopbutton.clicked.connect(self.stop)
self.hbuttonbox.addStretch(1)
self.volumeslider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
self.volumeslider.setMaximum(100)
self.volumeslider.setValue(self.mediaplayer.audio_get_volume())
self.volumeslider.setToolTip("Volume")
self.hbuttonbox.addWidget(self.volumeslider)
self.volumeslider.valueChanged.connect(self.set_volume)
self.vboxlayout = QtWidgets.QVBoxLayout()
self.vboxlayout.addWidget(self.videoframe)
self.vboxlayout.addWidget(self.positionslider)
self.vboxlayout.addLayout(self.hbuttonbox)
self.widget.setLayout(self.vboxlayout)
menu_bar = self.menuBar()
# File menu
file_menu = menu_bar.addMenu("File")
# Add actions to file menu
open_action = QtWidgets.QAction("Load Video", self)
close_action = QtWidgets.QAction("Close App", self)
file_menu.addAction(open_action)
file_menu.addAction(close_action)
open_action.triggered.connect(self.open_file)
close_action.triggered.connect(sys.exit)
self.timer = QtCore.QTimer(self)
self.timer.setInterval(100)
self.timer.timeout.connect(self.update_ui)
def play_pause(self):
"""Toggle play/pause status
"""
if self.mediaplayer.is_playing():
self.mediaplayer.pause()
self.playbutton.setText("Play")
self.is_paused = True
self.timer.stop()
else:
if self.mediaplayer.play() == -1:
self.open_file()
return
self.mediaplayer.play()
self.playbutton.setText("Pause")
self.timer.start()
self.is_paused = False
def stop(self):
"""Stop player
"""
self.mediaplayer.stop()
self.playbutton.setText("Play")
def open_file(self):
"""Open a media file in a MediaPlayer
"""
dialog_txt = "Choose Media File"
filename = QtWidgets.QFileDialog.getOpenFileName(self, dialog_txt, os.path.expanduser('~'))
if not filename:
return
# getOpenFileName returns a tuple, so use only the actual file name
self.media = self.instance.media_new(filename[0])
# Put the media in the media player
self.mediaplayer.set_media(self.media)
# Parse the metadata of the file
self.media.parse()
# Set the title of the track as window title
self.setWindowTitle(self.media.get_meta(0))
# The media player has to be 'connected' to the QFrame (otherwise the
# video would be displayed in it's own window). This is platform
# specific, so we must give the ID of the QFrame (or similar object) to
# vlc. Different platforms have different functions for this
if platform.system() == "Linux": # for Linux using the X Server
self.mediaplayer.set_xwindow(int(self.videoframe.winId()))
elif platform.system() == "Windows": # for Windows
self.mediaplayer.set_hwnd(int(self.videoframe.winId()))
elif platform.system() == "Darwin": # for MacOS
self.mediaplayer.set_nsobject(int(self.videoframe.winId()))
self.play_pause()
def set_volume(self, volume):
"""Set the volume
"""
self.mediaplayer.audio_set_volume(volume)
def set_position(self):
"""Set the movie position according to the position slider.
"""
# The vlc MediaPlayer needs a float value between 0 and 1, Qt uses
# integer variables, so you need a factor; the higher the factor, the
# more precise are the results (1000 should suffice).
# Set the media position to where the slider was dragged
self.timer.stop()
pos = self.positionslider.value()
self.mediaplayer.set_position(pos / 1000.0)
self.timer.start()
def update_ui(self):
"""Updates the user interface"""
# Set the slider's position to its corresponding media position
# Note that the setValue function only takes values of type int,
# so we must first convert the corresponding media position.
media_pos = int(self.mediaplayer.get_position() * 1000)
self.positionslider.setValue(media_pos)
# No need to call this function if nothing is played
if not self.mediaplayer.is_playing():
self.timer.stop()
# After the video finished, the play button stills shows "Pause",
# which is not the desired behavior of a media player.
# This fixes that "bug".
if not self.is_paused:
self.stop()
def main():
"""Entry point for our simple vlc player
"""
app = QtWidgets.QApplication(sys.argv)
player = Player()
player.show()
player.resize(640, 480)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
However, when I select a file from my phone connected with USB, I get this warning.
libdvdread: Attempting to use device /dev/sda4 mounted on / for CSS authentication
libdvdread: Could not open input: Permission denied
libdvdread: Can't open /dev/sda4 for reading
libdvdread: Device /dev/sda4 inaccessible, CSS authentication not available.
libdvdread:DVDOpenFilePath:findDVDFile /VIDEO_TS/VIDEO_TS.IFO failed
libdvdread:DVDOpenFilePath:findDVDFile /VIDEO_TS/VIDEO_TS.BUP failed
libdvdread: Can't open file VIDEO_TS.IFO.
libdvdnav: vm: failed to read VIDEO_TS.IFO
Do I have to copy over the files temporarily to play them? Or is there another way?
If the device is mass storage you don't have to copy over but for phones that don't have a feature like that I had to copy over the file before playing. I used shutil for it. In a thread other than the main thread, of course.
import shutil
copied_file = shutil.copyfile(src_filepath, dest_filepath)
self.media = self.instance.media_new(copied_file)
This question already has answers here:
Equivalent to time.sleep for a PyQt application
(5 answers)
Closed 1 year ago.
I trying create GUI Api. First i build python script with only print information in console.
So I wanted to rebuild applications into applications with an interface. I decided to use PyQt5
Like this:
To(first look):
I ran into a problem with the loop While. Aplication just freeze when while is runing
I prepared a short script simulating the problem. The main program looks different
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtWidgets
from termcolor import colored
import time
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'API NORD'
self.left = 0
self.top = 0
self.width = 300
self.height = 200
self.setWindowTitle(self.title)
self.resize(800, 600)
self.center()
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.show()
def center(self):
# geometry of the main window
qr = self.frameGeometry()
# center point of screen
cp = QDesktopWidget().availableGeometry().center()
# move rectangle's center point to screen's center point
qr.moveCenter(cp)
# top left of rectangle becomes top left of window centering it
self.move(qr.topLeft())
class MyTableWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.pushButton1 = QPushButton("Run")
self.layout.addWidget(self.pushButton1)
self.pushButton1.clicked.connect(self.button2_clicked)
self.textedit = QtWidgets.QTextEdit(readOnly=True)
self.layout.addWidget(self.textedit)
self.textedit.setText("STATUS")
def onClicked(self):
radioButton = self.sender()
if radioButton.isChecked():
x=0
# print("Shop is %s" % (radioButton.shop))
self.Sklep=radioButton.shop
self.l1.setText(self.Sklep)
return
def checkBulkStatus(self):
Status = "Start"
x=0
self.textedit.setText("Start")
while x < 5:
print("Aktualny Status:", colored(Status,"yellow"))
Status="Running"
self.textedit.append(Status)
if Status=="FAILED":
print("Error")
break
time.sleep(2.5)
x+=1
print("Aktualny Status: ", colored("COMPLETED", "green"))
self.textedit.setText("COMPLETED")
def button2_clicked(self):
self.checkBulkStatus()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
In main program I ussing while to check status of BULK request in GraphQL:
def checkBulkStatus(self):
self.url = self.auth(self.Sklep)["url_auth"]
print(self.url)
Status = "Start"
self.textedit.setText("Start")
while Status != "COMPLETED":
print("Aktualny Status:", colored(Status,"yellow"))
checking = self.Core.callShopifyGraphQL(self.Core.CheckQuery,self.url)
result = checking.json()
Status=result["data"]["currentBulkOperation"]["status"]
self.textedit.append(Status)
if Status=="FAILED":
print(result["data"]["currentBulkOperation"])
break
time.sleep(2.5)
print("Aktualny Status: ", colored("COMPLETED", "green"))
URL_bulk=result["data"]["currentBulkOperation"]["url"]
The problem is that the gui runs in the same thread as the script, so when you run the script it freezes the interface. To prevent this from happening, you need to run the script in a thread, as this way you can share variables with the main thread.
I hope it helps you, greetings.
I'm using PyQt5 to create an app with multiple main windows. I want to be able to allow the user to save and load window sizes and window positions. That's easy with, e.g., QMainWindow.saveGeometry() and QMainWindow.loadGeometry() or the corresponding .saveState() and .loadState() variants. These work great for position and size, but if the user moves or resizes one window so that it occludes another, I want to also restore this positioning. I don't mind writing my own code to save the info for each window, but I can't see any way to detect the relative Z order of windows. Am I missing it in the docs, or is this not possible?
To see what I mean, try this:
from PyQt5.QtWidgets import QApplication, QMainWindow, QPlainTextEdit
from PyQt5.QtCore import QSettings
from PyQt5.QtGui import QCloseEvent
'''
context: Linux Mint 19.3 Tricia x86_64
Python 3.9
PyQt5 5.15.1
'''
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setWindowTitle(win_name)
self.can_close = False
def restore_window(self) -> bool:
try:
settings = QSettings("PyQtExamples", "RememberWinTest")
self.restoreGeometry(settings.value(f'{self.win_name} Geometry'))
self.restoreState(settings.value(f'{self.win_name} State'))
return True
except:
return False
def closeEvent(self, event: QCloseEvent):
if not self.can_close:
event.ignore()
else:
settings = QSettings("PyQtExamples", "RememberWinTest")
settings.setValue(f'{self.win_name} Geometry', self.saveGeometry())
settings.setValue(f'{self.win_name} State', self.saveState())
QMainWindow.closeEvent(self, event)
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
super(ControlWindow, self).__init__(win_name=win_name)
self.can_close = True
self.window1 = RememberWin(win_name='WindowOne')
self.window2 = RememberWin(win_name='WindowTwo')
self.text = QPlainTextEdit(self)
s = "Try making Window1 wide enough to cover Window2.\n" \
"Then close this window (auto closes others).\n" \
"Re-run the app and you'll notice that Window2\n" \
"is not on top of Window1 which means that this\n" \
"info isn't getting saved."
self.text.setPlainText(s)
self.setCentralWidget(self.text)
if not self.restore_window():
self.setGeometry(100, 390, 512, 100)
if not self.window1.restore_window():
self.window1.setGeometry(100, 100, 512, 384)
if not self.window2.restore_window():
self.window2.setGeometry(622, 100, 512, 384)
self.window1.show()
self.window2.show()
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
super(ControlWindow, self).closeEvent(event)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = ControlWindow(win_name='ControlWindow (You can only close this one)')
window.show()
sys.exit(app.exec_())
The simplest way to do what you want to achieve is to keep track of the current focused widget, or, to be precise, the top level window of the last focused widget.
You can store the focused windows in the settings as a list, using a unique objectName for each window (you are already doing this, so you just need to use setObjectName()), then restore the window by showing them in the correct order as long as the object name matches.
class RememberWin(QMainWindow):
def __init__(self, win_name: str):
super(RememberWin, self).__init__()
self.win_name = win_name
self.setObjectName(win_name)
self.setWindowTitle(win_name)
self.can_close = False
# ...
class ControlWindow(RememberWin):
def __init__(self, win_name: str = "ControlWindow"):
# ...
self.settings = QSettings("PyQtExamples", "RememberWinTest")
self.zOrder = []
QApplication.instance().focusObjectChanged.connect(self.focusChanged)
windowOrder = self.settings.value('windowOrder', type='QStringList')
topLevelWindows = QApplication.topLevelWidgets()
if windowOrder:
for objName in windowOrder:
for win in topLevelWindows:
if win.objectName() == objName:
win.show()
else:
self.window1.show()
self.window2.show()
def focusChanged(self, obj):
if not obj or obj.window() == self.window():
return
if obj.window() in self.zOrder[:-1]:
self.zOrder.remove(obj.window())
self.zOrder.append(obj.window())
def closeEvent(self, event: QCloseEvent):
for win in (self.window1, self.window2):
win.can_close = True
win.close()
self.settings.setValue('windowOrder',
[w.window().objectName() for w in self.zOrder])
super(ControlWindow, self).closeEvent(event)
This is an example of code for simple system tray PyQt application.
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon('test.png'), app)
menu = QtGui.QMenu()
exitAction = menu.addAction("Exit")
trayIcon.setContextMenu(menu)
# I'd like to show picture in tooltip, BUT IT'S NOT WORK IN WINDOWS
trayIcon.setTooltip('<img src="SomePicture.png" width="48" height="48"/>')
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
In this code I'd like to show balloon tooltip with a some picture and some kind of text formating. For this purpose I use RichText tags formatting. As the result for Ubuntu Linux system (Gnome desktop) everything is Ok. But when I try use RichText formatting for tooltip in Windows XP system, nothing works. Tooltip text equals source string: ''.
Python version on Windows 2.7, on Linux 2.6 but I think that problem is not in different versions.
If in Windows OS RichText isn't parsing how can I make same kind of GUI (Crossplatform is prefered)?
On Windows Qt uses the os' tooltip system, which only supports text.
If you want something more advanced, you could QSystemTrayIcon.showMessage() use as described here. You'll probably have to install an eventfilter or override the QTrayIcons event method to get the help event.
If someone also interested in create of balloon widget. This my code:
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, parent = None):
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
self.connect(self, QtCore.SIGNAL(traySignal), self._activateRoutine)
self.balloon = balloonWidget(name)
def _activateRoutine(self, reason):
if reason == QtGui.QSystemTrayIcon.Trigger:
self.balloon.show(self.geometry())
class balloonWidget(QtGui.QWidget):
def __init__(self,name):
QtGui.QWidget.__init__(self, parent = None, flags = QtCore.Qt.Popup)
self.name = name
self.offsetX = 10
self.offsetY = 10
self.outInfo = QtGui.QLabel(self)
self.setStyleSheet("QWidget {border:5px solid rgb(170, 170, 255);}")
def show(self,coord):
richText = tr('Any text with Rich Format')
self.outInfo.setText(richText)
self.outInfo.show()
self.adjustSize()
origin = QtGui.QDesktopWidget().availableGeometry().bottomRight()
if coord.y() < origin.y()/2:
moveY = coord.bottomLeft().y() + self.offsetY
else:
moveY = coord.topLeft().y() - (self.height() + self.offsetY)
if coord.x() + self.width() + self.offsetX >= origin.x():
moveX = origin.x() - (self.width() + self.offsetX)
else:
moveX = coord.x()
self.move(moveX,moveY)
self.setVisible(True)
def closeEvent(self, event):
event.ignore()
self.hide()
def mousePressEvent(self, event):
self.close()
I'm trying to play a single mp3 file on my software when a button is pressed.
Here's how i did it:
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), playsong)
and the function:
def playsong():
m_media = Phonon.MediaObject()
m_media.setCurrentSource(Phonon.MediaSource("files/song.mp3"))
m_media.play()
This doesnt raise any error.
But the song wont play.
I've seen a lot of exemples in C++ and some in python which has a lot of songs, and playlist, etc.
I just want to play a single song, am i missing something?
I use phonon on pyqt and my code has a few more lines:
output = Phonon.AudioOutput(Phonon.MusicCategory)
m_media = Phonon.MediaObject()
Phonon.createPath(m_media, output)
m_media.setCurrentSource(Phonon.MediaSource("files/song.mp3"))
m_media.play()
But honestly, I've found out that phonon is not able to play some specific songs with weird ID3 tags, so I've switched to pyaudiere (https://pypi.python.org/pypi/pyaudiere), which is much more stable (but yes, its less integrated with Qt).
Here's a simple music player example:
from PyQt4 import QtGui, QtCore
from PyQt4.phonon import Phonon
class Window(QtGui.QPushButton):
def __init__(self):
QtGui.QPushButton.__init__(self, 'Choose File')
self.mediaObject = Phonon.MediaObject(self)
self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
Phonon.createPath(self.mediaObject, self.audioOutput)
self.mediaObject.stateChanged.connect(self.handleStateChanged)
self.clicked.connect(self.handleButton)
def handleButton(self):
if self.mediaObject.state() == Phonon.PlayingState:
self.mediaObject.stop()
else:
path = QtGui.QFileDialog.getOpenFileName(self, self.text())
if path:
self.mediaObject.setCurrentSource(Phonon.MediaSource(path))
self.mediaObject.play()
def handleStateChanged(self, newstate, oldstate):
if newstate == Phonon.PlayingState:
self.setText('Stop')
elif newstate == Phonon.StoppedState:
self.setText('Choose File')
elif newstate == Phonon.ErrorState:
source = self.mediaObject.currentSource().fileName()
print 'ERROR: could not play:', source.toLocal8Bit().data()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('Phonon')
win = Window()
win.resize(200, 100)
win.show()
sys.exit(app.exec_())