Skip to content

Commit

Permalink
Improve handling of big media directories
Browse files Browse the repository at this point in the history
  • Loading branch information
Et0h committed Oct 7, 2024
1 parent 4f1fe8d commit e52ba99
Show file tree
Hide file tree
Showing 19 changed files with 1,470 additions and 44 deletions.
79 changes: 79 additions & 0 deletions Allow_player_arguments_with_spaces_quotes_(#665).patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Subject: [PATCH] Allow player arguments with spaces/quotes (#665)
---
Index: syncplay/utils.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/syncplay/utils.py b/syncplay/utils.py
--- a/syncplay/utils.py (revision b22c9ab72148ef4c94fd8cb55803dc49a1b32fa5)
+++ b/syncplay/utils.py (date 1706291957961)
@@ -191,6 +191,10 @@
return itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s), minLength, -1))


+def parseCommandLineString(s):
+ arsToReturn = re.findall(constants.ARGUMENT_SPLIT_REGEX, s)
+ return arsToReturn
+
def blackholeStdoutForFrozenWindow():
if getattr(sys, 'frozen', '') == "windows_exe":
class Stderr(object):
Index: syncplay/ui/GuiConfiguration.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/syncplay/ui/GuiConfiguration.py b/syncplay/ui/GuiConfiguration.py
--- a/syncplay/ui/GuiConfiguration.py (revision b22c9ab72148ef4c94fd8cb55803dc49a1b32fa5)
+++ b/syncplay/ui/GuiConfiguration.py (date 1706289487195)
@@ -279,7 +279,7 @@
currentplayerpath = self.executablepathCombobox.currentText()

if currentplayerpath:
- NewPlayerArgs = self.playerargsTextbox.text().split(" ") if self.playerargsTextbox.text() else ""
+ NewPlayerArgs = utils.parseCommandLineString(self.playerargsTextbox.text()) if self.playerargsTextbox.text() else ""
self.perPlayerArgs[self.executablepathCombobox.currentText()] = NewPlayerArgs

def languageChanged(self):
Index: syncplay/players/vlc.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/syncplay/players/vlc.py b/syncplay/players/vlc.py
--- a/syncplay/players/vlc.py (revision b22c9ab72148ef4c94fd8cb55803dc49a1b32fa5)
+++ b/syncplay/players/vlc.py (date 1706291938733)
@@ -487,10 +487,14 @@

call.extend(self.__playerController.SLAVE_ARGS)
if args:
- call.extend(args)
+ for arg in args:
+ if "=" in arg and "\"" in arg:
+ (argName, argValue) = arg.split("=", 1)
+ if argValue.startswith("\"") and argValue.endswith("\""):
+ arg = argName + "=" + argValue[1:-1]
+ call.extend([arg])

self._vlcVersion = None
-
if isWindows() and getattr(sys, 'frozen', '') and getattr(sys, '_MEIPASS', '') is not None: # Needed for pyinstaller --onefile bundle
self.__process = subprocess.Popen(
call, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
Index: syncplay/constants.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/syncplay/constants.py b/syncplay/constants.py
--- a/syncplay/constants.py (revision b22c9ab72148ef4c94fd8cb55803dc49a1b32fa5)
+++ b/syncplay/constants.py (date 1706289344189)
@@ -115,6 +115,7 @@
FILENAME_STRIP_REGEX = "[-~_\.\[\](): ]"
CONTROL_PASSWORD_STRIP_REGEX = "[^a-zA-Z0-9\-]"
ROOM_NAME_STRIP_REGEX = "^(\+)(?P<roomnamebase>.*)(:)(\w{12})$"
+ARGUMENT_SPLIT_REGEX = r'(?:[^\s"]+|"[^"]*")+'
COMMANDS_UNDO = ["u", "undo", "revert"]
COMMANDS_CHAT = ["ch", "chat"]
COMMANDS_LIST = ["l", "list", "users"]
993 changes: 993 additions & 0 deletions Readiness_override_(initial_implementation).patch

Large diffs are not rendered by default.

47 changes: 18 additions & 29 deletions syncplay/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
from syncplay.messages import getMissingStrings, getMessage, isNoOSDMessage
from syncplay.protocols import SyncClientProtocol
from syncplay.utils import isMacOS


class SyncClientFactory(ClientFactory):
def __init__(self, client, retry=constants.RECONNECT_RETRIES):
self._client = client
Expand Down Expand Up @@ -74,6 +72,7 @@ def __init__(self, playerClass, ui, config):
constants.FOLDER_SEARCH_FIRST_FILE_TIMEOUT = config['folderSearchFirstFileTimeout']
constants.FOLDER_SEARCH_TIMEOUT = config['folderSearchTimeout']
constants.FOLDER_SEARCH_DOUBLE_CHECK_INTERVAL = config['folderSearchDoubleCheckInterval']
constants.FOLDER_SEARCH_WARNING_THRESHOLD = config['folderSearchWarningThreshold']

self.controlpasswords = {}
self.lastControlPasswordAttempt = None
Expand Down Expand Up @@ -2197,6 +2196,9 @@ def _updateInfoThread(self):
self.currentlyUpdating = True
dirsToSearch = self.mediaDirectories

if not self.folderSearchEnabled:
return

if dirsToSearch:
# Spin up hard drives to prevent premature timeout
randomFilename = "RandomFile"+str(random.randrange(10000, 99999))+".txt"
Expand All @@ -2216,13 +2218,21 @@ def _updateInfoThread(self):
# Actual directory search
newMediaFilesCache = {}
startTime = time.time()
fileCount = 0
lastWarningTime = None
for directory in dirsToSearch:
for root, dirs, files in os.walk(directory):
fileCount += 1
newMediaFilesCache[root] = files
if time.time() - startTime > constants.FOLDER_SEARCH_TIMEOUT:
self.directorySearchError = getMessage("folder-search-timeout-error").format(directory)
timeTakenSoFar = time.time() - startTime
if timeTakenSoFar > constants.FOLDER_SEARCH_TIMEOUT:
reactor.callLater(0.1, self._client.ui.showErrorMessage, getMessage("folder-search-timeout-error").format(directory, fileCount),False)
self.folderSearchEnabled = False
return
if timeTakenSoFar > constants.FOLDER_SEARCH_WARNING_THRESHOLD:
if not lastWarningTime or timeTakenSoFar - lastWarningTime >= 1:
reactor.callLater(0.1, self._client.ui.showErrorMessage, getMessage("folder-search-timeout-warning").format(int(timeTakenSoFar), fileCount, directory),False)
lastWarningTime = timeTakenSoFar

if self.mediaFilesCache != newMediaFilesCache:
self.mediaFilesCache = newMediaFilesCache
Expand Down Expand Up @@ -2250,33 +2260,12 @@ def findFilepath(self, filename, highPriority=False):
if os.path.isfile(filepath):
return filepath

if highPriority and self.folderSearchEnabled and self.mediaDirectories is not None:
if self.folderSearchEnabled and self.mediaDirectories is not None:
directoryList = self.mediaDirectories
# Spin up hard drives to prevent premature timeout
randomFilename = "RandomFile"+str(random.randrange(10000, 99999))+".txt"
for directory in directoryList:
startTime = time.time()
if os.path.isfile(os.path.join(directory, randomFilename)):
randomFilename = "RandomFile"+str(random.randrange(10000, 99999))+".txt"
print("Found random file (?)")
if not self.folderSearchEnabled:
return
if time.time() - startTime > constants.FOLDER_SEARCH_FIRST_FILE_TIMEOUT:
self.folderSearchEnabled = False
self.directorySearchError = getMessage("folder-search-first-file-timeout-error").format(directory)
return

startTime = time.time()
if filename and directoryList:
for directory in directoryList:
for root, dirs, files in os.walk(directory):
if filename in files:
return os.path.join(root, filename)
if time.time() - startTime > constants.FOLDER_SEARCH_TIMEOUT:
self.folderSearchEnabled = False
self.directorySearchError = getMessage("folder-search-timeout-error").format(directory)
return None
return None
filepath = os.path.join(directory, filename)
if os.path.isfile(filepath):
return filepath

def areWatchedFilenamesInCache(self):
if self.filenameWatchlist is not None:
Expand Down
3 changes: 2 additions & 1 deletion syncplay/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def getValueForOS(constantDict):
# Options for the File Switch feature:
FOLDER_SEARCH_FIRST_FILE_TIMEOUT = 25.0 # Secs - How long to wait to find the first file in folder search (to take account of HDD spin up)
FOLDER_SEARCH_TIMEOUT = 20.0 # Secs - How long to wait until searches in folder to update cache are aborted (after first file is found)
FOLDER_SEARCH_WARNING_THRESHOLD = 2.0 # Secs - how long until a warning saying how many files have been scanned
FOLDER_SEARCH_DOUBLE_CHECK_INTERVAL = 30.0 # Secs - Frequency of updating cache

# Usually there's no need to adjust these
Expand Down Expand Up @@ -364,4 +365,4 @@ def getValueForOS(constantDict):
CONSOLE_UI_MODE = "CLI"
GRAPHICAL_UI_MODE = "GUI"
UNKNOWN_UI_MODE = "Unknown"
FALLBACK_ASSUMED_UI_MODE = GRAPHICAL_UI_MODE
FALLBACK_ASSUMED_UI_MODE = GRAPHICAL_UI_MODE
3 changes: 2 additions & 1 deletion syncplay/messages_de.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@
"invalid-offset-value": "Ungültiger Offset-Wert",

"switch-file-not-found-error": "Konnte nicht zur Datei „{0}“ wechseln. Syncplay sucht im Verzeichnis der aktuellen Datei und angegebenen Medienverzeichnissen.", # File not found, folder it was not found in
"folder-search-timeout-error": "Die Suche nach Medien in den Medienverzeichnissen wurde abgebrochen, weil es zu lange gedauert hat, „{}“ zu durchsuchen. Das kann passieren, wenn du in deiner Liste der Medienverzeichnisse ein Verzeichnis mit zu vielen Unterverzeichnissen auswhälst. Damit der automatische Dateiwechsel wieder funktioniert, wähle Datei->Medienverzeichnisse auswählen in der Menüleiste und entferne dieses Verzeichnis oder ersetze es mit einem geeigneten Unterverzeichnis. Wenn das Verzeichnis in Ordnung ist, kannst du es reaktivieren, indem du Datei->Medienverzeichnisse auswählen wählst und „OK“ drückst.", # Folder
"folder-search-timeout-error": "Die Suche nach Medien in den Medienverzeichnissen wurde abgebrochen, weil es zu lange gedauert hat, „{}“ zu durchsuchen (after having processed the first {:,} files). Das kann passieren, wenn du in deiner Liste der Medienverzeichnisse ein Verzeichnis mit zu vielen Unterverzeichnissen auswhälst. Damit der automatische Dateiwechsel wieder funktioniert, wähle Datei->Medienverzeichnisse auswählen in der Menüleiste und entferne dieses Verzeichnis oder ersetze es mit einem geeigneten Unterverzeichnis. Wenn das Verzeichnis in Ordnung ist, kannst du es reaktivieren, indem du Datei->Medienverzeichnisse auswählen wählst und „OK“ drückst.", # Folder, Files processed - Note: {:,} is {} but with added commas seprators - TODO: Translate
"folder-search-timeout-warning": "Warning: It has taken {} seconds to scan {:,} files in the folder '{}'. This will occur if you select a folder with too many sub-folders in your list of media folders to search through or if there are too many files to process.", # Folder, Files processed. Note: {:,} is {} but with added commas seprators. TODO: Translate
"folder-search-first-file-timeout-error": "Die Suche nach Medien in den Medienverzeichnissen wurde abgebrochen, weil es zu lange gedauert hat, auf „{}“ zuzugreifen. Das kann passieren, wenn es sich dabei um ein Netzwerkgerät handelt und du eingestellt hast, dass es sich nach Inaktivität ausschaltet. Damit der automatische Dateiwechsel wieder funktioniert, wähle Datei->Medienverzeichnisse auswählen in der Menüleiste und entferne dieses Verzeichnis oder löse das Problem (z.B. indem du die Energiespareinstellungen anpasst).", # Folder
"added-file-not-in-media-directory-error": "Du hast eine Datei in im Verzeichnis „{}“ geladeden, welches kein bekanntes Medienverzeichnis ist. Du kannst es als Medienverzeichnis hinzufügen, indem du Datei->Medienverzeichnisse auswählen in der Menüleiste wählst.", # Folder
"no-media-directories-error": "Es wurden keine Medienverzeichnisse ausgewählt. Damit geteilte Playlists und Dateiwechsel korrekt funktionieren, wähle Datei->Medienverzeichnisse auswählen in der Menüleiste und gib an, wo Syncplay nach Mediendateien suchen soll.",
Expand Down
3 changes: 2 additions & 1 deletion syncplay/messages_en.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@
"invalid-offset-value": "Invalid offset value",

"switch-file-not-found-error": "Could not switch to file '{0}'. Syncplay looks in specified media directories.", # File not found
"folder-search-timeout-error": "The search for media in media directories was aborted as it took too long to search through '{}'. This will occur if you select a folder with too many sub-folders in your list of media folders to search through. For automatic file switching to work again please select File->Set Media Directories in the menu bar and remove this directory or replace it with an appropriate sub-folder. If the folder is actually fine then you can re-enable it by selecting File->Set Media Directories and pressing 'OK'.", # Folder
"folder-search-timeout-error": "The search for media in media directories was aborted as it took too long to search through '{}' after having processed the first {:,} files. This will occur if you select a folder with too many sub-folders in your list of media folders to search through or if there are too many files to process. For automatic file switching to work again please select File->Set Media Directories in the menu bar and remove this directory or replace it with an appropriate sub-folder. If the folder is actually fine then you can re-enable it by selecting File->Set Media Directories and pressing 'OK'.", # Folder, Files processed. Note: {:,} is {} but with added commas seprators.
"folder-search-timeout-warning": "Warning: It has taken {} seconds to scan {:,} files in the folder '{}'. This will occur if you select a folder with too many sub-folders in your list of media folders to search through or if there are too many files to process.", # Folder, Files processed. Note: {:,} is {} but with added commas seprators.
"folder-search-first-file-timeout-error": "The search for media in '{}' was aborted as it took too long to access the directory. This could happen if it is a network drive or if you configure your drive to spin down after a period of inactivity. For automatic file switching to work again please go to File->Set Media Directories and either remove the directory or resolve the issue (e.g. by changing power saving settings).", # Folder
"added-file-not-in-media-directory-error": "You loaded a file in '{}' which is not a known media directory. You can add this as a media directory by selecting File->Set Media Directories in the menu bar.", # Folder
"no-media-directories-error": "No media directories have been set. For shared playlist and file switching features to work properly please select File->Set Media Directories and specify where Syncplay should look to find media files.",
Expand Down
3 changes: 2 additions & 1 deletion syncplay/messages_eo.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@
"invalid-offset-value": "Nevalida valoro de frueco",

"switch-file-not-found-error": "Ne povis ŝalti dosieron «{0}». Syncplay serĉas en donitaj dosierujoj kun vidaŭdaĵoj.", # File not found
"folder-search-timeout-error": "La serĉado de vidaŭdaĵoj en dosierujoj kun vidaŭdaĵoj haltis, ĉar serĉado en «{}» postulis tro da tempo. Ĉi tio okazos, se vi elektos dosierujon kun tro multaj subdosierujoj en via listo de enserĉotaj dosierujoj kun vidaŭdaĵoj. Por refunkciigi memagan ŝaltadon de dosieroj, bonvolu elekti menueron «Dosiero → Agordi dosierujojn kun vidaŭdaĵoj» en la menubreto, kaj forigi ĉi tiun dosierujon, aŭ anstataŭigi ĝin per taŭga sub-dosierujo. Se vi trovos, ke la dosierujo fakte funkcias bone, vi povos reŝalti ĝin per «Dosiero → Agordi dosierujojn kun vidaŭdaĵoj» kaj klako al «Bone».", # Folder
"folder-search-timeout-error": "La serĉado de vidaŭdaĵoj en dosierujoj kun vidaŭdaĵoj haltis, ĉar serĉado en «{}» postulis tro da tempo (after having processed the first {:,} files). Ĉi tio okazos, se vi elektos dosierujon kun tro multaj subdosierujoj en via listo de enserĉotaj dosierujoj kun vidaŭdaĵoj. Por refunkciigi memagan ŝaltadon de dosieroj, bonvolu elekti menueron «Dosiero → Agordi dosierujojn kun vidaŭdaĵoj» en la menubreto, kaj forigi ĉi tiun dosierujon, aŭ anstataŭigi ĝin per taŭga sub-dosierujo. Se vi trovos, ke la dosierujo fakte funkcias bone, vi povos reŝalti ĝin per «Dosiero → Agordi dosierujojn kun vidaŭdaĵoj» kaj klako al «Bone».", # Folder, Files processed - Note: {:,} is {} but with added commas seprators - TODO: Translate
"folder-search-timeout-warning": "Warning: It has taken {} seconds to scan {:,} files in the folder '{}'. This will occur if you select a folder with too many sub-folders in your list of media folders to search through or if there are too many files to process.", # Folder, Files processed. Note: {:,} is {} but with added commas seprators. TODO: Translate
"folder-search-first-file-timeout-error": "La serĉo de vidaŭdaĵoj en «{}» haltis, ĉar aliro al la dosierujo postulis tro da tempo. Ĉi tio povas okazi se ĝi estas reta disko aŭ se vi agordis vian diskon malrapidiĝi post neaktivado. Por ke funkciu memaga ŝanĝado de dosieroj, bonvolu iri al «Dosiero → Agordi vidaŭdaĵajn dosierujojn», kaj forigu la dosierujon, aŭ solvu la problemon (ekz. per ŝanĝo de viaj agordoj por konservado de elektro).", # Folder
"added-file-not-in-media-directory-error": "Vi enlegis dosieron el «{}», kiu ne estas konata vidaŭdaĵa dosierujo. Vi povas aldoni ĝin al vidaŭdaĵaj dosierujoj per la menuero «Dosiero → Agordi vidaŭdaĵajn dosierujojn» en la menua breto.", # Folder
"no-media-directories-error": "Neniuj vidaŭdaĵaj dosierujoj estas agorditaj. Por ke kapabloj de komunaj ludlistoj kaj ŝanĝado de dosieroj funkciu ĝuste, bonvolu elekti menueron «Dosiero → Agordi vidaŭdaĵajn dosierujojn», kaj precizigu, kie Syncplay serĉu vidaŭdaĵojn.",
Expand Down
Loading

0 comments on commit e52ba99

Please sign in to comment.