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

osdep/file_dialog: add file dialog for macOS, Windows and Linux #15845

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

kasper93
Copy link
Contributor

@kasper93 kasper93 commented Feb 10, 2025

  • - figure out multi file selection or disable it
  • - working macOS impl
  • - connect more commands (?)
  • - add Linux impl

@kasper93
Copy link
Contributor Author

@Akemi: Could you help me with macOS implementation? I tried to put something together to make sure the api will work nicely, but it is missing filters and probably doesn't work at all currently. Also I made objc, but I don't mind replacing it completely with swift impl or anything.

@kasper93
Copy link
Contributor Author

Currently connected only to loadfile / loaddir. Can be used for more open/save commands like screenshots and so on. Also can be exported as standalone command for script use, but not sure how useful that would be.

@kasper93 kasper93 force-pushed the file-dialog branch 2 times, most recently from 9f42128 to 38844b3 Compare February 10, 2025 09:39
@Akemi
Copy link
Member

Akemi commented Feb 10, 2025

sure, i will have a look. give me a few days to think about the implementation details for macOS.

from the top of my head, i would probably move the (open) dialog functionality (https://github.com/mpv-player/mpv/blob/master/osdep/mac/menu_bar.swift#L325-L361) out of the menu bar into its own class and make it reusable. also extending its functionality to be usable with your changes.

if you don't mind, i would prepare something you can then just (re-)use here.

@na-na-hi
Copy link
Contributor

I think it's better to add a separate command instead of making loadfile accepting empty url, because the semantics of the loadfile command means that the command cannot return until it knows which items are added, and this syncronous process blocks the core.

A separate command which opens the file dialog in a separate thread, and signals the core after the file is selected would be a better idea. This can reuse the the mp_event_drop_files function used by drag and drop.

@kasper93
Copy link
Contributor Author

I think it's better to add a separate command instead of making loadfile accepting empty url, because the semantics of the loadfile command means that the command cannot return until it knows which items are added, and this syncronous process blocks the core.

Could you explain the issue, I don't understand. It works perfectly fine.

A separate command which opens the file dialog in a separate thread, and signals the core

Why? It already spawns a thread, unlocks core and wait for user selection. Also you can use asynchronous command if you don't want to wait for loadfile selection on calling thread.

@kasper93 kasper93 changed the title osdep/file_dialog: add file dialog for macOS and Windows osdep/file_dialog: add file dialog for macOS, Windows and Linux Feb 10, 2025
@kasper93
Copy link
Contributor Author

Added kdialog and zenity support. More can be added later, I think it's enough for now.

@kasper93 kasper93 force-pushed the file-dialog branch 4 times, most recently from 84e3947 to 589654d Compare February 10, 2025 23:39
Copy link

github-actions bot commented Feb 11, 2025

Download the artifacts for this pull request:

Windows
macOS

@hooke007
Copy link
Contributor

@dyphire
Copy link
Contributor

dyphire commented Feb 11, 2025

I think the support for file dialogs should be added to the audio-add and sub-add commands also.

@dyphire
Copy link
Contributor

dyphire commented Feb 11, 2025

Also can be exported as standalone command for script use, but not sure how useful that would be.

This will be useful for third-party scripts and greatly increases scalability

@na-na-hi
Copy link
Contributor

Could you explain the issue, I don't understand. It works perfectly fine.

Sorry, I didn't notice spawn_thread. However, you avoided blocking by unlocking the core which can result in data race. The only other command that does this is subprocess, and that's fine because mp_subprocess does not access mpctx. But here the thread accesses mpctx and filter options which are also accessed by the core.

So to make this viable, mp_file_dialog_get_files shouldn't take mpctx, and all filter strings need to be duplicated, before unlocking the core.

@kasper93
Copy link
Contributor Author

kasper93 commented Feb 11, 2025

Could you explain the issue, I don't understand. It works perfectly fine.

Sorry, I didn't notice spawn_thread. However, you avoided blocking by unlocking the core which can result in data race. The only other command that does this is subprocess, and that's fine because mp_subprocess does not access mpctx. But here the thread accesses mpctx and filter options which are also accessed by the core.

So to make this viable, mp_file_dialog_get_files shouldn't take mpctx, and all filter strings need to be duplicated, before unlocking the core.

Not having synchronized access to mpctx doesn't mean that we cannot use parts of it that are thread-safe, like for example mpctx->log that would be always valid. I could even move the locking inside the impl. Regardless, I don't needed it and this is kinda leftover from initial version. So no need to complicate things.

The only other command that does this is subprocess, and that's fine because mp_subprocess does not access mpctx.

The behavior of spawn_thread is well documented, no need to base it on examples. But fyi all commands that spawn thread, are unlocking core one way or another. For example track manipulation do that in mp_add_external_file.

@kasper93 kasper93 force-pushed the file-dialog branch 3 times, most recently from 2a9bbc3 to a4c405e Compare February 11, 2025 07:23
@kasper93 kasper93 marked this pull request as ready for review February 11, 2025 07:24
@kasper93
Copy link
Contributor Author

kasper93 commented Feb 11, 2025

Also can be exported as standalone command for script use, but not sure how useful that would be.

This will be useful for third-party scripts and greatly increases scalability

Added file-dialog command. Need to add docs and filtering for it still. And whole thing needs another pass of cleaning.

@kasper93 kasper93 force-pushed the file-dialog branch 4 times, most recently from 0438edd to 64b6db0 Compare February 11, 2025 18:38
@kasper93
Copy link
Contributor Author

If you find script based solution too cumbersome, that implementation can be omitted for now. With portal there is already cross-platform support, and kdialog/zenity can be added later in a way that don't go into player core.

Nah, it doesn't work like this. Put your money where your mouth is. You don't get to talk and back out when you are asked for actual specifics. You are conveniently omitting details in your nicely worded "make it simpler with the script". So I want to see what you really mean.

@kasper93
Copy link
Contributor Author

Since this command execution thing is hardcoded and can't be disabled, unlike scripts, something like CVE-2021-32563 is going to happen. This affects all libmpv clients including all GUI frontends.

I don't think you understand what this is about. Clearly we are not executing or running any files in external programs. But hey, you do you.

@avih
Copy link
Member

avih commented Feb 13, 2025

That I consider this feature non-essential for mpv as a "commandline" player, but it would be essential if mpv wants to be a GUI-centric player, so I just want to know whether mpv wants to go to that direction.

Specifically about this point: I don't think mpv was ever a "commandline" player, despite using this description, and neither did mplayer.

mpv and mplayer are interactive media players, and always have been. They're also graphical, at least when playing a video (and ignoring TCT etc).

They also have very extensive interactive UI, mpv more so than mplayer, and even while ignoring the OSC - using key bindings, typically with visual feedback of some kind (seek, pause, etc).

So in that sense mpv is a "commandline" media player the same way that vim is a "commandline" editor (ignoring its "ed" origins). Both are not. Both are very interactive and not limited to command line options.

Now that we've put that out of the way, let's see what we do have in terms of GUI:

  • The OSC is pure GUI, and mpv has had it for ages. Sure, it doesn't use any external widgets toolkit, but it does implement such kit internally, even if it doesn't include everything which GUI toolkits usually support (it mainly has buttons), but for all intents and purposes it's a normal mouse-driven GUI as far as GUI goes.
  • Recently, there are the "select.lua" additions, which are both enhanced keypress-based UI, but also GUI as they can or will support the mouse too.

And now this PR adds file-selection dialog, which I think no one would disagree that it's typically an essential functionality in media players.

The main difference here is that it diverges from the internal-GUI-toolkit paradigm into external kits, which is indeed a very meaningful departure, mainly in the sense of dependencies, but IMO not in the sense of it being a commandline player or not, and it's definitely worth the discussions in this PR.

So please don't use "commandline player" as an argument, because mpv never was that, and the file selection dialog is not a meaningful departure from any existing usage paradigm which have been used forever with mpv (OSC).

The only real topics at hand IMO are the external dependencies (which to use, how to use, how far are we willing to go, if at all, etc), and the integration of the dialog with commands - mainly whether we should modify commands (and the technical or maintenance hurdles it may have), or only supply a dialog building block while allowing scripts to do the rest, possibly with also a builtin script which could streamline the common use cases while using the dialog as a building block.

@avih
Copy link
Member

avih commented Feb 13, 2025

Since this command execution thing is hardcoded and can't be disabled, unlike scripts, something like CVE-2021-32563 is going to happen. This affects all libmpv clients including all GUI frontends.

I don't think you understand what this is about. Clearly we are not executing or running any files in external programs. But hey, you do you.

This patchset does fallback to zenity or kdialog if portal is unavailable, which, without reading that CVE or PR code in details, I think does fall into the realm of executing external apps (without user consent?), and therefore potentially with similar vulnerabilities, but I admit to not reading it very carefully, so hopefully I'm wrong.

That being said, it would not be the first external executable which mpv uses without asking the user, and I'm thinking mainly yt-dl, but this allows the user to disable it via config or command line (commandline player to the rescue!).

But ytdl is enabled by default, and it's likely susceptible to the same class of vulnerabilities.

Regardless, adding more external executables increases the risk, and maybe it could be useful to allow disabling the fallback part via some option, if it doesn't already exist (I hope it does exist).

@dyphire
Copy link
Contributor

dyphire commented Feb 13, 2025

Because if you want to do this, it should be also applied to all other commands which take a file, along with suitable filters. There is no reason why some commands do this where others don't. You then need to duplicate the same 30-40 lines of code for every single command changed, along with hardcoded filter lists.

Adding one helper function in default.lua and default.js to handle the most common case will be plenty enough

This consideration makes sense. mpv has many commands that can pass file parameters. In addition to these already implemented, there are various protocols commands (such as bd:// and cdda://, etc.)
Modifying all such commands to add file dialog support does produce a lot of repetitive code. It seems more appropriate to use the file-dialog command to open the file dialog box and call the specified command after opening it through internal or external scripts. In addition, there are some benefits that C code does not have: when the open file type is subtitles or iso file, the script can flexibly call relevant commands, while the loadfile command cannot be implemented. In fact, there are already similar third-party script implementations: https://github.com/dyphire/mpv-scripts/blob/main/open_dialog.lua

@avih
Copy link
Member

avih commented Feb 13, 2025

As far as using a builtin script instead of modifying each command which takes a filename (in addition to allowing any 3rd party script to use it as well), here's an outline of what I had in mind:

  • Usage wise, it would support exactly the same use cases which the modified commands support, with two exception: it would use %f (TBD) instead of "" as placeholder for the dialog output, and it would require a dlg command "prefix". It's quoted because it looks like a prefix but it's actually a command (trivial one, which we'd add), which, for the user, replaces each %f argument with an appropriate dialog which matches the command, and without any %f argument it adds implicitly a final %f, and under the hood it simply runs script-message-to builtin-dialog-script (name TBD) with the remaining argument, and that script takes it from there.
  • In the rare cases where the build is without lua, the dlg command would error or warn.
  • The script will have a table, where each of loadfile, loadfiles, sub-add, etc have an associated set of dialog options appropriate for that command. These likely include at least default filename extensions and whether multiple items are allowed. Essentially, I'm guessing the same kind of options which the current PR does for each command, just in one table in one script.
  • Once we have the table, it's trivial: if there's no %f, then it adds it implicitly at the end. Then spawns a dialog with the options appropriate for the 1st-arg command, else some default dialog options.

And this should allow basically everything which the PR does by modifying commands, but instead by adding one command and one script, e.g. in input.conf:

  • x dlg loadfile
  • y dlg loadfile %f append
  • z dlg sub-add
    etc.

Additionally, we can consider adding even more functionality than the builtin commands modifications allow, for instance maybe %f or %a is "auto", %s is single item, and %m is multiple items.

We could specify a form of adding options to this % thing, e.g. maybe %s/foo,bar can define the default file extensions to be used, etc (this would require some thought, to accomodate all supported options reasonably, while keeping it extensible, e.g. maybe %s/e{foo,bar}/y{...} where e is for extensions, y for whatever, etc).

I don't think it would be too bad for the user, and I think both this script and the new dlg command can be reasonably tight and effective, and from then onward all the dialog changes - as far as usage goes - can be made in one place (that script), and there's no need to modify any existing command.

@kasper93 kasper93 force-pushed the file-dialog branch 4 times, most recently from e50ef06 to d164a1b Compare February 13, 2025 17:25
@na-na-hi
Copy link
Contributor

Nah, it doesn't work like this. Put your money where your mouth is. You don't get to talk and back out when you are asked for actual specifics. You are conveniently omitting details in your nicely worded "make it simpler with the script". So I want to see what you really mean.

avih has outlined a script solution, and I think that can be used for zenity/kdialog by implementing them in the script. The difficulty comes if you want zenity/kdialog have 100% feature parity as the file-dialog command beyond the most common cases, then packing and unpacking a large number of arguments would be unavoidable: I backed out here, not where the "convience solution" is.

I don't think you understand what this is about. Clearly we are not executing or running any files in external programs. But hey, you do you.

Executing external programs is already a risk factor, especially when it can't be disabled and the user has not specifically requested it, just like that CVE. The impact is also larger than a file manager since it affects all libmpv users.

Specifically about this point: I don't think mpv was ever a "commandline" player, despite using this description, and neither did mplayer.

Sure, mpv is interactive, just like ffplay, which also reacts to key bindings and provides feedbacks in terminal outputs. But it does not work in the same way as what is expected from a "normal" GUI program:

  • When running mpv without argument, mpv just prints build info and exits. In some special situations "Pseudo GUI mode" is activated, which is as it says, a "pseudo" GUI, because all it does is to show the initial window, but doesn't change behavior otherwise.
  • When the playback is finished, mpv just closes. This is similar to typical commandline programs like curl, cat, etc., and unlike any other GUI players like mpc-hc and vlc.

Putting OSC aside, mpv isn't really much different from ffplay, which I don't think is a GUI program as normally defined.

Now that we've put that out of the way, let's see what we do have in terms of GUI:

Well, the mpv documentation says:

mpv has no official GUI, other than the OSC (ON SCREEN CONTROLLER), which is not a full GUI and is not meant to be. However, to compensate for the lack of expected GUI behavior, mpv will in some cases start with some settings changed to behave slightly more like a GUI mode.

It points out that mpv has no official GUI, that OSC is not a full GUI and is not meant to be one, that mpv has a lack of expected GUI behavior. At best this can be passed as a GUI on mobile platforms due to the lack of concept of windows, but it's not a GUI in a desktop platform sense.

Desktop GUI media players like mpc-hc, vlc, and many mpv frontends typically have popup dialogs for file selection (which is what this PR does), adjusting settings, viewing media info, etc., in the GUI toolkit of the desktop platform. It's a fundamentally different paradigm from having everything as overlays over the video, like video game HUDs.

Regardless, adding more external executables increases the risk, and maybe it could be useful to allow disabling the fallback part via some option, if it doesn't already exist (I hope it does exist).

Agreed. I think this is especially true for libmpv-based GUI frontends, since they would want to use their own dialogs instead.

As far as using a builtin script instead of modifying each command which takes a filename (in addition to allowing any 3rd party script to use it as well), here's an outline of what I had in mind:

Thanks for posting this. These are all good ideas to make the script solution as concise as possible.

The dlg command here is functionally identical to something like script-message-to dlg. I don't think this was the main reason why this script solution was criticized, and it has the drawback of creating a dependence of core on a specific script name, so I don't think this is necessary.

@kasper93
Copy link
Contributor Author

avih has outlined a script solution, and I think that can be used for zenity/kdialog by implementing them in the script.

Sure. It's easy to imagine interface that looks nice. The difficult part is to implement it in a way that is maintainable. Because mind I remind you, your main concern is that adding it in C is "a lot" of code. So I want to see how you manage to port it to script with the same feature parity with less code and duplication. I will say it again, I don't see how duplicating and reimplenenting "dialog version" of each command is easier, simpler and less loc than C version.

Executing external programs is already a risk factor, especially when it can't be disabled and the user has not specifically requested it, just like that CVE. The impact is also larger than a file manager since it affects all libmpv users.

The mentioned CVE is problematic, because it can exploit external applications, by opening the file based on mime type. The most prominent example would be if a script or bytecode is opened by some interpreter Y. Which is unexpected by the user who run application X.

It has nothing to do with our case. We are not passing any user provided payloads/files to the external application. Moreover we are not trying to lookup any application based on mime type. We have hardcoded certain application with all arguments, provided by us and validated. The only variable arg is filter list, but this is passed only to trusted applications.

I would appreciate if you stay on topic and not try to side track discussion with some bullshit.

Also mind I remind you that kdialog and zenity are literally designed to be called by external applications/scripts. We are not doing anything strange here.

Executing external programs is already a risk factor

So, you propose to remove subprocess command from mpv? Or ytdl? Or whole scripting support? Because mpv allows to execute arbitrary code in form of lua and js payloads.

Sure, mpv is interactive, just like ffplay, which also reacts to key bindings and provides feedbacks in terminal outputs. But it does not work in the same way as what is expected from a "normal" GUI program:

Stop it, just stop. It's not relevant to this PR. If you don't like having file dialog in mpv, just say it. Don't dance around it and find some excuses.

When the playback is finished, mpv just closes. This is similar to typical commandline programs like curl, cat, etc., and unlike any other GUI players like mpc-hc and vlc.

You know it is not true. mpv is fully fledged GUI application on Windows. I'm sure you know that... On linux there is no real distinction between GUI and console applications, but you also must know that console applications doesn't generally use Wayland or X11.

Adding external file selection dialog will not change that.

Agreed. I think this is especially true for libmpv-based GUI frontends, since they would want to use their own dialogs instead.

And they can. Nothing will prevent them from doing so.

@kasper93
Copy link
Contributor Author

This consideration makes sense. mpv has many commands that can pass file parameters. In addition to these already implemented, there are various protocols commands (such as bd:// and cdda://, etc.)

Those are not commands. cdda-device, dvd-device, bluray-device are properties. But that's good idea to set them. I've added set-property argument to file-dialog which will pass the selected path to the property/option of your choosing.

@kasper93 kasper93 force-pushed the file-dialog branch 2 times, most recently from d164a1b to 322f76e Compare February 13, 2025 19:35
@kasper93 kasper93 removed the priority:on-ice may be revisited later label Feb 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants