def wait_until_restart_or_shutdown(self): # type: () -> None """ :return: """ clz = BaseDiscoverMovies finished = False while not finished: Monitor.wait_for_abort(timeout=1.0) self.throw_exception_on_forced_to_stop()
def wait_for_is_not_playing_video(self, timeout=None, trace=None): # type: (float, str) -> Union[bool, None] ''' This is a mess. The preferred way to deal with this is to monitor onPlayBackStarted/ onPlayBackEnded events, but onPlayBackEnded is not reliably sent. So, poll isPlayingVideo, which is True prior to the video actually being played, so some method calls can throw exceptions until onPlayBackStarted is issued. Sigh Perhaps rely on onVidowWindowOpened/Closed, but that depends upon the actual dialog opening/closing. Not good ''' local_class = AdvancedPlayer try: if timeout is None: timeout = 0 if self._player_window_open: timeout = self.getTime() timeout = self.getTotalTime() - timeout + 2 except Exception: # Player must be finished timeout = 0 timeout = timeout * 1000 # Convert to ms while (self._player_window_open and timeout > 0 and not Monitor.wait_for_abort(0.250)): timeout -= 250 if timeout > 0: return False return True
def waitForIsPlayingVideo(self, timeout=None): # type: (Optional[float]) -> bool ''' This is a mess. The preferred way to deal with this is to monitor onPlayBackStarted/ onPlayBackEnded events, but onPlayBackEnded is not reliably sent. So, poll isPlayingVideo, which is True prior to the video actually being played, so some method calls can throw exceptions until onPlayBackStarted is issued. Sigh Perhaps rely on onVidowWindowOpened/Closed, but that depends upon the actual dialog opening/closing. Not good ''' local_class = AdvancedPlayer if timeout is None: timeout = 3600 # An hour, insane timeout = timeout * 1000 # Convert to ms # TODO: Add check for failures: onPlabackFailed/Ended/Error while not self._player_window_open and timeout > 0 and not Monitor.wait_for_abort(0.250): timeout -= 250 if timeout <= 0: return False return True
def join_dead_threads(cls): finished = False while not finished: with cls._lock: joined_threads: List[threading.Thread] = [] for thread in cls._threads_to_join: if not thread.is_alive(): thread.join(timeout=0.0) if not thread.is_alive(): joined_threads.append(thread) for thread in joined_threads: cls._threads_to_join.remove(thread) if Monitor.wait_for_abort(timeout=10.0): finished = True
def _monitor(self): local_class = AdvancedPlayer try: if type(self).DEBUG_MONITOR: local_class._logger.enter() while not Monitor.wait_for_abort(0.1) and not self._closed: if (type(self).DEBUG_MONITOR and local_class._logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE)): if not self.isPlaying(): local_class._logger.debug_extra_verbose('Player: Idling...') while not self.isPlaying() and not self._closed: Monitor.throw_exception_if_abort_requested(timeout=0.1) if self.isPlayingVideo(): if (type(self).DEBUG_MONITOR and local_class._logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE)): local_class._logger.debug_verbose('Monitoring video...') self._video_monitor() elif self.isPlayingAudio(): if (type(self).DEBUG_MONITOR and local_class._logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE)): local_class._logger.debug_verbose('Monitoring audio...') self._audio_monitor() elif self.isPlaying(): if (type(self).DEBUG_MONITOR and local_class._logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE)): local_class._logger.debug_verbose('Monitoring pre-play...') self._preplay_monitor() if (type(self).DEBUG_MONITOR and local_class._logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE)): local_class._logger.debug_verbose('Player: Closed') except AbortException: pass # Just exit thread except Exception as e: local_class._logger.exception('') finally: pass
def run_cmd(self) -> int: self.rc = 0 self.run_thread = threading.Thread(target=self.run_worker, name='normalize audio') Monitor.throw_exception_if_abort_requested() self.run_thread.start() self.cmd_finished = False while not Monitor.wait_for_abort(timeout=0.1): try: if self.process is not None: # Wait to start rc = self.process.poll() if rc is not None: self.rc = rc self.cmd_finished = True break # Complete except subprocess.TimeoutExpired: pass if not self.cmd_finished: # Shutdown in process self.process: subprocess.Popen self.process.kill( ) # SIGKILL. Should cause stderr & stdout to exit self.rc = 9 if self.run_thread.is_alive(): self.run_thread.join(timeout=1.0) if self.stdout_thread.is_alive(): self.stdout_thread.join(timeout=0.2) if self.stderr_thread.is_alive(): self.stderr_thread.join(timeout=0.2) Monitor.throw_exception_if_abort_requested(timeout=0.0) # If abort did not occur, then process finished if self.rc != 0: self.log_output() return self.rc
def load_fetch_queue(self) -> None: """ Load the _trailers_to_fetch_queue from._discovered_trailers_queue. If _trailers_to_fetch_queue is full, then return If discoveryComplete and _discovered_trailers is empty, then return If discoveryComplete and._discovered_trailers_queue is empty, then shuffle_discovered_trailers and fill the _trailers_to_fetch_queue from it. If there are not enough items to fill the fetch queue, then get as many as are available. Otherwise, discoveryComplete == False: If._discovered_trailers_queue is empty and _trailers_to_fetch_queue is not empty, then return without loading any. If._discovered_trailers_queue is empty and _trailers_to_fetch_queue is empty then block until an item becomes available or discoveryComplete == True. Finally, _trailers_to_fetch_queue is not full, fill it from any available items from._discovered_trailers_queue. :return: """ clz = AbstractMovieData start_time = datetime.datetime.now() if AbstractMovieData._first_load: Monitor.wait_for_abort(timeout=2.0) AbstractMovieData._first_load = False Monitor.throw_exception_if_abort_requested() finished = False attempts = 0 discovery_complete_queue_empty = 0 discovered_and_fetch_queues_empty = 0 discovery_incomplete_fetch_not_empty = 0 discovery_incomplete_fetch_queue_empty = 0 get_attempts = 0 put_attempts = 0 while not finished: trailer = None # type: Union[MovieType, None] Monitor.throw_exception_if_abort_requested() attempts += 1 shuffle = False iteration_successful = False try: elapsed = datetime.datetime.now() - start_time if attempts > 0: if (attempts > 1 and self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE)): self.logger.debug_extra_verbose('Attempt:', attempts, 'elapsed:', elapsed.seconds) if self._trailers_to_fetch_queue.full(): if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose('_trailers_to_fetch_queue full', trace=Trace.TRACE) finished = True iteration_successful = True elif self._discovery_complete and len(self._discovered_trailers) == 0: if (not self._discovery_complete_reported and self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE)): self._discovery_complete_reported = True self.logger.debug_extra_verbose( 'Discovery Complete and nothing found.', trace=Trace.TRACE) finished = True iteration_successful = True elif self._discovery_complete and self._discovered_trailers_queue.empty(): self.logger.error( 'discoveryComplete,_discovered_trailers_queue empty') if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose( 'discoveryComplete,_discovered_trailers_queue empty', trace=Trace.TRACE) shuffle = True discovery_complete_queue_empty += 1 # # In the following, Discovery is INCOMPLETE # elif (self._discovered_trailers_queue.empty() and not self._trailers_to_fetch_queue.empty): discovered_and_fetch_queues_empty += 1 # Use what we have if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose('Discovery incomplete._discovered_trailers_queue', 'empty and _trailers_to_fetch_queue not empty', trace=Trace.TRACE) finished = True elif not self._trailers_to_fetch_queue.empty(): # Fetch queue is not empty, nor full. Discovery # is not complete. Get something from _discoveredTrailerQueue # if available try: discovery_incomplete_fetch_not_empty += 1 with self._discovered_trailers_lock: # self.logger.debug_verbose('Have discovered_trailers_lock') trailer = self._discovered_trailers_queue.get(timeout=0.25) # if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): # self.logger.debug_extra_verbose(' Got', trailer[Movie.TITLE], # 'from _discoveredTrailerQueue') except KodiQueue.Empty: pass if trailer is not None: try: self.put_in_fetch_queue( trailer, timeout=1) # if self.logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE): # self.logger.debug_verbose('Put in _trailers_to_fetch_queue qsize:', # self._trailers_to_fetch_queue.qsize(), # trailer.get(Movie.TITLE), # trace=Trace.TRACE) iteration_successful = True except KodiQueue.Full: if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose( '_trailers_to_fetch_queue.put failed', trace=Trace.TRACE) # # It is not a crisis if the put fails. Since the # fetch queue does have at least one entry, we are ok # Even if the trailer is lost from the FetchQueue, # it will get reloaded once the queue is exhausted. # # But since iteration_successful is not true, we might # still fix it at the end. # else: # Discovery incomplete, fetch queue is empty # wait until we get an item, or discovery complete discovery_incomplete_fetch_queue_empty += 1 if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose('Discovery incomplete,', '_trailers_to_fetch_queue empty, ' 'will wait', trace=Trace.TRACE) if not iteration_successful: if (self._discovered_trailers_queue.empty() and self._discovered_trailers.len() > 0): if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose( 'Shuffling due to empty _discovered_trailers_queue and', '_discovered_trailers not empty') shuffle = True if shuffle: # Because we were empty if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose( 'Shuffling due to empty _discovered_trailers_queue') Monitor.throw_exception_if_abort_requested() if self.logger.isEnabledFor(LazyLogger.DEBUG_EXTRA_VERBOSE): self.logger.debug_extra_verbose('load_fetch_queue Shuffling because', 'discoveredTrailerQueue empty', trace=Trace.TRACE_DISCOVERY) self.shuffle_discovered_trailers(mark_unplayed=True) if trailer is None: get_finished = False while not get_finished: try: get_attempts += 1 with self._discovered_trailers_lock: # self.logger.debug_verbose('Have discovered_trailers_lock') trailer = self._discovered_trailers_queue.get( timeout=0.5) get_finished = True except KodiQueue.Empty: Monitor.throw_exception_if_abort_requested() put_finished = False while not put_finished: try: put_attempts += 1 self.put_in_fetch_queue(trailer, timeout=0.25) put_finished = True except KodiQueue.Full: Monitor.throw_exception_if_abort_requested() iteration_successful = True if trailer is not None: movie_title = trailer.get(Movie.TITLE) else: movie_title = 'no movie' # if self.logger.isEnabledFor(LazyLogger.DEBUG_VERBOSE): # self.logger.debug_verbose('Queue has:', # self._trailers_to_fetch_queue.qsize(), # 'Put in _trailers_to_fetch_queue:', movie_title) except AbortException: reraise(*sys.exc_info()) except Exception as e: self.logger.exception('') # TODO Continue? if self._trailers_to_fetch_queue.full(): finished = True if not self._trailers_to_fetch_queue.empty() and not iteration_successful: finished = True if not finished: if attempts % 10 == 0: if self.logger.isEnabledFor(LazyLogger.DEBUG): self.logger.debug( 'hung reloading from._discovered_trailers_queue.', 'length of _discovered_trailers:', len(self._discovered_trailers), 'length of._discovered_trailers_queue:', self._discovered_trailers_queue.qsize(), trace=Trace.TRACE) Monitor.throw_exception_if_abort_requested(timeout=0.5) stop_time = datetime.datetime.now() duration = stop_time - start_time self._load_fetch_total_duration += duration.seconds attempts = 0 discovery_complete_queue_empty = 0 discovered_and_fetch_queues_empty = 0 discovery_incomplete_fetch_not_empty = 0 discovery_incomplete_fetch_queue_empty = 0 get_attempts = 0 put_attempts = 0