예제 #1
0
class Channel(QObject):
    def __init__(self,
                 name: T.Optional[str],
                 parent: T.Optional[QObject] = None) -> None:
        super().__init__(parent)
        self.name = name
        self.slider_volume: Number = 100
        self.threshold = PlaybackThreshold.Everything

        self._loop_sound: T.Optional[Sound] = None
        self._loop_player = QMediaPlayer(self)
        self._loop_volume_adjustment: Number = 0
        self._loop_player.setAudioRole(QAudio.GameRole)
        self._loop_playlist = QMediaPlaylist(self)
        self._loop_playlist.setPlaybackMode(QMediaPlaylist.CurrentItemOnce)
        self._loop_player.setPlaylist(self._loop_playlist)
        self._loop_player.stateChanged.connect(
            self._on_loop_player_state_changed)

        self._one_shot_player = QMediaPlayer(self)
        self._one_shot_volume_adjustment: Number = 0
        self._one_shot_player.setAudioRole(QAudio.GameRole)
        self._one_shot_player.stateChanged.connect(
            self._on_one_shot_player_state_changed)

    @property
    def is_playing(self):
        return (self._loop_player.state() == QMediaPlayer.PlayingState
                or self._one_shot_player.state() == QMediaPlayer.PlayingState)

    def _on_loop_player_state_changed(self, state: QMediaPlayer.State) -> None:
        logger.trace("Loop player state changed: {!r}", state)
        if state != QMediaPlayer.StoppedState:
            return

        decibel = -self._loop_volume_adjustment
        logger.trace("Readjusting loop player volume by {}db", decibel)
        self.adjust_player_volume_by_decibel(self._loop_player, decibel)
        self._loop_volume_adjustment = 0

        # Loop playlist is empty
        if not self._loop_playlist.mediaCount():
            logger.trace("Loop playlist is empty, not queueing a new file")
            return

        # This shouldn't ever happen, it's just here to make mypy happy
        if not self._loop_sound:
            return

        file = random.choices(self._loop_sound.files,
                              [file.weight
                               for file in self._loop_sound.files])[0]
        index = self._loop_sound.files.index(file)
        logger.trace(
            "Loop player playing file: {!r} at playlist index: {}",
            file,
            index,
        )
        self._loop_playlist.setCurrentIndex(index)
        self._loop_player.play()

    def _on_one_shot_player_state_changed(self,
                                          state: QMediaPlayer.State) -> None:
        logger.trace("One-shot player state changed: {!r}", state)
        if state != QMediaPlayer.StoppedState:
            return

        decibel = -self._one_shot_volume_adjustment
        logger.trace("Readjusting one-shot player volume by {}db", decibel)
        self.adjust_player_volume_by_decibel(self._one_shot_player, decibel)
        self._one_shot_volume_adjustment = 0

        logger.trace("One-shot player stopped, resuming loop player")
        self._loop_player.play()

    def play_sound(self, sound: Sound) -> None:
        if sound.playback_threshold > self.threshold:
            logger.trace("Ignoring sound {!r} because of threshold", sound)
            return

        if sound.loop is Loop.Start:
            self._loop_sound = sound
            # New looping sound, rebuild playlist
            self._loop_playlist.clear()
            for file in sound.files:
                media = QUrl.fromLocalFile(file.file_name)
                self._loop_playlist.addMedia(media)

            # Select file based on weight and set the matching playlist index
            weights = [file.weight for file in sound.files]
            file = random.choices(sound.files, weights)[0]
            index = sound.files.index(file)
            self._loop_playlist.setCurrentIndex(index)

            logger.trace("Adjusting loop player volume by {}db",
                         file.volume_adjustment)
            self._loop_volume_adjustment = self.adjust_player_volume_by_decibel(
                self._loop_player, file.volume_adjustment)
            logger.trace("Adjusted One-shot player volume by {}db",
                         self._loop_volume_adjustment)
            self._loop_player.play()
            logger.trace(
                "Loop player playing file: {!r} at playlist index: {}",
                file,
                index,
            )
            return
        if sound.loop is Loop.Stop:
            logger.trace("Stopping loop player")
            self._loop_sound = None
            self._loop_playlist.clear()
            self._loop_player.stop()
        else:
            logger.trace("Pausing loop player for one-shot sound")
            self._loop_player.pause()

        file = random.choices(sound.files,
                              [file.weight for file in sound.files])[0]
        media = QUrl.fromLocalFile(file.file_name)
        self._one_shot_player.setMedia(media)
        self._one_shot_volume_adjustment = self.adjust_player_volume_by_decibel(
            self._one_shot_player, file.volume_adjustment)
        logger.trace("Adjusted one-shot player volume by {}db",
                     self._one_shot_volume_adjustment)
        self._one_shot_player.play()
        logger.trace("One-shot player playing file: {!r}", file)

    def set_player_volumes(self, volume: Number) -> None:
        volume = round(volume)
        self._loop_player.setVolume(volume)
        self._one_shot_player.setVolume(volume)

    # noinspection PyMethodMayBeStatic
    def adjust_player_volume_by_decibel(self, player: QMediaPlayer,
                                        decibel: Number) -> Number:
        original_volume = player.volume()
        target_volume = round(
            add_decibel_to_linear_volume(original_volume, decibel))
        player.setVolume(target_volume)

        # Return clamped volume difference, so increasing linear volume 100 by n > 1 db
        # returns 0
        return player.volume() - original_volume

    def set_threshold(self, threshold: PlaybackThreshold) -> None:
        logger.trace("Setting channel threshold: {!r}", threshold)
        self.threshold = threshold

        if not self._loop_sound:
            return

        if self._loop_sound.playback_threshold > threshold:
            logger.trace("Stopping loop player, new threshold too low")
            self._loop_playlist.clear()
            self._loop_player.stop()
            return

        logger.trace("Loop player state: {!r}", self._loop_player.state())
        if (self._loop_sound.playback_threshold <= threshold
                and self._loop_player.state() == QMediaPlayer.StoppedState):
            logger.trace(
                "Replaying sound: {!r} in loop player from stopped state")
            self.play_sound(self._loop_sound)
예제 #2
0
class YoutubePlayer(QObject):

    titlesListChanged = Signal(list)

    def __init__(self,
                 titles: List[Title] = [],
                 widgetToPlay: QVideoWidget = None):
        QObject.__init__(self)

        self.__titles = titles
        self.__playlist = QMediaPlaylist(self)
        self.__player = QMediaPlayer(self)
        self.__videoWidget = widgetToPlay
        self.__player.setVideoOutput(self.__videoWidget)

        self.titlesListChanged.connect(self.resetPlayList)

    @property
    def titles(self):
        return self.__titles

    @titles.setter
    def titles(self, value):
        self.__titles = value
        self.titlesListChanged.emit(self.__titles)

    @Slot()
    def setTitles(self, titles: List[Title]):

        self.__titles = titles
        self.titlesListChanged.emit(self.__titles)

    @Slot()
    def resetPlayList(self, list_of_titles: List[Title]):
        self.__playlist.clear()

        for t in list_of_titles:
            url = t.link
            video = pafy.new(url)
            best = video.getbest()

            self.__playlist.addMedia(QMediaContent(QUrl(best.url)))

        self.__playlist.setCurrentIndex(0)
        self.__player.setPlaylist(self.__playlist)

    @Slot()
    def playVideo(self, index: int):

        self.__playlist.setCurrentIndex(index)
        self.__player.play()

    @Slot()
    def stopVideo(self):

        self.__player.stop()

    @Slot()
    def pauseVideo(self):
        if self.__player.state() == QMediaPlayer.PlayingState:
            self.__player.pause()
        else:
            self.__player.play()