mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 05:06:16 -08:00
fix(playback): seek Embedded MPV steps relative to mpv's own position
Arrow keys and the ±10 s buttons in the Embedded MPV player advanced only about a second per press when pressed repeatedly or held. The shortcuts already asked for 5 s steps, but `EmbeddedMpvCommandRunner.seekBy` turned each step into an absolute `seek` computed from `session.positionSeconds`, which is floored to whole seconds, polled every 500 ms (helper snapshots at most every 250 ms) and not refreshed by the seek reply. Every press inside that window therefore landed on the same target. Steps now go through a new `EMBEDDED_MPV_SEEK_BY` IPC / `seekEmbeddedMpvBy` bridge method that every backend forwards as mpv `seek <delta> relative+exact`: `seekBy` exports in the macOS addon and the Windows/Linux `wid` addon (Linux over its JSON IPC socket), and a `seek-by` stdin command in the frame-copy helper. mpv resolves the delta against its own position and merges queued relative seeks, so presses accumulate as in mpv itself. The absolute form survives only as a fallback for a preload without the method or an addon binary without `seekBy`; the timeline scrub still commits an absolute target. Validated with a real mpv 0.39 IPC probe: three relative seeks in a burst advance +15 s, three absolute seeks from one stale base advance +5 s. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
078bd07d94
commit
ae85428065
18 files changed
+300
-7
No files matched your search
@@ -2051,6 +2051,50 @@ Napi::Value Seek(const Napi::CallbackInfo& info)
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value SeekBy(const Napi::CallbackInfo& info)
|
||||
{
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() < 2 || !info[0].IsString() || !info[1].IsNumber()) {
|
||||
throw Napi::TypeError::New(env, "Expected session id and seek delta.");
|
||||
}
|
||||
|
||||
const std::string sessionId = info[0].As<Napi::String>().Utf8Value();
|
||||
const auto session = getSessionOrThrow(env, sessionId);
|
||||
const auto delta = info[1].As<Napi::Number>().DoubleValue();
|
||||
const std::string deltaValue = std::to_string(delta);
|
||||
// Relative step (arrow keys, ±10 s buttons): mpv resolves the delta
|
||||
// against its own playback position and merges relative seeks that are
|
||||
// still queued, so a burst of presses accumulates instead of collapsing
|
||||
// onto one target computed from the renderer's stale snapshot.
|
||||
const char* command[] = {
|
||||
"seek",
|
||||
deltaValue.c_str(),
|
||||
"relative+exact",
|
||||
nullptr,
|
||||
};
|
||||
const int result = mpv_command_async(
|
||||
session->handle,
|
||||
nextAsyncRequestId(),
|
||||
command
|
||||
);
|
||||
|
||||
if (result < 0) {
|
||||
throw Napi::Error::New(
|
||||
env,
|
||||
std::string("Failed to seek playback: ") +
|
||||
mpv_error_string(result)
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(session->mutex);
|
||||
session->snapshot.positionSeconds =
|
||||
std::max(0.0, session->snapshot.positionSeconds + delta);
|
||||
}
|
||||
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value SetVolume(const Napi::CallbackInfo& info)
|
||||
{
|
||||
Napi::Env env = info.Env();
|
||||
@@ -2540,6 +2584,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
||||
exports.Set("setBounds", Napi::Function::New(env, SetBounds));
|
||||
exports.Set("setPaused", Napi::Function::New(env, SetPaused));
|
||||
exports.Set("seek", Napi::Function::New(env, Seek));
|
||||
exports.Set("seekBy", Napi::Function::New(env, SeekBy));
|
||||
exports.Set("setVolume", Napi::Function::New(env, SetVolume));
|
||||
exports.Set("setAudioTrack", Napi::Function::New(env, SetAudioTrack));
|
||||
exports.Set(
|
||||
|
||||
@@ -2000,6 +2000,55 @@ Napi::Value Seek(const Napi::CallbackInfo& info)
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value SeekBy(const Napi::CallbackInfo& info)
|
||||
{
|
||||
Napi::Env env = info.Env();
|
||||
if (info.Length() < 2 || !info[0].IsString() || !info[1].IsNumber()) {
|
||||
throw Napi::TypeError::New(env, "Expected session id and seek delta.");
|
||||
}
|
||||
const auto session =
|
||||
getSessionOrThrow(env, info[0].As<Napi::String>().Utf8Value());
|
||||
const double delta = info[1].As<Napi::Number>().DoubleValue();
|
||||
const std::string seconds = formatInvariantDouble(delta);
|
||||
// Relative step (arrow keys, ±10 s buttons): mpv resolves the delta
|
||||
// against its own playback position and merges relative seeks that are
|
||||
// still queued, so a burst of presses accumulates instead of collapsing
|
||||
// onto one target computed from the renderer's stale snapshot.
|
||||
#ifdef __linux__
|
||||
std::string socketPath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(session->mutex);
|
||||
socketPath = session->mpvIpcSocketPath;
|
||||
session->snapshot.positionSeconds =
|
||||
std::max(0.0, session->snapshot.positionSeconds + delta);
|
||||
}
|
||||
if (!socketPath.empty()) {
|
||||
sendLinuxMpvCommand(
|
||||
socketPath,
|
||||
"{\"command\":[\"seek\"," + seconds + ",\"relative+exact\"]}\n"
|
||||
);
|
||||
}
|
||||
return env.Undefined();
|
||||
#endif
|
||||
const char* command[] = {
|
||||
"seek", seconds.c_str(), "relative+exact", nullptr
|
||||
};
|
||||
const int result = mpv_command_async(
|
||||
session->handle,
|
||||
nextAsyncRequestId(),
|
||||
command
|
||||
);
|
||||
if (result < 0) {
|
||||
throw Napi::Error::New(env, mpv_error_string(result));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(session->mutex);
|
||||
session->snapshot.positionSeconds =
|
||||
std::max(0.0, session->snapshot.positionSeconds + delta);
|
||||
}
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Napi::Value SetVolume(const Napi::CallbackInfo& info)
|
||||
{
|
||||
Napi::Env env = info.Env();
|
||||
@@ -2360,6 +2409,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
||||
exports.Set("setBounds", Napi::Function::New(env, SetBounds));
|
||||
exports.Set("setPaused", Napi::Function::New(env, SetPaused));
|
||||
exports.Set("seek", Napi::Function::New(env, Seek));
|
||||
exports.Set("seekBy", Napi::Function::New(env, SeekBy));
|
||||
exports.Set("setVolume", Napi::Function::New(env, SetVolume));
|
||||
exports.Set("setAudioTrack", Napi::Function::New(env, SetAudioTrack));
|
||||
#ifndef __linux__
|
||||
|
||||
Reference in new issue
Block a user