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

player: add immediate command prefix #15913

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Dudemanguy
Copy link
Member

@Dudemanguy Dudemanguy commented Feb 19, 2025

cc @christoph-heinrich: I think with this you just need to do this (potential backwards compatibility handling ignored):

diff --git a/subtitle-lines.lua b/subtitle-lines.lua
index d836b83..556796f 100644
--- a/subtitle-lines.lua
+++ b/subtitle-lines.lua
@@ -130,7 +130,7 @@ local function acquire_subtitles()
     mp.set_property_bool(sub_strings.visibility, false)
 
     -- go to the first subtitle line
-    mp.commandv('set', sub_strings.delay, mp.get_property_number('duration', 0) + 365 * 24 * 60 * 60)
+    mp.commandv('immediate', 'set', sub_strings.delay, mp.get_property_number('duration', 0) + 365 * 24 * 60 * 60)
     mp.commandv('sub-step', 1, sub_strings.step)
 
     -- this shouldn't be necessary, but it's kept just in case there actually
@@ -207,7 +207,7 @@ local function acquire_subtitles()
         mp.commandv('sub-step', 1, sub_strings.step)
     end
 
-    mp.set_property_number(sub_strings.delay, sub_delay)
+    mp.commandv('immediate', 'set', sub_strings.delay, sub_delay)
     mp.set_property_bool(sub_strings.visibility, sub_visibility)
 
     for _, subtitle in ipairs(subtitles) do

And you'll get the old behavior back.

@Dudemanguy Dudemanguy force-pushed the immediate-prefix branch 3 times, most recently from dc415c7 to fec1212 Compare February 19, 2025 05:56
Copy link

github-actions bot commented Feb 19, 2025

Download the artifacts for this pull request:

Windows
macOS

@verygoodlee
Copy link
Contributor

New command prefix need to be added to these places as well.

mpv/player/lua/console.lua

Lines 1669 to 1677 in fc2f176

-- Skip command prefixes because it is not worth lumping them together with
-- command completions when they are useless for interactive usage.
local command_prefixes = {
['osd-auto'] = true, ['no-osd'] = true, ['osd-bar'] = true,
['osd-msg'] = true, ['osd-msg-bar'] = true, ['raw'] = true,
['expand-properties'] = true, ['repeatable'] = true,
['nonrepeatable'] = true, ['nonscalable'] = true,
['async'] = true, ['sync'] = true
}

mpv/player/lua/stats.lua

Lines 414 to 420 in fc2f176

-- command prefix tokens to strip - includes generic property commands
local cmd_prefixes = {
osd_auto=1, no_osd=1, osd_bar=1, osd_msg=1, osd_msg_bar=1, raw=1, sync=1,
async=1, expand_properties=1, repeatable=1, nonrepeatable=1, nonscalable=1,
set=1, add=1, multiply=1, toggle=1, cycle=1, cycle_values=1, ["!reverse"]=1,
change_list=1,
}

@kasper93
Copy link
Contributor

Shouldn't the whole feature go through a deprecation period?

We added a new behavior that breaks multiple use-cases (this subtitle thing and hwdec thing), now we add a command prefix to revert to old behavior. This is breaking change and we need to give users time to migrate their scripts to immediate command.

This defered options callback invites all sort of race conditions like shown by subtitle-lines.lua. Not all setters/getter return the opts/property value, some read real state of mpv, so it may be unexpected that the state doesn't change.

@Dudemanguy
Copy link
Member Author

hwdec thing

To be fair, that didn't really work before. You would need some kind of queueing approach to wait until the hwdec is actually set for real before printing it no matter what.

This defered options callback invites all sort of race conditions like shown by subtitle-lines.lua

It's always been a bit racy. The earlier hwdec is a good example since it may take a few frames before it gets applied. So if you do a get right after setting it, it could be wrong. This specific script has failures because it sets the sub-delay and then immediately performs a sub-step which is directly reliant on sub-delay. And the timing requirements are small enough to where the next playloop isn't sufficient. I'm not saying there aren't people out there that will be affected, but I still think it's a low number of people.

Deprecating is easy enough and I'm not like opposed to it or anything. All I'd have to do is make immediate always true, but I'm not sure how we would actually communicate that to users. I mean yeah we can put it in the release notes/docs but is anyone going to really read it? I don't think printing a warning makes much sense either.

@kasper93
Copy link
Contributor

Deprecating is easy enough and I'm not like opposed to it or anything. All I'd have to do is make immediate always true, but I'm not sure how we would actually communicate that to users. I mean yeah we can put it in the release notes/docs but is anyone going to really read it? I don't think printing a warning makes much sense either.

I don't mind either way. We need to be careful not to release next stable version without making sure it is safe. I'm fine with having this change, but we need to monitor the impact. It's basically Hyrum's law, it really doesn't matter how we define this, what matters how it works and if it start breaking scripts even in subtle way, because they depended on some strange behavior it's a problem.

@na-na-hi
Copy link
Contributor

I think it's clear now that the impact of this change was very underestimated. sub-delay has the UPDATE_OSD flag which means it has a high potential of breakage because it involves callbacks.

Instead of this command prefix, the option change coalescing should be disabled for UPDATE_OSD flag, and potentially some other flags of high risk, and then gradually enable this handling for options of a particular UPDATE_* flag once it's known to not break.

@Dudemanguy
Copy link
Member Author

I think it's clear now that the impact of this change was very underestimated.

I'd appreciate it if we could at least wait until there's a sample size greater than 1 before we start making melodramatic statements.

@christoph-heinrich
Copy link
Contributor

This doesn't work for me. I end up with messed up timestamps. I tried adding immediate before the sub-step commands as well, but that didn't help.

@Dudemanguy
Copy link
Member Author

Sorry implementation flaw on my part. Does it work correctly now?

Every change breaks someone's workflow and sure enough a user pointed
out that bbac628 degraded one of their
scripts. It was very timing sensitive and inherently relied on the
immediate update behavior of the old code. We'd still like to coalesce
these by default, sending notifications to property observers are
coalesced after all, but some users do have a genuine use case for the
old behavior. So solve this by adding a new 'immediate' command prefix.
If passed, the option update will trigger its callback immediately and
skip the internal queueing process. Note that the implementation of this
means it will only work with the property manipulation commands (set,
multiply, cycle-values, etc.) and not any mpv_set_property type API. But
that's OK, using these commands have the exact same end effect.
@christoph-heinrich
Copy link
Contributor

It works now, even without adding the immediate to sub-step.

To make the script backwards compatible I'll need some way to check if immediate is available.
I can run immediate ignore and then check the return value, but that logs an error. Any other ideas?
After the release I can simply check the version.

@Dudemanguy
Copy link
Member Author

Dudemanguy commented Feb 20, 2025

It's silly but something like this would work.

local function check_immediate()
    have_immediate = mp.commandv('immediate', 'ignore') or false
    mp.commandv('set', 'msg-level', 'subtitle_lines=info')
    mp.unobserve_property(check_immediate)
end
mp.observe_property('msg-level', 'string', check_immediate)
mp.commandv('set', 'msg-level', 'subtitle_lines=no')

@christoph-heinrich
Copy link
Contributor

It's silly but something like this would work.

local function check_immediate()
    have_immediate = mp.commandv('immediate', 'ignore') or false
    mp.commandv('set', 'msg-level', 'subtitle_lines=info')
    mp.unobserve_property(check_immediate)
end
mp.observe_property('msg-level', 'string', check_immediate)
mp.commandv('set', 'msg-level', 'subtitle_lines=no')

Considering that this is a temporary solution, I guess that would work.
Alternatively we could create a prefix-list like the already existing command-list, which could then also be used in console.lua instead of having an array with prefixes. But that's not that important, I'd be fine with leaving things as they already are.

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.

6 participants