@@ -73,6 +73,9 @@ def __init__(self, playerClass, ui, config):
7373 constants .FOLDER_SEARCH_TIMEOUT = config ['folderSearchTimeout' ]
7474 constants .FOLDER_SEARCH_DOUBLE_CHECK_INTERVAL = config ['folderSearchDoubleCheckInterval' ]
7575 constants .FOLDER_SEARCH_WARNING_THRESHOLD = config ['folderSearchWarningThreshold' ]
76+ constants .WATCHED_SUBFOLDER = config ['watchedSubfolder' ]
77+ constants .WATCHED_AUTOMOVE = config ['watchedAutoMove' ] if len (constants .WATCHED_SUBFOLDER ) > 0 else False
78+ constants .WATCHED_AUTOCREATESUBFOLDERS = config ['watchedSubfolderAutocreate' ] if len (constants .WATCHED_SUBFOLDER ) > 0 else False
7679
7780 self .controlpasswords = {}
7881 self .lastControlPasswordAttempt = None
@@ -81,7 +84,9 @@ def __init__(self, playerClass, ui, config):
8184 self .serverFeatures = {}
8285
8386 self .lastRewindTime = None
87+ self ._pendingWatchedMoves = []
8488 self .lastUpdatedFileTime = None
89+ self ._lastWatchedMoveAttempt = 0.0 #Secs
8590 self .lastAdvanceTime = None
8691 self .fileOpenBeforeChangingPlaylistIndex = None
8792 self .waitingToLoadNewfile = False
@@ -248,6 +253,12 @@ def updatePlayerStatus(self, paused, position):
248253 ):
249254 pauseChange = self ._toggleReady (pauseChange , paused )
250255
256+ if self ._pendingWatchedMoves and (time .time () - (self ._lastWatchedMoveAttempt or 0.0 )) >= constants .WATCHED_CHECKQUEUE_INTERVAL :
257+ self ._lastWatchedMoveAttempt = time .time ()
258+ try :
259+ self ._tryMovePendingWatchedFiles ()
260+ except Exception :
261+ pass
251262 if self ._lastGlobalUpdate :
252263 self ._lastPlayerUpdate = time .time ()
253264 if (pauseChange or seeked ) and self ._protocol :
@@ -263,6 +274,13 @@ def prepareToChangeToNewPlaylistItemAndRewind(self):
263274 self .fileOpenBeforeChangingPlaylistIndex = self .userlist .currentUser .file ["path" ] if self .userlist .currentUser .file else None
264275 self .waitingToLoadNewfile = True
265276 self .waitingToLoadNewfileSince = time .time ()
277+ position = self .getStoredPlayerPosition ()
278+ currentLength = self .userlist .currentUser .file ["duration" ] if self .userlist .currentUser .file else 0
279+ if (
280+ currentLength > constants .PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and
281+ abs (position - currentLength ) < constants .PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD
282+ ):
283+ self .markWatchedFilePendingMove ()
266284
267285 def prepareToAdvancePlaylist (self ):
268286 if self .playlist .canSwitchToNextPlaylistIndex ():
@@ -516,6 +534,88 @@ def getGlobalPaused(self):
516534 return True
517535 return self ._globalPaused
518536
537+ def markWatchedFilePendingMove (self ):
538+ try :
539+ currentFile = self .userlist .currentUser .file if self .userlist and self .userlist .currentUser else None
540+ currentFilePath = currentFile .get ("path" ) if currentFile else None
541+ if currentFilePath and not utils .isURL (currentFilePath ) and currentFilePath not in self ._pendingWatchedMoves :
542+ self ._pendingWatchedMoves .append (currentFilePath )
543+ self .ui .showDebugMessage ("Marked for watched move: {}" .format (currentFilePath ))
544+ except Exception as e :
545+ self .ui .showDebugMessage ("Could not mark watched file: {}" .format (e ))
546+
547+ def userInitiatedMarkWatched (self , fileSourcePath ):
548+ try :
549+ directory = os .path .dirname (fileSourcePath )
550+ filename = os .path .basename (fileSourcePath )
551+ watchedDirectory = utils .getWatchedSubfolder (directory )
552+ utils .createWatchedSubdirIfNeeded (watchedDirectory )
553+ if not os .path .isdir (watchedDirectory ):
554+ self .ui .showErrorMessage ("'{}' subfolder not found for this file." .format (constants .WATCHED_SUBFOLDER )) # TODO: Move to Language
555+ return
556+ watchedDirectoryFilepath = os .path .join (watchedDirectory , filename )
557+ watchedDirectoryName = os .path .basename (os .path .dirname (watchedDirectoryFilepath ))
558+ if os .path .isfile (watchedDirectoryFilepath ):
559+ self .ui .showErrorMessage ("A file with the same name already exists in '{}' subfolder." .format (watchedDirectoryName )) # TODO: Move to Language
560+ return
561+ utils .moveFile (fileSourcePath , watchedDirectoryFilepath )
562+ self .fileSwitch .updateInfo ()
563+ self .ui .showMessage ("Moved file '{}' to '\{}\\ '" .format (fileSourcePath , watchedDirectoryName ))
564+ except Exception as e :
565+ self .ui .showErrorMessage ("Could not mark as watched: {}" .format (e )) # TODO: Move to language
566+
567+ def userInitiatedMarkUnwatched (self , fileSourcePath ):
568+ try :
569+ watchedDirectoryPath = os .path .dirname (fileSourcePath )
570+ filename = os .path .basename (fileSourcePath )
571+ if not utils .isWatchedSubfolder (watchedDirectoryPath ):
572+ self .ui .showErrorMessage ("This file is not in a '{}' subfolder." .format (constants .WATCHED_SUBFOLDER ))
573+ return
574+ unwatchedDirectoryPath = utils .getUnwatchedParentfolder (watchedDirectoryPath )
575+ unwatchedDirectoryPathName = os .path .basename (unwatchedDirectoryPath )
576+ unwatchedFilePath = os .path .join (unwatchedDirectoryPath , filename )
577+ if os .path .isfile (unwatchedFilePath ):
578+ self .ui .showErrorMessage ("A file with the same name already exists in the parent folder." )
579+ return
580+ utils .moveFile (fileSourcePath , unwatchedFilePath )
581+ self .fileSwitch .updateInfo ()
582+ self .ui .showMessage ("Moved file '{}' to '\{}\\ '" .format (fileSourcePath , unwatchedDirectoryPathName )) # TODO: Move to Language
583+ except Exception as e :
584+ self .ui .showErrorMessage ("Could not mark as unwatched: {}" .format (e )) # TODO: Move to Language
585+
586+ def _tryMovePendingWatchedFiles (self ):
587+ if not constants .WATCHED_AUTOMOVE :
588+ self ._pendingWatchedMoves = []
589+ return
590+
591+ if not self ._pendingWatchedMoves :
592+ return
593+
594+ for pendingWatchedMove in list (self ._pendingWatchedMoves ):
595+ try :
596+ if not os .path .exists (pendingWatchedMove ):
597+ self ._pendingWatchedMoves .remove (pendingWatchedMove )
598+ continue
599+ originalDir = os .path .dirname (pendingWatchedMove )
600+ watchedDir = utils .getWatchedSubfolder (originalDir )
601+ utils .createWatchedSubdirIfNeeded (watchedDir )
602+ if not os .path .isdir (watchedDir ):
603+ self ._pendingWatchedMoves .remove (pendingWatchedMove )
604+ continue
605+ destFilepath = os .path .join (watchedDir , os .path .basename (pendingWatchedMove ))
606+ if os .path .exists (destFilepath ):
607+ self .ui .showErrorMessage (getMessage ("cannot-move-file-due-to-name-conflict-error" ).format (pendingWatchedMove , constants .WATCHED_SUBFOLDER ))
608+ self ._pendingWatchedMoves .remove (pendingWatchedMove )
609+ continue
610+ utils .moveFile (pendingWatchedMove , destFilepath )
611+ self .fileSwitch .updateInfo ()
612+ try :
613+ self .ui .showMessage ("Moved '{}' to '{}' sub-folder" .format (pendingWatchedMove , constants .WATCHED_SUBFOLDER ))
614+ self ._pendingWatchedMoves .remove (pendingWatchedMove )
615+ except Exception :
616+ pass
617+ except Exception as e :
618+ self .ui .showDebugMessage ("Deferring watched move for '{}': {}" .format (pendingWatchedMove , e ))
519619 def eofReportedByPlayer (self ):
520620 if self .playlist .notJustChangedPlaylist () and self .userlist .currentUser .file :
521621 self .ui .showDebugMessage ("Fixing file duration to allow for playlist advancement" )
@@ -914,6 +1014,16 @@ def stop(self, promptForAction=False):
9141014 self .destroyProtocol ()
9151015 if self ._player :
9161016 self ._player .drop ()
1017+
1018+ if self ._pendingWatchedMoves :
1019+ for _ in range (constants .WATCHED_PLAYERWAIT_MAXRETRIES ):
1020+ try :
1021+ self ._tryMovePendingWatchedFiles ()
1022+ if not self ._pendingWatchedMoves :
1023+ break
1024+ except Exception :
1025+ pass
1026+ time .sleep (constants .WATCHED_PLAYERWAIT_INTERVAL )
9171027 if self .ui :
9181028 self .ui .drop ()
9191029 reactor .callLater (0.1 , reactor .stop )
@@ -2091,7 +2201,8 @@ def advancePlaylistCheck(self):
20912201 abs (position - currentLength ) < constants .PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD and
20922202 self .notJustChangedPlaylist ()
20932203 ):
2094- self .loadNextFileInPlaylist ()
2204+ self ._client .markWatchedFilePendingMove ()
2205+ self .loadNextFileInPlaylist ()
20952206
20962207 def notJustChangedPlaylist (self ):
20972208 secondsSinceLastChange = time .time () - self ._lastPlaylistIndexChange
@@ -2278,20 +2389,22 @@ def findFilepath(self, filename, highPriority=False):
22782389 return
22792390
22802391 if self ._client .userlist .currentUser .file and utils .sameFilename (filename , self ._client .userlist .currentUser .file ['name' ]):
2281- return self ._client .userlist .currentUser .file ['path' ]
2392+ return utils . getCorrectedPathForFile ( self ._client .userlist .currentUser .file ['path' ])
22822393
22832394 if self .mediaFilesCache is not None :
22842395 for directory in self .mediaFilesCache :
22852396 files = self .mediaFilesCache [directory ]
22862397 if len (files ) > 0 and filename in files :
22872398 filepath = os .path .join (directory , filename )
2399+ filepath = utils .getCorrectedPathForFile (filepath )
22882400 if os .path .isfile (filepath ):
22892401 return filepath
22902402
22912403 if self .folderSearchEnabled and self .mediaDirectories is not None :
22922404 directoryList = self .mediaDirectories
22932405 for directory in directoryList :
22942406 filepath = os .path .join (directory , filename )
2407+ filepath = utils .getCorrectedPathForFile (filepath )
22952408 if os .path .isfile (filepath ):
22962409 return filepath
22972410
@@ -2313,7 +2426,13 @@ def getDirectoryOfFilenameInCache(self, filename):
23132426 for directory in self .mediaFilesCache :
23142427 files = self .mediaFilesCache [directory ]
23152428 if filename in files :
2316- return directory
2429+ filepath = os .path .join (directory , filename )
2430+ if os .path .isfile (filepath ):
2431+ return directory
2432+ watched_directory = os .path .join (directory , constants .WATCHED_SUBFOLDER )
2433+ watched_filepath = os .path .join (directory , constants .WATCHED_SUBFOLDER , filename )
2434+ if os .path .isfile (watched_filepath ):
2435+ return watched_directory
23172436 return None
23182437
23192438 def isDirectoryInList (self , directoryToFind , folderList ):
0 commit comments