Сбой музыкального проигрывателя PyQt6

Я загружаю плейлист, нажимая «Добавить в плейлист». Когда я нажимаю на любой элемент в списке, плеер работает нормально. Но если я попытаюсь выбрать другой трек в списке, программа вылетит. Я заметил следующие факторы:

  1. Я нажимаю на определенный трек, а затем нажимаю на него еще раз, все работает нормально, и я могу без сбоев выбрать любой другой трек из списка.
  2. Я нажимаю на определенный трек, а затем перематываю музыку с помощью положения ползунка или кнопок, я также могу выбрать любой другой трек из списка без сбоев.
  3. Но если я щелкну определенную дорожку, а затем щелкну другую, не перематывая первую выбранную дорожку, программа выйдет из строя.
  4. Также я замечал ошибку такого типа каждый раз, когда выбираю новый трек: [mp3float @ 000001A17DE3A040] Не удалось обновить временные метки для пропущенных сэмплов.

Я пытался это исправить, но это не сработало. Заранее спасибо.

import os
import sys
from PyQt6.QtCore import Qt, QUrl, QTimer
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput, QAudio
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QSlider, QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, \
    QListWidget, QListWidgetItem


class MusicPlayer(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Music Player")
        self.setGeometry(100, 100, 400, 200)
        self.initUI()
        self.initPlayer()
        self.initSlider()
        self.initTimer()

    def initTimer(self):
        self.tmr0 = QTimer()
        self.tmr0.timeout.connect(self.on_time)
        # self.tmr0.setInterval(5000)
        self.tmr0.start(1)

    def on_time(self):
        if not self.position_slider.isSliderDown():
            pos = self.player.position()
            self.position_slider.setSliderPosition(pos)

    def initSlider(self):
        self.position_slider.setMaximum(self.player.duration())
        self.position_slider.setToolTip("Позиция трека")

    def initPlayer(self):
        self.player = QMediaPlayer()
        self.playlist = []
        self.audio_output = QAudioOutput()
        self.player.setAudioOutput(self.audio_output)
        self.saved_volume = 0.5
        self.audio_output.setVolume(self.saved_volume)

    def initUI(self):

        self.play_button = QPushButton("Play")
        self.play_button.clicked.connect(self.play_music)

        self.pause_button = QPushButton("Pause")
        self.pause_button.clicked.connect(self.pause_music)

        self.stop_button = QPushButton("Stop")
        self.stop_button.clicked.connect(self.stop_music)

        self.volume_slider = QSlider(Qt.Orientation.Horizontal)
        self.volume_slider.setValue(50)
        self.volume_slider.setMinimum(0)
        self.volume_slider.setMaximum(100)
        self.volume_slider.setToolTip("Volume")
        self.volume_slider.valueChanged.connect(self.set_volume)

        self.position_slider = QSlider(Qt.Orientation.Horizontal)
        self.position_slider.setToolTip("Position")
        # self.position_slider.sliderMoved.connect(self.set_position)
        self.position_slider.sliderReleased.connect(self.on_slider_release)

        self.backward_button = QPushButton("<< 10 sec")
        self.backward_button.clicked.connect(self.backward_music)

        self.forward_button = QPushButton("10 sec >>")
        self.forward_button.clicked.connect(self.forward_music)

        self.select_file_button = QPushButton("Add to playlist")
        self.select_file_button.clicked.connect(self.select_file)

        self.clear_playlist_button = QPushButton("Clear playlist")
        self.clear_playlist_button.clicked.connect(self.clear_playlist)

        self.playlist_widget = QListWidget()
        self.playlist_widget.itemDoubleClicked.connect(self.play_selected_track)

        self.track_label = QLabel("Track name")

        vbox = QVBoxLayout()
        hbox1 = QHBoxLayout()
        hbox2 = QHBoxLayout()
        hbox3 = QHBoxLayout()

        hbox1.addWidget(self.play_button)
        hbox1.addWidget(self.pause_button)
        hbox1.addWidget(self.stop_button)
        hbox1.addWidget(self.volume_slider)

        hbox2.addWidget(self.backward_button)
        hbox2.addWidget(self.position_slider)
        hbox2.addWidget(self.forward_button)

        hbox3.addWidget(self.track_label)
        hbox3.addWidget(self.select_file_button)
        hbox3.addWidget(self.clear_playlist_button)

        vbox.addWidget(self.playlist_widget)
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        self.setLayout(vbox)

    def select_file(self):
        folder_path = QFileDialog.getExistingDirectory(self, "Выбрать папку с музыкальными файлами", "")
        if folder_path:
            files = [os.path.join(folder_path, file) for file in os.listdir(folder_path) if
                     file.endswith(('.mp3', '.wav', '.ogg'))]
            file_names = [file for file in os.listdir(folder_path) if file.endswith(('.mp3', '.wav', '.ogg'))]
            for file in files:
                self.playlist.append(file)

            for file_name in file_names:
                item = QListWidgetItem(file_name)
                self.playlist_widget.addItem(item)

    def play_music(self):
        item = self.playlist_widget.currentItem()
        index = self.playlist_widget.row(item)
        if self.player.playbackState() == QMediaPlayer.PlaybackState.PausedState:
            self.player.play()
        else:
            if (self.playlist):
                url = QUrl.fromLocalFile(self.playlist[index])  # Создаем объект QUrl из строки с путем к файлу
                self.player.durationChanged.connect(self.initSlider)
                self.player.setSource(url)
                self.audio_output.setVolume(self.saved_volume)
                self.player.play()

    def play_selected_track(self, item):
        index = self.playlist_widget.row(item)
        if 0 <= index < len(self.playlist):
            url = QUrl.fromLocalFile(self.playlist[index])
            self.player.setSource(url)
            self.player.durationChanged.connect(self.initSlider)
            self.audio_output.setVolume(self.saved_volume)
            self.player.play()

    def pause_music(self):
        self.player.pause()

    def stop_music(self):
        self.player.stop()

    def set_volume(self):
        volume = self.volume_slider.value()
        self.saved_volume = self.real_volume(volume)
        self.audio_output.setVolume(self.saved_volume)

    """Метод конвертации значения слайдера (от 0 до 100) 
        к виду (от 0.0 до 1.0) и преобразование шкалы громкости
         в логарифмическую(удобную для восприятия человеком)"""

    def real_volume(self, slider_value):
        return QAudio.convertVolume(
            slider_value * .01,
            QAudio.VolumeScale.LogarithmicVolumeScale,
            QAudio.VolumeScale.LinearVolumeScale
        )
    def backward_music(self):
        position_m = max(0, self.player.position() - 10000)
        self.player.setPosition(position_m)

    def forward_music(self):
        position_m = min(self.player.duration(), self.player.position() + 10000)
        self.player.setPosition(position_m)

    def on_slider_release(self):
        self.player.setPosition(self.position_slider.value())

    def clear_playlist(self):
        self.playlist_widget.clear()
        self.playlist.clear()


app = QApplication(sys.argv)
playerM = MusicPlayer()
playerM.show()
sys.exit(app.exec())

Я подумал, что, возможно, потребуется сбросить источник перед выбором новой дорожки, но я не нашел команду. Хочу переключать треки без вылетов. Также я заметил сбой в строке 180: self.player.setSource(url)

Я бы начал с удаления ненужных подключений, которые могут и не иметь отношения к реальной проблеме, но уж точно не подходят: например, вам следует подключиться к durationChanged только один раз, а сейчас вы подключаетесь каждый раз, когда загружается новый файл. , что явно бесполезно. Кроме того, проверять положение ползунка каждую миллисекунду совершенно бессмысленно и неправильно: просто используйте соответствующие сигналы и возможности, предоставляемые QAbstractSlider.

musicamante 14.03.2024 15:53

Я удалил все соединения и отключил таймер, но он все равно вылетает. Также я заметил сбой в строке 180: self.player.setSource(url)

RD60 14.03.2024 18:51

Затем попробуйте запустить программу в терминале или командной строке и посмотрите, отображает ли она какой-либо отладочный вывод. Если это так, но вы все еще не можете понять, что является причиной этого, пожалуйста, отредактируйте свой вопрос и покажите нам этот результат.

musicamante 15.03.2024 02:24

Я нашел какое-то решение. Прежде чем установить новый источник для воспроизведения, я останавливаю проигрыватель, а затем проверяю, остановлен ли проигрыватель. После этого я вызываю функцию с задержкой, используя QTimer.singleShot.

RD60 15.03.2024 08:02

Это лишь частичное решение, так как это может быть ошибка, и нам следует знать о ней больше, но мы не можем сделать это без дополнительной информации. Вы сделали то, что предложили выше?

musicamante 15.03.2024 16:33
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел какое-то решение. Прежде чем установить новый источник для воспроизведения, я останавливаю проигрыватель, а затем проверяю, остановлен ли проигрыватель. После этого я вызываю функцию с задержкой, используя QTimer.singleShot.

self.player.stop()
        if self.player.playbackState() == QMediaPlayer.PlaybackState.StoppedState:
            QTimer.singleShot(1, lambda: self.source_setter(url))

def source_setter(self, url):
    self.player.setSource(url)
    self.player.play()

Другие вопросы по теме