@@ -259,6 +259,10 @@ def updatePlayerStatus(self, paused, position):
259259 self ._tryMovePendingWatchedFiles ()
260260 except Exception :
261261 pass
262+ self .currentlyPlayingFilename = self .userlist .currentUser .file ["name" ] if self .userlist .currentUser .file else None
263+ playingCurrentIndex = not self .playlist ._notPlayingCurrentIndex ()
264+ if playingCurrentIndex :
265+ self .playlist .recordPlayedNearEOF (paused , position )
262266 if self ._lastGlobalUpdate :
263267 self ._lastPlayerUpdate = time .time ()
264268 if (pauseChange or seeked ) and self ._protocol :
@@ -534,10 +538,16 @@ def getGlobalPaused(self):
534538 return True
535539 return self ._globalPaused
536540
537- def markWatchedFilePendingMove (self ):
541+ def markWatchedFilePendingMove (self , oldFilePath = None ):
542+ self .playlist .lastNearEOFName = None
543+ self .playlist .lastNearEOFPath = None
544+
538545 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
546+ if oldFilePath :
547+ currentFilePath = oldFilePath
548+ else :
549+ currentFile = self .userlist .currentUser .file if self .userlist and self .userlist .currentUser else None
550+ currentFilePath = currentFile .get ("path" ) if currentFile else None
541551 if currentFilePath and not utils .isURL (currentFilePath ) and currentFilePath not in self ._pendingWatchedMoves :
542552 self ._pendingWatchedMoves .append (currentFilePath )
543553 self .ui .showDebugMessage ("Marked for watched move: {}" .format (currentFilePath ))
@@ -645,6 +655,7 @@ def updateFile(self, filename, duration, path):
645655 self .userlist .currentUser .setFile (filename , duration , size , path )
646656 self .sendFile ()
647657 self .playlist .changeToPlaylistIndexFromFilename (filename )
658+ self .playlist .doubleCheckForWatchedPreviousFile ()
648659
649660 def setTrustedDomains (self , newTrustedDomains ):
650661 from syncplay .ui .ConfigurationGetter import ConfigurationGetter
@@ -727,16 +738,19 @@ def openFile(self, filePath, resetPosition=False, fromUser=False):
727738 self .establishRewindDoubleCheck ()
728739 self .lastRewindTime = time .time ()
729740 self .autoplayCheck ()
741+ self .playlist .doubleCheckForWatchedPreviousFile ()
730742
731743 def fileSwitchFoundFiles (self ):
732744 self .ui .fileSwitchFoundFiles ()
733745 self .playlist .loadCurrentPlaylistIndex ()
734746
735747 def setPlaylistIndex (self , index ):
736748 self ._protocol .setPlaylistIndex (index )
749+ self .playlist .doubleCheckForWatchedPreviousFile ()
737750
738751 def changeToPlaylistIndex (self , * args , ** kwargs ):
739752 self .playlist .changeToPlaylistIndex (* args , ** kwargs )
753+ self .playlist .doubleCheckForWatchedPreviousFile ()
740754
741755 def loopSingleFiles (self ):
742756 return self ._config ["loopSingleFiles" ] or self .isPlayingMusic ()
@@ -1879,6 +1893,10 @@ def __init__(self, client):
18791893 self .addedChangeListCallback = False
18801894 self .switchToNewPlaylistItem = False
18811895 self ._lastPlaylistIndexChange = time .time ()
1896+ self .lastNearEOFName = None
1897+ self .lastNearEOFPath = None
1898+ self .lastNearEOFFirstTime = 0.0
1899+ self .lastNearEOFLastTime = 0.0
18821900
18831901 def needsSharedPlaylistsEnabled (f ): # @NoSelf
18841902 @wraps (f )
@@ -2000,6 +2018,7 @@ def changeToPlaylistIndex(self, index, username=None, resetPosition=False):
20002018 self ._client ._protocol .sendMessage ({"State" : state })
20012019 self ._playerPaused = True
20022020 self ._client .autoplayCheck ()
2021+ self .doubleCheckForWatchedPreviousFile ()
20032022 elif index is not None :
20042023 filename = self ._playlist [index ]
20052024 self ._ui .setPlaylistIndexFilename (filename )
@@ -2150,6 +2169,7 @@ def changePlaylist(self, files, username=None, resetIndex=False):
21502169 else :
21512170 self ._ui .setPlaylist (self ._playlist )
21522171 self ._ui .showMessage (getMessage ("playlist-contents-changed-notification" ).format (username ))
2172+ self .doubleCheckForWatchedPreviousFile ()
21532173
21542174 def addToPlaylist (self , file ):
21552175 self .changePlaylist ([* self ._playlist , file ])
@@ -2207,6 +2227,48 @@ def advancePlaylistCheck(self):
22072227 self ._client .markWatchedFilePendingMove ()
22082228 self .loadNextFileInPlaylist ()
22092229
2230+ @needsSharedPlaylistsEnabled
2231+ def recordPlayedNearEOF (self , paused , position ):
2232+ if not self ._client .userlist .currentUser .file :
2233+ return
2234+ if position == None :
2235+ return
2236+ currentLength = self ._client .userlist .currentUser .file ["duration" ] if self ._client .userlist .currentUser .file else 0
2237+ isPlaying = paused is False
2238+ remainingTime = currentLength - position
2239+
2240+ if (
2241+ isPlaying and
2242+ remainingTime < constants .PLAYLIST_NEAR_EOF_WINDOW and
2243+ currentLength > (constants .PLAYLIST_NEAR_EOF_WINDOW * 2 ) and # The EOF window must represent at least the last half of the video to avoid misdetection when playing start of a short file
2244+ currentLength > constants .PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and
2245+ self .notJustChangedPlaylist ()
2246+ ):
2247+ now_monotime = time .monotonic ()
2248+ if self .lastNearEOFName != self ._client .userlist .currentUser .file ['name' ]:
2249+ self .lastNearEOFName = self ._client .userlist .currentUser .file ['name' ]
2250+ self .lastNearEOFPath = self ._client .userlist .currentUser .file ['path' ]
2251+ self .lastNearEOFFirstTime = now_monotime
2252+ self .lastNearEOFLastTime = now_monotime
2253+
2254+ @needsSharedPlaylistsEnabled
2255+ def doubleCheckForWatchedPreviousFile (self ):
2256+ if not self .lastNearEOFName or not self .lastNearEOFPath :
2257+ return False
2258+
2259+ if self ._playingSpecificFilename (self .lastNearEOFName ):
2260+ return False
2261+
2262+ now_monotime = time .monotonic ()
2263+ dwell = max (0.0 , self .lastNearEOFLastTime - self .lastNearEOFFirstTime )
2264+ if dwell < constants .PLAYLIST_NEAR_EOF_MIN_DWELL :
2265+ return False
2266+
2267+ age = now_monotime - self .lastNearEOFLastTime
2268+ if age > constants .PLAYLIST_NEAR_EOF_LATCH_TTL :
2269+ return False
2270+ self ._client .markWatchedFilePendingMove (self .lastNearEOFPath )
2271+
22102272 def notJustChangedPlaylist (self ):
22112273 secondsSinceLastChange = time .time () - self ._lastPlaylistIndexChange
22122274 return secondsSinceLastChange > constants .PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD
@@ -2246,6 +2308,12 @@ def _notPlayingCurrentIndex(self):
22462308 self ._ui .showDebugMessage ("Not playing current index - Filename mismatch or no file" )
22472309 return True
22482310
2311+ def _playingSpecificFilename (self , filenameToCompare ):
2312+ if self ._client .userlist .currentUser .file :
2313+ return self ._client .userlist .currentUser .file ['name' ] == filenameToCompare
2314+ else :
2315+ return False
2316+
22492317 def _thereIsNextPlaylistIndex (self ):
22502318 if self ._playlistIndex is None :
22512319 return False
@@ -2324,6 +2392,7 @@ def checkForFileSwitchUpdate(self):
23242392 if self .directorySearchError :
23252393 self ._client .ui .showErrorMessage (self .directorySearchError )
23262394 self .directorySearchError = None
2395+ self ._client .playlist .doubleCheckForWatchedPreviousFile ()
23272396
23282397 def updateInfo (self ):
23292398 if not self .currentlyUpdating and self .mediaDirectories :
0 commit comments