castero/players/mpvplayer.py

Summary

Maintainability
A
0 mins
Test Coverage
B
84%
from castero.player import Player, PlayerDependencyError
from castero import helpers, constants


class MPVPlayer(Player):
    """Interface for the mpv media player."""

    NAME = "mpv"

    def __init__(self, title, path, episode) -> None:
        super().__init__(title, path, episode)

        import mpv

        self.mpv = mpv

    @staticmethod
    def check_dependencies():
        """Checks whether dependencies are met for playing a player."""
        try:
            import mpv

            mpv.MPV()
        except (ImportError, NameError, OSError, AttributeError):
            raise PlayerDependencyError(
                "Dependency mpv not found, which is required for playing" " media files"
            )

    def _create_player(self) -> None:
        """Creates the player object while making sure it is a valid file."""
        self._player = self.mpv.MPV()
        self._player.vid = False
        self._player.pause = False

        self._duration = 5

    def play(self) -> None:
        """Plays the media."""
        if self._player is None:
            self._create_player()

        self._player.play(self._path)

        self._player.pause = False
        self._state = 1

    def play_from(self, seconds) -> None:
        """play media from point."""
        if self._player is None:
            self._create_player()

        timestamp = helpers.seconds_to_time(seconds)
        self._player.start = timestamp

        self.play()

    def stop(self) -> None:
        """Stops the media."""
        if self._player is not None:
            self._player.terminate()
            self._state = 0

    def pause(self) -> None:
        """Pauses the media."""
        if self._player is not None:
            self._player.pause = True
            self._state = 2

    def seek(self, direction, amount) -> None:
        """Seek forward or backward in the media."""
        assert direction == 1 or direction == -1
        if self._player is not None:
            self._player.seek(direction * amount)

    def set_rate(self, rate) -> None:
        """Set the playback speed."""
        if self._player is not None:
            self._player.speed = rate

    def set_volume(self, volume) -> None:
        """Set the player volume."""
        if self._player is not None:
            self._player.volume = volume

    @property
    def duration(self) -> int:
        """int: the duration of the player"""
        result = 0
        if self._player is not None:
            d = self._player.duration
            result = 5000 if d is None else d * constants.MILLISECONDS_IN_SECOND
        return result

    @property
    def volume(self) -> int:
        """int: the volume of the player"""
        if self._player is not None:
            return self._player.volume

    @property
    def time(self) -> int:
        """int: the current time of the player"""
        if self._player is not None:
            t = self._player.time_pos
            return 0 if t is None else t * constants.MILLISECONDS_IN_SECOND

    @property
    def time_str(self) -> str:
        """str: the formatted time and duration of the player"""
        result = "00:00:00/00:00:00"
        if self._player is not None:
            time_seconds = int(self.time / constants.MILLISECONDS_IN_SECOND)
            length_seconds = int(self.duration / constants.MILLISECONDS_IN_SECOND)
            t = helpers.seconds_to_time(time_seconds)
            d = helpers.seconds_to_time(length_seconds)
            result = "%s/%s" % (t, d)
        return result