Coder Social home page Coder Social logo

mpv-user-input's Introduction

mpv-user-input

This script aims to create a common API that other scripts can use to request text input from the user via the OSD. This script was built from mpv's console.lua. The logging, commands, and tab completion have been removed, leaving just the text input and history code. As a result this script's text input has almost identical behaviour to console.lua.

Around the original code is a system to recieve input requests via script messages, and respond with the users input, and an error message if the request was somehow terminated. The script utilises a queue system to handle multiple requests at once, and there are various option flags to control how to handle multiple requests from the same source.

Usage of this API requires that standard interface functions be used to request and cancel input requests, these functions are packaged into user-input-module.lua, which can be loaded as a module, or simply pasted into another script. If a script does choose to load the module, then I recommend it be loaded from ~~/script-modules rather than ~~/scripts.

The aim of this script is that it be seamless enough that it could be added to mpv player officially.

For versions of mpv โ‰ค v0.36 see the mpv-v0.36 branch.

Installation

If you've been directed here by another script that requires this API follow these instructions unless told otherwise.

Place user-input.lua inside the ~~/scripts/ directory, and place user-input-module.lua inside the ~~/script-modules/ directory. Create these directories if they do not exist. ~~/ represents the mpv config directory.

Advanced

What is important is that user-input.lua is loaded as a script my mpv, which can be done from anywhere using the --script option. Meanwhile, user-input-module.lua needs to be in one of the lua package paths; scripts that use this API are recommended to use ~~/script-modules/, but you can set any directory using the LUA_PATH environment variable.

Developers

If you use the recommended ~~/script-modules/ directory then load this addon with the following code:

package.path = mp.command_native({"expand-path", "~~/script-modules/?.lua;"})..package.path
local input = require "user-input-module"

Interface Functions - v0.1.0

Note: this API is still in its early stages, so these functions may change.

get_user_input(fn [, options [, ...]])

Requests input from the user and returns a request table.

input.get_user_input(print) -- prints the user input plus the error code

fn is called when user-input sends a response, the first argument will be the input string the user entered, the second argument will be an error string if the input is nil. Any additional arguments sent after the options table will be sent to fn as additional arguments after the error string.

The following error codes currently exist:

    exited          the user closed the input instead of pressing Enter
    already_queued  a request with the specified id was already in the queue
    cancelled       the request was cancelled
    replaced        request was replaced

If the request throws an error for whatever reason then that Lua error message will be returned instead. Those error messages are undefined and could change at any time.

options

Options is an optional table of values and flags which can be used to control the behaviour of user-input. The function will preset some options if they are left blank. The following options are currently available:

name type default description
id string mp.get_script_name()../ used for storing input history and detecting duplicate requests
source string mp.get_script_name() used to show the source of the request in square brackets
request_text string requesting user input: printed above the input box - use it to describe the input request
default_input string text to pre-enter into the input
cursor_pos number 1 the numerical position to place the cursor - for use with the default_input field
queueable boolean false allows requests to be queued even if there is already one queued with the same id
replace boolean false replace the queued request with the same id with the new request

The function prepends the script name to any id to avoid conflicts between different scripts. Do not use both the queuable and replace flags for input requests with the same ID, the behaviour is undefined and may change at any time.

Here is an example for printing only a sucessful input:

input.get_user_input(function(line, err)
        if line then print(line) end
    end, { request_text = "print text:" })

request table

The request table returned by get_user_input can be used to modify the behaviour of an existing request. The defined fields are:

name type description
callback function the callback function - same as fn passed to get_user_input() - can be set to a different function to modify the callback
passthrough_args table an array of extra arguments to pass to the callback - cannot be nil
pending boolean true if the request is still pending, false if the request is completed
cancel method cancels the request - unlike cancel_user_input() this does not cancel all requests with a matching id
update method takes an options table and updates the request - maintains the original request unlike the replace flag - not all options can be changed

A method is referring to a function that is called with Lua's method syntax:

local request = input.get_user_input(print)
request:update{
    request_text = "hello world:"
}
request:cancel()

cancel_user_input([id])

Removes all input requests with a matching string id. If no id is provided, then the default id for get_user_input() will be used.

The cancellation happens asynchronously.

get_user_input_co([options [, co_resume]])

This is a wrapper function around get_user_input() that uses coroutines to make the input request behave synchronously. It returns line, err, as would normally be passed to the callback function.

This function will yield the current coroutine and resume once the input response has been received. If the coroutine is forcibly resumed by the user then it will send a cancellation request to user-input and will return nil, 'cancelled'. The request object is passed to the yield function.

local function main()
    local line, err = input.get_user_input_co({ request_text = 'test input:' })
    if line then print(line) end
end

local co = coroutine.create(main)
local success, request = coroutine.resume(co)

If a function is passed as co_resume then custom resume behaviour can be setup instead of the default coroutine.resume. This can be useful if you want to define what happens when an error is thrown. This function is the equivalent of the usual callback function, except it's purpose is to resume the yielded coroutine and that it has three agruments: uid, line, err where uid is a unique variable that needs to be passed to coroutine.resume(). The functions created by coroutine.wrap() can be passed into here. The following examples show how this can be used to propogate errors using coroutine.wrap(), and how to safely catch and print errors using a custom error handler.

-- if an error is thrown the script will crash instead of the error being caught
local driver
driver = coroutine.wrap(function()
    local line, err = input.get_user_input_co({ request_text = 'test input:' }, driver)
    if line then print(line) end
end)

local request = driver()
-- if the coroutine throws an error it is caught and a stack trace is printed
-- note that the error handler shown here is actually what is used by default when `co_resume` is nil
function coroutine_resume_err(uid, line, err)
    local co = coroutine.running()
    local success, err = coroutine.resume(co, uid, line, err)
    if not success then
        msg.warn( debug.traceback(co) )
        msg.error(err)
    end
end

local function main()
    local line, err = input.get_user_input_co({ request_text = 'test input:' }, coroutine_resume_err)
    if line then print(line) end
end

local co = coroutine.create(main)
local success, request = coroutine.resume(co)

Examples

The examples folder contains some scripts that make user of the API.

You can find more examples in the wiki page.

mpv-user-input's People

Contributors

akemi avatar cogentredtester avatar guidocella avatar mar04 avatar nkh0472 avatar rossy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mpv-user-input's Issues

[feature request, question] vi-like input

Hi, I've tried mpv-rename which is based on this thread. It works as advertised, however, imo anything involving long input without basic vi-like input is awkward (e.g. ESC to enter normal mode)--spamming left/right arrow keys (especially with faster key rate) is less than ideal.

Also (not a feature request, but a question): is it possible to have cursor default to right before an extension like .mkv as opposed to beginning of filename? It would be fine to assume the cursor is right before the last . regex-wise. The code is mpv-rename.

Much appreciated.

`shared_script_property_observe` is obsolete in MPV `v0.37.0`

Hi @CogentRedTester,

Thank you for your MPV scripts.

The recent release of MPV, v0.37.0 to be precise, has made the shared_script_property_observe function obsolete, and according to this conversation, the recommendation is to switch to user-data.

I'm not very fluent in MPV scripting with Lua. But considering how useful your scripts and the mpv-user-input API layer are, I think it would be great to have these upgraded to support MPV v0.37.0.

I'm more than happy to help where I can. Please have a look. Thanks a lot!

[user_input] stack traceback:
[user_input]    [C]: at 0x010bc4fe50
[user_input]    [C]: at 0x010bc4f590
[user_input] Lua error: /Users/bart/.config/mpv/scripts/user-input.lua:568: attempt to call field 'shared_script_property_observe' (a nil value)

Would this be possible?

This is exactly what I need for a script I have been looking for forever. I simply want to be able to rename my current playing file using a hotkey. Afterward, an input field should pop up, and once entered in the new name it should refresh MPV and catch the current filename. Would that be possible?

Command line integration

Even though it works in the MPV cli mode, users can't see the input being written

issue

Is there a way around this issue?

Hope support Chinese input

window 10 22H2 19045.3693
mpv 0.37.0
At present, it seems that it couldn't switch input method through shift and input Chinese. Is there any plan to support it in the future?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.