zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

如何解决 QMediaPlayer 占用歌曲导致 PermissionError: [Error 13] 的问题

2023-02-18 16:31:02 时间

问题描述

当我们使用 QMediaPlayer 播放歌曲时,歌曲文件的句柄会被占用。如果想使用 mutagen 库对正在播放地歌曲进行数据写入,就会出现下述问题:

Traceback (most recent call last):
  File "D:\Anaconda\envs\Groove\lib\site-packages\mutagen\_util.py", line 251, in _openfile
    fileobj = open(filename, "rb+" if writable else "rb")
PermissionError: [Errno 13] Permission denied: 'resource/test_audio/aiko - 微熱.opus'

问题解决

为了对正在播放的歌曲进行数据写入,我们需要先释放当前正在播放歌曲的文件句柄。Qt 中没有直接提供释放句柄的方法,但是我们可以暂时将 QMediaPlayer 的播放列表清空,接着进行数据写入,最后还原播放列表。代码如下所示:

# coding:utf-8
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist


class MediaPlayer(QMediaPlayer):
    """ Media player """

    def __init__(self, playlist: QMediaPlaylist, parent=None) -> None:
        super().__init__(parent=parent)
        self.mediaPlaylist = playlist
        self.currentIndex = None
        self.__position = 0
        self.__isPlayingBefore = False
        self.setNotifyInterval(1000)
        self.setPlaylist(playlist)

    def isPlaying(self):
        """ whether the player is playing """
        return self.state() == self.PlayingState

    @property
    def isPlayingBeforeRelease(self):
        return self.__isPlayingBefore

    def releaseAudioHandle(self):
        """ release the handle of audio file """
        self.currentIndex = self.mediaPlaylist.currentIndex()
        self.__position = self.position()
        self.__isPlayingBefore = self.isPlaying()

        # block the signal to prevent switching songs
        self.mediaPlaylist.blockSignals(True)
        self.blockSignals(True)
        self.setMedia(QMediaContent())

    def recoverAudioHandle(self):
        """ recover the handle of audio file """
        self.setPlaylist(self.mediaPlaylist)
        self.mediaPlaylist.setCurrentIndex(self.currentIndex)
        self.setPosition(self.__position)

        self.blockSignals(False)
        self.mediaPlaylist.blockSignals(False)

现在只要调用 releaseAudioHandle() 暂时释放文件句柄,之后再 recoverAudioHandle() 就能恢复播放了,以上~~