Skip to content

Commit

Permalink
Merge pull request #5634 from OpenShot/choose-profile-v2
Browse files Browse the repository at this point in the history
Adding new "Choose Profile" context menu to Project Files
  • Loading branch information
jonoomph authored Oct 12, 2024
2 parents 2ee8cd6 + 898f8f7 commit 5ed8300
Show file tree
Hide file tree
Showing 18 changed files with 1,115 additions and 172 deletions.
3 changes: 3 additions & 0 deletions doc/files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ is not currently visible, OpenShot will automatically display the panel.

.. image:: images/quick-start-drop-files.jpg

.. _file_menu_ref:

File Menu
---------
To view the file menu, right click on a file (in the **Project Files** panel). Here are the actions you can use from the
Expand All @@ -73,6 +75,7 @@ Split File Split a file into many smaller files. The new trimmed file
Edit Title Edit an existing title SVG file
Duplicate Title Make a copy, and then edit the copied title SVG file
Add to Timeline Add many files to the timeline in one step, including transitions or alternating tracks.
Choose Profile Change the current project profile to match the selected file. If the file's profile does not match a known profile, it will give you the option to create a custom profile.
File Properties View the properties of a file, such as frame rate, size, etc...
Remove from Project Remove a file from the project
==================== ============
Expand Down
Binary file modified doc/images/file-menu.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/profiles-editor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 39 additions & 2 deletions doc/profiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ It is best practice to always switch to your target profile before you begin edi
1080p 30fps, switch to that profile before you begin editing your project. For a full list of included profiles
see :ref:`profile_list_ref`.

**Tip:** To quickly select a profile, you can right-click on any file in your **Project Files**, and select the
:guilabel:`Choose Profile` option (see :ref:`file_menu_ref`).

.. image:: images/profiles.jpg

== ================== ============
Expand All @@ -59,8 +62,39 @@ Choose Profile Dialog
2 Selected Profile Click on the desired profile, and then the :guilabel:`OK` button. You can also double click a profile to select it.
3 Filtered Count Count of filtered profiles
4 Accept Profile Click the :guilabel:`OK` button to switch to the selected profile.
5 Context Menu Right click on any row to :guilabel:`Set as Default Profile` or :guilabel:`Duplicate` a profile. Duplicated and custom profiles also include an :guilabel:`Edit` and :guilabel:`Delete` option. **Note**: *The current profile can not be deleted*.
== ================== ============

.. _profiles_editor_ref:

Edit/Duplicate Profile
----------------------

To create a custom profile, right-click on any profile in OpenShot and choose :guilabel:`Duplicate` to open up the Profile Editor.
Custom profiles also include an :guilabel:`Edit` and :guilabel:`Delete` option, if you need to customize them further. You can edit
the description, resolution, frame rate, aspect ratio, and pixel ratio of the custom profile. **NOTE**: *It is important that
each custom profile has a unique profile name*.

The custom profiles are saved in the ``~/.openshot_qt/profiles/`` or ``C:\Users\USERNAME\.openshot_qt\profiles`` folder.

.. image:: images/profiles-editor.jpg

.. table::
:widths: 5 28 80

== =================== ===================================================================
# Name Description
== =================== ===================================================================
1 **File Path** The location on your system where the custom profile is saved.
2 **Description** A text description for your custom profile, which is displayed in OpenShot.
3 **Width** The horizontal resolution (in pixels) of the video.
4 **Height** The vertical resolution (in pixels) of the video.
5 **Frame Rate** The frame rate of the video (frames per second).
6 **Aspect Ratio** The display aspect ratio of the video (automatically calculated from width/height and pixel ratio).
7 **Pixel Ratio** The aspect ratio of each pixel in the video. A ratio of 1:1 means square pixels (default).
8 **Interlaced** Whether the video is interlaced (Yes) or progressive (No).
== =================== ===================================================================

Converting Profiles
-------------------
When switching profiles (or exporting to a different profile), OpenShot will do it's best to convert all clip,
Expand Down Expand Up @@ -92,8 +126,11 @@ Custom Profile
--------------
Although OpenShot has more than 400 profiles (:ref:`profile_list_ref`) included by default, you can also create
your own custom profiles. Create a new text file in the ``~/.openshot_qt/profiles/`` or
``C:\Users\USERNAME\.openshot_qt\profiles`` folder. Use the following text as your template (i.e. copy and
paste this into the new file):
``C:\Users\USERNAME\.openshot_qt\profiles`` folder.

NOTE: See :ref:`profiles_editor_ref` for an alternative method of duplicating an existing profile.

Use the following text as your template (*i.e. copy and paste this into the new file*):

.. code-block:: python
Expand Down
2 changes: 1 addition & 1 deletion doc/transitions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ A transition is used to gradually fade (or wipe) between two clip images. In Ope
transitions are represented by blue, rounded rectangles on the timeline. They are automatically created when you
overlap two clips, and can be added manually by dragging one onto the timeline from the **Transitions** panel.
A transition must be placed on top of a clip (overlapping it), with the most common location being the beginning or end
or a clip.
of a clip.

NOTE: Transitions **do not** affect **audio**, so if you are intending to fade in/out the audio volume of a clip,
you must adjust the ``volume`` clip property. See :ref:`clip_properties_ref`
Expand Down
41 changes: 41 additions & 0 deletions src/classes/project_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,47 @@ def changed(self, action):
action.set_old_values(old_vals) # Save previous values to reverse this action
self.has_unsaved_changes = True

if len(action.key) == 1 and action.key[0] in ["fps"]:
# FPS changed (apply profile)
profile_key = self._data.get("profile")
profile = self.get_profile(profile_key)
if profile:
# Get current FPS (prior to changing)
new_fps = self._data.get("fps")
new_fps_float = float(new_fps["num"]) / float(new_fps["den"])
old_fps_float = float(old_vals["num"]) / float(old_vals["den"])
fps_factor = float(new_fps_float / old_fps_float)

if fps_factor != 1.0:
log.info(f"Convert {old_fps_float} FPS to {new_fps_float} FPS (profile: {profile.ShortName()})")
# Snap to new FPS grid (start, end, duration)
change_profile(self._data["clips"] + self._data["effects"], profile)

# Rescale keyframes to match new FPS
self.rescale_keyframes(fps_factor)

# Update size of audio-only files
for file in self._data.get("files", []):
# Check for audio-only files
if file.get("has_audio") and not file.get("has_video"):
# Audio-only file should match the current project size and FPS
file["width"] = profile.info.width
file["height"] = profile.info.height
file["fps"]["num"] = profile.info.fps.num
file["fps"]["den"] = profile.info.fps.den
file["display_ratio"]["num"] = profile.info.display_ratio.num
file["display_ratio"]["den"] = profile.info.display_ratio.den

# Change all related clips
for clip in self._data.get("clips", []):
if clip.get("reader", {}).get("id") == file.get("id"):
clip["reader"] = file

# Broadcast this change out
get_app().updates.load(self._data, reset_history=False)
else:
log.warning(f"No profile found for {profile_key}")

elif action.type == "delete":
# Delete existing item
old_vals = self._set(action.key, remove=True)
Expand Down
30 changes: 29 additions & 1 deletion src/classes/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
"""

import os
import json
import os

import openshot

from classes import info
from classes.app import get_app
Expand Down Expand Up @@ -257,6 +259,32 @@ def relative_path(self):
# Convert path to relative (based on current working directory of Python)
return os.path.relpath(file_path, info.CWD)

def profile(self):
""" Get the profile of the file """
# Load file Json into Profile object
file_profile = openshot.Profile()
file_profile.SetJson(json.dumps(self.data))

if file_profile.info.display_ratio.num == 1 and file_profile.info.display_ratio.den == 1:
# Some audio / image files have inaccurate DAR - calculate from size and pixel ratio
file_profile.info.display_ratio = openshot.Fraction(round(file_profile.info.width * file_profile.info.pixel_ratio.ToFloat()), file_profile.info.height)
file_profile.info.display_ratio.Reduce()

# Iterate through all possible profiles
for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]:
for file in reversed(sorted(os.listdir(profile_folder))):
profile_path = os.path.join(profile_folder, file)
if os.path.isdir(profile_path):
continue
try:
# Load Profile
profile = openshot.Profile(profile_path)
if profile == file_profile:
return profile
except RuntimeError as e:
pass
return file_profile


class Marker(QueryObject):
""" This class allows Markers to be queried, updated, and deleted from the project data. """
Expand Down
Loading

0 comments on commit 5ed8300

Please sign in to comment.