diff --git a/syncplay/constants.py b/syncplay/constants.py index 98c2743..a506fe7 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -91,6 +91,7 @@ MPC_RETRY_WAIT_TIME = 0.01 MPC_MAX_RETRIES = 30 MPC_PAUSE_TOGGLE_DELAY = 0.05 MPV_NEWFILE_IGNORE_TIME = 1 +MPV_LOCK_WAIT_TIME = 0.2 VLC_OPEN_MAX_WAIT_TIME = 15 VLC_MIN_PORT = 10000 VLC_MAX_PORT = 55000 diff --git a/syncplay/players/mplayer.py b/syncplay/players/mplayer.py index efee9fc..03b1ea2 100644 --- a/syncplay/players/mplayer.py +++ b/syncplay/players/mplayer.py @@ -25,7 +25,6 @@ class MplayerPlayer(BasePlayer): self.quitReason = None self.lastLoadedTime = None self.fileLoaded = False - self.lastResetTime = None try: self._listener = self.__Listener(self, playerPath, filePath, args) except ValueError: @@ -93,8 +92,7 @@ class MplayerPlayer(BasePlayer): self._listener.sendLine(u'loadfile {}'.format(self._quoteArg(filePath))) def openFile(self, filePath, resetPosition=False): - if resetPosition: - self.lastResetTime = time.time() + self._filepath = filePath self._loadFile(filePath) self._onFileUpdate() if self._paused != self._client.getGlobalPaused(): @@ -135,9 +133,6 @@ class MplayerPlayer(BasePlayer): def _fileIsLoaded(self): return True - def _clearFileLoaded(self): - pass - def _handleUnknownLine(self, line): pass diff --git a/syncplay/players/mpv.py b/syncplay/players/mpv.py index fcf36a6..6f8d277 100644 --- a/syncplay/players/mpv.py +++ b/syncplay/players/mpv.py @@ -6,130 +6,22 @@ from syncplay import constants import os, sys, time class MpvPlayer(MplayerPlayer): - POSITION_QUERY = 'time-pos' - OSD_QUERY = 'show_text' RE_VERSION = re.compile('.*mpv (\d)\.(\d)\.\d.*') - def _setProperty(self, property_, value): - self._listener.sendLine("no-osd set {} {}".format(property_, value)) - - def setPaused(self, value): - if self._paused <> value: - self._paused = not self._paused - self._listener.sendLine('cycle pause') - - def _storePosition(self, value): - if self._recentlyReset(): - self._position = 0 - elif self._fileIsLoaded(): - self._position = value - else: - self._position = self._client.getGlobalPosition() - - def _storePauseState(self, value): - if self._fileIsLoaded(): - self._paused = value - else: - self._paused = self._client.getGlobalPaused() - - def _onFileUpdate(self): - if not constants.MPV_NEW_VERSION: - oldFilename = self._filename - oldLength = self._duration - oldFilepath = self._filepath - self._fileUpdateClearEvents() - self._getFilename() - self._getLength() - self._getFilepath() - self._fileUpdateWaitEvents() - if (self._filename != oldFilename) or (self._duration != oldLength) or (self._filepath != oldFilepath): - self._client.updateFile(self._filename, self._duration, self._filepath) - - def _clearFileLoaded(self): - self.fileLoaded = False - self.lastLoadedTime = None - - def _loadFile(self, filePath): - if constants.MPV_NEW_VERSION: - self._clearFileLoaded() - self._listener.sendLine(u'loadfile {}'.format(self._quoteArg(filePath))) - - def openFile(self, filePath, resetPosition=False): - if resetPosition: - self.lastResetTime = time.time() - self._loadFile(filePath) - if self._paused != self._client.getGlobalPaused(): - self.setPaused(self._client.getGlobalPaused()) - self.setPosition(self._client.getGlobalPosition()) - - def _handleUnknownLine(self, line): - if "Error parsing option" in line or "Error parsing commandline option" in line: - self.quitReason = getMessage("mpv-version-error") - - elif "Could not open pipe at '/dev/stdin'" in line: - self.reactor.callFromThread(self._client.ui.showErrorMessage, getMessage("mpv-version-error"), True) - self.drop() - - elif line == "": - self._clearFileLoaded() - - elif line == "": - self._onMPVFileUpdate() - - elif "Failed to get value of property" in line: - if "filename" in line: - self._getFilename() - elif "length" in line: - self._getLength() - elif "path" in line: - self._getFilepath() - elif "time-pos" in line: - self.setPosition(self._client.getGlobalPosition()) - self._positionAsk.set() - - elif "Playing:" in line: - if constants.MPV_NEW_VERSION: - self._clearFileLoaded() - else: - self.fileLoaded = True - if not self._recentlyReset(): - self._onMPVFileUpdate() - self.reactor.callFromThread(self._onFileUpdate) - - def _recentlyReset(self): - if not self.lastResetTime: - return False - elif time.time() < self.lastResetTime + constants.MPV_NEWFILE_IGNORE_TIME: - return True - else: - return False - - def _onMPVFileUpdate(self): - self.fileLoaded = True - self.lastLoadedTime = time.time() - self.reactor.callFromThread(self._client.updateFile, self._filename, self._duration, self._filepath) - if not (self._recentlyReset()): - self.reactor.callFromThread(self.setPosition, self._client.getGlobalPosition()) - if self._paused != self._client.getGlobalPaused(): - self.reactor.callFromThread(self._client.getGlobalPaused) - - def _fileIsLoaded(self): - if self.fileLoaded == True and self.lastLoadedTime != None and time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME): - return True - else: - return False - @staticmethod def run(client, playerPath, filePath, args): - return MpvPlayer(client, MpvPlayer.getExpandedPath(playerPath), filePath, args) - - @staticmethod - def getStartupArgs(path): try: - ver = MpvPlayer.RE_VERSION.search(subprocess.check_output([path, '--version'])) + ver = MpvPlayer.RE_VERSION.search(subprocess.check_output([playerPath, '--version'])) except: ver = None constants.MPV_NEW_VERSION = ver is None or int(ver.group(1)) > 0 or int(ver.group(2)) >= 5 + if constants.MPV_NEW_VERSION: + return NewMpvPlayer(client, MpvPlayer.getExpandedPath(playerPath), filePath, args) + else: + return OldMpvPlayer(client, MpvPlayer.getExpandedPath(playerPath), filePath, args) + + @staticmethod + def getStartupArgs(path): args = constants.MPV_SLAVE_ARGS if constants.MPV_NEW_VERSION or sys.platform.startswith('win'): args.extend(constants.MPV_SLAVE_ARGS_NEW) @@ -173,3 +65,112 @@ class MpvPlayer(MplayerPlayer): @staticmethod def getIconPath(path): return constants.MPV_ICONPATH + +class OldMpvPlayer(MpvPlayer): + POSITION_QUERY = 'time-pos' + OSD_QUERY = 'show_text' + + def _setProperty(self, property_, value): + self._listener.sendLine("no-osd set {} {}".format(property_, value)) + + def setPaused(self, value): + if self._paused <> value: + self._paused = not self._paused + self._listener.sendLine('cycle pause') + + def mpvVersionErrorCheck(self, line): + if "Error parsing option" in line or "Error parsing commandline option" in line: + self.quitReason = getMessage("mpv-version-error") + + elif "Could not open pipe at '/dev/stdin'" in line: + self.reactor.callFromThread(self._client.ui.showErrorMessage, getMessage("mpv-version-error"), True) + self.drop() + + def _handleUnknownLine(self, line): + self.mpvVersionErrorCheck(line) + if "Playing: " in line: + newpath = line[9:] + oldpath = self._filepath + if newpath != oldpath and oldpath is not None: + self.reactor.callFromThread(self._onFileUpdate) + if self._paused != self._client.getGlobalPaused(): + self.setPaused(self._client.getGlobalPaused()) + self.setPosition(self._client.getGlobalPosition()) + +class NewMpvPlayer(OldMpvPlayer): + lastResetTime = None + + def _storePosition(self, value): + if self._recentlyReset(): + self._position = 0 + elif self._fileIsLoaded(): + self._position = value + else: + self._position = self._client.getGlobalPosition() + + def _storePauseState(self, value): + if self._fileIsLoaded(): + self._paused = value + else: + self._paused = self._client.getGlobalPaused() + + def askForStatus(self): + self._positionAsk.clear() + self._pausedAsk.clear() + self._getPaused() + self._getPosition() + self._positionAsk.wait(constants.MPV_LOCK_WAIT_TIME) + self._pausedAsk.wait(constants.MPV_LOCK_WAIT_TIME) + self._client.updatePlayerStatus(self._paused, self._position) + + def _preparePlayer(self): + self.setPaused(True) + self.reactor.callLater(0, self._client.initPlayer, self) + + def _clearFileLoaded(self): + self.fileLoaded = False + self.lastLoadedTime = None + + def _loadFile(self, filePath): + self._clearFileLoaded() + self._listener.sendLine(u'loadfile {}'.format(self._quoteArg(filePath))) + + def openFile(self, filePath, resetPosition=False): + if resetPosition: + self.lastResetTime = time.time() + self._loadFile(filePath) + if self._paused != self._client.getGlobalPaused(): + self.setPaused(self._client.getGlobalPaused()) + self.setPosition(self._client.getGlobalPosition()) + + def _handleUnknownLine(self, line): + self.mpvVersionErrorCheck(line) + + if line == "" or "Playing:" in line: + self._clearFileLoaded() + + elif line == "": + self._onFileUpdate() + + def _recentlyReset(self): + if not self.lastResetTime: + return False + elif time.time() < self.lastResetTime + constants.MPV_NEWFILE_IGNORE_TIME: + return True + else: + return False + + def _onFileUpdate(self): + self.fileLoaded = True + self.lastLoadedTime = time.time() + self.reactor.callFromThread(self._client.updateFile, self._filename, self._duration, self._filepath) + if not (self._recentlyReset()): + self.reactor.callFromThread(self.setPosition, self._client.getGlobalPosition()) + if self._paused != self._client.getGlobalPaused(): + self.reactor.callFromThread(self._client.getGlobalPaused) + + def _fileIsLoaded(self): + if self.fileLoaded == True and self.lastLoadedTime != None and time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME): + return True + else: + return False \ No newline at end of file