syncplay/syncplay/ui/consoleUI.py
Florian Badie b09fb90b34
Console improvements (#327), including work from #316 and #319
* add videos to playlist from chat

* add urls to playlist

* add files in media directory to playlist

* add commands to show the playlist and select an index

* add command to delete files from the playlist

* show selected index in playlist

* fix adding files with queue command in GUI mode

* start indexing the playlist at 1

or at least that's what it would look like to the user

* start all commands related to playlist with `q`

Co-authored-by: kiscs <csandras05@gmail.com>
2020-09-13 16:45:38 +01:00

253 lines
10 KiB
Python
Executable File

import re
import sys
import threading
import time
import os
import syncplay
from syncplay import constants
from syncplay import utils
from syncplay.messages import getMessage
from syncplay.utils import formatTime, isURL
class ConsoleUI(threading.Thread):
def __init__(self):
self.promptMode = threading.Event()
self.PromptResult = ""
self.promptMode.set()
self._syncplayClient = None
threading.Thread.__init__(self, name="ConsoleUI")
def addClient(self, client):
self._syncplayClient = client
def addFileToPlaylist(self, file):
if not isURL(file):
if not self._syncplayClient.fileSwitch.findFilepath(file):
print(f"{file} is not in any media directory")
return
self._syncplayClient.playlist.addToPlaylist(file)
def drop(self):
pass
def setPlaylist(self, newPlaylist, newIndexFilename=None):
pass
def setPlaylistIndexFilename(self, filename):
pass
def run(self):
try:
while True:
data = input()
data = data.rstrip('\n\r')
if not self.promptMode.isSet():
self.PromptResult = data
self.promptMode.set()
elif self._syncplayClient:
self.executeCommand(data)
except EOFError:
pass
def updateRoomName(self, room=""):
pass
def updateAutoPlayState(self, newState):
pass
def promptFor(self, prompt=">", message=""):
if message != "":
print(message)
self.promptMode.clear()
print(prompt, end='')
self.promptMode.wait()
return self.PromptResult
def showUserList(self, currentUser, rooms):
for room in rooms:
message = "In room '{}':".format(room)
self.showMessage(message, True)
for user in rooms[room]:
userflags = ""
if user.isController():
userflags += "({}) ".format(getMessage("controller-userlist-userflag"))
if user.isReady():
userflags += "({}) ".format(getMessage("ready-userlist-userflag"))
username = userflags + "*<{}>*".format(user.username) if user == currentUser else userflags + "<{}>".format(user.username)
if user.file:
message = getMessage("userlist-playing-notification").format(username)
self.showMessage(message, True)
message = " {}: '{}' ({})".format(getMessage("userlist-file-notification"), user.file['name'], formatTime(user.file['duration']))
if currentUser.file:
if user.file['name'] == currentUser.file['name'] and user.file['size'] != currentUser.file['size']:
message += getMessage("different-filesize-notification")
self.showMessage(message, True)
else:
message = getMessage("no-file-played-notification").format(username)
self.showMessage(message, True)
def userListChange(self):
pass
def fileSwitchFoundFiles(self):
pass
def setFeatures(self, featureList):
pass
def showMessage(self, message, noTimestamp=False):
message = message.encode(sys.stdout.encoding, 'replace')
try:
message = message.decode('utf-8')
except UnicodeEncodeError:
pass
if noTimestamp:
print(message)
else:
print(time.strftime(constants.UI_TIME_FORMAT, time.localtime()) + message)
def showDebugMessage(self, message):
print(message)
def showErrorMessage(self, message, criticalerror=False):
print("ERROR:\t" + message)
def setSSLMode(self, sslMode, sslInformation):
pass
def _extractSign(self, m):
if m:
if m == "-":
return -1
else:
return 1
else:
return None
def _tryAdvancedCommands(self, 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'))
if t is None:
return
if o.group('sign') == "/":
t = self._syncplayClient.getPlayerPosition() - t
elif sign:
t = self._syncplayClient.getUserOffset() + sign * t
self._syncplayClient.setUserOffset(t)
return True
elif s:
sign = self._extractSign(s.group('sign'))
t = utils.parseTime(s.group('time'))
if t is None:
return
if sign:
t = self._syncplayClient.getGlobalPosition() + sign * t
self._syncplayClient.setPosition(t)
return True
return False
def executeCommand(self, data):
command = re.match(constants.UI_COMMAND_REGEX, data)
if not command:
return
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 constants.COMMANDS_LIST:
self.getUserlist()
elif command.group('command') in constants.COMMANDS_CHAT:
message = command.group('parameter')
self._syncplayClient.sendChat(message)
elif command.group('command') in constants.COMMANDS_PAUSE:
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
elif command.group('command') in constants.COMMANDS_ROOM:
room = command.group('parameter')
if room is None:
if self._syncplayClient.userlist.currentUser.file:
room = self._syncplayClient.userlist.currentUser.file["name"]
else:
room = self._syncplayClient.defaultRoom
self._syncplayClient.setRoom(room, resetAutoplay=True)
self._syncplayClient.ui.updateRoomName(room)
self._syncplayClient.sendRoom()
elif command.group('command') in constants.COMMANDS_CREATE:
roombasename = command.group('parameter')
if roombasename is None:
roombasename = self._syncplayClient.getRoom()
roombasename = utils.stripRoomName(roombasename)
self._syncplayClient.createControlledRoom(roombasename)
elif command.group('command') in constants.COMMANDS_AUTH:
controlpassword = command.group('parameter')
self._syncplayClient.identifyAsController(controlpassword)
elif command.group('command') in constants.COMMANDS_TOGGLE:
self._syncplayClient.toggleReady()
elif command.group('command') in constants.COMMANDS_QUEUE:
filename = command.group('parameter')
if filename is None:
self.showErrorMessage("No file/url given")
return
self._syncplayClient.ui.addFileToPlaylist(filename)
elif command.group('command') in constants.COMMANDS_PLAYLIST:
playlist = self._syncplayClient.playlist
playlist_elements = [f"\t{i+1}: {el}" for i, el in enumerate(playlist._playlist)]
if playlist_elements:
i = playlist._playlistIndex
if i is not None and i in range(len(playlist_elements)):
playlist_elements[i] = " *" + playlist_elements[i]
print(*playlist_elements, sep='\n')
else:
print("playlist is currently empty.")
elif command.group('command') in constants.COMMANDS_SELECT:
try:
index = int(command.group('parameter').strip()) - 1
self._syncplayClient.playlist.changeToPlaylistIndex(index, resetPosition=True)
self._syncplayClient.rewindFile()
except TypeError:
print("invalid index")
elif command.group('command') in constants.COMMANDS_DELETE:
try:
index = int(command.group('parameter').strip()) - 1
self._syncplayClient.playlist.deleteAtIndex(index)
except TypeError:
print("invalid index")
else:
if self._tryAdvancedCommands(data):
return
if command.group('command') not in constants.COMMANDS_HELP:
self.showMessage(getMessage("unrecognized-command-notification"))
self.showMessage(getMessage("commandlist-notification"), True)
self.showMessage(getMessage("commandlist-notification/room"), True)
self.showMessage(getMessage("commandlist-notification/list"), True)
self.showMessage(getMessage("commandlist-notification/undo"), True)
self.showMessage(getMessage("commandlist-notification/pause"), True)
self.showMessage(getMessage("commandlist-notification/seek"), True)
self.showMessage(getMessage("commandlist-notification/help"), True)
self.showMessage(getMessage("commandlist-notification/toggle"), True)
self.showMessage(getMessage("commandlist-notification/create"), True)
self.showMessage(getMessage("commandlist-notification/auth"), True)
self.showMessage(getMessage("commandlist-notification/chat"), True)
self.showMessage(getMessage("commandList-notification/queue"), True)
self.showMessage(getMessage("commandList-notification/playlist"), True)
self.showMessage(getMessage("commandList-notification/select"), True)
self.showMessage(getMessage("commandList-notification/delete"), True)
self.showMessage(getMessage("syncplay-version-notification").format(syncplay.version), True)
self.showMessage(getMessage("more-info-notification").format(syncplay.projectURL), True)
def getUserlist(self):
self._syncplayClient.getUserList()