Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: merge media controls. #805

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

csponge
Copy link
Contributor

@csponge csponge commented Feb 18, 2025

Initial commit to merge audio/video files. There are still a few bugs around widget sizing that need fixing.

@CyanVoxel CyanVoxel added Type: Enhancement New feature or request Type: Refactor Code that needs to be restructured or cleaned up Type: UI/UX User interface and/or user experience labels Feb 18, 2025
@CyanVoxel CyanVoxel linked an issue Feb 18, 2025 that may be closed by this pull request
3 tasks
@csponge
Copy link
Contributor Author

csponge commented Feb 23, 2025

Hi @CyanVoxel. I think I'm getting closer, but still running into an issue with correctly fitting the overlay with the thumbnail. Is there an easy way to get the size of the rendered thumbnail image?

Thanks!

@CyanVoxel
Copy link
Member

Thank you for your work on this so far! It should be fairly straightfoward to get the size of an image, but it differs a bit depending on what type of variable it is. PIL images have .width and .height properties while QPixmaps have .width() and .height() methods along with a .size() method which returns both as a QSize object. Depending on what you're doing it also may or may not be necessary to take into account the screen pixel ratio. Qt usually takes care of this for you, but images rendered from PIL do not.

As of your last commit I don't think I see the issue you're describing, but it might be part of the screenshot I've attached below. Since you're getting closer to finishing I also went ahead and jotted down some quick feedback based on the current state of the PR:

  • The volume and playback sliders can't be clicked anywhere along the bar to set their values and instead can only be changed by dragging the handle. If it was just the volume silder then maybe this could pass, but it makes playback seeking rather difficult. (Maybe this post could be of help?)
  • Given certain video sizes the volume slider covers the playback timers and potentially gets cut off of the screen image
  • The toggle mute setting is not respected
  • The autoplay setting is not respected
  • The right-click context menu is missing
  • Clicking on the preview outside of the controls opens the file - while this is the default behavior for other file types such as images, for media playback this is undesirable and the more intuitive behavior would be for the pause state to be toggled

@csponge
Copy link
Contributor Author

csponge commented Feb 25, 2025

Hi,

Thanks for the comment! I'll be sure to work on those features/fixes.

On my original issue, here is a screenshot of the issue I'm having:
overlay_oversized

In this case, the thumbnail image stops growing, while the rest of the media player widget keeps growing. This only happens when I make the preview panel very large.

Let me know if you have any questions.

@CyanVoxel
Copy link
Member

In this case, the thumbnail image stops growing, while the rest of the media player widget keeps growing. This only happens when I make the preview panel very large.

Ahh, I see! It looks like this is due to the max resolution used for the preview panel thumb which is 512x512 in most places. It's unfortunately a messy hardcoded limit sprinkled around the codebase. I won't stop you if you're interested in improving it, but I also wouldn't burden you with that for this feature.

@csponge
Copy link
Contributor Author

csponge commented Feb 28, 2025

Hi,

I just pushed a fix that should fix the sliders, autoplay, context menu, and the behavior when clicking on the media widget. I am running into a mypy issue that I'm not sure how to resolve yet.

On the thumbnail sizing, I guess I could also lock it to 512x512 for now. I'll try to get that in the next commit.

I have some questions on the your other comments:

  • What should the behavior be when there is not enough space to display all the widgets? Do I need to resize them? Hide some of them?
  • How should toggle mute behave? I assume it would be similar to the autoplay setting. Start the media muted?

Thank you!

@CyanVoxel
Copy link
Member

Thank you for implementing the feedback so far!

I am running into a mypy issue that I'm not sure how to resolve yet.

I see what you mean:
opt.subControls = QStyle.SubControl.SC_SliderGroove | QStyle.SubControl.SC_SliderHandle
"QStyleOptionSlider" has no attribute "subControls" [attr-defined]

From what I can tell, PySide6 is not implementing the subControls attribute like it says so in the Qt documentation. However from poking around in the code I also don't know if it would accept any SubControl value other than the ones beginning with SO_. In any case, removing this line doesn't appear to change any behavior?

On the thumbnail sizing, I guess I could also lock it to 512x512 for now. I'll try to get that in the next commit.

Sounds good to me!

What should the behavior be when there is not enough space to display all the widgets? Do I need to resize them? Hide some of them?

Would this be in cases like this? If so, I think hiding the volume slider when it would normally overlap with the timecode would be an alright solution in this case
image

How should toggle mute behave? I assume it would be similar to the autoplay setting. Start the media muted?

It should work the same way it currently does on main with videos, which in this case yes would be to start the media muted


I appreciate you implementing the feedback for jumping the seek position when clicking! However, I would expect it to move the handle to the clicked position as well, allowing you to continue holding down and dragging to seek. This is the behavior of any video/media player I can think of off the top of my head (e.g. YouTube, QuickTime, VLC, etc.)

@CyanVoxel
Copy link
Member

I just happened to notice the mypy errors here - Translations.translate_qobject() has been removed in favor of just using strings returned from Translations["key_name"] (for keys without placeholders).

So in the case of something like

open_file_action = QAction(self)
Translations.translate_qobject(open_file_action, "file.open_file")

this now becomes:

open_file_action = QAction(Translations["file.open_file"])

(I tried to comment on the code directly but GitHub didn't let me for some reason)

@csponge
Copy link
Contributor Author

csponge commented Mar 6, 2025

Thanks for letting me know, I'll make sure to update that when pulling in the main branch.

I don't think I'm able to reproduce the issue you had when clicking the slider. Clicking the slider causes the handle to move to the position I clicked. Does the most recent commit fix this issue for you?

This might be a weird request, but would you be able to share a small video with me so I can test the widget overlap issues? If not, is there a resource I could find a sample video?

P.S. I don't think locking the media player to 512x512 will work. It seems that the preview thumbnail grows past that size. Forgive me, as I'm not super familiar with it. I think we need a way of telling the media player when the thumbnail resizes. Currently, I'm not sure how to do that. Will research...

@SkeleyM
Copy link
Contributor

SkeleyM commented Mar 6, 2025

Hi, i know this isnt open for review, i just thought i'd mention i tried dynamically resizing the volume bar. it fixes the overlap issue but its pretty hard to control at smaller sizes.

image
image

heres the patch if youre interested
dynamic.patch

perhaps a better approach could be to make the volume slider vertical and popup when the media has a small width. however this does somewhat work

also here is a link to find stock videos of that size, just right click and press "Save Video As"
https://www.shutterstock.com/video/search?aspect_ratio=9%3A16

@csponge
Copy link
Contributor Author

csponge commented Mar 7, 2025

Hey @SkeleyM,

Thanks for the patch! I tried it and it seemed to make it better. And I agree that it can get too small. Feel free to add more if you like :)

I'd be interested in trying a vertical slider. I'll see if I can get something like that working.

Also, thanks for the tip on the test videos!

@csponge
Copy link
Contributor Author

csponge commented Mar 9, 2025

Hello,

I refactored quite a bit in this last fix. In addition to the refactor, I added the ability to switch the orientation of the volume slider based on the size of the media player. Thank you @SkeleyM for the suggestion. How does it look?

Also, I made the volume slider only visible when hovering over the mute button. I thought that was a neat feature :)

There is still the issue on matching the size of the thumbnail for audio files. Need to continue researching there.

@CyanVoxel
Copy link
Member

I apologize for the inconvenience - a large refactor was recently merged (#844) that has moved several files throughout the codebase. This was done in order to correct some deep issues with the project's layout and was performed now as it seemed to be the best opportunity (as of 3/6/25) to disrupt as few open PRs as possible.

Unfortunately this PR is one that's been disrupted by this change. A rebase targeting main will be required to resolve the merge conflicts generated here. A merge commit is possible, however I do not recommend it as a rebase will be much smoother and much less work.


I also apologize for not getting back to you about the slider issue. While clicking it does move the handle to the pointer location, it does not let you continue dragging the handle from there. This makes it a bit awkward to control vs other media players.

Please let me know if there's anything else I can do and if you'd like any help with this. You've done some fantastic work so far and the last thing I want is to scare you off with a rebase or too many requests!

@csponge
Copy link
Contributor Author

csponge commented Mar 10, 2025

Hi @CyanVoxel,

I just did a rebase and tested locally. I think I did it correctly... please let me know if I caused any issues.

As for the slider issue, I see what you mean now. I'll work on that next!

The only other thing I need help with is the sizing for thumbnail. If you have any good ways to fix it, please let me know. I will continue researching as well.

Thanks!

@xarvex
Copy link
Member

xarvex commented Mar 11, 2025

Something didn’t go quite as planned it seems, a merge might have been conducted in place of a rebase, so instead of your commits going on top of the new ones, things went the other way around. To amend this is a little of a complex fix that I wouldn’t expect someone to do, so I do not mind taking care of this at all. It will require me to force push into your branch, so if you have something you didn’t push it would affect that. Let me know if that’s fine and if you’re ready.

@csponge
Copy link
Contributor Author

csponge commented Mar 11, 2025

Hi @xarvex,

Sorry, I hope I didn't create a bunch of work for you all. I have nothing to push at the moment, so I think you should be good to go.

csponge added 2 commits March 11, 2025 12:24
Initial commit to merge audio/video files. There are
still a few bugs around widget sizing that need fixing.
Add widgets to a sublayout to allow for centering
in a QStackedLayout.

Remove references to the legacy video player in
the thumb preview.
@xarvex
Copy link
Member

xarvex commented Mar 11, 2025

That's okay! Rebases aren't an easy thing, so don't be harsh on yourself.

To preserve the current state of this PR, I pushed to a new branch in our repo: https://github.com/TagStudioDev/TagStudio/tree/pull/805

I had to rebase from the point of the commit before the refactor (239a1b4) and manually redo the commit that came after (098840c).

If all looks good there, I will force push to here.

CC @csponge @CyanVoxel

csponge added 5 commits March 11, 2025 13:23
Subclass QSlider to handle click events
and allow for easier seeking.

Implement context menu along with autoplay
setting for the media widget.

Pause video when media player is clicked
instead of opening file.
Start video/audio muted on initial load of
the media player.

Remove code causing mypy issue.

Add new method for getting slider click state.
Add various layouts for positioning widgets instead
of manually moving widgets.

Change the volume slider orientation at smaller
media sizes.
Fix position label color to white so it stays visible
regardless of theme.
@csponge
Copy link
Contributor Author

csponge commented Mar 12, 2025

Hi @xarvex,

I looked at the code and tested locally. Everything seems to be in place.

Thank you so much for fixing this! Feel free to push it.

@xarvex xarvex force-pushed the merge-media-controls branch from 098840c to b62db08 Compare March 12, 2025 01:25
Copy link
Member

@CyanVoxel CyanVoxel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is still a draft, but I wanted to get a jump on checking out the underlying code now that the player itself is coming further along.

Overall I think you've done a great job with this feature, and the media player is currently much more usable than the previous video and audio player setup. There's just some comments I have on the current code structure, a few bugs, and some miscellaneous suggestions.

So far I have some concerns about the new media player code being somewhat "grafted" onto the existing code for the legacy video player and previous audio player code rather than outright replacing it. When I previously refactored and split up the preview panel, I made sure to refer to the video player code as "legacy" to denote that it's going to be replaced by a future combined media player and I named the audio player as "media" to serve as a jumping off point. I understand that this wasn't really communicated on my part though, so I get if there was some hesitation on replacing this code. But all the legacy video player code, including the video_player.py file, will no longer be required thanks to this new combined player and can/should be removed. Really after this point should just be code for "images", "animated images/gifs", and "media (audio/video)".

In addition to this, I feel that the new QStackedLayout is not being fully taken advantage of and is currently just adding extra code with no current benefit. I would suggest looking into whether or not this layout can be used to replace the previous state management system that involved hiding widgets not in use with switch_preview() or to revert to the previous layout layout pattern. Currently there's one foot in the old system and one foot in this potential new system, when really it just needs to be one or the other.

Finally there's some bugs introduced here, with the current ones I've found being:

  • The image and GIF previews no longer have right-click menus and cannot be opened via left click anymore
  • The media player is missing the "Send to Trash" right-click option
  • Videos do not loop, as was the previous default behavior
  • The translation key for "Open file" is incorrect (see suggested change)

I hope this isn't too much, and please let me know if you have any questions or would like some help with this. You've done some great work so far and I would love to see this feature make it to the end!

@@ -290,15 +303,15 @@ def _update_video_legacy(self, filepath: Path) -> dict:
stats["width"] = image.width
stats["height"] = image.height
if success:
self.preview_vid.play(filepath_, QSize(image.width, image.height))
self.media_player.show()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that there's still separate _update_video_legacy() and _update_media() methods despite these now both being given responsibilities for the new combined media player. All methods and mentions of the "legacy" video player should be removed and combined into the "media" player logic, as this introduction of the combined media player is what is intended to replace the legacy video player (and greatly rework the audio player).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on this, and I had an idea. The QMediaPlayer class has its own metaData property. There is a lot of useful information potentially available in the metadata, including video resolution. This could replace the use of cv2 to get these stats, making the _update_media method a bit cleaner. There is a downside though.

From what I can tell, certain metadata isn't immediately available. We need to wait for the media to load before we can access it. This would require us to connect to a signal for metadata changes. Also, this would require us to change how we get file metadata in general. Instead of an immediate response, from update_preview, we would need to have a general signal to send the stats dictionary.

What are thoughts on this? It might be a bit overkill, so I'd also be fine leaving the cv2 logic in place.

@csponge
Copy link
Contributor Author

csponge commented Mar 17, 2025

Hi @CyanVoxel,

Sorry for not responding sooner, I was away last weekend.

Thank you for doing a review! I appreciate all the feedback. I'll take some time today and work through your suggestions.

csponge and others added 2 commits March 17, 2025 09:20
fix: apply suggestions from code review.

Co-authored-by: Travis Abendshien <[email protected]>
Combine the stats logic for video/audio into one method.

Fix several issues after incorrectly implementing suggestions.
@csponge
Copy link
Contributor Author

csponge commented Mar 17, 2025

Hi @CyanVoxel,

Videos do not loop, as was the previous default behavior

Would it be beneficial to have looping as a setting, like autoplay? This is pretty easy to implement. Only downside is the setting needs to be translated.

@CyanVoxel
Copy link
Member

Hi @CyanVoxel,

Videos do not loop, as was the previous default behavior

Would it be beneficial to have looping as a setting, like autoplay? This is pretty easy to implement. Only downside is the setting needs to be translated.

This would be great! I would do it exactly like how the autoplay setting is done, and have the default behavior be set to true. For the translation key, I would make it:

"media_player.loop": "Loop",

And remember that the en.json file is sorted alphabetically, so in this case the key will be immediately below the autoplay key.

@csponge
Copy link
Contributor Author

csponge commented Mar 17, 2025

Tried adding the delete action with this last commit, but I'm not sure I got it working.

The loop setting works okay, but I can't get the delete action to show for some reason. I've added the action to both the preview_gif and the media_player, but it is not showing for either. Any ideas on this?

image

Make a single method to control widget state.

Works with the main QStackLayout and cleans up
widget state if it is needed (i.e., stopping the media
player when switching to a different preview).
@CyanVoxel
Copy link
Member

Tried adding the delete action with this last commit, but I'm not sure I got it working.

The loop setting works okay, but I can't get the delete action to show for some reason. I've added the action to both the preview_gif and the media_player, but it is not showing for either. Any ideas on this?

The delete action seems to appear and work just fine for me (macOS) 🤔
Video:
image
GIF:
image

Although I've got a new issue where the program will launch with the preview panel now taking up half the width of the application window:
Screenshot 2025-03-20 at 01 28 39

Fixes a regression in commit 4c6934. We need the pages
to properly center the widgets in the QStackLayout.
@csponge
Copy link
Contributor Author

csponge commented Mar 20, 2025

Okay, I think I know where I went wrong.

I was accidentally running an older version of the code somehow. This most recent commit should fix the issues.

Thanks!

Fix and issue where the media_player would expand past the
thumbnail on resize.
@csponge csponge marked this pull request as ready for review March 22, 2025 18:05
@csponge
Copy link
Contributor Author

csponge commented Mar 22, 2025

With my latest commit, I believe I've fixed one of my biggest issues with this feature. I think it should be good enough to be reviewed now.

Please let me know if there are any more issues.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Enhancement New feature or request Type: Refactor Code that needs to be restructured or cleaned up Type: UI/UX User interface and/or user experience
Projects
Status: 🚧 In progress
Development

Successfully merging this pull request may close these issues.

[Feature Request]: Single Control Set for Audio/Video Files
4 participants