def main(): video_play_thread = [1] is_looking_thread = IsLookingThread(video_play_thread) video_player = VideoPlayer("tanioka.mp4") is_looking_thread.start() while (True): video_player.play() video_player.check_state(video_play_thread[0]) if cv2.waitKey(1) & 0xFF == ord('q'): break
class Core(object): WAIT_BEGIN = 0 WAIT_END = 1 def __init__(self): self.player = None self.last_save = False self.exercise = None self.config = config self.logger = logging.Logger("Core") self.logger.setLevel(defaultLoggingLevel) self.logger.addHandler(defaultLoggingHandler) #Call by the main, give an handler to the main gui def set_gui(self, gui): self.gui_controller = gui #Create a new exercice based on paths. load the new exercise and #begin to play def new_exercise(self, videoPath, exercisePath, translationPath, langId): self.exercise = Exercise() self.exercise.set_media_change_callback(self.media_change_call_back) self.exercise.new() self.exercise.set_language_id(langId) self._set_paths(videoPath, exercisePath, translationPath) # This initialize the exercise self._reload(True) self._activate_sequence() self.gui_controller.set_title("", True) #Configure the paths for the current exercice. Reload subtitles list. def _set_paths(self, videoPath, exercisePath, translationPath): self.exercise.set_video_path(videoPath) self.exercise.set_exercise_path(exercisePath) self.exercise.set_translation_path(translationPath) self.exercise.initialize() #Reload media player and begin to play (if the params is True) def _reload(self, load): if self.player != None: self.player.close() self.player = VideoPlayer() self.player.set_window_id(self.gui_controller.get_video_window_id()) self.player.activate_video_callback( self.gui_controller.activate_video_area) self.player.open(self.exercise.get_video_path()) self.player.set_callback(self._time_callback) self.paused = False self.gui_controller.activate_video_area(False) self.gui_controller.activate("loaded") self._update_word_list() self.timeUpdateThreadId = thread.start_new_thread( self.time_update_thread, ()) if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() else: self.pause() #play the media def play(self): self.gui_controller.set_playing(True) self.player.play() self.paused = False #pause the media def pause(self): self.gui_controller.set_playing(False) self.player.pause() self.paused = True #Modify media speed def set_speed(self, speed): self.gui_controller.set_speed(speed) self.player.set_speed(speed) #Callback call by video player to notify change of media position. #Stop the media at the end of uncompleted sequences def _time_callback(self): if self.state == Core.WAIT_BEGIN: self.player.set_next_callback_time( self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) self.state = Core.WAIT_END elif self.state == Core.WAIT_END: self.state = Core.WAIT_BEGIN if self.exercise.get_current_sequence().is_valid(): gtk.gdk.threads_enter() self.next_sequence(False) gtk.gdk.threads_leave() else: self.pause() #Repeat the currence sequence def repeat_sequence(self): if not self.exercise.is_current_sequence_repeat_limit_reach(): #Repeat limit not reach or no limit self.goto_sequence_begin() self.play() self.exercise.increment_current_sequence_repeat_count() #Change the active sequence def select_sequence(self, num, load=True): if self.exercise.get_current_sequence_id() == num: return self.exercise.goto_sequence(num) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() self.set_can_save(True) #Goto next sequence def next_sequence(self, load=True): if self.exercise.goto_next_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto previous sequence def previous_sequence(self, load=True): if self.exercise.goto_previous_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto next valid sequence def next_valid_sequence(self, load=True): if self.exercise.goto_next_valid_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto previous valid sequence def previous_valid_sequence(self, load=True): if self.exercise.goto_previous_valid_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Update interface with new sequence. Configure stop media callback def _activate_sequence(self): self.state = Core.WAIT_BEGIN self.set_speed(1) self.player.set_next_callback_time( self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before()) self.gui_controller.set_sequence_number( self.exercise.get_current_sequence_id(), self.exercise.get_sequence_count()) self.gui_controller.set_sequence(self.exercise.get_current_sequence()) self.__activate_translation() self.__activate_previous_sequence_text() self._update_stats() #_update displayed translation on new active sequence def __activate_translation(self): if not self.exercise.get_translation_list(): self.gui_controller.set_translation("") else: translation = "" currentBegin = self.exercise.get_current_sequence().get_time_begin( ) currentEnd = self.exercise.get_current_sequence().get_time_end() for sub in self.exercise.get_translation_list(): begin = sub.get_time_begin() end = sub.get_time_end() if (begin >= currentBegin and begin <= currentEnd) or ( end >= currentBegin and end <= currentEnd) or (begin <= currentBegin and end >= currentEnd): translation += sub.get_text() + " " self.gui_controller.set_translation(translation) #_update displayed previous sentence text def __activate_previous_sequence_text(self): previous_sequence_text = "" previous_sequence = self.exercise.get_previous_sequence() if previous_sequence: for i, symbol in enumerate(previous_sequence.get_symbols()): previous_sequence_text += symbol if i < len(previous_sequence.get_words()): word = previous_sequence.get_words()[i] if word.is_valid(): previous_sequence_text += word.get_valid(lower=False) else: word_text = word.get_text() if len(word_text): previous_sequence_text += word.get_text() else: previous_sequence_text += "_" self.gui_controller.set_previous_sequence_text(previous_sequence_text) #Update displayed stats on new active sequence def _update_stats(self): sequenceCount = self.exercise.get_sequence_count() sequenceFound = 0 wordCount = 0 wordFound = 0 for sequence in self.exercise.get_sequence_list(): wordCount = wordCount + sequence.get_word_count() if sequence.is_valid(): sequenceFound += 1 wordFound += sequence.get_word_count() else: wordFound += sequence.get_word_found() if wordFound == 0: repeatRate = float(0) else: repeatRate = float( self.exercise.get_repeat_count()) / float(wordFound) self.gui_controller.set_statitics(sequenceCount, sequenceFound, wordCount, wordFound, repeatRate) def _update(self): self.gui_controller.set_sequence(self.exercise.get_current_sequence()) self.__validate_sequence() #Verify if the sequence is complete def __validate_sequence(self): if self.exercise.get_current_sequence().is_valid(): if self.exercise.get_repeat_after_completed(): if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() else: self.next_sequence(load=False) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited if self.player.get_seek( ) > (self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before()): self.goto_sequence_begin() self.play() else: self.play() #Goto beginning of the current sequence. Can start to play as soon #as the media player is ready def goto_sequence_begin(self, asSoonAsReady=False): self.state = Core.WAIT_END begin_time = self.exercise.get_current_sequence().get_time_begin( ) - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 if asSoonAsReady: self.player.seek_as_soon_as_ready(begin_time) else: self.player.seek(begin_time) self.player.set_next_callback_time( self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) #Write a char in current sequence at cursor position def write_char(self, char): if self.exercise.is_character_match(char): self.exercise.get_current_sequence().write_char(char) self.exercise.get_current_sequence().update_cursor_position() self._update() self.set_can_save(True) else: self._update() #Goto next word in current sequence def next_word(self): self.exercise.get_current_sequence().next_word() self._update() #Goto previous word in current sequence def previous_word(self): self.exercise.get_current_sequence().previous_word() self._update() #Choose current word in current sequence def select_sequence_word(self, wordIndex, wordIndexPos): try: self.exercise.get_current_sequence().select_sequence_word( wordIndex, wordIndexPos) except NoCharPossible: self.exercise.get_current_sequence().select_sequence_word( wordIndex, -1) self._update() #Goto first word in current sequence def first_word(self): self.exercise.get_current_sequence().first_word() self._update() #Goto last word in current sequence def last_word(self): self.exercise.get_current_sequence().last_word() self._update() #Delete a char before the cursor in current sequence def delete_previous_char(self): self.exercise.get_current_sequence().delete_previous_char() self._update() self.set_can_save(True) #Delete a char after the cursor in current sequence def delete_next_char(self): self.exercise.get_current_sequence().delete_next_char() self._update() self.set_can_save(True) #Goto previous char in current sequence def previous_char(self): self.exercise.get_current_sequence().previous_char() #The sequence don't change but the cursor position is no more up to date self._update() #Goto next char in current sequence def next_char(self): self.exercise.get_current_sequence().next_char() #The sequence don't change but the cursor position is no more up to date self._update() #Reveal correction for word at cursor in current sequence def complete_word(self): self.exercise.get_current_sequence().show_hint() self._update() self.set_can_save(True) #Reveal correction for word at cursor in current sequence def reveal_word(self): self.exercise.get_current_sequence().complete_word() self.exercise.get_current_sequence().next_word() self._update() self.set_can_save(True) #Reveal correction for word at cursor in current sequence def reveal_sequence(self): self.exercise.get_current_sequence().complete_all() self._update() self.set_can_save(True) #reset whole exercise def reset_exercise_content(self): self.exercise.reset() self.exercise.goto_sequence(0) #FIXME self._update() self.set_can_save(True) self.logger.debug("need to stop the current sequence") #FIXME #pause or play media def toggle_pause(self): if self.player.is_paused() and self.paused: self.play() elif not self.player.is_paused() and not self.paused: self.pause() #Change position in media and play it def seek_sequence(self, time): begin_time = self.exercise.get_current_sequence().get_time_begin( ) - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 pos = begin_time + time self.player.seek(pos) self.player.set_next_callback_time( self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) self.state = Core.WAIT_END if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #Thread to update slider position in gui def time_update_thread(self): timeUpdateThreadId = self.timeUpdateThreadId while timeUpdateThreadId == self.timeUpdateThreadId: time.sleep(0.5) pos_int = self.player.get_current_time() if pos_int != None: end_time = self.exercise.get_current_sequence().get_time_end() begin_time = self.exercise.get_current_sequence( ).get_time_begin() - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 duration = end_time - begin_time pos = pos_int - begin_time self.gui_controller.set_sequence_time(pos, duration) #Save current exercice def save(self, saveAs=False): if not self.exercise: self.logger.error("Save called but no exercise load") return if saveAs or self.exercise.get_output_save_path() == None: outputSavePath = self.gui_controller.ask_save_path() if not outputSavePath: return self.exercise.set_output_save_path(outputSavePath + ".perroquet") save_exercise(self.exercise, self.exercise.get_output_save_path()) self.config.set("lastopenfile", self.exercise.get_output_save_path()) #lastopenfileS l = self.config.get("lastopenfiles") path = self.exercise.get_output_save_path() name = self.exercise.get_name() or path self.config.set("lastopenfiles", [[path, name]] + [p for p in l if p[0] != path][:10]) self.set_can_save(False) #load the exercice at path def load_exercise(self, path): self.gui_controller.activate("closed") if self.exercise: self.save() try: self.exercise = load_exercise(path) self.exercise.set_media_change_callback( self.media_change_call_back) except IOError: self.logger.exception("No file at " + path) return if not self.exercise: return validPaths, errorList = self.exercise.is_paths_valid() if not validPaths: for error in errorList: self.gui_controller.signal_exercise_bad_path(error) self.set_can_save(False) self.gui_controller.activate("load_failed") self.gui_controller.ask_properties() return self._reload(False) if self.exercise.get_output_save_path() == None: self.set_can_save(True) else: self.set_can_save(False) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #Change paths of current exercice and reload subtitles and video def _update_paths(self, videoPath, exercisePath, translationPath): self.exercise.set_video_path(videoPath) self.exercise.set_exercise_path(exercisePath) self.exercise.set_translation_path(translationPath) validPaths, errorList = self.exercise.is_paths_valid() if not validPaths: for error in errorList: self.gui_controller.signal_exercise_bad_path(error) self.gui_controller.activate("load_failed") self.set_can_save(False) return self._set_paths(videoPath, exercisePath, translationPath) self._reload(True) self.set_can_save(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() def update_properties(self): self.exercise.initialize() self._reload(True) self.set_can_save(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #get paths of current exercise def get_paths(self): return (self.exercise.get_video_path(), self.exercise.get_exercise_path(), self.exercise.get_translation_path()) #Udpates vocabulary list in interface def _update_word_list(self): self.gui_controller.set_word_list(self.exercise.extract_word_list()) #Notify the user use the repeat command (for stats) def user_repeat(self): self.exercise.increment_repeat_count() self.set_can_save(True) #Signal to the gui that the exercise has unsaved changes def set_can_save(self, save): self.gui_controller.set_can_save(save) if self.exercise == None: title = "" elif self.exercise.get_name() != None: title = self.exercise.get_name() elif self.exercise.get_output_save_path() != None: title = self.exercise.get_output_save_path() else: title = _("Untitled exercise") self.last_save = save self.gui_controller.set_title(title, save) def get_can_save(self): return self.last_save def get_exercise(self): return self.exercise def get_player(self): return self.player def media_change_call_back(self): self.logger.info("new media : " + self.exercise.get_video_path()) """self.Pause() self.player.open(self.exercise.get_video_path()) """ self._reload(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() def export_as_template(self): self.gui_controller.ask_properties_advanced() path = self.gui_controller.ask_export_as_template_path() if path: self.exercise.set_template(True) save_exercise(self.exercise, path) self.exercise.set_template(False) def export_as_package(self): self.gui_controller.ask_properties_advanced() path = self.gui_controller.ask_export_as_package_path() if path: repoManager = ExerciseRepositoryManager() repoManager.export_as_package(self.exercise, path) self.logger.info("Export done") else: self.logger.warn("No valid path to export??") def import_package(self): import_path = self.gui_controller.ask_import_package() if import_path is not None: repo_manager = ExerciseRepositoryManager() error = repo_manager.import_package(import_path) if error is None: self.gui_controller.display_message( _("Import finish succesfully. Use the exercises manager to use the newly installed exercise." )) else: self.gui_controller.display_message( _("Import failed." + " " + error))
from video_player import VideoPlayer video_input = 'input/project_dataset/frames/concert' audio_samples = 'input/project_dataset/audio/concert.wav' player = VideoPlayer(video_input, audio_samples, 30) player.play()
class Core(object): WAIT_BEGIN = 0 WAIT_END = 1 def __init__(self): self.player = None self.last_save = False self.exercise = None self.config = config self.logger = logging.Logger("Core") self.logger.setLevel(defaultLoggingLevel) self.logger.addHandler(defaultLoggingHandler) #Call by the main, give an handler to the main gui def set_gui(self, gui): self.gui_controller = gui #Create a new exercice based on paths. load the new exercise and #begin to play def new_exercise(self, videoPath, exercisePath, translationPath, langId): self.exercise = Exercise() self.exercise.set_media_change_callback(self.media_change_call_back) self.exercise.new() self.exercise.set_language_id(langId) self._set_paths(videoPath, exercisePath, translationPath) # This initialize the exercise self._reload(True); self._activate_sequence() self.gui_controller.set_title("", True) #Configure the paths for the current exercice. Reload subtitles list. def _set_paths(self, videoPath, exercisePath, translationPath): self.exercise.set_video_path(videoPath) self.exercise.set_exercise_path(exercisePath) self.exercise.set_translation_path(translationPath) self.exercise.initialize() #Reload media player and begin to play (if the params is True) def _reload(self, load): if self.player != None: self.player.close() self.player = VideoPlayer() self.player.set_window_id(self.gui_controller.get_video_window_id()) self.player.activate_video_callback(self.gui_controller.activate_video_area) self.player.open(self.exercise.get_video_path()) self.player.set_callback(self._time_callback) self.paused = False self.gui_controller.activate_video_area(False) self.gui_controller.activate("loaded") self._update_word_list() self.timeUpdateThreadId = thread.start_new_thread(self.time_update_thread, ()) if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() else: self.pause() #play the media def play(self): self.gui_controller.set_playing(True) self.player.play() self.paused = False #pause the media def pause(self): self.gui_controller.set_playing(False) self.player.pause() self.paused = True #Modify media speed def set_speed(self, speed): self.gui_controller.set_speed(speed) self.player.set_speed(speed) #Callback call by video player to notify change of media position. #Stop the media at the end of uncompleted sequences def _time_callback(self): if self.state == Core.WAIT_BEGIN: self.player.set_next_callback_time(self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) self.state = Core.WAIT_END elif self.state == Core.WAIT_END: self.state = Core.WAIT_BEGIN if self.exercise.get_current_sequence().is_valid(): gtk.gdk.threads_enter() self.next_sequence(False) gtk.gdk.threads_leave() else: self.pause() #Repeat the currence sequence def repeat_sequence(self): if not self.exercise.is_current_sequence_repeat_limit_reach(): #Repeat limit not reach or no limit self.goto_sequence_begin() self.play() self.exercise.increment_current_sequence_repeat_count() #Change the active sequence def select_sequence(self, num, load=True): if self.exercise.get_current_sequence_id() == num: return self.exercise.goto_sequence(num) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() self.set_can_save(True) #Goto next sequence def next_sequence(self, load=True): if self.exercise.goto_next_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto previous sequence def previous_sequence(self, load=True): if self.exercise.goto_previous_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto next valid sequence def next_valid_sequence(self, load=True): if self.exercise.goto_next_valid_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Goto previous valid sequence def previous_valid_sequence(self, load=True): if self.exercise.goto_previous_valid_sequence(): self.set_can_save(True) self._activate_sequence() if load and self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() #Update interface with new sequence. Configure stop media callback def _activate_sequence(self): self.state = Core.WAIT_BEGIN self.set_speed(1) self.player.set_next_callback_time(self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before()) self.gui_controller.set_sequence_number(self.exercise.get_current_sequence_id(), self.exercise.get_sequence_count()) self.gui_controller.set_sequence(self.exercise.get_current_sequence()) self.__activate_translation() self.__activate_previous_sequence_text() self._update_stats() #_update displayed translation on new active sequence def __activate_translation(self): if not self.exercise.get_translation_list(): self.gui_controller.set_translation("") else: translation = "" currentBegin = self.exercise.get_current_sequence().get_time_begin() currentEnd = self.exercise.get_current_sequence().get_time_end() for sub in self.exercise.get_translation_list(): begin = sub.get_time_begin() end = sub.get_time_end() if (begin >= currentBegin and begin <= currentEnd) or (end >= currentBegin and end <= currentEnd) or (begin <= currentBegin and end >= currentEnd): translation += sub.get_text() + " " self.gui_controller.set_translation(translation) #_update displayed previous sentence text def __activate_previous_sequence_text(self): previous_sequence_text = ""; previous_sequence = self.exercise.get_previous_sequence() if previous_sequence: for i, symbol in enumerate(previous_sequence.get_symbols()): previous_sequence_text += symbol if i < len(previous_sequence.get_words()): word = previous_sequence.get_words()[i] if word.is_valid(): previous_sequence_text += word.get_valid(lower=False) else: word_text = word.get_text() if len(word_text): previous_sequence_text += word.get_text() else: previous_sequence_text += "_" self.gui_controller.set_previous_sequence_text(previous_sequence_text) #Update displayed stats on new active sequence def _update_stats(self): sequenceCount = self.exercise.get_sequence_count() sequenceFound = 0 wordCount = 0 wordFound = 0 for sequence in self.exercise.get_sequence_list(): wordCount = wordCount + sequence.get_word_count() if sequence.is_valid(): sequenceFound += 1 wordFound += sequence.get_word_count() else: wordFound += sequence.get_word_found() if wordFound == 0: repeatRate = float(0) else: repeatRate = float(self.exercise.get_repeat_count()) / float(wordFound) self.gui_controller.set_statitics(sequenceCount, sequenceFound, wordCount, wordFound, repeatRate) def _update(self): self.gui_controller.set_sequence(self.exercise.get_current_sequence()) self.__validate_sequence() #Verify if the sequence is complete def __validate_sequence(self): if self.exercise.get_current_sequence().is_valid(): if self.exercise.get_repeat_after_completed(): if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.repeat_sequence() else: self.next_sequence(load=False) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited if self.player.get_seek() > (self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before()): self.goto_sequence_begin() self.play() else: self.play() #Goto beginning of the current sequence. Can start to play as soon #as the media player is ready def goto_sequence_begin(self, asSoonAsReady=False): self.state = Core.WAIT_END begin_time = self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 if asSoonAsReady: self.player.seek_as_soon_as_ready(begin_time) else: self.player.seek(begin_time) self.player.set_next_callback_time(self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) #Write a char in current sequence at cursor position def write_char(self, char): if self.exercise.is_character_match(char): self.exercise.get_current_sequence().write_char(char) self.exercise.get_current_sequence().update_cursor_position() self._update() self.set_can_save(True) else: self._update() #Goto next word in current sequence def next_word(self): self.exercise.get_current_sequence().next_word() self._update() #Goto previous word in current sequence def previous_word(self): self.exercise.get_current_sequence().previous_word() self._update() #Choose current word in current sequence def select_sequence_word(self, wordIndex, wordIndexPos): try: self.exercise.get_current_sequence().select_sequence_word(wordIndex, wordIndexPos) except NoCharPossible: self.exercise.get_current_sequence().select_sequence_word(wordIndex, -1) self._update() #Goto first word in current sequence def first_word(self): self.exercise.get_current_sequence().first_word() self._update() #Goto last word in current sequence def last_word(self): self.exercise.get_current_sequence().last_word() self._update() #Delete a char before the cursor in current sequence def delete_previous_char(self): self.exercise.get_current_sequence().delete_previous_char() self._update() self.set_can_save(True) #Delete a char after the cursor in current sequence def delete_next_char(self): self.exercise.get_current_sequence().delete_next_char() self._update() self.set_can_save(True) #Goto previous char in current sequence def previous_char(self): self.exercise.get_current_sequence().previous_char() #The sequence don't change but the cursor position is no more up to date self._update() #Goto next char in current sequence def next_char(self): self.exercise.get_current_sequence().next_char() #The sequence don't change but the cursor position is no more up to date self._update() #Reveal correction for word at cursor in current sequence def complete_word(self): self.exercise.get_current_sequence().show_hint() self._update() self.set_can_save(True) #Reveal correction for word at cursor in current sequence def reveal_word(self): self.exercise.get_current_sequence().complete_word() self.exercise.get_current_sequence().next_word() self._update() self.set_can_save(True) #Reveal correction for word at cursor in current sequence def reveal_sequence(self): self.exercise.get_current_sequence().complete_all() self._update() self.set_can_save(True) #reset whole exercise def reset_exercise_content(self): self.exercise.reset() self.exercise.goto_sequence(0) #FIXME self._update() self.set_can_save(True) self.logger.debug("need to stop the current sequence") #FIXME #pause or play media def toggle_pause(self): if self.player.is_paused() and self.paused: self.play() elif not self.player.is_paused() and not self.paused: self.pause() #Change position in media and play it def seek_sequence(self, time): begin_time = self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 pos = begin_time + time self.player.seek(pos) self.player.set_next_callback_time(self.exercise.get_current_sequence().get_time_end() + self.exercise.get_play_margin_after()) self.state = Core.WAIT_END if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #Thread to update slider position in gui def time_update_thread(self): timeUpdateThreadId = self.timeUpdateThreadId while timeUpdateThreadId == self.timeUpdateThreadId: time.sleep(0.5) pos_int = self.player.get_current_time() if pos_int != None: end_time = self.exercise.get_current_sequence().get_time_end() begin_time = self.exercise.get_current_sequence().get_time_begin() - self.exercise.get_play_margin_before() if begin_time < 0: begin_time = 0 duration = end_time - begin_time pos = pos_int - begin_time self.gui_controller.set_sequence_time(pos, duration) #Save current exercice def save(self, saveAs=False): if not self.exercise: self.logger.error("Save called but no exercise load") return if saveAs or self.exercise.get_output_save_path() == None: outputSavePath = self.gui_controller.ask_save_path() if not outputSavePath: return self.exercise.set_output_save_path(outputSavePath + ".perroquet") save_exercise(self.exercise, self.exercise.get_output_save_path()) self.config.set("lastopenfile", self.exercise.get_output_save_path()) #lastopenfileS l = self.config.get("lastopenfiles") path = self.exercise.get_output_save_path() name = self.exercise.get_name() or path self.config.set("lastopenfiles", [[path, name]] + [p for p in l if p[0] != path][:10]) self.set_can_save(False) #load the exercice at path def load_exercise(self, path): self.gui_controller.activate("closed") if self.exercise: self.save() try: self.exercise = load_exercise(path) self.exercise.set_media_change_callback(self.media_change_call_back) except IOError: self.logger.exception("No file at " + path) return if not self.exercise: return validPaths, errorList = self.exercise.is_paths_valid() if not validPaths: for error in errorList: self.gui_controller.signal_exercise_bad_path(error) self.set_can_save(False) self.gui_controller.activate("load_failed") self.gui_controller.ask_properties() return self._reload(False) if self.exercise.get_output_save_path() == None: self.set_can_save(True) else: self.set_can_save(False) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #Change paths of current exercice and reload subtitles and video def _update_paths(self, videoPath, exercisePath, translationPath): self.exercise.set_video_path(videoPath) self.exercise.set_exercise_path(exercisePath) self.exercise.set_translation_path(translationPath) validPaths, errorList = self.exercise.is_paths_valid() if not validPaths: for error in errorList: self.gui_controller.signal_exercise_bad_path(error) self.gui_controller.activate("load_failed") self.set_can_save(False) return self._set_paths(videoPath, exercisePath, translationPath) self._reload(True) self.set_can_save(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() def update_properties(self): self.exercise.initialize() self._reload(True) self.set_can_save(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() #get paths of current exercise def get_paths(self): return (self.exercise.get_video_path(), self.exercise.get_exercise_path(), self.exercise.get_translation_path()) #Udpates vocabulary list in interface def _update_word_list(self): self.gui_controller.set_word_list(self.exercise.extract_word_list()) #Notify the user use the repeat command (for stats) def user_repeat(self): self.exercise.increment_repeat_count() self.set_can_save(True) #Signal to the gui that the exercise has unsaved changes def set_can_save(self, save): self.gui_controller.set_can_save(save) if self.exercise == None: title = "" elif self.exercise.get_name() != None: title = self.exercise.get_name() elif self.exercise.get_output_save_path() != None: title = self.exercise.get_output_save_path() else: title = _("Untitled exercise") self.last_save = save self.gui_controller.set_title(title, save) def get_can_save(self): return self.last_save def get_exercise(self): return self.exercise def get_player(self): return self.player def media_change_call_back(self): self.logger.info("new media : " + self.exercise.get_video_path()) """self.Pause() self.player.open(self.exercise.get_video_path()) """ self._reload(True) self._activate_sequence() self.goto_sequence_begin(True) if self.exercise.get_repeat_count_limit_by_sequence() == 0: #Auto start play only if repeat is not limited self.play() def export_as_template(self): self.gui_controller.ask_properties_advanced() path = self.gui_controller.ask_export_as_template_path() if path: self.exercise.set_template(True) save_exercise(self.exercise, path) self.exercise.set_template(False) def export_as_package(self): self.gui_controller.ask_properties_advanced() path = self.gui_controller.ask_export_as_package_path() if path: repoManager = ExerciseRepositoryManager() repoManager.export_as_package(self.exercise, path) self.logger.info("Export done") else: self.logger.warn("No valid path to export??") def import_package(self): import_path = self.gui_controller.ask_import_package() if import_path is not None: repo_manager = ExerciseRepositoryManager() error = repo_manager.import_package(import_path) if error is None: self.gui_controller.display_message(_("Import finish succesfully. Use the exercises manager to use the newly installed exercise.")) else: self.gui_controller.display_message(_("Import failed." + " " + error))
class Gui(QWidget): def __init__(self: 'Gui'): super().__init__() self.title = 'CSCI 576 Final Project' self.left = 0 self.top = 0 self.width = 1000 self.height = 360 self.jpgFolder = None self.rgbFolder = None self.wavFile = None self.playJpgFolder = None self.playWavFile = None self.threadpool = QThreadPool() self.playing_video = False self.video_paused = False self.keyboard_emulator = Controller() self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) # Evaluator Progress Bar self.evaluator_progress_bar = self.createProgressBarPercent() # Box Layout self.windowLayout = QVBoxLayout() # Options are to choose folders for video evaluation or play existing video self.online_mode_widget = self.createOnlineModeButtons() self.offline_mode_widget = self.createOfflineModeButtons() # Add buttons self.windowLayout.addWidget(self.online_mode_widget) self.windowLayout.addWidget(self.offline_mode_widget) # Set layout and show self.setLayout(self.windowLayout) self.show() def createProgressBarPercent(self: 'Gui') -> QProgressBar: progress_bar = QProgressBar() progress_bar.setMinimum(0) progress_bar.setMaximum(100) return progress_bar def createOnlineModeButtons(self: 'Gui') -> QGroupBox: onlineModeGroup = QGroupBox( "Choose your JPG, RGB, and WAV Files/Folders for video evaluation") onlineModeGroup.setFixedHeight(250) groupLayout = QVBoxLayout() pathLayout = QHBoxLayout() jpgBox = QVBoxLayout() self.jpgLabel = QLabel() jpgBox.addWidget( self.createButton('Choose JPG Folder', self.setJpgFolder)) jpgBox.addWidget(self.jpgLabel) pathLayout.addLayout(jpgBox) rgbBox = QVBoxLayout() self.rgbLabel = QLabel() rgbBox.addWidget( self.createButton('Choose RGB Folder', self.setRgbFolder)) rgbBox.addWidget(self.rgbLabel) pathLayout.addLayout(rgbBox) wavBox = QVBoxLayout() self.wavLabel = QLabel() wavBox.addWidget(self.createButton('Choose WAV File', self.setWavFile)) wavBox.addWidget(self.wavLabel) pathLayout.addLayout(wavBox) groupLayout.addLayout(pathLayout) evalLayout = QHBoxLayout() evalBox = QVBoxLayout() self.evaluatorProgressLabel = QLabel() evalBox.addWidget( self.createButton('Evaluate Video', self.evaulate_video)) evalBox.addWidget(self.evaluator_progress_bar) evalBox.addWidget(self.evaluatorProgressLabel) evalLayout.addLayout(evalBox) groupLayout.addLayout(evalLayout) playLayout = QHBoxLayout() playBox = QVBoxLayout() self.play_converted_video_button = self.createButton( 'Play', self.play_converted_video) playBox.addWidget(self.play_converted_video_button) playLayout.addLayout(playBox) groupLayout.addLayout(playLayout) onlineModeGroup.setLayout(groupLayout) return onlineModeGroup @pyqtSlot() def setJpgFolder(self: 'Gui'): self.jpgFolder = self.getFolderPathDialog('JPG Folder') + '/' self.jpgLabel.setText('/'.join(self.jpgFolder.split('/')[-5:])) @pyqtSlot() def setRgbFolder(self: 'Gui'): self.rgbFolder = self.getFolderPathDialog('RGB Folder') + '/' self.rgbLabel.setText('/'.join(self.rgbFolder.split('/')[-5:])) @pyqtSlot() def setWavFile(self: 'Gui'): self.wavFile = self.getFilePathDialog('WAV File', 'WAV Audio Files (*.wav)') self.wavLabel.setText('/'.join(self.wavFile.split('/')[-4:])) def createOfflineModeButtons(self: 'Gui') -> QGroupBox: groupBox = QGroupBox( "Or choose your JPG Folder and WAV File for Video Play") groupBox.setFixedHeight(100) layout = QHBoxLayout() jpgBox = QVBoxLayout() self.playJpgLabel = QLabel() jpgBox.addWidget( self.createButton('Choose JPG Folder', self.setPlayJpgFolder)) jpgBox.addWidget(self.playJpgLabel) layout.addLayout(jpgBox) wavBox = QVBoxLayout() self.playWavLabel = QLabel() wavBox.addWidget( self.createButton('Choose WAV File', self.setPlayWavFile)) wavBox.addWidget(self.playWavLabel) layout.addLayout(wavBox) playBox = QVBoxLayout() self.play_video_button = self.createButton('Play', self.play_video) playBox.addWidget(self.play_video_button) playBox.addWidget(QLabel()) layout.addLayout(playBox) groupBox.setLayout(layout) return groupBox @pyqtSlot() def play_video(self: 'Gui'): if not self.playing_video: self.playing_video = True self.video_player = VideoPlayer(self.playJpgFolder, self.playWavFile, 30) self.play_video_button.setText('Pause') self.video_player.play() self.play_video_button.setText('Play') self.playing_video = False else: self.keyboard_emulator.press('p') self.keyboard_emulator.release('p') self.video_paused = not self.video_paused if self.video_paused: self.play_video_button.setText('Play') else: self.play_video_button.setText('Pause') @pyqtSlot() def setPlayJpgFolder(self: 'Gui'): self.playJpgFolder = self.getFolderPathDialog('JPG Folder') + '/' self.playJpgLabel.setText('/'.join(self.playJpgFolder.split('/')[-4:])) @pyqtSlot() def setPlayWavFile(self: 'Gui'): self.playWavFile = self.getFilePathDialog('WAV File', 'WAV Audio Files (*.wav)') self.playWavLabel.setText('/'.join(self.playWavFile.split('/')[-3:])) def createButton(self: 'Gui', label: str, callback) -> QPushButton: button = QPushButton(label, self) button.clicked.connect(callback) return button def getFolderPathDialog(self: 'Gui', caption: str) -> str or None: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog options |= QFileDialog.ShowDirsOnly dirname = QFileDialog.getExistingDirectory(self, caption, directory=os.getcwd(), options=options) return dirname def getFilePathDialog(self: 'Gui', caption: str, filter: str) -> str or None: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName(self, caption, directory=os.getcwd(), filter=filter, options=options) return fileName @pyqtSlot() def evaulate_video(self: 'Gui'): worker = EvaluatorWorker(self.rgbFolder, self.wavFile) worker.signals.finished_with_results.connect(self.evaluation_complete) worker.signals.report_progress.connect(self.setProgress) self.threadpool.start(worker) def setProgress(self: 'Gui', information: Tuple[str, float]): label = information[0] percentComplete = information[1] progress = max(min(100, round(100 * percentComplete)), 0) print(label) print(progress) self.evaluatorProgressLabel.setText(label) # Trying this to prevent obscure error time.sleep(1) self.evaluator_progress_bar.setValue(progress) def evaluation_complete(self: 'Gui', information: Tuple[list, Wav]): frame_nums_to_write = information[0] audio = information[1] self.frame_nums_to_write = frame_nums_to_write self.audio = audio def play_converted_video(self: 'Gui'): self.converter.play() @pyqtSlot() def play_converted_video(self: 'Gui'): if not self.playing_video: self.playing_video = True converter = VideoConverter(self.frame_nums_to_write, self.jpgFolder, self.audio.data, 30, \ self.audio.rate, self.audio.sampwidth) self.play_converted_video_button.setText('Pause') converter.play() self.play_converted_video_button.setText('Play') self.playing_video = False else: self.keyboard_emulator.press('p') self.keyboard_emulator.release('p') self.video_paused = not self.video_paused if self.video_paused: self.play_converted_video_button.setText('Play') else: self.play_converted_video_button.setText('Pause')