def actionThumbnailView_trigger(self, event): log.info("Switch to Thumbnail View") # Get settings app = get_app() s = settings.get_settings() # Files if app.context_menu_object == "files": s.set("file_view", "thumbnail") self.tabFiles.layout().removeWidget(self.filesTreeView) self.filesTreeView.deleteLater() self.filesTreeView = None self.filesTreeView = FilesListView(self) self.tabFiles.layout().addWidget(self.filesTreeView) # Transitions elif app.context_menu_object == "transitions": s.set("transitions_view", "thumbnail") self.tabTransitions.layout().removeWidget(self.transitionsTreeView) self.transitionsTreeView.deleteLater() self.transitionsTreeView = None self.transitionsTreeView = TransitionsListView(self) self.tabTransitions.layout().addWidget(self.transitionsTreeView) # Effects elif app.context_menu_object == "effects": s.set("effects_view", "thumbnail") self.tabEffects.layout().removeWidget(self.effectsTreeView) self.effectsTreeView.deleteLater() self.effectsTreeView = None self.effectsTreeView = EffectsListView(self) self.tabEffects.layout().addWidget(self.effectsTreeView)
def __init__(self, window): self.app = get_app() self.window = window project = self.app.project s = settings.get_settings() # Get some settings from the project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) # Create an instance of a libopenshot Timeline object self.timeline = openshot.Timeline(width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) self.timeline.info.channel_layout = channel_layout self.timeline.info.has_audio = True self.timeline.info.has_video = True self.timeline.info.video_length = 99999 self.timeline.info.duration = 999.99 self.timeline.info.sample_rate = sample_rate self.timeline.info.channels = channels # Open the timeline reader self.timeline.Open() # Add self as listener to project data updates (at the beginning of the list) # This listener will receive events before others. self.app.updates.add_listener(self, 0) # Connect to signal self.window.MaxSizeChanged.connect(self.MaxSizeChangedCB)
def __init__(self, win): """ Constructor """ self.tutorials = [] self.win = win self.current_dialog = None # get translations app = get_app() _ = app._tr # get settings s = get_settings() self.tutorial_enabled = s.get("tutorial_enabled") self.tutorial_ids = s.get("tutorial_ids").split(",") # Add all possible tutorials self.tutorial_objects = [ {"id":"1", "x":20, "y":0, "object_id":"filesTreeView", "text":_("<b>Project Files:</b> Get started with your project by adding video, audio, and image files here. Drag and drop files from your file system.")}, {"id":"2", "x":200, "y":-15, "object_id":"timeline", "text":_("<b>Timeline:</b> Arrange your clips on the timeline here. Overlap clips to create automatic transitions. Access lots of fun presets and options by right-clicking on clips.")}, {"id":"3", "x":150, "y":100, "object_id":"dockVideoContents", "text":_("<b>Video Preview:</b> Watch your timeline video preview here. Use the buttons (play, rewind, fast-forward) to control the video playback.")}, {"id":"4", "x":20, "y":-35, "object_id":"propertyTableView", "text":_("<b>Properties:</b> View and change advanced properties of clips and effects here. Right-clicking on clips is usually faster than manually changing properties.")}, {"id":"5", "x":20, "y":10, "object_id":"transitionsTreeView", "text":_("<b>Transitions:</b> Create a gradual fade from one clip to another. Drag and drop a transition onto the timeline and position it on top of a clip (usually at the beginning or ending).")}, {"id":"6", "x":20, "y":20, "object_id":"effectsTreeView", "text":_("<b>Effects:</b> Adjust brigthness, contrast, saturation, and add exciting special effects. Drag and drop an effect onto the timeline and position it on top of a clip (or track)")}, {"id":"7", "x":-265, "y":-22, "object_id":"export_button", "text":_("<b>Export Video:</b> When you are ready to create your finished video, click this button to export your timeline as a single video file.")} ] # Connect to dock widgets self.win.dockFiles.visibilityChanged.connect(functools.partial(self.process, "dockFiles")) self.win.dockTransitions.visibilityChanged.connect(functools.partial(self.process, "dockTransitions")) self.win.dockEffects.visibilityChanged.connect(functools.partial(self.process, "dockEffects")) self.win.dockProperties.visibilityChanged.connect(functools.partial(self.process, "dockProperties")) self.win.dockVideo.visibilityChanged.connect(functools.partial(self.process, "dockVideo")) # Process tutorials (1 by 1) if self.tutorial_enabled: self.process()
def btnAdvanced_clicked(self): _ = self.app._tr # use an external editor to edit the image try: # Get settings s = settings.get_settings() # get the title editor executable path prog = s.get("title_editor") # launch advanced title editor # debug info log.info("Advanced title editor command: {} {} ".format(prog, self.filename)) p = subprocess.Popen([prog, self.filename]) # wait for process to finish (so we can update the preview) p.communicate() # update image preview self.load_svg_template() self.display_svg() except OSError: msg = QMessageBox() msg.setText(_("Please install {} to use this function").format(prog.capitalize())) msg.exec_()
def __init__(self, window): self.app = get_app() self.window = window project = self.app.project s = settings.get_settings() # Get some settings from the project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) # Create an instance of a libopenshot Timeline object self.timeline = openshot.Timeline( width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) self.timeline.info.channel_layout = channel_layout self.timeline.info.has_audio = True self.timeline.info.has_video = True self.timeline.info.video_length = 99999 self.timeline.info.duration = 999.99 self.timeline.info.sample_rate = sample_rate self.timeline.info.channels = channels # Open the timeline reader self.timeline.Open() # Add self as listener to project data updates (at the beginning of the list) # This listener will receive events before others. self.app.updates.add_listener(self, 0)
def add_to_recent_files(self, file_path): """ Add this project to the recent files list """ if not file_path or "backup.osp" in file_path: # Ignore backup recovery project return s = settings.get_settings() recent_projects = s.get("recent_projects") # Make sure file_path is absolute file_path = os.path.abspath(file_path) # Remove existing project if file_path in recent_projects: recent_projects.remove(file_path) # Remove oldest item (if needed) if len(recent_projects) > 10: del recent_projects[0] # Append file path to end of recent files recent_projects.append(file_path) # Save setting s.set("recent_projects", recent_projects) s.save()
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Track metrics track_metric_screen("preferences-screen") # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item # Connect search textbox self.txtSearch.textChanged.connect(self.txtSearch_changed) self.requires_restart = False self.category_names = {} self.category_tabs = {} self.category_sort = {} self.visible_category_names = {} # Tested hardware modes (default cpu mode with graphics card 0) self.hardware_tests_cards = { 0: [ 0, ] } # Populate preferences self.Populate() # Restore normal cursor get_app().restoreOverrideCursor()
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Track metrics track_metric_screen("profile-screen") # Loop through profiles self.profile_names = [] self.profile_paths = {} for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) # Add description of Profile to list self.profile_names.append(profile.info.description) self.profile_paths[profile.info.description] = profile_path # Sort list self.profile_names.sort() # Loop through sorted profiles box_index = 0 selected_index = 0 for profile_name in self.profile_names: # Add to dropdown self.cboProfile.addItem(profile_name, self.profile_paths[profile_name]) # Set default (if it matches the project) if app.project.get(['profile']) == profile_name: selected_index = box_index # increment item counter box_index += 1 # Connect signal self.cboProfile.currentIndexChanged.connect( functools.partial(self.dropdown_index_changed, self.cboProfile)) # Set current item (from project) self.cboProfile.setCurrentIndex(selected_index)
def new(self): """ Try to load default project settings file, will raise error on failure """ import openshot self._data = self.read_from_file(self.default_project_filepath) self.current_filepath = None self.has_unsaved_changes = False # Get default profile s = settings.get_settings() default_profile = s.get("default-profile") # Loop through profiles for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) if default_profile == profile.info.description: log.info("Setting default profile to %s" % profile.info.description) # Update default profile self._data["profile"] = profile.info.description self._data["width"] = profile.info.width self._data["height"] = profile.info.height self._data["fps"] = { "num": profile.info.fps.num, "den": profile.info.fps.den } break # Get the default audio settings for the timeline (and preview playback) default_sample_rate = int(s.get("default-samplerate")) default_channel_ayout = s.get("default-channellayout") channels = 2 channel_layout = openshot.LAYOUT_STEREO if default_channel_ayout == "LAYOUT_MONO": channels = 1 channel_layout = openshot.LAYOUT_MONO elif default_channel_ayout == "LAYOUT_STEREO": channels = 2 channel_layout = openshot.LAYOUT_STEREO elif default_channel_ayout == "LAYOUT_SURROUND": channels = 3 channel_layout = openshot.LAYOUT_SURROUND elif default_channel_ayout == "LAYOUT_5POINT1": channels = 6 channel_layout = openshot.LAYOUT_5POINT1 elif default_channel_ayout == "LAYOUT_7POINT1": channels = 8 channel_layout = openshot.LAYOUT_7POINT1 # Set default samplerate and channels self._data["sample_rate"] = default_sample_rate self._data["channels"] = channels self._data["channel_layout"] = channel_layout
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Track metrics track_metric_screen("profile-screen") # Loop through profiles self.profile_names = [] self.profile_paths = {} for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) # Add description of Profile to list self.profile_names.append(profile.info.description) self.profile_paths[profile.info.description] = profile_path # Sort list self.profile_names.sort() # Loop through sorted profiles box_index = 0 selected_index = 0 for profile_name in self.profile_names: # Add to dropdown self.cboProfile.addItem(profile_name, self.profile_paths[profile_name]) # Set default (if it matches the project) if app.project.get(['profile']) == profile_name: selected_index = box_index # increment item counter box_index += 1 # Connect signal self.cboProfile.currentIndexChanged.connect(functools.partial(self.dropdown_index_changed, self.cboProfile)) # Set current item (from project) self.cboProfile.setCurrentIndex(selected_index)
def load_settings(self): s = settings.get_settings() # Window state and geometry (also toolbar and dock locations) if s.get('window_geometry'): self.restoreGeometry(qt_types.str_to_bytes(s.get('window_geometry'))) if s.get('window_state'): self.restoreState(qt_types.str_to_bytes(s.get('window_state'))) # Load Recent Projects self.load_recent_menu()
def load_settings(self): s = settings.get_settings() # Window state and geometry (also toolbar and dock locations) if s.get('window_state_v2'): self.restoreState(qt_types.str_to_bytes(s.get('window_state_v2'))) if s.get('window_geometry_v2'): self.restoreGeometry( qt_types.str_to_bytes(s.get('window_geometry_v2')))
def inject_params(self, path, frame=None): # determine if this is 'preview' mode? is_preview = False if frame: # if a frame is passed in, we are in preview mode. # This is used to turn the background color to off-white... instead of transparent is_preview = True # prepare string to inject user_params = "\n#BEGIN INJECTING PARAMS\n" for k, v in self.params.items(): if type(v) == int or type(v) == float or type(v) == list or type(v) == bool: user_params += "params['{}'] = {}\n".format(k, v) if type(v) == str: user_params += "params['{}'] = u'{}'\n".format(k, v.replace("'", r"\'")) for k, v in self.get_project_params(is_preview).items(): if type(v) == int or type(v) == float or type(v) == list or type(v) == bool: user_params += "params['{}'] = {}\n".format(k, v) if type(v) == str: user_params += "params['{}'] = u'{}'\n".format(k, v.replace("'", r"\'").replace("\\", "\\\\")) user_params += "#END INJECTING PARAMS\n" # Force the Frame to 1 frame (for previewing) if frame: user_params += "\n#ONLY RENDER 1 FRAME FOR PREVIEW\n" user_params += "params['{}'] = {}\n".format("start_frame", frame) user_params += "params['{}'] = {}\n".format("end_frame", frame) user_params += "#END ONLY RENDER 1 FRAME FOR PREVIEW\n" # If GPU rendering is selected, see if GPU enable code is available s = settings.get_settings() gpu_code_body = None if s.get("blender_gpu_enabled"): gpu_enable_py = os.path.join(info.PATH, "blender", "scripts", "gpu_enable.py") try: f = open(gpu_enable_py, 'r') gpu_code_body = f.read() except IOError as e: log.error("Could not load GPU enable code! {}".format(e)) if gpu_code_body: log.info("Injecting GPU enable code from {}".format(gpu_enable_py)) user_params += "\n#ENABLE GPU RENDERING\n" user_params += gpu_code_body user_params += "\n#END ENABLE GPU RENDERING\n" # Open new temp .py file, and inject the user parameters with open(path, 'r') as f: script_body = f.read() # modify script variable script_body = script_body.replace("# INJECT_PARAMS_HERE", user_params) # Write update script with open(path, "w", encoding="UTF-8", errors="strict") as f: f.write(script_body)
def new(self): """ Try to load default project settings file, will raise error on failure """ import openshot self._data = self.read_from_file(self.default_project_filepath) self.current_filepath = None self.has_unsaved_changes = False # Get default profile s = settings.get_settings() default_profile = s.get("default-profile") # Loop through profiles for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) if default_profile == profile.info.description: log.info("Setting default profile to %s" % profile.info.description) # Update default profile self._data["profile"] = profile.info.description self._data["width"] = profile.info.width self._data["height"] = profile.info.height self._data["fps"] = {"num" : profile.info.fps.num, "den" : profile.info.fps.den} break # Get the default audio settings for the timeline (and preview playback) default_sample_rate = int(s.get("default-samplerate")) default_channel_ayout = s.get("default-channellayout") channels = 2 channel_layout = openshot.LAYOUT_STEREO if default_channel_ayout == "LAYOUT_MONO": channels = 1 channel_layout = openshot.LAYOUT_MONO elif default_channel_ayout == "LAYOUT_STEREO": channels = 2 channel_layout = openshot.LAYOUT_STEREO elif default_channel_ayout == "LAYOUT_SURROUND": channels = 3 channel_layout = openshot.LAYOUT_SURROUND elif default_channel_ayout == "LAYOUT_5POINT1": channels = 6 channel_layout = openshot.LAYOUT_5POINT1 elif default_channel_ayout == "LAYOUT_7POINT1": channels = 8 channel_layout = openshot.LAYOUT_7POINT1 # Set default samplerate and channels self._data["sample_rate"] = default_sample_rate self._data["channels"] = channels self._data["channel_layout"] = channel_layout
def checkbox_metrics_callback(self, state): """ Callback for error and anonymous usage checkbox""" s = get_settings() if state == Qt.Checked: # Enabling metrics sending s.set("send_metrics", True) # Opt-in for metrics tracking track_metric_screen("metrics-opt-in") else: # Opt-out for metrics tracking track_metric_screen("metrics-opt-out") # Disable metric sending s.set("send_metrics", False)
def load_theme(): """ Load the current OS theme, or fallback to a default one """ s = settings.get_settings() # If theme not reported by OS if QIcon.themeName() == '' and not s.get("theme") == "No Theme": # Address known Ubuntu bug of not reporting configured theme name, use default ubuntu theme if os.getenv('DESKTOP_SESSION') == 'ubuntu': QIcon.setThemeName('unity-icon-theme') # Windows/Mac use packaged theme else: QIcon.setThemeName(DEFAULT_THEME_NAME)
def run(self): # Running self.running = True # Get settings s = settings.get_settings() # Get port from settings port = s.get("debug-port") debug_enabled = s.get("debug-mode") # Set port on ZmqLogger singleton openshot.ZmqLogger.Instance().Connection("tcp://*:%s" % port) # Set filepath for ZmqLogger also openshot.ZmqLogger.Instance().Path( os.path.join(info.USER_PATH, 'libopenshot.log')) # Enable / Disable logger openshot.ZmqLogger.Instance().Enable(debug_enabled) # Socket to talk to server context = zmq.Context() socket = context.socket(zmq.SUB) socket.setsockopt_string(zmq.SUBSCRIBE, '') poller = zmq.Poller() poller.register(socket, zmq.POLLIN) log.info("Connecting to libopenshot with debug port: %s" % port) socket.connect("tcp://localhost:%s" % port) while self.running: msg = None # Receive all debug message sent from libopenshot (if any) socks = dict(poller.poll(1000)) if socks: if socks.get(socket) == zmq.POLLIN: msg = socket.recv(zmq.NOBLOCK) # Log the message (if any) if msg: log.info(msg.strip().decode('UTF-8'))
def __init__(self, win): """ Constructor """ self.win = win self.dock = win.dockTutorial self.current_dialog = None # get translations app = get_app() _ = app._tr # get settings s = get_settings() self.tutorial_enabled = s.get("tutorial_enabled") self.tutorial_ids = s.get("tutorial_ids").split(",") # Add all possible tutorials self.tutorial_objects = [ {"id":"0", "x":400, "y":0, "object_id":"filesTreeView", "text":_("<b>Welcome!</b> Magic VideoX Pro is an award-winning, open-source video editing application! This tutorial will walk you through the basics.<br><br>Would you like to automatically send errors and metrics to help improve Magic VideoX Pro?"), "arrow":False}, {"id":"1", "x":20, "y":0, "object_id":"filesTreeView", "text":_("<b>Project Files:</b> Get started with your project by adding video, audio, and image files here. Drag and drop files from your file system."), "arrow":True}, {"id":"2", "x":200, "y":-15, "object_id":"timeline", "text":_("<b>Timeline:</b> Arrange your clips on the timeline here. Overlap clips to create automatic transitions. Access lots of fun presets and options by right-clicking on clips."), "arrow":True}, {"id":"3", "x":200, "y":100, "object_id":"dockVideoContents", "text":_("<b>Video Preview:</b> Watch your timeline video preview here. Use the buttons (play, rewind, fast-forward) to control the video playback."), "arrow":True}, {"id":"4", "x":20, "y":-35, "object_id":"propertyTableView", "text":_("<b>Properties:</b> View and change advanced properties of clips and effects here. Right-clicking on clips is usually faster than manually changing properties."), "arrow":True}, {"id":"5", "x":20, "y":10, "object_id":"transitionsTreeView", "text":_("<b>Transitions:</b> Create a gradual fade from one clip to another. Drag and drop a transition onto the timeline and position it on top of a clip (usually at the beginning or ending)."), "arrow":True}, {"id":"6", "x":20, "y":20, "object_id":"effectsTreeView", "text":_("<b>Effects:</b> Adjust brightness, contrast, saturation, and add exciting special effects. Drag and drop an effect onto the timeline and position it on top of a clip (or track)"), "arrow":True}, {"id":"7", "x":-265, "y":-22, "object_id":"export_button", "text":_("<b>Export Video:</b> When you are ready to create your finished video, click this button to export your timeline as a single video file."), "arrow":True} ] # Configure tutorial frame self.dock.setTitleBarWidget(QWidget()) # Prevents window decoration self.dock.setAttribute(Qt.WA_NoSystemBackground, True) self.dock.setAttribute(Qt.WA_TranslucentBackground, True) self.dock.setWindowFlags(Qt.FramelessWindowHint) self.dock.setFloating(True) # Connect to interface dock widgets self.win.dockFiles.visibilityChanged.connect(functools.partial(self.process, "dockFiles")) self.win.dockTransitions.visibilityChanged.connect(functools.partial(self.process, "dockTransitions")) self.win.dockEffects.visibilityChanged.connect(functools.partial(self.process, "dockEffects")) self.win.dockProperties.visibilityChanged.connect(functools.partial(self.process, "dockProperties")) self.win.dockVideo.visibilityChanged.connect(functools.partial(self.process, "dockVideo")) # Process tutorials (1 by 1) if self.tutorial_enabled: self.process()
def __init__(self, win): """ Constructor """ self.win = win self.dock = win.dockTutorial self.current_dialog = None # get translations app = get_app() _ = app._tr # get settings s = get_settings() self.tutorial_enabled = s.get("tutorial_enabled") self.tutorial_ids = s.get("tutorial_ids").split(",") # Add all possible tutorials self.tutorial_objects = [ {"id":"0", "x":400, "y":0, "object_id":"filesTreeView", "text":_("<b>Welcome!</b> OpenShot Video Editor is an award-winning, open-source video editing application! This tutorial will walk you through the basics.<br><br>Would you like to automatically send errors and metrics to help improve OpenShot?"), "arrow":False}, {"id":"1", "x":20, "y":0, "object_id":"filesTreeView", "text":_("<b>Project Files:</b> Get started with your project by adding video, audio, and image files here. Drag and drop files from your file system."), "arrow":True}, {"id":"2", "x":200, "y":-15, "object_id":"timeline", "text":_("<b>Timeline:</b> Arrange your clips on the timeline here. Overlap clips to create automatic transitions. Access lots of fun presets and options by right-clicking on clips."), "arrow":True}, {"id":"3", "x":200, "y":100, "object_id":"dockVideoContents", "text":_("<b>Video Preview:</b> Watch your timeline video preview here. Use the buttons (play, rewind, fast-forward) to control the video playback."), "arrow":True}, {"id":"4", "x":20, "y":-35, "object_id":"propertyTableView", "text":_("<b>Properties:</b> View and change advanced properties of clips and effects here. Right-clicking on clips is usually faster than manually changing properties."), "arrow":True}, {"id":"5", "x":20, "y":10, "object_id":"transitionsTreeView", "text":_("<b>Transitions:</b> Create a gradual fade from one clip to another. Drag and drop a transition onto the timeline and position it on top of a clip (usually at the beginning or ending)."), "arrow":True}, {"id":"6", "x":20, "y":20, "object_id":"effectsTreeView", "text":_("<b>Effects:</b> Adjust brightness, contrast, saturation, and add exciting special effects. Drag and drop an effect onto the timeline and position it on top of a clip (or track)"), "arrow":True}, {"id":"7", "x":-265, "y":-22, "object_id":"export_button", "text":_("<b>Export Video:</b> When you are ready to create your finished video, click this button to export your timeline as a single video file."), "arrow":True} ] # Configure tutorial frame self.dock.setTitleBarWidget(QWidget()) # Prevents window decoration self.dock.setAttribute(Qt.WA_NoSystemBackground, True) self.dock.setAttribute(Qt.WA_TranslucentBackground, True) self.dock.setWindowFlags(Qt.FramelessWindowHint) self.dock.setFloating(True) # Connect to interface dock widgets self.win.dockFiles.visibilityChanged.connect(functools.partial(self.process, "dockFiles")) self.win.dockTransitions.visibilityChanged.connect(functools.partial(self.process, "dockTransitions")) self.win.dockEffects.visibilityChanged.connect(functools.partial(self.process, "dockEffects")) self.win.dockProperties.visibilityChanged.connect(functools.partial(self.process, "dockProperties")) self.win.dockVideo.visibilityChanged.connect(functools.partial(self.process, "dockVideo")) # Process tutorials (1 by 1) if self.tutorial_enabled: self.process()
def add_to_recent_files(self, file_path): """ Add this project to the recent files list """ s = settings.get_settings() recent_projects = s.get("recent_projects") # Remove existing project if file_path in recent_projects: recent_projects.remove(file_path) # Remove oldest item (if needed) if len(recent_projects) > 10: del recent_projects[0] # Append file path to end of recent files recent_projects.append(file_path) # Save setting s.set("recent_projects", recent_projects)
def __init__(self, window): QWebView.__init__(self) self.document_is_ready = False self.window = window self.setAcceptDrops(True) # Get settings self.settings_obj = settings.get_settings() # Add self as listener to project data updates (used to update the timeline) get_app().updates.add_listener(self) # set url from configuration (QUrl takes absolute paths for file system paths, create from QFileInfo) self.setUrl( QUrl.fromLocalFile(QFileInfo(self.html_path).absoluteFilePath())) # Connect signal of javascript initialization to our javascript reference init function self.page().mainFrame().javaScriptWindowObjectCleared.connect( self.setup_js_data)
def run(self): # Running self.running = True # Get settings s = settings.get_settings() # Get port from settings port = s.get("debug-port") debug_enabled = s.get("debug-mode") # Set port on ZmqLogger singleton openshot.ZmqLogger.Instance().Connection("tcp://*:%s" % port) # Set filepath for ZmqLogger also openshot.ZmqLogger.Instance().Path(os.path.join(info.USER_PATH, 'libopenshot.log')) # Enable / Disable logger openshot.ZmqLogger.Instance().Enable(debug_enabled) # Socket to talk to server context = zmq.Context() socket = context.socket(zmq.SUB) socket.setsockopt_string(zmq.SUBSCRIBE, '') poller = zmq.Poller() poller.register(socket, zmq.POLLIN) log.info("Connecting to libopenshot with debug port: %s" % port) socket.connect ("tcp://localhost:%s" % port) while self.running: msg = None # Receive all debug message sent from libopenshot (if any) socks = dict(poller.poll(1000)) if socks: if socks.get(socket) == zmq.POLLIN: msg = socket.recv(zmq.NOBLOCK) # Log the message (if any) if msg: log.info(msg.strip().decode('UTF-8'))
def new(self): """ Try to load default project settings file, will raise error on failure """ import openshot self._data = self.read_from_file(self.default_project_filepath) self.current_filepath = None self.has_unsaved_changes = False # Get default profile s = settings.get_settings() default_profile = s.get("default-profile") # Loop through profiles for file in os.listdir(info.PROFILES_PATH): # Load Profile and append description profile_path = os.path.join(info.PROFILES_PATH, file) profile = openshot.Profile(profile_path) if default_profile == profile.info.description: log.info("Setting default profile to %s" % profile.info.description) # Update default profile self._data["profile"] = profile.info.description self._data["width"] = profile.info.width self._data["height"] = profile.info.height self._data["fps"] = {"num" : profile.info.fps.num, "den" : profile.info.fps.den} # Clear any previous thumbnails try: if os.path.exists(info.THUMBNAIL_PATH): # Remove thumbnail folder shutil.rmtree(info.THUMBNAIL_PATH) # Create thumbnail folder os.mkdir(info.THUMBNAIL_PATH) # Clear any blender animations if os.path.exists(info.BLENDER_PATH): # Remove blender folder shutil.rmtree(info.BLENDER_PATH) # Create blender folder os.mkdir(info.BLENDER_PATH) except: pass
def hide_tips(self, tid, user_clicked=False): """ Hide the current tip, and don't show anymore """ s = get_settings() # Loop through and find current tid for tutorial_object in self.tutorial_objects: # Get details tutorial_id = tutorial_object["id"] if tutorial_id == tid: # Hide dialog self.close_dialogs() # Update settings that this tutorial is completed if tid not in self.tutorial_ids: self.tutorial_ids.append(str(tid)) s.set("tutorial_ids", ",".join(self.tutorial_ids)) # Mark tutorial as completed (if settings) if user_clicked: # Disable all tutorials self.tutorial_enabled = False s.set("tutorial_enabled", False)
def error_with_blender(self, version=None, command_output=None): """ Show a friendly error message regarding the blender executable or version. """ _ = self.app._tr s = settings.get_settings() version_message = "" if version: version_message = _("\n\nVersion Detected:\n{}").format(version) if command_output: version_message = _("\n\nError Output:\n{}").format(command_output) # show error message blender_version = "2.62" # Handle exception msg = QMessageBox() msg.setText(_("Blender, the free open source 3D content creation suite is required for this action (http://www.blender.org).\n\nPlease check the preferences in OpenShot and be sure the Blender executable is correct. This setting should be the path of the 'blender' executable on your computer. Also, please be sure that it is pointing to Blender version {} or greater.\n\nBlender Path:\n{}{}").format(blender_version, s.get("blender_command"), version_message)) msg.exec_() # Enable the Render button again self.enable_interface()
def load_recent_menu(self): """ Clear and load the list of recent menu items """ s = settings.get_settings() _ = get_app()._tr # Get translation function # Get list of recent projects recent_projects = s.get("recent_projects") # Add Recent Projects menu (after Open File) import functools if not self.recent_menu: # Create a new recent menu self.recent_menu = self.menuFile.addMenu(QIcon.fromTheme("document-open-recent"), _("Recent Projects")) self.menuFile.insertMenu(self.actionRecent_Placeholder, self.recent_menu) else: # Clear the existing children self.recent_menu.clear() # Add recent projects to menu for file_path in reversed(recent_projects): new_action = self.recent_menu.addAction(file_path) new_action.triggered.connect(functools.partial(self.recent_project_clicked, file_path))
def error_with_blender(self, version=None, command_output=None): """ Show a friendly error message regarding the blender executable or version. """ _ = self.app._tr s = settings.get_settings() version_message = "" if version: version_message = _("\n\nVersion Detected:\n{}").format(version) log.error("Blender version detected: {}".format(version)) if command_output: version_message = _("\n\nError Output:\n{}").format(command_output) log.error("Blender error output:\n{}".format(command_output)) msg = QMessageBox() msg.setText(_( "Blender, the free open source 3D content creation suite is required for this action (http://www.blender.org).\n\nPlease check the preferences in OpenShot and be sure the Blender executable is correct. This setting should be the path of the 'blender' executable on your computer. Also, please be sure that it is pointing to Blender version {} or greater.\n\nBlender Path:\n{}{}").format( info.BLENDER_MIN_VERSION, s.get("blender_command"), version_message)) msg.exec_() # Enable the Render button again self.enable_interface()
def accept(self): """ Start exporting video, but don't close window """ # Get settings self.s = settings.get_settings() # Disable controls self.txtFileName.setEnabled(False) self.txtExportFolder.setEnabled(False) self.tabWidget.setEnabled(False) self.export_button.setEnabled(False) self.exporting = True # Test Succeeded # Determine final exported file path file_name_with_ext = "%s.%s" % (self.txtFileName.text().strip(), self.txtVideoFormat.text().strip()) export_file_path = os.path.join(self.txtExportFolder.text().strip(), file_name_with_ext) log.info(export_file_path) # Translate object _ = get_app()._tr # Handle exception if os.path.exists(export_file_path): # File already exists! Prompt user ret = QMessageBox.question(self, _("Export Video"), _("%s already exists.\nDo you want to replace it?") % file_name_with_ext, QMessageBox.No | QMessageBox.Yes) if ret == QMessageBox.No: # Stop and don't do anything # Re-enable controls self.txtFileName.setEnabled(True) self.txtExportFolder.setEnabled(True) self.tabWidget.setEnabled(True) self.export_button.setEnabled(True) self.exporting = False return # Create FFmpegWriter try: w = openshot.FFmpegWriter(export_file_path) # Set video options w.SetVideoOptions(True, self.txtVideoCodec.text(), openshot.Fraction(self.txtFrameRateNum.value(), self.txtFrameRateDen.value()), self.txtWidth.value(), self.txtHeight.value(), openshot.Fraction(self.txtPixelRatioNum.value(), self.txtPixelRatioDen.value()), False, False, int(self.convert_to_bytes(self.txtVideoBitRate.text()))) # Set audio options w.SetAudioOptions(True, self.txtAudioCodec.text(), self.txtSampleRate.value(), self.txtChannels.value(), self.cboChannelLayout.currentData(), int(self.convert_to_bytes(self.txtAudioBitrate.text()))) # Open the writer w.Open() # Init progress bar self.progressExportVideo.setMinimum(self.txtStartFrame.value()) self.progressExportVideo.setMaximum(self.txtEndFrame.value()) # Write each frame in the selected range for frame in range(self.txtStartFrame.value(), self.txtEndFrame.value() + 1): # Update progress bar self.progressExportVideo.setValue(frame) # Process events (to show the progress bar moving) QCoreApplication.processEvents() # Write the frame object to the video w.WriteFrame(get_app().window.timeline_sync.timeline.GetFrame(frame)) # Check if we need to bail out if not self.exporting: break # Close writer w.Close() except Exception as e: # TODO: Find a better way to catch the error. This is the only way I have found that # does not throw an error error_type_str = str(e) log.info("Error type string: %s" % error_type_str) if "InvalidChannels" in error_type_str: log.info("Error setting invalid # of channels (%s)" % (self.txtChannels.value())) track_metric_error("invalid-channels-%s-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text(), self.txtChannels.value())) elif "InvalidSampleRate" in error_type_str: log.info("Error setting invalid sample rate (%s)" % (self.txtSampleRate.value())) track_metric_error("invalid-sample-rate-%s-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text(), self.txtSampleRate.value())) elif "InvalidFormat" in error_type_str: log.info("Error setting invalid format (%s)" % (self.txtVideoFormat.text())) track_metric_error("invalid-format-%s" % (self.txtVideoFormat.text())) elif "InvalidCodec" in error_type_str: log.info("Error setting invalid codec (%s/%s/%s)" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text())) track_metric_error("invalid-codec-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text())) elif "ErrorEncodingVideo" in error_type_str: log.info("Error encoding video frame (%s/%s/%s)" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text())) track_metric_error("video-encode-%s-%s-%s" % (self.txtVideoFormat.text(), self.txtVideoCodec.text(), self.txtAudioCodec.text())) # Show friendly error friendly_error = error_type_str.split("> ")[0].replace("<", "") # Prompt error message msg = QMessageBox() _ = get_app()._tr msg.setWindowTitle(_("Export Error")) msg.setText(_("Sorry, there was an error exporting your video: \n%s") % friendly_error) msg.exec_() # Accept dialog super(Export, self).accept() # Restore timeline settings self.restoreTimeline() log.info("End Accept")
def __init__(self): #Create dialog class QDialog.__init__(self) #Load UI from designer ui_util.load_ui(self, self.ui_path) #Init UI ui_util.init_ui(self) #get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item self.category_names = {} self.category_tabs = {} # Loop through settings and find all unique categories for item in self.settings_data: category = item["category"] setting_type = item["type"] if not setting_type == "hidden": # Load setting if not category in self.category_names: self.category_names[category] = [] # Add new category as a tab tabWidget = QWidget(self) self.tabCategories.addTab(tabWidget, _(category)) self.category_tabs[category] = tabWidget # Add form layout to this tab layout = QFormLayout(tabWidget) # Append settings into correct category self.category_names[category].append(item) # Loop through each category setting, and add them to the tabs for category in self.category_tabs.keys(): tabWidget = self.category_tabs[category] # Loop through settings for each category for param in self.category_names[category]: # Create Label widget = None label = QLabel() label.setText(_(param["title"])) label.setToolTip(_(param["title"])) if param["type"] == "spinner": # create spinner widget = QDoubleSpinBox() widget.setMinimum(float(param["min"])) widget.setMaximum(float(param["max"])) widget.setValue(float(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param)) elif param["type"] == "text": # create spinner widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect(functools.partial(self.text_value_changed, widget, param)) elif param["type"] == "bool": # create spinner widget = QCheckBox() if param["value"] == True: widget.setCheckState(Qt.Checked) else: widget.setCheckState(Qt.Unchecked) widget.stateChanged.connect(functools.partial(self.bool_value_changed, widget, param)) elif param["type"] == "dropdown": # create spinner widget = QComboBox() # Add normal values box_index = 0 for value_item in param["values"]: k = value_item["name"] v = value_item["value"] # add dropdown item widget.addItem(_(k), v) # select dropdown (if default) if v == param["value"]: widget.setCurrentIndex(box_index) box_index = box_index + 1 widget.currentIndexChanged.connect(functools.partial(self.dropdown_index_changed, widget, param)) # Add Label and Widget to the form if (widget and label): tabWidget.layout().addRow(label, widget) elif (label): tabWidget.layout().addRow(label)
def __init__(self, files=None, position=0.0): # Create dialog class QDialog.__init__(self) # Load UI from Designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # Get settings self.settings = settings.get_settings() # Get translation object self.app = get_app() _ = self.app._tr # Track metrics track_metric_screen("add-to-timeline-screen") # Add custom treeview to window self.treeFiles = TimelineTreeView(self) self.vboxTreeParent.insertWidget(0, self.treeFiles) # Update data in model self.treeFiles.timeline_model.update_model(files) # Refresh view self.treeFiles.refresh_view() # Init start position self.txtStartTime.setValue(position) # Init default image length self.txtImageLength.setValue(self.settings.get("default-image-length")) self.txtImageLength.valueChanged.connect(self.updateTotal) self.cmbTransition.currentIndexChanged.connect(self.updateTotal) self.cmbFade.currentIndexChanged.connect(self.updateTotal) self.txtFadeLength.valueChanged.connect(self.updateTotal) self.txtTransitionLength.valueChanged.connect(self.updateTotal) # Add all tracks to dropdown tracks = Track.filter() for track in reversed(tracks): # Add to dropdown self.cmbTrack.addItem(_('Track %s' % track.data['number']), track.data['number']) # Add all fade options self.cmbFade.addItem(_('None'), None) self.cmbFade.addItem(_('Fade In'), 'Fade In') self.cmbFade.addItem(_('Fade Out'), 'Fade Out') self.cmbFade.addItem(_('Fade In & Out'), 'Fade In & Out') # Add all zoom options self.cmbZoom.addItem(_('None'), None) self.cmbZoom.addItem(_('Random'), 'Random') self.cmbZoom.addItem(_('Zoom In'), 'Zoom In') self.cmbZoom.addItem(_('Zoom Out'), 'Zoom Out') # Add all transitions transitions_dir = os.path.join(info.PATH, "transitions") common_dir = os.path.join(transitions_dir, "common") extra_dir = os.path.join(transitions_dir, "extra") transition_groups = [{"type": "common", "dir": common_dir, "files": os.listdir(common_dir)}, {"type": "extra", "dir": extra_dir, "files": os.listdir(extra_dir)}] self.cmbTransition.addItem(_('None'), None) self.cmbTransition.addItem(_('Random'), 'random') self.transitions = [] for group in transition_groups: type = group["type"] dir = group["dir"] files = group["files"] for filename in sorted(files): path = os.path.join(dir, filename) (fileBaseName, fileExtension) = os.path.splitext(filename) # Skip hidden files (such as .DS_Store, etc...) if filename[0] == "." or "thumbs.db" in filename.lower(): continue # split the name into parts (looking for a number) suffix_number = None name_parts = fileBaseName.split("_") if name_parts[-1].isdigit(): suffix_number = name_parts[-1] # get name of transition trans_name = fileBaseName.replace("_", " ").capitalize() # replace suffix number with placeholder (if any) if suffix_number: trans_name = trans_name.replace(suffix_number, "%s") trans_name = _(trans_name) % suffix_number else: trans_name = _(trans_name) # Check for thumbnail path (in build-in cache) thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName)) # Check built-in cache (if not found) if not os.path.exists(thumb_path): # Check user folder cache thumb_path = os.path.join(info.CACHE_PATH, "{}.png".format(fileBaseName)) # Add item self.transitions.append(path) self.cmbTransition.addItem(QIcon(thumb_path), _(trans_name), path) # Connections self.btnMoveUp.clicked.connect(self.btnMoveUpClicked) self.btnMoveDown.clicked.connect(self.btnMoveDownClicked) self.btnShuffle.clicked.connect(self.btnShuffleClicked) self.btnRemove.clicked.connect(self.btnRemoveClicked) self.btnBox.accepted.connect(self.accept) self.btnBox.rejected.connect(self.reject) # Update total self.updateTotal()
def save_settings(self): s = settings.get_settings() # Save window state and geometry (saves toolbar and dock locations) s.set('window_state', qt_types.bytes_to_str(self.saveState())) s.set('window_geometry', qt_types.bytes_to_str(self.saveGeometry()))
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Track metrics track_metric_screen("preferences-screen") # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item self.requires_restart = False self.category_names = {} self.category_tabs = {} # Loop through settings and find all unique categories for item in self.settings_data: category = item["category"] setting_type = item["type"] if not setting_type == "hidden": # Load setting if not category in self.category_names: self.category_names[category] = [] # Add new category as a tab tabWidget = QWidget(self) self.tabCategories.addTab(tabWidget, _(category)) self.category_tabs[category] = tabWidget # Add form layout to this tab layout = QFormLayout(tabWidget) # Append settings into correct category self.category_names[category].append(item) # Loop through each category setting, and add them to the tabs for category in self.category_tabs.keys(): tabWidget = self.category_tabs[category] # Loop through settings for each category for param in self.category_names[category]: # Create Label widget = None label = QLabel() label.setText(_(param["title"])) label.setToolTip(_(param["title"])) if param["type"] == "spinner": # create QDoubleSpinBox widget = QDoubleSpinBox() widget.setMinimum(float(param["min"])) widget.setMaximum(float(param["max"])) widget.setValue(float(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect( functools.partial(self.spinner_value_changed, param)) if param["type"] == "spinner-int": # create QDoubleSpinBox widget = QSpinBox() widget.setMinimum(int(param["min"])) widget.setMaximum(int(param["max"])) widget.setValue(int(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect( functools.partial(self.spinner_value_changed, param)) elif param["type"] == "text": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect( functools.partial(self.text_value_changed, widget, param)) elif param["type"] == "bool": # create spinner widget = QCheckBox() if param["value"] == True: widget.setCheckState(Qt.Checked) else: widget.setCheckState(Qt.Unchecked) widget.stateChanged.connect( functools.partial(self.bool_value_changed, widget, param)) elif param["type"] == "dropdown": # create spinner widget = QComboBox() # Get values value_list = param["values"] # Overwrite value list (for profile dropdown) if param["setting"] == "default-profile": value_list = [] # Loop through profiles for profile_folder in [ info.USER_PROFILES_PATH, info.PROFILES_PATH ]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join( profile_folder, file) profile = openshot.Profile(profile_path) value_list.append({ "name": profile.info.description, "value": profile.info.description }) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Overwrite value list (for language dropdown) if param["setting"] == "default-language": value_list = [] # Loop through languages for locale, language, country in get_all_languages(): # Load Profile and append description if language: lang_name = "%s (%s)" % (language, locale) value_list.append({ "name": lang_name, "value": locale }) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Add Default to top of list value_list.insert(0, { "name": _("Default"), "value": "Default" }) # Add normal values box_index = 0 for value_item in value_list: k = value_item["name"] v = value_item["value"] # add dropdown item widget.addItem(_(k), v) # select dropdown (if default) if v == param["value"]: widget.setCurrentIndex(box_index) box_index = box_index + 1 widget.currentIndexChanged.connect( functools.partial(self.dropdown_index_changed, widget, param)) # Add Label and Widget to the form if (widget and label): tabWidget.layout().addRow(label, widget) elif (label): tabWidget.layout().addRow(label)
def initTimeline(self, cuts, clips_json): project = get_app().project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) ''' self.file_path = file.absolute_path() self.video_length = int(file.data['video_length']) self.fps_num = int(file.data['fps']['num']) self.fps_den = int(file.data['fps']['den']) self.fps = float(self.fps_num) / float(self.fps_den) self.width = int(file.data['width']) self.height = int(file.data['height']) self.sample_rate = int(file.data['sample_rate']) self.channels = int(file.data['channels']) self.channel_layout = int(file.data['channel_layout']) # Open video file with Reader log.info(self.file_path) ''' # Create an instance of a libopenshot Timeline object timeline = openshot.Timeline(width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) try: # Add clip for current preview file clip = openshot.Clip("/Users/admin/Downloads/BLACKPINK_Kill_This_Love.mp4") # Show waveform for audio files if not clip.Reader().info.has_video and clip.Reader().info.has_audio: clip.Waveform(True) # Set has_audio property #timeline.info.has_audio = clip.Reader().info.has_audio timeline.AddClip(clip) except: log.error('Failed to load media file into preview player: %s' % self.file_path) return None timeline.Open() return timeline try: import json except ImportError: import simplejson as json s = settings.get_settings() project = get_app().project # Get some settings from the project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) # Create an instance of a libopenshot Timeline object timeline = openshot.Timeline(width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) timeline.info.channel_layout = channel_layout timeline.info.has_audio = True timeline.info.has_video = True timeline.info.video_length = 99999 timeline.info.duration = 999.99 timeline.info.sample_rate = sample_rate timeline.info.channels = channels # Open the timeline reader timeline.Open() #self.timeline.ApplyMapperToClips print("0------", timeline.info) #return timeline clips = self.jsonToClips(clips_json) print("222222222222221111", clips) for cut in cuts: intersecting_clips = self.getIntersectClips(clips, float(cut["start"])) print("111111111", intersecting_clips, fps) if intersecting_clips: for clip in intersecting_clips: print("222222222", clip["reader"]["path"]) path = clip["reader"]["path"] print("-----000000", path) c = openshot.Clip(path) #c.Start(cut["start"]) #c.End(cut["end"]) #c.Position = 0#cut["start"] # Append missing attributes to Clip JSON #new_clip = json.loads(c.Json(), strict=False) #new_clip.SetJson(clip.Json()) #new_clip["start"] = cut["start"] #new_clip["end"] = cut["end"] #new_clip["position"] = 0#cut["start"] try: # Add clip for current preview file #c.SetJson(new_clip) c.display = openshot.FRAME_DISPLAY_CLIP timeline.AddClip(c) #print('add into preview video player: %s', c.Json()) except: log.error('Failed to add into preview video player: %s' % c.Json()) # Get list of clip ids #clip_ids = [c.id for c in intersecting_clips] #self.timeline.Slice_Triggered(0, clip_ids, trans_ids, playhead_position) # Open and set reader #timeline.Open() return timeline # Connect to signal #self.window.MaxSizeChanged.connect(self.MaxSizeChangedCB) ''' if action.type == "load": # This JSON is initially loaded to libopenshot to update the timeline self.timeline.SetJson(action.json(only_value=True)) self.timeline.Open() # Re-Open the Timeline reader # The timeline's profile changed, so update all clips self.timeline.ApplyMapperToClips() # Refresh current frame (since the entire timeline was updated) self.window.refreshFrameSignal.emit() else: # This JSON DIFF is passed to libopenshot to update the timeline self.timeline.ApplyJsonDiff(action.json(is_array=True)) ''' '''
def __init__(self, id, text, arrow, *args): # Invoke parent init QWidget.__init__(self, *args) # get translations app = get_app() _ = app._tr # Keep track of widget to position next to self.id = id self.arrow = arrow # Create vertical box vbox = QVBoxLayout() vbox.setContentsMargins(32,10,10,10) # Add label self.label = QLabel(self) self.label.setText(text) self.label.setTextFormat(Qt.RichText) self.label.setWordWrap(True) self.label.setStyleSheet("margin-left: 20px;") vbox.addWidget(self.label) # Add error and anonymous metrics checkbox (for ID=0) tooltip # This is a bit of a hack, but since it's the only exception, it's # probably okay for now. if self.id == "0": # Get settings s = get_settings() # create spinner checkbox_metrics = QCheckBox() checkbox_metrics.setText(_("Yes, I would like to improve OpenShot!")) checkbox_metrics.setStyleSheet("margin-left: 25px; margin-bottom: 5px;") if s.get("send_metrics"): checkbox_metrics.setCheckState(Qt.Checked) else: checkbox_metrics.setCheckState(Qt.Unchecked) checkbox_metrics.stateChanged.connect(functools.partial(self.checkbox_metrics_callback)) vbox.addWidget(checkbox_metrics) # Add button box hbox = QHBoxLayout() hbox.setContentsMargins(20,10,0,0) # Create buttons self.btn_close_tips = QPushButton(self) self.btn_close_tips.setText(_("Hide Tutorial")) self.btn_next_tip = QPushButton(self) self.btn_next_tip.setText(_("Next")) self.btn_next_tip.setStyleSheet("font-weight:bold;") hbox.addWidget(self.btn_close_tips) hbox.addWidget(self.btn_next_tip) vbox.addLayout(hbox) # Set layout self.setLayout(vbox) # Set size self.setMinimumWidth(350) self.setMinimumHeight(100) # Make transparent self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAttribute(Qt.WA_TranslucentBackground, True)
def LoadFile(self, path=None): """ Load a media file into the video player """ # Check to see if this path is already loaded # TODO: Determine why path is passed in as an empty string instead of None if path == self.clip_path or (not path and not self.clip_path): return log.info("LoadFile %s" % path) s = settings.get_settings() # Determine the current frame of the timeline (when switching to a clip) seek_position = 1 if path and not self.clip_path: # Track the current frame self.original_position = self.player.Position() # If blank path, switch back to self.timeline reader if not path: # Return to self.timeline reader log.info("Set timeline reader again in player: %s" % self.timeline) self.player.Reader(self.timeline) # Clear clip reader reference self.clip_reader = None self.clip_path = None # Switch back to last timeline position seek_position = self.original_position else: # Get extension of media path ext = os.path.splitext(path) # Create new timeline reader (to preview selected clip) s = settings.get_settings() project = get_app().project # Get some settings from the project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) # Create an instance of a libopenshot Timeline object self.clip_reader = openshot.Timeline(width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) self.clip_reader.info.channel_layout = channel_layout self.clip_reader.info.has_audio = True self.clip_reader.info.has_video = True self.clip_reader.info.video_length = 999999 self.clip_reader.info.duration = 999999 self.clip_reader.info.sample_rate = sample_rate self.clip_reader.info.channels = channels try: # Add clip for current preview file new_clip = openshot.Clip(path) self.clip_reader.AddClip(new_clip) except: log.error('Failed to load media file into video player: %s' % path) return # Assign new clip_reader self.clip_path = path # Keep track of previous clip readers (so we can Close it later) self.previous_clips.append(new_clip) self.previous_clip_readers.append(self.clip_reader) # Open and set reader self.clip_reader.Open() self.player.Reader(self.clip_reader) # Close and destroy old clip readers (leaving the 3 most recent) while len(self.previous_clip_readers) > 3: log.info('Removing old clips from preview: %s' % self.previous_clip_readers[0]) previous_clip = self.previous_clips.pop(0) previous_clip.Close() previous_reader = self.previous_clip_readers.pop(0) previous_reader.Close() # Seek to frame 1, and resume speed self.Seek(seek_position)
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Track metrics track_metric_screen("preferences-screen") # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item self.requires_restart = False self.category_names = {} self.category_tabs = {} # Loop through settings and find all unique categories for item in self.settings_data: category = item["category"] setting_type = item["type"] if not setting_type == "hidden": # Load setting if not category in self.category_names: self.category_names[category] = [] # Add new category as a tab tabWidget = QWidget(self) self.tabCategories.addTab(tabWidget, _(category)) self.category_tabs[category] = tabWidget # Add form layout to this tab layout = QFormLayout(tabWidget) # Append settings into correct category self.category_names[category].append(item) # Loop through each category setting, and add them to the tabs for category in self.category_tabs.keys(): tabWidget = self.category_tabs[category] # Loop through settings for each category for param in self.category_names[category]: # Create Label widget = None label = QLabel() label.setText(_(param["title"])) label.setToolTip(_(param["title"])) if param["type"] == "spinner": # create QDoubleSpinBox widget = QDoubleSpinBox() widget.setMinimum(float(param["min"])) widget.setMaximum(float(param["max"])) widget.setValue(float(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param)) if param["type"] == "spinner-int": # create QDoubleSpinBox widget = QSpinBox() widget.setMinimum(int(param["min"])) widget.setMaximum(int(param["max"])) widget.setValue(int(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param)) elif param["type"] == "text": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect(functools.partial(self.text_value_changed, widget, param)) elif param["type"] == "bool": # create spinner widget = QCheckBox() if param["value"] == True: widget.setCheckState(Qt.Checked) else: widget.setCheckState(Qt.Unchecked) widget.stateChanged.connect(functools.partial(self.bool_value_changed, widget, param)) elif param["type"] == "dropdown": # create spinner widget = QComboBox() # Get values value_list = param["values"] # Overwrite value list (for profile dropdown) if param["setting"] == "default-profile": value_list = [] # Loop through profiles for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) value_list.append({"name":profile.info.description, "value":profile.info.description}) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Overwrite value list (for language dropdown) if param["setting"] == "default-language": value_list = [] # Loop through languages for locale, language, country in get_all_languages(): # Load Profile and append description if language: lang_name = "%s (%s)" % (language, locale) value_list.append({"name":lang_name, "value":locale}) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Add Default to top of list value_list.insert(0, {"name":_("Default"), "value":"Default"}) # Add normal values box_index = 0 for value_item in value_list: k = value_item["name"] v = value_item["value"] # add dropdown item widget.addItem(_(k), v) # select dropdown (if default) if v == param["value"]: widget.setCurrentIndex(box_index) box_index = box_index + 1 widget.currentIndexChanged.connect(functools.partial(self.dropdown_index_changed, widget, param)) # Add Label and Widget to the form if (widget and label): tabWidget.layout().addRow(label, widget) elif (label): tabWidget.layout().addRow(label)
def init_language(): """ Find the current locale, and install the correct translators """ # Get app instance app = QCoreApplication.instance() # Setup of our list of translators and paths translator_types = ( { "type": 'QT', "pattern": 'qt_%s', # Older versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath) }, { "type": 'QT', "pattern": 'qtbase_%s', # Newer versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath) }, { "type": 'QT', "pattern": 'qt_%s', "path": os.path.join(info.PATH, 'locale', 'QT') }, # Optional path where we package QT translations { "type": 'QT', "pattern": 'qtbase_%s', "path": os.path.join(info.PATH, 'locale', 'QT') }, # Optional path where we package QT translations { "type": 'OpenShot', "pattern": os.path.join('%s', 'LC_MESSAGES', 'OpenShot'), # Our custom translations "path": os.path.join(info.PATH, 'locale') }, ) # Determine the environment locale, or default to system locale name locale_names = [ os.environ.get('LANG', QLocale().system().name()), os.environ.get('LOCALE', QLocale().system().name()) ] # Determine if the user has overwritten the language (in the preferences) preference_lang = settings.get_settings().get('default-language') if preference_lang != "Default": # Append preference lang to top of list locale_names.insert(0, preference_lang) # Output all system languages detected log.info("Qt Detected Languages: {}".format( QLocale().system().uiLanguages())) log.info("LANG Environment Variable: {}".format( os.environ.get('LANG', QLocale().system().name()))) log.info("LOCALE Environment Variable: {}".format( os.environ.get('LOCALE', QLocale().system().name()))) # Default the locale to C, for number formatting locale.setlocale(locale.LC_ALL, 'C') # Loop through environment variables found_language = False for locale_name in locale_names: # Don't try on default locale, since it fails to load what is the default language if 'en_US' in locale_name: log.info("Skipping English language (no need for translation): {}". format(locale_name)) continue # Go through each translator and try to add for current locale for type in translator_types: trans = QTranslator(app) if find_language_match(type["pattern"], type["path"], trans, locale_name): # Install translation app.installTranslator(trans) found_language = True # Exit if found language if found_language: log.info( "Exiting translation system (since we successfully loaded: {})" .format(locale_name)) break
def Render(self, blend_file_path, target_script, preview_mode=False): """ Worker's Render method which invokes the Blender rendering commands """ # Init regex expression used to determine blender's render progress s = settings.get_settings() _ = get_app()._tr # get the blender executable path self.blender_exec_path = s.get("blender_command") self.preview_mode = preview_mode self.frame_detected = False self.last_frame = 0 self.version = None self.command_output = "" self.process = None self.is_running = False blender_frame_re = re.compile(r"Fra:([0-9,]*)") blender_saved_re = re.compile(r"Saved: '(.*\.png)") blender_version_re = re.compile(r"Blender (.*?) ") startupinfo = None if sys.platform == 'win32': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW try: # Shell the blender command to create the image sequence command_get_version = [self.blender_exec_path, '-v'] command_render = [self.blender_exec_path, '-b', blend_file_path, '-P', target_script] # Check the version of Blender import shlex log.info("Checking Blender version, command: {}".format( " ".join([shlex.quote(x) for x in command_get_version]))) self.process = subprocess.Popen( command_get_version, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=startupinfo, ) # Check the version of Blender try: # Give Blender up to 10 seconds to respond (out, err) = self.process.communicate(timeout=10) except subprocess.TimeoutExpired: self.blender_error_nodata.emit() return ver_string = out.decode('utf-8') ver_match = blender_version_re.search(ver_string) if not ver_match: raise Exception("No Blender version detected in output") self.version = ver_match.group(1) log.info("Found Blender version {}".format(self.version)) if self.version < info.BLENDER_MIN_VERSION: # Wrong version of Blender. self.blender_version_error.emit(self.version) return # debug info log.info("Running Blender, command: {}".format( " ".join([shlex.quote(x) for x in command_render]))) log.info("Blender output:") # Run real command to render Blender project self.process = subprocess.Popen( command_render, bufsize=512, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=startupinfo, ) self.is_running = True except subprocess.SubprocessError: # Error running command. Most likely the blender executable path in # the settings is incorrect, or is not a supported Blender version self.is_running = False self.blender_error_nodata.emit() raise except Exception as ex: log.error("{}".format(ex)) return while self.is_running and self.process.poll() is None: for outline in iter(self.process.stdout.readline, b''): line = outline.decode('utf-8').strip() # Skip blank output if not line: continue # append all output into a variable, and log self.command_output = self.command_output + line + "\n" log.info(" {}".format(line)) # Look for progress info in the Blender Output output_frame = blender_frame_re.search(line) output_saved = blender_saved_re.search(line) # Does it have a match? if output_frame or output_saved: # Yes, we have a match self.frame_detected = True if output_frame: current_frame = int(output_frame.group(1)) # Update progress bar if current_frame != self.last_frame and not self.preview_mode: # update progress on frame change, if in 'render' mode self.progress.emit(current_frame) self.last_frame = current_frame if output_saved: # Update preview image self.image_updated.emit(output_saved.group(1)) log.info("Blender process exited.") # Re-enable the interface self.enable_interface.emit() # Check if NO FRAMES are detected if not self.frame_detected: # Show Error that no frames are detected. This is likely caused by # the wrong command being executed... or an error in Blender. self.blender_error_with_data.emit(_("No frame was found in the output from Blender")) # Done with render (i.e. close window) elif self.is_running and not self.preview_mode: # only add file to project data if in 'render' mode and not canceled self.finished.emit() # Thread finished if not self.is_running: # close window if thread was killed self.closed.emit() # mark thread as finished self.is_running = False
def LoadFile(self, path=None): """ Load a media file into the video player """ s = settings.get_settings() # Check to see if this path is already loaded # TODO: Determine why path is passed in as an empty string instead of None if path == self.clip_path or (not path and not self.clip_path): return # Determine the current frame of the timeline (when switching to a clip) seek_position = 1 if path and not self.clip_path: # Track the current frame self.original_position = self.player.Position() # Stop player (very important to prevent crashing) self.original_speed = self.player.Speed() self.player.Speed(0) # If blank path, switch back to self.timeline reader if not path: # Return to self.timeline reader log.info("Set timeline reader again in player: %s" % self.timeline) self.player.Reader(self.timeline) # Clear clip reader reference self.clip_reader = None self.clip_path = None # Switch back to last timeline position seek_position = self.original_position else: # Get extension of media path ext = os.path.splitext(path) # Load Reader based on extension new_reader = None if ext in ['.avi', 'mov', 'mkv', 'mpg', 'mpeg', 'mp3', 'mp4', 'mts', 'ogg', 'wav', 'wmv', 'webm', 'vob']: try: new_reader = openshot.FFmpegReader(path) new_reader.Open() except: try: new_reader = openshot.QtImageReader(path) new_reader.Open() except: log.error('Failed to load media file into video player: %s' % path) return else: try: new_reader = openshot.QtImageReader(path) new_reader.Open() except: try: new_reader = openshot.FFmpegReader(path) new_reader.Open() except: log.error('Failed to load media file into video player: %s' % path) return # Wrap reader in FrameMapper (to match current settings of timeline) new_mapper = openshot.FrameMapper(new_reader, self.timeline.info.fps, openshot.PULLDOWN_NONE, self.timeline.info.sample_rate, self.timeline.info.channels, self.timeline.info.channel_layout) # Keep track of previous clip readers (so we can Close it later) self.previous_clip_mappers.append(new_mapper) self.previous_clip_readers.append(new_reader) # Assign new clip_reader self.clip_reader = new_mapper self.clip_path = path # Open reader self.clip_reader.Open() log.info("Set new FrameMapper reader in player: %s" % self.clip_reader) self.player.Reader(self.clip_reader) # Close and destroy old clip readers (leaving the 3 most recent) while len(self.previous_clip_readers) > 3: log.info('Removing old clip reader: %s' % self.previous_clip_readers[0]) self.previous_clip_mappers.pop(0) self.previous_clip_readers.pop(0) # Seek to frame 1, and resume speed self.player.Seek(seek_position) self.player.Speed(self.original_speed)
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Track metrics track_metric_screen("preferences-screen") # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item self.requires_restart = False self.category_names = {} self.category_tabs = {} self.category_sort = {} # Loop through settings and find all unique categories for item in self.settings_data: category = item.get("category") setting_type = item.get("type") sort_category = item.get("sort") # Indicate sorted category if sort_category: self.category_sort[category] = sort_category if not setting_type == "hidden": # Load setting if not category in self.category_names: self.category_names[category] = [] # Create scrollarea scroll_area = QScrollArea(self) scroll_area.setWidgetResizable(True) scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Create tab widget and layout layout = QVBoxLayout() tabWidget = QWidget(self) tabWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) tabWidget.setLayout(layout) scroll_area.setWidget(tabWidget) # Add tab self.tabCategories.addTab(scroll_area, _(category)) self.category_tabs[category] = tabWidget # Append translated title item["title_tr"] = _(item.get("title")) # Append settings into correct category self.category_names[category].append(item) # Loop through each category setting, and add them to the tabs for category in self.category_tabs.keys(): tabWidget = self.category_tabs[category] # Get list of items in category params = self.category_names[category] if self.category_sort.get(category): # Sort this category by translated title params.sort(key=operator.itemgetter("title_tr")) # Loop through settings for each category for param in params: # Create Label widget = None extraWidget = None label = QLabel() label.setText(_(param["title"])) label.setToolTip(_(param["title"])) if param["type"] == "spinner": # create QDoubleSpinBox widget = QDoubleSpinBox() widget.setMinimum(float(param["min"])) widget.setMaximum(float(param["max"])) widget.setValue(float(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param)) if param["type"] == "spinner-int": # create QDoubleSpinBox widget = QSpinBox() widget.setMinimum(int(param["min"])) widget.setMaximum(int(param["max"])) widget.setValue(int(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param)) elif param["type"] == "text": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect(functools.partial(self.text_value_changed, widget, param)) elif param["type"] == "browse": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect(functools.partial(self.text_value_changed, widget, param)) extraWidget = QPushButton(_("Browse...")) extraWidget.clicked.connect(functools.partial(self.selectExecutable, widget, param)) elif param["type"] == "bool": # create spinner widget = QCheckBox() if param["value"] == True: widget.setCheckState(Qt.Checked) else: widget.setCheckState(Qt.Unchecked) widget.stateChanged.connect(functools.partial(self.bool_value_changed, widget, param)) elif param["type"] == "dropdown": # create spinner widget = QComboBox() # Get values value_list = param["values"] # Overwrite value list (for profile dropdown) if param["setting"] == "default-profile": value_list = [] # Loop through profiles for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) value_list.append({"name":profile.info.description, "value":profile.info.description}) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Overwrite value list (for language dropdown) if param["setting"] == "default-language": value_list = [] # Loop through languages for locale, language, country in get_all_languages(): # Load Profile and append description if language: lang_name = "%s (%s)" % (language, locale) value_list.append({"name":lang_name, "value":locale}) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Add Default to top of list value_list.insert(0, {"name":_("Default"), "value":"Default"}) # Add normal values box_index = 0 for value_item in value_list: k = value_item["name"] v = value_item["value"] # add dropdown item widget.addItem(_(k), v) # select dropdown (if default) if v == param["value"]: widget.setCurrentIndex(box_index) box_index = box_index + 1 widget.currentIndexChanged.connect(functools.partial(self.dropdown_index_changed, widget, param)) # Add Label and Widget to the form if (widget and label): # Add minimum size label.setMinimumWidth(180); label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) # Create HBox layout layout_hbox = QHBoxLayout() layout_hbox.addWidget(label) layout_hbox.addWidget(widget) if (extraWidget): layout_hbox.addWidget(extraWidget) # Add widget to layout tabWidget.layout().addLayout(layout_hbox) elif (label): # Add widget to layout tabWidget.layout().addWidget(label) # Add stretch to bottom of layout tabWidget.layout().addStretch()
import urllib.parse from copy import deepcopy from classes import info from classes import language from classes.logger import log from classes import settings import openshot from PyQt5.QtCore import QT_VERSION_STR from PyQt5.Qt import PYQT_VERSION_STR # Get libopenshot version libopenshot_version = openshot.GetVersion() # Get settings s = settings.get_settings() # Determine OS version os_version = "X11; Linux %s" % platform.machine() linux_distro = "None" try: if platform.system() == "Darwin": v = platform.mac_ver() os_version = "Macintosh; Intel Mac OS X %s" % v[0].replace(".", "_") linux_distro = "OS X %s" % v[0] elif platform.system() == "Windows": v = platform.win32_ver() # TODO: Upgrade windows python (on build server) version to 3.5, so it correctly identifies Windows 10 os_version = "Windows NT %s; %s" % (v[0], v[1]) linux_distro = "Windows %s" % "-".join(platform.win32_ver())
def Render(self, blend_file_path, target_script, preview_mode=False): """ Worker's Render method which invokes the Blender rendering commands """ log.info("QThread Render Method Invoked") # Init regex expression used to determine blender's render progress s = settings.get_settings() # get the blender executable path self.blender_exec_path = s.get("blender_command") self.blender_frame_expression = re.compile(r"Fra:([0-9,]*).*Mem:(.*?) .*Part ([0-9,]*)-([0-9,]*)") self.blender_saved_expression = re.compile(r"Saved: (.*.png)(.*)") self.blender_version = re.compile(r"Blender (.*?) ") self.blend_file_path = blend_file_path self.target_script = target_script self.preview_mode = preview_mode self.frame_detected = False self.version = None self.command_output = "" self.process = None self.is_running = True _ = get_app()._tr try: # Shell the blender command to create the image sequence command_get_version = [self.blender_exec_path, '-v'] command_render = [self.blender_exec_path, '-b', self.blend_file_path, '-P', self.target_script] self.process = subprocess.Popen(command_get_version, stdout=subprocess.PIPE) # Check the version of Blender self.version = self.blender_version.findall(str(self.process.stdout.readline())) if self.version: if float(self.version[0]) < 2.62: # change cursor to "default" and stop running blender command self.is_running = False # Wrong version of Blender. Must be 2.62+: self.blender_version_error.emit(float(self.version[0])) return # debug info log.info( "Blender command: {} {} '{}' {} '{}'".format(command_render[0], command_render[1], command_render[2], command_render[3], command_render[4])) # Run real command to render Blender project self.process = subprocess.Popen(command_render, stdout=subprocess.PIPE) except: # Error running command. Most likely the blender executable path in the settings # is not correct, or is not the correct version of Blender (i.e. 2.62+) self.is_running = False self.blender_error_nodata.emit() return while self.is_running and self.process.poll() is None: # Look for progress info in the Blender Output line = str(self.process.stdout.readline()) self.command_output = self.command_output + line + "\n" # append all output into a variable output_frame = self.blender_frame_expression.findall(line) # Does it have a match? if output_frame: # Yes, we have a match self.frame_detected = True current_frame = output_frame[0][0] memory = output_frame[0][1] current_part = output_frame[0][2] max_parts = output_frame[0][3] # Update progress bar if not self.preview_mode: # only update progress if in 'render' mode self.progress.emit(float(current_frame), float(current_part), float(max_parts)) # Look for progress info in the Blender Output output_saved = self.blender_saved_expression.findall(str(line)) # Does it have a match? if output_saved: # Yes, we have a match self.frame_detected = True image_path = output_saved[0][0] time_saved = output_saved[0][1] # Update preview image self.image_updated.emit(image_path) # Re-enable the interface self.enable_interface.emit() # Check if NO FRAMES are detected if not self.frame_detected: # Show Error that no frames are detected. This is likely caused by # the wrong command being executed... or an error in Blender. self.blender_error_with_data.emit(_("No frame was found in the output from Blender")) # Done with render (i.e. close window) elif not self.preview_mode: # only close window if in 'render' mode self.finished.emit() # Thread finished log.info("Blender render thread finished") if self.is_running == False: # close window if thread was killed self.closed.emit() # mark thread as finished self.is_running = False
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Track metrics track_metric_screen("export-screen") # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Add buttons to interface self.export_button = QPushButton(_('Export Video')) self.buttonBox.addButton(self.export_button, QDialogButtonBox.AcceptRole) self.buttonBox.addButton(QPushButton(_('Cancel')), QDialogButtonBox.RejectRole) self.exporting = False # Clear timeline preview cache (to get more avaiable memory) if get_app().window.cache_object: get_app().window.cache_object.Clear() # Hide audio channels self.lblChannels.setVisible(False) self.txtChannels.setVisible(False) # Get the original timeline settings width = get_app().window.timeline_sync.timeline.info.width height = get_app().window.timeline_sync.timeline.info.height fps = get_app().window.timeline_sync.timeline.info.fps sample_rate = get_app().window.timeline_sync.timeline.info.sample_rate channels = get_app().window.timeline_sync.timeline.info.channels channel_layout = get_app( ).window.timeline_sync.timeline.info.channel_layout # Create new "export" openshot.Timeline object self.timeline = openshot.Timeline(width, height, openshot.Fraction(fps.num, fps.den), sample_rate, channels, channel_layout) # Init various properties self.timeline.info.channel_layout = get_app( ).window.timeline_sync.timeline.info.channel_layout self.timeline.info.has_audio = get_app( ).window.timeline_sync.timeline.info.has_audio self.timeline.info.has_video = get_app( ).window.timeline_sync.timeline.info.has_video self.timeline.info.video_length = get_app( ).window.timeline_sync.timeline.info.video_length self.timeline.info.duration = get_app( ).window.timeline_sync.timeline.info.duration self.timeline.info.sample_rate = get_app( ).window.timeline_sync.timeline.info.sample_rate self.timeline.info.channels = get_app( ).window.timeline_sync.timeline.info.channels # Load the "export" Timeline reader with the JSON from the real timeline json_timeline = json.dumps(get_app().project._data) self.timeline.SetJson(json_timeline) # Open the "export" Timeline reader self.timeline.Open() # Default export path recommended_path = recommended_path = os.path.join(info.HOME_PATH) if app.project.current_filepath: recommended_path = os.path.dirname(app.project.current_filepath) export_path = get_app().project.get(["export_path"]) if os.path.exists(export_path): # Use last selected export path self.txtExportFolder.setText(export_path) else: # Default to home dir self.txtExportFolder.setText(recommended_path) # Is this a saved project? if not get_app().project.current_filepath: # Not saved yet self.txtFileName.setText(_("Untitled Project")) else: # Yes, project is saved # Get just the filename parent_path, filename = os.path.split( get_app().project.current_filepath) filename, ext = os.path.splitext(filename) self.txtFileName.setText( filename.replace("_", " ").replace("-", " ").capitalize()) # Default image type self.txtImageFormat.setText("%05.png") # Loop through Export To options export_options = [_("Video & Audio"), _("Image Sequence")] for option in export_options: # append profile to list self.cboExportTo.addItem(option) # Add channel layouts self.channel_layout_choices = [] for layout in [(openshot.LAYOUT_MONO, _("Mono (1 Channel)")), (openshot.LAYOUT_STEREO, _("Stereo (2 Channel)")), (openshot.LAYOUT_SURROUND, _("Surround (3 Channel)")), (openshot.LAYOUT_5POINT1, _("Surround (5.1 Channel)")), (openshot.LAYOUT_7POINT1, _("Surround (7.1 Channel)"))]: log.info(layout) self.channel_layout_choices.append(layout[0]) self.cboChannelLayout.addItem(layout[1], layout[0]) # Connect signals self.btnBrowse.clicked.connect( functools.partial(self.btnBrowse_clicked)) self.cboSimpleProjectType.currentIndexChanged.connect( functools.partial(self.cboSimpleProjectType_index_changed, self.cboSimpleProjectType)) self.cboProfile.currentIndexChanged.connect( functools.partial(self.cboProfile_index_changed, self.cboProfile)) self.cboSimpleTarget.currentIndexChanged.connect( functools.partial(self.cboSimpleTarget_index_changed, self.cboSimpleTarget)) self.cboSimpleVideoProfile.currentIndexChanged.connect( functools.partial(self.cboSimpleVideoProfile_index_changed, self.cboSimpleVideoProfile)) self.cboSimpleQuality.currentIndexChanged.connect( functools.partial(self.cboSimpleQuality_index_changed, self.cboSimpleQuality)) self.cboChannelLayout.currentIndexChanged.connect(self.updateChannels) get_app().window.ExportFrame.connect(self.updateProgressBar) # ********* Advaned Profile List ********** # Loop through profiles self.profile_names = [] self.profile_paths = {} for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]: for file in os.listdir(profile_folder): # Load Profile profile_path = os.path.join(profile_folder, file) profile = openshot.Profile(profile_path) # Add description of Profile to list self.profile_names.append(profile.info.description) self.profile_paths[profile.info.description] = profile_path # Sort list self.profile_names.sort() # Loop through sorted profiles box_index = 0 self.selected_profile_index = 0 for profile_name in self.profile_names: # Add to dropdown self.cboProfile.addItem(profile_name, self.profile_paths[profile_name]) # Set default (if it matches the project) if app.project.get(['profile']) == profile_name: self.selected_profile_index = box_index # increment item counter box_index += 1 # ********* Simple Project Type ********** # load the simple project type dropdown presets = [] for file in os.listdir(info.EXPORT_PRESETS_DIR): xmldoc = xml.parse(os.path.join(info.EXPORT_PRESETS_DIR, file)) type = xmldoc.getElementsByTagName("type") presets.append(_(type[0].childNodes[0].data)) # Exclude duplicates type_index = 0 selected_type = 0 presets = list(set(presets)) for item in sorted(presets): self.cboSimpleProjectType.addItem(item, item) if item == _("All Formats"): selected_type = type_index type_index += 1 # Always select 'All Formats' option self.cboSimpleProjectType.setCurrentIndex(selected_type) # Populate all profiles self.populateAllProfiles(app.project.get(['profile'])) # Connect framerate signals self.txtFrameRateNum.valueChanged.connect(self.updateFrameRate) self.txtFrameRateDen.valueChanged.connect(self.updateFrameRate) self.txtWidth.valueChanged.connect(self.updateFrameRate) self.txtHeight.valueChanged.connect(self.updateFrameRate) self.txtSampleRate.valueChanged.connect(self.updateFrameRate) self.txtChannels.valueChanged.connect(self.updateFrameRate) self.cboChannelLayout.currentIndexChanged.connect(self.updateFrameRate) # Determine the length of the timeline (in frames) self.updateFrameRate()
def Render(self, blend_file_path, target_script, preview_mode=False): """ Worker's Render method which invokes the Blender rendering commands """ log.info("QThread Render Method Invoked") # Init regex expression used to determine blender's render progress s = settings.get_settings() # get the blender executable path self.blender_exec_path = s.get("blender_command") self.blender_frame_expression = re.compile( r"Fra:([0-9,]*).*Mem:(.*?) .*Part ([0-9,]*)-([0-9,]*)") self.blender_saved_expression = re.compile(r"Saved: '(.*.png)(.*)'") self.blender_version = re.compile(r"Blender (.*?) ") self.blend_file_path = blend_file_path self.target_script = target_script self.preview_mode = preview_mode self.frame_detected = False self.version = None self.command_output = "" self.process = None self.is_running = True _ = get_app()._tr try: # Shell the blender command to create the image sequence command_get_version = [self.blender_exec_path, '-v'] command_render = [ self.blender_exec_path, '-b', self.blend_file_path, '-P', self.target_script ] self.process = subprocess.Popen(command_get_version, stdout=subprocess.PIPE) # Check the version of Blender self.version = self.blender_version.findall( str(self.process.stdout.readline())) if self.version: if float(self.version[0]) < 2.78: # change cursor to "default" and stop running blender command self.is_running = False # Wrong version of Blender. Must be 2.62+: self.blender_version_error.emit(float(self.version[0])) return # debug info log.info("Blender command: {} {} '{}' {} '{}'".format( command_render[0], command_render[1], command_render[2], command_render[3], command_render[4])) # Run real command to render Blender project self.process = subprocess.Popen(command_render, stdout=subprocess.PIPE) except: # Error running command. Most likely the blender executable path in the settings # is not correct, or is not the correct version of Blender (i.e. 2.62+) self.is_running = False self.blender_error_nodata.emit() return while self.is_running and self.process.poll() is None: # Look for progress info in the Blender Output line = str(self.process.stdout.readline()) self.command_output = self.command_output + line + "\n" # append all output into a variable output_frame = self.blender_frame_expression.findall(line) # Does it have a match? if output_frame: # Yes, we have a match self.frame_detected = True current_frame = output_frame[0][0] memory = output_frame[0][1] current_part = output_frame[0][2] max_parts = output_frame[0][3] # Update progress bar if not self.preview_mode: # only update progress if in 'render' mode self.progress.emit(float(current_frame), float(current_part), float(max_parts)) # Look for progress info in the Blender Output output_saved = self.blender_saved_expression.findall(str(line)) log.info("Image detected from blender regex: %s" % output_saved) # Does it have a match? if output_saved: # Yes, we have a match self.frame_detected = True image_path = output_saved[0][0] time_saved = output_saved[0][1] # Update preview image self.image_updated.emit(image_path) # Re-enable the interface self.enable_interface.emit() # Check if NO FRAMES are detected if not self.frame_detected: # Show Error that no frames are detected. This is likely caused by # the wrong command being executed... or an error in Blender. self.blender_error_with_data.emit( _("No frame was found in the output from Blender")) # Done with render (i.e. close window) elif not self.preview_mode: # only close window if in 'render' mode self.finished.emit() # Thread finished log.info("Blender render thread finished") if self.is_running == False: # close window if thread was killed self.closed.emit() # mark thread as finished self.is_running = False
def __init__(self, files=None, position=0.0): # Create dialog class QDialog.__init__(self) # Load UI from Designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # Get settings self.settings = settings.get_settings() # Get translation object self.app = get_app() _ = self.app._tr # Track metrics track_metric_screen("add-to-timeline-screen") # Add custom treeview to window self.treeFiles = TimelineTreeView(self) self.vboxTreeParent.insertWidget(0, self.treeFiles) # Update data in model self.treeFiles.timeline_model.update_model(files) # Refresh view self.treeFiles.refresh_view() # Init start position self.txtStartTime.setValue(position) # Init default image length self.txtImageLength.setValue(self.settings.get("default-image-length")) self.txtImageLength.valueChanged.connect(self.updateTotal) self.cmbTransition.currentIndexChanged.connect(self.updateTotal) self.cmbFade.currentIndexChanged.connect(self.updateTotal) self.txtFadeLength.valueChanged.connect(self.updateTotal) self.txtTransitionLength.valueChanged.connect(self.updateTotal) # Add all tracks to dropdown tracks = Track.filter() for track in reversed(tracks): # Add to dropdown self.cmbTrack.addItem(_('Track %s' % track.data['number']), track.data['number']) # Add all fade options self.cmbFade.addItem(_('None'), None) self.cmbFade.addItem(_('Fade In'), 'Fade In') self.cmbFade.addItem(_('Fade Out'), 'Fade Out') self.cmbFade.addItem(_('Fade In & Out'), 'Fade In & Out') # Add all zoom options self.cmbZoom.addItem(_('None'), None) self.cmbZoom.addItem(_('Random'), 'Random') self.cmbZoom.addItem(_('Zoom In'), 'Zoom In') self.cmbZoom.addItem(_('Zoom Out'), 'Zoom Out') # Add all transitions transitions_dir = os.path.join(info.PATH, "transitions") common_dir = os.path.join(transitions_dir, "common") extra_dir = os.path.join(transitions_dir, "extra") transition_groups = [{ "type": "common", "dir": common_dir, "files": os.listdir(common_dir) }, { "type": "extra", "dir": extra_dir, "files": os.listdir(extra_dir) }] self.cmbTransition.addItem(_('None'), None) self.cmbTransition.addItem(_('Random'), 'random') self.transitions = [] for group in transition_groups: type = group["type"] dir = group["dir"] files = group["files"] for filename in sorted(files): path = os.path.join(dir, filename) (fileBaseName, fileExtension) = os.path.splitext(filename) # Skip hidden files (such as .DS_Store, etc...) if filename[0] == "." or "thumbs.db" in filename.lower(): continue # split the name into parts (looking for a number) suffix_number = None name_parts = fileBaseName.split("_") if name_parts[-1].isdigit(): suffix_number = name_parts[-1] # get name of transition trans_name = fileBaseName.replace("_", " ").capitalize() # replace suffix number with placeholder (if any) if suffix_number: trans_name = trans_name.replace(suffix_number, "%s") trans_name = _(trans_name) % suffix_number else: trans_name = _(trans_name) # Check for thumbnail path (in build-in cache) thumb_path = os.path.join(info.IMAGES_PATH, "cache", "{}.png".format(fileBaseName)) # Check built-in cache (if not found) if not os.path.exists(thumb_path): # Check user folder cache thumb_path = os.path.join(info.CACHE_PATH, "{}.png".format(fileBaseName)) # Add item self.transitions.append(path) self.cmbTransition.addItem(QIcon(thumb_path), _(trans_name), path) # Connections self.btnMoveUp.clicked.connect(self.btnMoveUpClicked) self.btnMoveDown.clicked.connect(self.btnMoveDownClicked) self.btnShuffle.clicked.connect(self.btnShuffleClicked) self.btnRemove.clicked.connect(self.btnRemoveClicked) self.btnBox.accepted.connect(self.accept) self.btnBox.rejected.connect(self.reject) # Update total self.updateTotal()
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Track metrics track_metric_screen("preferences-screen") # Load all user values self.params = {} for item in self.settings_data: if "setting" in item and "value" in item: self.params[item["setting"]] = item self.requires_restart = False self.category_names = {} self.category_tabs = {} self.category_sort = {} # Loop through settings and find all unique categories for item in self.settings_data: category = item.get("category") setting_type = item.get("type") sort_category = item.get("sort") # Indicate sorted category if sort_category: self.category_sort[category] = sort_category if not setting_type == "hidden": # Load setting if not category in self.category_names: self.category_names[category] = [] # Create scrollarea scroll_area = QScrollArea(self) scroll_area.setWidgetResizable(True) scroll_area.setVerticalScrollBarPolicy( Qt.ScrollBarAsNeeded) scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Create tab widget and layout layout = QVBoxLayout() tabWidget = QWidget(self) tabWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) tabWidget.setLayout(layout) scroll_area.setWidget(tabWidget) # Add tab self.tabCategories.addTab(scroll_area, _(category)) self.category_tabs[category] = tabWidget # Append translated title item["title_tr"] = _(item.get("title")) # Append settings into correct category self.category_names[category].append(item) # Loop through each category setting, and add them to the tabs for category in self.category_tabs.keys(): tabWidget = self.category_tabs[category] # Get list of items in category params = self.category_names[category] if self.category_sort.get(category): # Sort this category by translated title params.sort(key=operator.itemgetter("title_tr")) # Loop through settings for each category for param in params: # Create Label widget = None extraWidget = None label = QLabel() label.setText(_(param["title"])) label.setToolTip(_(param["title"])) if param["type"] == "spinner": # create QDoubleSpinBox widget = QDoubleSpinBox() widget.setMinimum(float(param["min"])) widget.setMaximum(float(param["max"])) widget.setValue(float(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect( functools.partial(self.spinner_value_changed, param)) if param["type"] == "spinner-int": # create QDoubleSpinBox widget = QSpinBox() widget.setMinimum(int(param["min"])) widget.setMaximum(int(param["max"])) widget.setValue(int(param["value"])) widget.setSingleStep(1.0) widget.setToolTip(param["title"]) widget.valueChanged.connect( functools.partial(self.spinner_value_changed, param)) elif param["type"] == "text": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect( functools.partial(self.text_value_changed, widget, param)) elif param["type"] == "browse": # create QLineEdit widget = QLineEdit() widget.setText(_(param["value"])) widget.textChanged.connect( functools.partial(self.text_value_changed, widget, param)) extraWidget = QPushButton(_("Browse...")) extraWidget.clicked.connect( functools.partial(self.selectExecutable, widget, param)) elif param["type"] == "bool": # create spinner widget = QCheckBox() if param["value"] == True: widget.setCheckState(Qt.Checked) else: widget.setCheckState(Qt.Unchecked) widget.stateChanged.connect( functools.partial(self.bool_value_changed, widget, param)) elif param["type"] == "dropdown": # create spinner widget = QComboBox() # Get values value_list = param["values"] # Overwrite value list (for profile dropdown) if param["setting"] == "default-profile": value_list = [] # Loop through profiles for profile_folder in [ info.USER_PROFILES_PATH, info.PROFILES_PATH ]: for file in os.listdir(profile_folder): # Load Profile and append description profile_path = os.path.join( profile_folder, file) profile = openshot.Profile(profile_path) value_list.append({ "name": profile.info.description, "value": profile.info.description }) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Overwrite value list (for language dropdown) if param["setting"] == "default-language": value_list = [] # Loop through languages for locale, language, country in get_all_languages(): # Load Profile and append description if language: lang_name = "%s (%s)" % (language, locale) value_list.append({ "name": lang_name, "value": locale }) # Sort profile list value_list.sort(key=operator.itemgetter("name")) # Add Default to top of list value_list.insert(0, { "name": _("Default"), "value": "Default" }) # Add normal values box_index = 0 for value_item in value_list: k = value_item["name"] v = value_item["value"] # add dropdown item widget.addItem(_(k), v) # select dropdown (if default) if v == param["value"]: widget.setCurrentIndex(box_index) box_index = box_index + 1 widget.currentIndexChanged.connect( functools.partial(self.dropdown_index_changed, widget, param)) # Add Label and Widget to the form if (widget and label): # Add minimum size label.setMinimumWidth(180) label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) # Create HBox layout layout_hbox = QHBoxLayout() layout_hbox.addWidget(label) layout_hbox.addWidget(widget) if (extraWidget): layout_hbox.addWidget(extraWidget) # Add widget to layout tabWidget.layout().addLayout(layout_hbox) elif (label): # Add widget to layout tabWidget.layout().addWidget(label) # Add stretch to bottom of layout tabWidget.layout().addStretch()
def __init__(self): # Create dialog class QDialog.__init__(self) # Load UI from designer ui_util.load_ui(self, self.ui_path) # Init UI ui_util.init_ui(self) # get translations app = get_app() _ = app._tr # Get settings self.s = settings.get_settings() # Dynamically load tabs from settings data self.settings_data = settings.get_settings().get_all_settings() # Add buttons to interface self.export_button = QPushButton(_('Export Video')) self.buttonBox.addButton(self.export_button, QDialogButtonBox.AcceptRole) self.buttonBox.addButton(QPushButton(_('Cancel')), QDialogButtonBox.RejectRole) self.exporting = False # Default export path recommended_path = recommended_path = os.path.join(info.HOME_PATH) if app.project.current_filepath: recommended_path = os.path.dirname(app.project.current_filepath) export_path = get_app().project.get(["export_path"]) if os.path.exists(export_path): # Use last selected export path self.txtExportFolder.setText(export_path) else: # Default to home dir self.txtExportFolder.setText(recommended_path) # Is this a saved project? if not get_app().project.current_filepath: # Not saved yet self.txtFileName.setText(_("Untitled Project")) else: # Yes, project is saved # Get just the filename parent_path, filename = os.path.split(get_app().project.current_filepath) filename, ext = os.path.splitext(filename) self.txtFileName.setText(filename.replace("_", " ").replace("-", " ").capitalize()) # Default image type self.txtImageFormat.setText("%05.png") # Loop through Export To options export_options = [_("Video & Audio"), _("Image Sequence")] for option in export_options: # append profile to list self.cboExportTo.addItem(option) # Connect signals self.btnBrowse.clicked.connect(functools.partial(self.btnBrowse_clicked)) self.cboSimpleProjectType.currentIndexChanged.connect( functools.partial(self.cboSimpleProjectType_index_changed, self.cboSimpleProjectType)) self.cboProfile.currentIndexChanged.connect(functools.partial(self.cboProfile_index_changed, self.cboProfile)) self.cboSimpleTarget.currentIndexChanged.connect( functools.partial(self.cboSimpleTarget_index_changed, self.cboSimpleTarget)) self.cboSimpleVideoProfile.currentIndexChanged.connect( functools.partial(self.cboSimpleVideoProfile_index_changed, self.cboSimpleVideoProfile)) self.cboSimpleQuality.currentIndexChanged.connect( functools.partial(self.cboSimpleQuality_index_changed, self.cboSimpleQuality)) # ********* Advaned Profile List ********** # Loop through profiles self.profile_names = [] self.profile_paths = {} for file in os.listdir(info.PROFILES_PATH): # Load Profile profile_path = os.path.join(info.PROFILES_PATH, file) profile = openshot.Profile(profile_path) # Add description of Profile to list self.profile_names.append(profile.info.description) self.profile_paths[profile.info.description] = profile_path # Sort list self.profile_names.sort() # Loop through sorted profiles box_index = 0 self.selected_profile_index = 0 for profile_name in self.profile_names: # Add to dropdown self.cboProfile.addItem(profile_name, self.profile_paths[profile_name]) # Set default (if it matches the project) if app.project.get(['profile']) == profile_name: self.selected_profile_index = box_index # increment item counter box_index += 1 # ********* Simple Project Type ********** # load the simple project type dropdown presets = [] for file in os.listdir(info.EXPORT_PRESETS_DIR): xmldoc = xml.parse(os.path.join(info.EXPORT_PRESETS_DIR, file)) type = xmldoc.getElementsByTagName("type") presets.append(_(type[0].childNodes[0].data)) # Exclude duplicates presets = list(set(presets)) for item in sorted(presets): self.cboSimpleProjectType.addItem(item, item) # Populate all profiles self.populateAllProfiles(app.project.get(['profile'])) # Connect framerate signals self.txtFrameRateNum.valueChanged.connect(self.updateFrameRate) self.txtFrameRateDen.valueChanged.connect(self.updateFrameRate) self.txtWidth.valueChanged.connect(self.updateFrameRate) self.txtHeight.valueChanged.connect(self.updateFrameRate) self.txtSampleRate.valueChanged.connect(self.updateFrameRate) self.txtChannels.valueChanged.connect(self.updateFrameRate) # Determine the length of the timeline (in frames) self.updateFrameRate()
from copy import deepcopy from classes import info from classes import language from classes.logger import log from classes import settings import openshot from PyQt5.QtCore import QT_VERSION_STR from PyQt5.Qt import PYQT_VERSION_STR # Get libopenshot version libopenshot_version = openshot.GetVersion() # Get settings s = settings.get_settings() # Determine OS version os_version = "X11; Linux %s" % platform.machine() linux_distro = "None" try: if platform.system() == "Darwin": v = platform.mac_ver() os_version = "Macintosh; Intel Mac OS X %s" % v[0].replace(".", "_") linux_distro = "OS X %s" % v[0] elif platform.system() == "Windows": v = platform.win32_ver() # TODO: Upgrade windows python (on build server) version to 3.5, so it correctly identifies Windows 10 os_version = "Windows NT %s; %s" % (v[0], v[1]) linux_distro = "Windows %s" % "-".join(platform.win32_ver())
def LoadFile(self, path=None): """ Load a media file into the video player """ s = settings.get_settings() # Check to see if this path is already loaded # TODO: Determine why path is passed in as an empty string instead of None if path == self.clip_path or (not path and not self.clip_path): return # Determine the current frame of the timeline (when switching to a clip) seek_position = 1 if path and not self.clip_path: # Track the current frame self.original_position = self.player.Position() # Stop player (very important to prevent crashing) self.original_speed = self.player.Speed() self.player.Speed(0) # If blank path, switch back to self.timeline reader if not path: # Return to self.timeline reader log.info("Set timeline reader again in player: %s" % self.timeline) self.player.Reader(self.timeline) # Clear clip reader reference self.clip_reader = None self.clip_path = None # Switch back to last timeline position seek_position = self.original_position else: # Get extension of media path ext = os.path.splitext(path) # Load Reader based on extension new_reader = None if ext in [ '.avi', 'mov', 'mkv', 'mpg', 'mpeg', 'mp3', 'mp4', 'mts', 'ogg', 'wav', 'wmv', 'webm', 'vob' ]: try: new_reader = openshot.FFmpegReader(path) new_reader.Open() except: try: new_reader = openshot.QtImageReader(path) new_reader.Open() except: log.error( 'Failed to load media file into video player: %s' % path) return else: try: new_reader = openshot.QtImageReader(path) new_reader.Open() except: try: new_reader = openshot.FFmpegReader(path) new_reader.Open() except: log.error( 'Failed to load media file into video player: %s' % path) return # Wrap reader in FrameMapper (to match current settings of timeline) new_mapper = openshot.FrameMapper( new_reader, self.timeline.info.fps, openshot.PULLDOWN_NONE, self.timeline.info.sample_rate, self.timeline.info.channels, self.timeline.info.channel_layout) # Keep track of previous clip readers (so we can Close it later) self.previous_clip_mappers.append(new_mapper) self.previous_clip_readers.append(new_reader) # Assign new clip_reader self.clip_reader = new_mapper self.clip_path = path # Open reader self.clip_reader.Open() log.info("Set new FrameMapper reader in player: %s" % self.clip_reader) self.player.Reader(self.clip_reader) # Close and destroy old clip readers (leaving the 3 most recent) while len(self.previous_clip_readers) > 3: log.info('Removing old clip reader: %s' % self.previous_clip_readers[0]) self.previous_clip_mappers.pop(0) self.previous_clip_readers.pop(0) # Seek to frame 1, and resume speed self.player.Seek(seek_position) self.player.Speed(self.original_speed)
def __init__(self, id, text, arrow, *args): # Invoke parent init QWidget.__init__(self, *args) # get translations app = get_app() _ = app._tr # Keep track of widget to position next to self.id = id self.arrow = arrow # Create vertical box vbox = QVBoxLayout() vbox.setContentsMargins(32, 10, 10, 10) # Add label self.label = QLabel(self) self.label.setText(text) self.label.setTextFormat(Qt.RichText) self.label.setWordWrap(True) self.label.setStyleSheet("margin-left: 20px;") vbox.addWidget(self.label) # Add error and anonymous metrics checkbox (for ID=0) tooltip # This is a bit of a hack, but since it's the only exception, it's # probably okay for now. if self.id == "0": # Get settings s = get_settings() # create spinner checkbox_metrics = QCheckBox() checkbox_metrics.setText( _("Yes, I would like to improve OpenShot!")) checkbox_metrics.setStyleSheet( "margin-left: 25px; margin-bottom: 5px;") if s.get("send_metrics"): checkbox_metrics.setCheckState(Qt.Checked) else: checkbox_metrics.setCheckState(Qt.Unchecked) checkbox_metrics.stateChanged.connect( functools.partial(self.checkbox_metrics_callback)) vbox.addWidget(checkbox_metrics) # Add button box hbox = QHBoxLayout() hbox.setContentsMargins(20, 10, 0, 0) # Create buttons self.btn_close_tips = QPushButton(self) self.btn_close_tips.setText(_("Hide Tutorial")) self.btn_next_tip = QPushButton(self) self.btn_next_tip.setText(_("Next")) self.btn_next_tip.setStyleSheet("font-weight:bold;") hbox.addWidget(self.btn_close_tips) hbox.addWidget(self.btn_next_tip) vbox.addLayout(hbox) # Set layout self.setLayout(vbox) # Set size self.setMinimumWidth(350) self.setMinimumHeight(100) # Make transparent self.setAttribute(Qt.WA_NoSystemBackground, True) self.setAttribute(Qt.WA_TranslucentBackground, True)
def init_language(): """ Find the current locale, and install the correct translators """ # Get app instance app = QCoreApplication.instance() # Setup of our list of translators and paths translator_types = ( {"type": 'QT', "pattern": 'qt_%s', # Older versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath)}, {"type": 'QT', "pattern": 'qtbase_%s', # Newer versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath)}, {"type": 'QT', "pattern": 'qt_%s', "path": os.path.join(info.PATH, 'locale', 'QT')}, # Optional path where we package QT translations {"type": 'QT', "pattern": 'qtbase_%s', "path": os.path.join(info.PATH, 'locale', 'QT')}, # Optional path where we package QT translations {"type": 'OpenShot', "pattern": os.path.join('%s', 'LC_MESSAGES', 'OpenShot'), # Our custom translations "path": os.path.join(info.PATH, 'locale')}, ) # Determine the environment locale, or default to system locale name locale_names = [os.environ.get('LANG', QLocale().system().name()), os.environ.get('LOCALE', QLocale().system().name()) ] # Determine if the user has overwritten the language (in the preferences) preference_lang = settings.get_settings().get('default-language') if preference_lang != "Default": # Append preference lang to top of list locale_names.insert(0, preference_lang) # Output all system languages detected log.info("Qt Detected Languages: {}".format(QLocale().system().uiLanguages())) log.info("LANG Environment Variable: {}".format(os.environ.get('LANG', QLocale().system().name()))) log.info("LOCALE Environment Variable: {}".format(os.environ.get('LOCALE', QLocale().system().name()))) # Default the locale to C, for number formatting locale.setlocale(locale.LC_ALL, 'C') # Loop through environment variables found_language = False for locale_name in locale_names: # Don't try on default locale, since it fails to load what is the default language if 'en_US' in locale_name: log.info("Skipping English language (no need for translation): {}".format(locale_name)) continue # Go through each translator and try to add for current locale for type in translator_types: trans = QTranslator(app) if find_language_match(type["pattern"], type["path"], trans, locale_name): # Install translation app.installTranslator(trans) found_language = True # Exit if found language if found_language: log.info("Exiting translation system (since we successfully loaded: {})".format(locale_name)) break
def LoadFile(self, path=None): """ Load a media file into the video player """ # Check to see if this path is already loaded # TODO: Determine why path is passed in as an empty string instead of None if path == self.clip_path or (not path and not self.clip_path): return log.info("LoadFile %s" % path) s = settings.get_settings() # Determine the current frame of the timeline (when switching to a clip) seek_position = 1 if path and not self.clip_path: # Track the current frame self.original_position = self.player.Position() # If blank path, switch back to self.timeline reader if not path: # Return to self.timeline reader log.info("Set timeline reader again in player: %s" % self.timeline) self.player.Reader(self.timeline) # Clear clip reader reference self.clip_reader = None self.clip_path = None # Switch back to last timeline position seek_position = self.original_position else: # Get extension of media path ext = os.path.splitext(path) # Create new timeline reader (to preview selected clip) s = settings.get_settings() project = get_app().project # Get some settings from the project fps = project.get(["fps"]) width = project.get(["width"]) height = project.get(["height"]) sample_rate = project.get(["sample_rate"]) channels = project.get(["channels"]) channel_layout = project.get(["channel_layout"]) # Create an instance of a libopenshot Timeline object self.clip_reader = openshot.Timeline( width, height, openshot.Fraction(fps["num"], fps["den"]), sample_rate, channels, channel_layout) self.clip_reader.info.channel_layout = channel_layout self.clip_reader.info.has_audio = True self.clip_reader.info.has_video = True self.clip_reader.info.video_length = 999999 self.clip_reader.info.duration = 999999 self.clip_reader.info.sample_rate = sample_rate self.clip_reader.info.channels = channels try: # Add clip for current preview file new_clip = openshot.Clip(path) self.clip_reader.AddClip(new_clip) except: log.error('Failed to load media file into video player: %s' % path) return # Assign new clip_reader self.clip_path = path # Keep track of previous clip readers (so we can Close it later) self.previous_clips.append(new_clip) self.previous_clip_readers.append(self.clip_reader) # Open and set reader self.clip_reader.Open() self.player.Reader(self.clip_reader) # Close and destroy old clip readers (leaving the 3 most recent) while len(self.previous_clip_readers) > 3: log.info('Removing old clips from preview: %s' % self.previous_clip_readers[0]) previous_clip = self.previous_clips.pop(0) previous_clip.Close() previous_reader = self.previous_clip_readers.pop(0) previous_reader.Close() # Seek to frame 1, and resume speed self.Seek(seek_position)
def init_language(): """ Find the current locale, and install the correct translators """ # Get app instance app = QCoreApplication.instance() # Setup of our list of translators and paths translator_types = ( { "type": 'QT', "prefix": 'qt_', # Older versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath) }, { "type": 'QT', "prefix": 'qtbase_', # Newer versions of Qt use this file (built-in translations) "path": QLibraryInfo.location(QLibraryInfo.TranslationsPath) }, { "type": 'QT', "prefix": 'qt_', "path": os.path.join(info.PATH, 'language') }, # Optional path where we package QT translations { "type": 'QT', "prefix": 'qtbase_', "path": os.path.join(info.PATH, 'language') }, # Optional path where we package QT translations { "type": 'OpenShot', "prefix": 'OpenShot.', # Our custom translations "path": language_path }, ) # Determine the environment locale, or default to system locale name locale_names = [ os.environ.get('LANG', QLocale().system().name()), os.environ.get('LOCALE', QLocale().system().name()) ] # Get the user's configured language preference preference_lang = settings.get_settings().get('default-language') # Output all languages detected from various sources log.info("Qt Detected Languages: {}".format( QLocale().system().uiLanguages())) log.info("LANG Environment Variable: {}".format(os.environ.get('LANG', ""))) log.info("LOCALE Environment Variable: {}".format( os.environ.get('LOCALE', ""))) log.info("OpenShot Preference Language: {}".format(preference_lang)) # Check if the language preference is something other than "Default" if preference_lang == "en_US": # Override language list with en_US, don't add to it locale_names = ["en_US"] elif preference_lang != "Default": # Prepend preference setting to list locale_names.insert(0, preference_lang) # If the user has used the --lang command line arg, override with that # (We've already checked that it's in SUPPORTED_LANGUAGES) if info.CMDLINE_LANGUAGE: locale_names = [info.CMDLINE_LANGUAGE] log.info("Language overridden on command line, using: {}".format( info.CMDLINE_LANGUAGE)) # Default the locale to C, for number formatting locale.setlocale(locale.LC_ALL, 'C') # Loop through environment variables found_language = False for locale_name in locale_names: # Go through each translator and try to add for current locale for type in translator_types: trans = QTranslator(app) if find_language_match(type["prefix"], type["path"], trans, locale_name): # Install translation app.installTranslator(trans) found_language = True # Exit if found language for type: "OpenShot" if found_language: log.debug( "Exiting translation system (since we successfully loaded: {})" .format(locale_name)) info.CURRENT_LANGUAGE = locale_name break
def __init__(self): # Create main window base class QMainWindow.__init__(self) # set window on app for reference during initialization of children get_app().window = self # Load UI from designer ui_util.load_ui(self, self.ui_path) # Load user settings for window s = settings.get_settings() self.recent_menu = None # Init UI ui_util.init_ui(self) # Setup toolbars that aren't on main window, set initial state of items, etc self.setup_toolbars() # Add window as watcher to receive undo/redo status updates get_app().updates.add_watcher(self) # Track the selected file(s) self.selected_files = [] self.selected_clips = [] self.selected_transitions = [] self.selected_markers = [] self.selected_tracks = [] self.selected_effects = [] # Init fullscreen menu visibility self.init_fullscreen_menu() # Setup timeline self.timeline = TimelineWebView(self) self.frameWeb.layout().addWidget(self.timeline) # Set Window title self.SetWindowTitle() # Setup files tree if s.get("file_view") == "details": self.filesTreeView = FilesTreeView(self) else: self.filesTreeView = FilesListView(self) self.tabFiles.layout().addWidget(self.filesTreeView) # Setup transitions tree if s.get("transitions_view") == "details": self.transitionsTreeView = TransitionsTreeView(self) else: self.transitionsTreeView = TransitionsListView(self) self.tabTransitions.layout().addWidget(self.transitionsTreeView) # Setup effects tree if s.get("effects_view") == "details": self.effectsTreeView = EffectsTreeView(self) else: self.effectsTreeView = EffectsListView(self) self.tabEffects.layout().addWidget(self.effectsTreeView) # Setup properties table self.propertyTableView = PropertiesTableView(self) self.dockPropertiesContent.layout().addWidget(self.propertyTableView, 3, 1) # Setup video preview QWidget self.videoPreview = VideoWidget() self.tabVideo.layout().insertWidget(0, self.videoPreview) # Load window state and geometry self.load_settings() # Create the timeline sync object (used for previewing timeline) self.timeline_sync = TimelineSync() # Start the preview thread self.preview_parent = PreviewParent() self.preview_parent.Init(self, self.timeline_sync.timeline) self.preview_thread = self.preview_parent.worker