mirror of
https://github.com/Syncplay/syncplay
synced 2025-01-19 05:20:55 +00:00
commit
663fc835ad
21
README.md
21
README.md
@ -18,7 +18,7 @@ Syncplay does not use video streaming or file sharing so each user must have the
|
||||
## Requirements
|
||||
Frozen Windows executables are available on the download page - https://github.com/Uriziel/syncplay/downloads
|
||||
|
||||
* On Windows: `Media Player Classic - Home Cinema (MPC-HC)` >= `1.6.4`.
|
||||
* On Windows: `Media Player Classic - Home Cinema (MPC-HC)` >= `1.6.4` or `mplayer2`.
|
||||
* On Linux: `mplayer2`. `MPlayer` >= `1.1` should be compatible, but is not supported.
|
||||
|
||||
### Python scripts (for those not using the frozen executable package)
|
||||
@ -33,9 +33,9 @@ If you are not using the frozen executable package then you will need the follow
|
||||
If you are using the frozen executable package available from the download page then you will not need to be able to run Python scripts.
|
||||
|
||||
## Supported players
|
||||
### mplayer2 on Linux
|
||||
### mplayer2 on Linux and Windows
|
||||
|
||||
On Linux `syncplay` acts as a front-end for mplayer2.
|
||||
On Linux and Windows `syncplay` acts as a front-end for mplayer2.
|
||||
To use it select "Open with..." in context menu and choose `Syncplay` or from command line: "syncplay video_filename". If you wish to pass more arguments to mplayer2 prepend them with -- argument, it's treated as the last argument for wrapper.
|
||||
|
||||
Default mplayer2 output is suppressed, but if mplayer2 quits with errors, those errors will be printed (at most 50 last lines).
|
||||
@ -48,19 +48,17 @@ On Windows simply running `syncplayClient.exe` opens a Syncplay command-line win
|
||||
|
||||
### Getting started with Syncplay on Windows
|
||||
|
||||
1. Ensure that you have the latest version of `Media Player Classic - Home Cinema (MPC-HC)` installed. The latest stable build is `1.6.4`.
|
||||
1. Ensure that you have the latest version of `Media Player Classic - Home Cinema (MPC-HC)` and/or `mplayer2` installed. The latest stable build of MPC-HC is `1.6.4`.
|
||||
|
||||
2. Download Syncplay frozen executable package from https://github.com/Uriziel/syncplay/downloads and extract to a folder of your choosing.
|
||||
2. Download Syncplay frozen executable package from the link provided in the topic of the #syncplay channel on irc.rizon.net and extract to a folder of your choosing.
|
||||
|
||||
3. If you are running your own server then open `syncplayServer.exe` (see "How to use the server", below).
|
||||
|
||||
4. Open `syncplayClient.exe` (or open the media file you wish to play with `syncplayClient.exe`, e.g. using "Open with").
|
||||
4. Open the media file you wish to play with `syncplayClient.exe` (e.g. using "Open with"). If you are using `MPC-HC`, you can alternatively open `syncplayClient.exe` directly and then load the file later.
|
||||
|
||||
5. Enter configuration settings (see "Configuration window", below). Ensure that you are on the same server and room as your fellow viewers.
|
||||
|
||||
6. If you don't have the file you want to play open then open it from within the MPC-HC instance initiated by Syncplay.
|
||||
|
||||
7. Playing, pausing and seeking from within the MPC-HC instance should now be synchronised with everyone else in the same 'room'.
|
||||
6. Playing, pausing and seeking from within the media player instance should now be synchronised with everyone else in the same 'room'.
|
||||
|
||||
### Getting started with Syncplay on Linux
|
||||
|
||||
@ -125,7 +123,9 @@ You can run `syncplayClient` with the following command-line switches to alter S
|
||||
|
||||
### Notification messages
|
||||
|
||||
* `Rewinded due to time difference with [user]` - This means that your media player ended up too far in front of the specified user and has jumped back to keep you in sync. This is usually because someone's computer isn't powerful enough to play the file smoothly. If someone is only a small amount in front then their playback rate will be reduced to 95% for a short amount of time to bring them back into sync.
|
||||
* `Rewinded due to time difference with [user]` - This means that your media player ended up too far in front of the specified user and has jumped back to help keep you in sync. This is usually because someone's computer isn't powerful enough to play the file smoothly - it might be helpful for them to close unnecessary applications.
|
||||
* `Slowing down due to time difference with [user]` - This means that your media player ended up too far in front of the specified user and has temporarily slowed down playback on your player to help keep you in sync. This is usually because someone's computer isn't powerful enough to play the file smoothly - it might be helpful for them to close unnecessary applications.
|
||||
* `Reverting speed back to normal` - Slowing down due to time difference with user has ended (see above).
|
||||
* `File you are playing appears to be different from [user]'s` - This means that the filename, size and/or duration of the file that the user is playing is different from the file that you are playing. This is for information only and is not an error.
|
||||
* `[User] has left` - This means that the user is no longer connected to the server. If room isolation is enabled on the server then this could also mean that the user moved to a different room.
|
||||
|
||||
@ -171,6 +171,7 @@ You might also be able to discuss your problem through Internet Relay Chat (IRC)
|
||||
1. Changing your system time while Syncplay is running confuses the sync. PROTIP: Don't do it.
|
||||
2. In MPC-HC the 'Remember File position' feature will not work as expected if you are using Syncplay. If you want to save/load the file position when using Syncplay then use MPC-HC's built in Favorites feature.
|
||||
3. Connecting to port 8999 is disallowed in some firewall configurations. Check your firewall settings if you are experiencing problems connecting to a server.
|
||||
4. Manually setting the playback rate may cause problems. Syncplay generally assumes a playback rate of 1.0 and in some instances sets the playback rate to help get everyone more in sync.
|
||||
|
||||
## Authors
|
||||
* *Concept and principal Syncplay developer* - Uriziel.
|
||||
|
@ -5,10 +5,10 @@ import time
|
||||
from twisted.internet.protocol import ClientFactory
|
||||
from twisted.internet import reactor, task
|
||||
from syncplay.protocols import SyncClientProtocol
|
||||
from syncplay import utils
|
||||
from syncplay import utils, constants
|
||||
|
||||
class SyncClientFactory(ClientFactory):
|
||||
def __init__(self, client, retry = 10):
|
||||
def __init__(self, client, retry = constants.RECONNECT_RETRIES):
|
||||
self._client = client
|
||||
self.retry = retry
|
||||
self._timesTried = 0
|
||||
@ -53,7 +53,7 @@ class SyncplayClient(object):
|
||||
self.userlist = SyncplayUserlist(self.ui, self)
|
||||
self._protocol = None
|
||||
if(args.room == None or args.room == ''):
|
||||
args.room = 'default'
|
||||
args.room = constants.DEFAULT_ROOM
|
||||
self.defaultRoom = args.room
|
||||
self.playerPositionBeforeLastSeek = 0.0
|
||||
self.setUsername(args.name)
|
||||
@ -94,7 +94,7 @@ class SyncplayClient(object):
|
||||
self._player = player
|
||||
self.scheduleAskPlayer()
|
||||
|
||||
def scheduleAskPlayer(self, when=0.1):
|
||||
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
||||
self._askPlayerTimer = task.LoopingCall(self.askPlayer)
|
||||
self._askPlayerTimer.start(when)
|
||||
|
||||
@ -106,7 +106,7 @@ class SyncplayClient(object):
|
||||
self.checkIfConnected()
|
||||
|
||||
def checkIfConnected(self):
|
||||
if(self._lastGlobalUpdate and self._protocol and time.time() - self._lastGlobalUpdate > 4.1):
|
||||
if(self._lastGlobalUpdate and self._protocol and time.time() - self._lastGlobalUpdate > constants.PROTOCOL_TIMEOUT):
|
||||
self._lastGlobalUpdate = None
|
||||
self.ui.showErrorMessage("Connection with server timed out")
|
||||
self._protocol.drop()
|
||||
@ -117,7 +117,7 @@ class SyncplayClient(object):
|
||||
pauseChange = self.getPlayerPaused() != paused and self.getGlobalPaused() != paused
|
||||
_playerDiff = abs(self.getPlayerPosition() - position)
|
||||
_globalDiff = abs(self.getGlobalPosition() - position)
|
||||
seeked = _playerDiff > 1 and _globalDiff > 1
|
||||
seeked = _playerDiff > constants.SEEK_BOUNDARY and _globalDiff > constants.SEEK_BOUNDARY
|
||||
return pauseChange, seeked
|
||||
|
||||
def updatePlayerStatus(self, paused, position):
|
||||
@ -182,12 +182,12 @@ class SyncplayClient(object):
|
||||
return madeChangeOnPlayer
|
||||
|
||||
def _slowDownToCoverTimeDifference(self, diff, setBy):
|
||||
if(1.5 < diff and not self._speedChanged):
|
||||
self._player.setSpeed(0.95)
|
||||
if(constants.SLOWDOWN_KICKIN_BOUNDARY < diff and not self._speedChanged):
|
||||
self._player.setSpeed(constants.SLOWDOWN_RATE)
|
||||
self._speedChanged = True
|
||||
message = "Slowing down due to time difference with <{}>".format(setBy)
|
||||
self.ui.showMessage(message)
|
||||
elif(self._speedChanged and diff < 0.1 ):
|
||||
elif(self._speedChanged and diff < constants.SLOWDOWN_RESET_BOUNDARY):
|
||||
self._player.setSpeed(1.00)
|
||||
self._speedChanged = False
|
||||
message = "Reverting speed back to normal"
|
||||
@ -363,7 +363,7 @@ class SyncplayUser(object):
|
||||
return False
|
||||
sameName = self.file['name'] == file_['name']
|
||||
sameSize = self.file['size'] == file_['size']
|
||||
sameDuration = int(self.file['duration']) - int(file_['duration']) < 1
|
||||
sameDuration = int(self.file['duration']) - int(file_['duration']) < constants.DIFFFERENT_DURATION_BOUNDARY
|
||||
return sameName and sameSize and sameDuration
|
||||
|
||||
def __lt__(self, other):
|
||||
|
43
syncplay/constants.py
Normal file
43
syncplay/constants.py
Normal file
@ -0,0 +1,43 @@
|
||||
DEFAULT_PORT = 8999
|
||||
MPC_OPEN_MAX_WAIT_TIME = 10
|
||||
MPC_LOCK_WAIT_TIME = 0.2
|
||||
OSD_DURATION = 3000
|
||||
MPC_OSD_POSITION = 2 #Right corner, 1 for left
|
||||
MPC_RETRY_WAIT_TIME = 0.01
|
||||
MPC_MAX_RETRIES = 30
|
||||
MPC_PAUSE_TOGGLE_DELAY = 0.05
|
||||
MPLAYER_OSD_LEVEL = 1
|
||||
MPLAYER_ANSWER_REGEX = "^ANS_([a-zA-Z_]+)=(.+)$"
|
||||
MPLAYER_SLAVE_ARGS = [ '-slave', '-msglevel', 'all=1:global=4']
|
||||
UI_COMMAND_REGEX = r"^(?P<command>[^\ ]+)(?:\ (?P<parameter>.+))?"
|
||||
UI_OFFSET_REGEX = r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d+(?:[^\d\.](?:\d+)){0,2}(?:\.(?:\d+))?)$"
|
||||
UI_SEEK_REGEX = r"^(?:s|seek)?\ ?(?P<sign>[+-])?(?P<time>\d+(?:[^\d\.](?:\d+)){0,2}(?:\.(?:\d+))?)$"
|
||||
UI_TIME_FORMAT = "[%X] "
|
||||
COMMANDS_UNDO = ["u", "undo", "revert"]
|
||||
COMMANDS_LIST = ["l", "list", "users"]
|
||||
COMMANDS_PAUSE = ["p", "play", "pause"]
|
||||
COMMANDS_ROOM = ["r", "room"]
|
||||
COMMANDS_HELP = ['help', 'h', '?', '/?', '\?']
|
||||
MPC_PATHS = [
|
||||
"C:\Program Files (x86)\MPC-HC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC-HC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC-HC\mpc-hc64.exe",
|
||||
"C:\Program Files\Media Player Classic - Home Cinema\mpc-hc.exe",
|
||||
"C:\Program Files\Media Player Classic - Home Cinema\mpc-hc64.exe",
|
||||
"C:\Program Files (x86)\Media Player Classic - Home Cinema\mpc-hc.exe",
|
||||
"C:\Program Files (x86)\K-Lite Codec Pack\Media Player Classic\mpc-hc.exe",
|
||||
"C:\Program Files\K-Lite Codec Pack\Media Player Classic\mpc-hc.exe",
|
||||
"C:\Program Files (x86)\Combined Community Codec Pack\MPC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC HomeCinema (x64)\mpc-hc64.exe",
|
||||
]
|
||||
RECONNECT_RETRIES = 10
|
||||
DEFAULT_ROOM = 'default'
|
||||
PLAYER_ASK_DELAY = 0.1
|
||||
PROTOCOL_TIMEOUT = 5
|
||||
SEEK_BOUNDARY = 1
|
||||
SLOWDOWN_RATE = 0.95
|
||||
SLOWDOWN_KICKIN_BOUNDARY = 1.5
|
||||
SLOWDOWN_RESET_BOUNDARY = 0.1
|
||||
DIFFFERENT_DURATION_BOUNDARY = 1
|
||||
PING_MOVING_AVERAGE_WEIGHT = 0.85
|
||||
PARSE_TIME_REGEX = r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$'
|
16
syncplay/messages.py
Normal file
16
syncplay/messages.py
Normal file
@ -0,0 +1,16 @@
|
||||
en = {
|
||||
"connecting" : "Attempting to connect to {}:{}"
|
||||
}
|
||||
|
||||
messages = {
|
||||
"en": en
|
||||
}
|
||||
|
||||
def getMessage(locale, type_):
|
||||
if(messages.has_key(locale)):
|
||||
if(messages[locale].has_key(type_)):
|
||||
return messages[locale][type_]
|
||||
if(messages["en"].has_key(type_)):
|
||||
return messages["en"][type_]
|
||||
else:
|
||||
raise KeyError()
|
@ -7,7 +7,7 @@ from functools import wraps
|
||||
from syncplay.players.basePlayer import BasePlayer
|
||||
import re
|
||||
from syncplay.utils import retry
|
||||
|
||||
from syncplay import constants
|
||||
|
||||
class MpcHcApi:
|
||||
def __init__(self):
|
||||
@ -31,7 +31,7 @@ class MpcHcApi:
|
||||
def waitForFileStateReady(f): #@NoSelf
|
||||
@wraps(f)
|
||||
def wrapper(self, *args, **kwds):
|
||||
if(not self.__locks.fileReady.wait(0.2)):
|
||||
if(not self.__locks.fileReady.wait(constants.MPC_LOCK_WAIT_TIME)):
|
||||
raise self.PlayerNotReadyException()
|
||||
return f(self, *args, **kwds)
|
||||
return wrapper
|
||||
@ -39,7 +39,7 @@ class MpcHcApi:
|
||||
def startMpc(self, path, args=()):
|
||||
args = "%s /slave %s" % (" ".join(args), str(self.__listener.hwnd))
|
||||
win32api.ShellExecute(0, "open", path, args, None, 1)
|
||||
if(not self.__locks.mpcStart.wait(10)):
|
||||
if(not self.__locks.mpcStart.wait(constants.MPC_OPEN_MAX_WAIT_TIME)):
|
||||
raise self.NoSlaveDetectedException("Unable to start MPC in slave mode!")
|
||||
self.__mpcExistenceChecking.start()
|
||||
|
||||
@ -76,7 +76,7 @@ class MpcHcApi:
|
||||
def setSpeed(self, rate):
|
||||
self.__listener.SendCommand(self.CMD_SETSPEED, unicode(rate))
|
||||
|
||||
def sendOsd(self, message, MsgPos=2, DurationMs=3000):
|
||||
def sendOsd(self, message, MsgPos=constants.MPC_OSD_POSITION, DurationMs=constants.OSD_DURATION):
|
||||
class __OSDDATASTRUCT(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('nMsgPos', ctypes.c_int32),
|
||||
@ -300,11 +300,6 @@ class MpcHcApi:
|
||||
('lpData', ctypes.c_void_p)
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class MPCHCAPIPlayer(BasePlayer):
|
||||
speedSupported = False
|
||||
|
||||
@ -383,9 +378,9 @@ class MPCHCAPIPlayer(BasePlayer):
|
||||
self._mpcApi.openFile(filePath)
|
||||
|
||||
def displayMessage(self, message):
|
||||
self._mpcApi.sendOsd(message, 2, 3000)
|
||||
self._mpcApi.sendOsd(message)
|
||||
|
||||
@retry(MpcHcApi.PlayerNotReadyException, 30, 0.01, 1)
|
||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||
def setPaused(self, value):
|
||||
if self.__switchPauseCalls:
|
||||
value = not value
|
||||
@ -394,17 +389,17 @@ class MPCHCAPIPlayer(BasePlayer):
|
||||
else:
|
||||
self._mpcApi.unpause()
|
||||
|
||||
@retry(MpcHcApi.PlayerNotReadyException, 30, 0.01, 1)
|
||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||
def setPosition(self, value):
|
||||
self._mpcApi.seek(value)
|
||||
|
||||
def __getPosition(self):
|
||||
self.__positionUpdate.clear()
|
||||
self._mpcApi.askForCurrentPosition()
|
||||
self.__positionUpdate.wait(0.2)
|
||||
self.__positionUpdate.wait(constants.MPC_LOCK_WAIT_TIME)
|
||||
return self._mpcApi.lastFilePosition
|
||||
|
||||
@retry(MpcHcApi.PlayerNotReadyException, 30, 0.01, 1)
|
||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||
def askForStatus(self):
|
||||
if(self.__preventAsking.wait(0) and self.__fileUpdate.acquire(0)):
|
||||
self.__fileUpdate.release()
|
||||
@ -421,14 +416,14 @@ class MPCHCAPIPlayer(BasePlayer):
|
||||
self.__client.updatePlayerStatus(self.__client.getGlobalPaused(), self.__client.getGlobalPosition())
|
||||
|
||||
def __forcePause(self):
|
||||
for _ in xrange(30):
|
||||
for _ in xrange(constants.MPC_MAX_RETRIES):
|
||||
self.setPaused(True)
|
||||
time.sleep(0.01)
|
||||
time.sleep(constants.MPC_RETRY_WAIT_TIME)
|
||||
|
||||
def __refreshMpcPlayState(self):
|
||||
for _ in xrange(2):
|
||||
self._mpcApi.playPause()
|
||||
time.sleep(0.05)
|
||||
time.sleep(constants.MPC_PAUSE_TOGGLE_DELAY)
|
||||
|
||||
def _setPausedAccordinglyToServer(self):
|
||||
self.__forcePause()
|
||||
@ -438,7 +433,7 @@ class MPCHCAPIPlayer(BasePlayer):
|
||||
if(self._mpcApi.isPaused() <> self.__client.getGlobalPaused()):
|
||||
self.__setUpStateForNewlyOpenedFile()
|
||||
|
||||
@retry(MpcHcApi.PlayerNotReadyException, 30, 0.1, 1)
|
||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||
def __setUpStateForNewlyOpenedFile(self):
|
||||
self._setPausedAccordinglyToServer()
|
||||
self._mpcApi.seek(self.__client.getGlobalPosition())
|
||||
|
@ -2,10 +2,11 @@ import subprocess
|
||||
import re
|
||||
import threading
|
||||
from syncplay.players.basePlayer import BasePlayer
|
||||
from syncplay import constants
|
||||
|
||||
class MplayerPlayer(BasePlayer):
|
||||
speedSupported = True
|
||||
RE_ANSWER = re.compile('^ANS_([a-zA-Z_]+)=(.+)$')
|
||||
RE_ANSWER = re.compile(constants.MPLAYER_ANSWER_REGEX)
|
||||
def __init__(self, client, playerPath, filePath, args):
|
||||
self._client = client
|
||||
self._paused = None
|
||||
@ -71,7 +72,7 @@ class MplayerPlayer(BasePlayer):
|
||||
self._listener.sendLine("get_property {}".format(property_))
|
||||
|
||||
def displayMessage(self, message):
|
||||
self._listener.sendLine('osd_show_text "{!s}" {} {}'.format(message, 3000, 1))
|
||||
self._listener.sendLine('osd_show_text "{!s}" {} {}'.format(message, constants.OSD_DURATION, constants.MPLAYER_OSD_LEVEL))
|
||||
|
||||
def setSpeed(self, value):
|
||||
self._setProperty('speed', "{:.2f}".format(value))
|
||||
@ -142,7 +143,8 @@ class MplayerPlayer(BasePlayer):
|
||||
self.__playerController = playerController
|
||||
if(not filePath):
|
||||
raise ValueError
|
||||
call = [playerPath, filePath, '-slave', '-msglevel', 'all=1:global=4']
|
||||
call = [playerPath, filePath]
|
||||
call.extend(constants.MPLAYER_SLAVE_ARGS)
|
||||
if(args):
|
||||
call.extend(args)
|
||||
self.__process = subprocess.Popen(call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
@ -6,6 +6,7 @@ from twisted.internet.protocol import Factory
|
||||
import syncplay
|
||||
from syncplay.protocols import SyncServerProtocol
|
||||
import time
|
||||
from syncplay import constants
|
||||
|
||||
class SyncFactory(Factory):
|
||||
def __init__(self, password = ''):
|
||||
@ -87,7 +88,7 @@ class SyncFactory(Factory):
|
||||
watcher.paused = paused
|
||||
watcher.position = position
|
||||
watcherProtocol.sendState(position, paused, doSeek, setBy, senderLatency, watcher.latency, forcedUpdate)
|
||||
if(time.time() - watcher.lastUpdate > 4.1):
|
||||
if(time.time() - watcher.lastUpdate > constants.PROTOCOL_TIMEOUT):
|
||||
watcherProtocol.drop()
|
||||
self.removeWatcher(watcherProtocol)
|
||||
|
||||
@ -95,7 +96,7 @@ class SyncFactory(Factory):
|
||||
if (latencyCalculation):
|
||||
ping = (time.time() - latencyCalculation) / 2
|
||||
if (watcher.latency):
|
||||
watcher.latency = watcher.latency * (0.85) + ping * (0.15) #Exponential moving average
|
||||
watcher.latency = watcher.latency * (constants.PING_MOVING_AVERAGE_WEIGHT) + ping * (1-constants.PING_MOVING_AVERAGE_WEIGHT) #Exponential moving average
|
||||
else:
|
||||
watcher.latency = ping
|
||||
|
||||
@ -190,7 +191,7 @@ class SyncFactory(Factory):
|
||||
def _checkUsers(self):
|
||||
for room in self._rooms.itervalues():
|
||||
for watcher in room.itervalues():
|
||||
if(time.time() - watcher.lastUpdate > 4.1):
|
||||
if(time.time() - watcher.lastUpdate > constants.PROTOCOL_TIMEOUT):
|
||||
watcher.watcherProtocol.drop()
|
||||
self.removeWatcher(watcher.watcherProtocol)
|
||||
self._checkUsers() #restart
|
||||
|
@ -2,6 +2,7 @@ import ConfigParser
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from syncplay import constants
|
||||
|
||||
class InvalidConfigValue(Exception):
|
||||
def __init__(self, message):
|
||||
@ -153,7 +154,7 @@ class ConfigurationGetter(object):
|
||||
self._args.host, port = self._args.host.split(':', 1)
|
||||
self._args.port = int(port)
|
||||
elif("port" not in self._args):
|
||||
self._args.port = 8999
|
||||
self._args.port = constants.DEFAULT_PORT
|
||||
|
||||
def setConfiguration(self, args):
|
||||
self._args = args
|
||||
@ -171,7 +172,7 @@ class ServerConfigurationGetter(ConfigurationGetter):
|
||||
self._prepareArgParser()
|
||||
self._args = self._parser.parse_args()
|
||||
if(self._args.port == None):
|
||||
self._args.port = 8999
|
||||
self._args.port = constants.DEFAULT_PORT
|
||||
return self._args
|
||||
|
||||
def _prepareArgParser(self):
|
||||
|
@ -1,5 +1,6 @@
|
||||
import pygtk
|
||||
import os
|
||||
from syncplay import constants
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
gtk.set_interactive(False)
|
||||
@ -51,18 +52,7 @@ class GuiConfiguration:
|
||||
|
||||
def _tryToFillUpMpcPath(self):
|
||||
if(self.args.player_path == None):
|
||||
paths = ["C:\Program Files (x86)\MPC-HC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC-HC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC-HC\mpc-hc64.exe",
|
||||
"C:\Program Files\Media Player Classic - Home Cinema\mpc-hc.exe",
|
||||
"C:\Program Files\Media Player Classic - Home Cinema\mpc-hc64.exe",
|
||||
"C:\Program Files (x86)\Media Player Classic - Home Cinema\mpc-hc.exe",
|
||||
"C:\Program Files (x86)\K-Lite Codec Pack\Media Player Classic\mpc-hc.exe",
|
||||
"C:\Program Files\K-Lite Codec Pack\Media Player Classic\mpc-hc.exe",
|
||||
"C:\Program Files (x86)\Combined Community Codec Pack\MPC\mpc-hc.exe",
|
||||
"C:\Program Files\MPC HomeCinema (x64)\mpc-hc64.exe",
|
||||
]
|
||||
for path in paths:
|
||||
for path in constants.MPC_PATHS:
|
||||
if(os.path.isfile(path)):
|
||||
self.args.player_path = path
|
||||
return
|
||||
|
@ -5,7 +5,7 @@ import syncplay
|
||||
import os
|
||||
import re
|
||||
from syncplay import utils
|
||||
|
||||
from syncplay import constants
|
||||
class ConsoleUI(threading.Thread):
|
||||
def __init__(self):
|
||||
self.promptMode = threading.Event()
|
||||
@ -41,7 +41,7 @@ class ConsoleUI(threading.Thread):
|
||||
if(noTimestamp):
|
||||
print(message)
|
||||
else:
|
||||
print(time.strftime("[%X] ", time.localtime()) + message)
|
||||
print(time.strftime(constants.UI_TIME_FORMAT, time.localtime()) + message)
|
||||
|
||||
def showDebugMessage(self, message):
|
||||
print(message)
|
||||
@ -59,8 +59,8 @@ class ConsoleUI(threading.Thread):
|
||||
return None
|
||||
|
||||
def _tryAdvancedCommands(self, data):
|
||||
o = re.match(r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d+(?:[^\d\.](?:\d+)){0,2}(?:\.(?:\d+))?)$", data)
|
||||
s = re.match(r"^(?:s|seek)?\ ?(?P<sign>[+-])?(?P<time>\d+(?:[^\d\.](?:\d+)){0,2}(?:\.(?:\d+))?)$", data)
|
||||
o = re.match(constants.UI_OFFSET_REGEX, data)
|
||||
s = re.match(constants.UI_SEEK_REGEX, data)
|
||||
if(o):
|
||||
sign = self._extractSign(o.group('sign'))
|
||||
t = utils.parseTime(o.group('time'))
|
||||
@ -84,18 +84,18 @@ class ConsoleUI(threading.Thread):
|
||||
return False
|
||||
|
||||
def _executeCommand(self, data):
|
||||
command = re.match(r"^(?P<command>[^\ ]+)(?:\ (?P<parameter>.+))?", data)
|
||||
command = re.match(constants.UI_COMMAND_REGEX, data)
|
||||
if(not command):
|
||||
return
|
||||
if(command.group('command') in ["u", "undo", "revert"]):
|
||||
if(command.group('command') in constants.COMMANDS_UNDO):
|
||||
tmp_pos = self._syncplayClient.getPlayerPosition()
|
||||
self._syncplayClient.setPosition(self._syncplayClient.playerPositionBeforeLastSeek)
|
||||
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
||||
elif (command.group('command') in ["l", "list", "users"]):
|
||||
elif (command.group('command') in constants.COMMANDS_LIST):
|
||||
self._syncplayClient.getUserList()
|
||||
elif (command.group('command') in ["p", "play", "pause"]):
|
||||
elif (command.group('command') in constants.COMMANDS_PAUSE):
|
||||
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
||||
elif (command.group('command') in ["r", "room"]):
|
||||
elif (command.group('command') in constants.COMMANDS_ROOM):
|
||||
room = command.group('parameter')
|
||||
if room == None:
|
||||
if self._syncplayClient.userlist.currentUser.file:
|
||||
@ -108,14 +108,14 @@ class ConsoleUI(threading.Thread):
|
||||
else:
|
||||
if(self._tryAdvancedCommands(data)):
|
||||
return
|
||||
if (command.group('command') not in ['help', 'h', '?', '/?', '\?']):
|
||||
if (command.group('command') not in constants.COMMANDS_HELP):
|
||||
self.showMessage("Unrecognized command")
|
||||
self.showMessage("Available commands:", True)
|
||||
self.showMessage("\tr [name] - change room", True)
|
||||
self.showMessage("\tl - show user list", True)
|
||||
self.showMessage("\tu - undo last seek", True)
|
||||
self.showMessage("\tp - toggle pause", True)
|
||||
self.showMessage("\t[s][+-][time] - seek to the given value of time, if + or - is not specified it's absolute time in seconds or min:sec", True)
|
||||
self.showMessage("\t[s][+-]time - seek to the given value of time, if + or - is not specified it's absolute time in seconds or min:sec", True)
|
||||
self.showMessage("\th - this help", True)
|
||||
self.showMessage("Syncplay version: {}".format(syncplay.version), True)
|
||||
self.showMessage("More info available at: {}".format(syncplay.projectURL), True)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import time
|
||||
import re
|
||||
import datetime
|
||||
from syncplay import constants
|
||||
|
||||
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||
"""Retry calling the decorated function using an exponential backoff.
|
||||
@ -44,7 +45,7 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||
return deco_retry
|
||||
|
||||
def parseTime(timeStr):
|
||||
regex = re.compile(r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$')
|
||||
regex = re.compile(constants.PARSE_TIME_REGEX)
|
||||
parts = regex.match(timeStr)
|
||||
if not parts:
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user