first commit
This commit is contained in:
958
mpv/scripts/file-browser/docs/addons.md
Normal file
958
mpv/scripts/file-browser/docs/addons.md
Normal file
@@ -0,0 +1,958 @@
|
||||
# How to Write an Addon - API v1.7.0
|
||||
|
||||
Addons provide ways for file-browser to parse non-native directory structures. This document describes how one can create their own custom addon.
|
||||
|
||||
If you have an independent script but want to use file-browser's parsing capabilities, perhaps to make use of existing addons, then look [here](https://github.com/CogentRedTester/mpv-file-browser#get-directory-contents).
|
||||
|
||||
## Terminology
|
||||
|
||||
For the purpose of this document addons refer to the scripts being loaded while parsers are the objects the scripts return.
|
||||
An addon can return multiple parsers, but when they only returns one the terms are almost synonymous.
|
||||
Additionally, `method` refers to functions called using the `object:funct()` syntax, and hence have access to the self object, whereas `function` is the standard `object.funct()` syntax.
|
||||
|
||||
## API Version
|
||||
|
||||
The API version, shown in the title of this document, allows file-browser to ensure that addons are using the correct
|
||||
version of the API. It follows [semantic versioning](https://semver.org/) conventions of `MAJOR.MINOR.PATCH`.
|
||||
A parser sets its version string with the `version` field, as seen [below](#overview).
|
||||
|
||||
Any change that breaks backwards compatability will cause the major version number to increase.
|
||||
A parser MUST have the same major version number as the API, otherwise an error message will be printed and the parser will
|
||||
not be loaded.
|
||||
|
||||
A minor version number denotes a change to the API that is backwards compatible. This includes additional API functions,
|
||||
or extra fields in tables that were previously unused. It may also include additional arguments to existing functions that
|
||||
add additional behaviour without changing the old behaviour.
|
||||
If the parser's minor version number is greater than the API_VERSION, then a warning is printed to the console.
|
||||
|
||||
Patch numbers denote bug fixes, and are ignored when loading an addon.
|
||||
For this reason addon authors are allowed to leave the patch number out of their version tag and just use `MAJOR.MINOR`.
|
||||
|
||||
## Overview
|
||||
|
||||
File-browser automatically loads any lua files from the `~~/script-modules/file-browser-addons` directory as modules.
|
||||
Each addon must return either a single parser table, or an array of parser tables. Each parser object must contain the following three members:
|
||||
|
||||
| key | type | arguments | returns | description |
|
||||
|-----------|--------|---------------------------|------------------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| priority | number | - | - | a number to determine what order parsers are tested - see [here](#priority-suggestions) for suggested values |
|
||||
| api_version| string | - | - | the API version the parser is using - see [API Version](#api-version) |
|
||||
| can_parse | method | string, parse_state_table | boolean | returns whether or not the given path is compatible with the parser |
|
||||
| parse | method | string, parse_state_table | list_table, opts_table | returns an array of item_tables, and a table of options to control how file_browser handles the list |
|
||||
|
||||
Additionally, each parser can optionally contain:
|
||||
|
||||
| key | type | arguments | returns | description |
|
||||
|--------------|--------|-----------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| name | string | - | - | the name of the parser used for debug messages and to create a unique id - by default uses the filename with `.lua` or `-browser.lua` removed |
|
||||
| keybind_name | string | - | - | the name to use when setting custom keybind filters - uses the value of name by default but can be set manually so that the same keys work with multiple addons |
|
||||
| setup | method | - | - | if it exists this method is automatically run after all parsers are imported and API functions are made available |
|
||||
| keybinds | table | - | - | an array of keybind objects for the browser to set when loading - see [#keybinds] |
|
||||
|
||||
All parsers are given a unique string ID based on their name. If there are collisions then numbers are appended to the end of the name until a free name is found.
|
||||
These IDs are primarily used for debug messages, though they may gain additional functionality in the future.
|
||||
|
||||
Here is an extremely simple example of an addon creating a parser table and returning it to file-browser.
|
||||
|
||||
```lua
|
||||
local parser = {
|
||||
api_version = '1.0.0',
|
||||
priority = 100,
|
||||
name = "example" -- this parser will have the id 'example' or 'example_#' if there are duplicates
|
||||
}
|
||||
|
||||
function parser:can_parse(directory)
|
||||
return directory == "Example/"
|
||||
end
|
||||
|
||||
function parser:parse(directory, state)
|
||||
local list, opts
|
||||
------------------------------
|
||||
--- populate the list here ---
|
||||
------------------------------
|
||||
return list, opts
|
||||
end
|
||||
|
||||
return parser
|
||||
|
||||
```
|
||||
|
||||
## Parsing
|
||||
|
||||
When a directory is loaded file-browser will iterate through the list of parsers from lowest to highest priority.
|
||||
The first parser for which `can_parse` returns true will be selected as the parser for that directory.
|
||||
|
||||
The `parse` method will then be called on the selected parser, which is expected to return either a table of list items, or nil.
|
||||
If an empty table is returned then file-browser will treat the directory as empty, otherwise if the list_table is nil then file-browser will attempt to run `parse` on the next parser for which `can_parse` returns true.
|
||||
This continues until a parser returns a list_table, or until there are no more parsers.
|
||||
|
||||
The entire parse operation is run inside of a coroutine, this allows parsers to pause execution to handle asynchronous operations.
|
||||
Please read [coroutines](#coroutines) for all the details.
|
||||
|
||||
### Parse State Table
|
||||
|
||||
The `parse` and `can_parse` functions are passed a state table as its second argument, this contains the following fields.
|
||||
|
||||
| key | type | description |
|
||||
|----------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| source | string | the source of the parse request |
|
||||
| directory | string | the directory of the parse request - for debugging purposes |
|
||||
| already_deferred | boolean | whether or not [defer](#advanced-functions) was called during this parse, if so then file-browser will not try to query any more parsers after receiving the result - set automatically, but can be manually disabled |
|
||||
| yield | method | a wrapper around `coroutine.yield()` - see [coroutines](#coroutines) |
|
||||
| is_coroutine_current | method | returns if the browser is waiting on the current coroutine to populate the list |
|
||||
|
||||
`already_deferred` is an optimisation. If a script uses defer and still returns nil, then that means that none of the remaining parsers will be able to parse the path.
|
||||
Therefore, it is more efficient to just immediately jump to the root.
|
||||
It is up to the addon author to manually disable this if their use of `defer` conflicts with this assumption.
|
||||
|
||||
Source can have the following values:
|
||||
|
||||
| source | description |
|
||||
|----------------|---------------------------------------------------------------------------------------------------------|
|
||||
| browser | triggered by the main browser window |
|
||||
| loadlist | the browser is scanning the directory to append to the playlist |
|
||||
| script-message | triggered by the `get-directory-contents` script-message |
|
||||
| addon | caused by an addon calling the `parse_directory` API function - note that addons can set a custom state |
|
||||
|
||||
Note that all calls to any `parse` function during a specific parse request will be given the same parse_state table.
|
||||
This theoretically allows parsers to communicate with parsers of a lower priority (or modify how they see source information),
|
||||
but no guarantees are made that specific keys will remain unused by the API.
|
||||
|
||||
#### Coroutines
|
||||
|
||||
Any calls to `parse()` (or `can_parse()`, but you should never be yielding inside there) are done in a [Lua coroutine](https://www.lua.org/manual/5.1/manual.html#2.11).
|
||||
This means that you can arbitrarily pause the parse operation if you need to wait for some asynchronous operation to complete,
|
||||
such as waiting for user input, or for a network request to complete.
|
||||
|
||||
Making these operations asynchronous has performance
|
||||
advantages as well, for example recursively opening a network directory tree could cause the browser to freeze
|
||||
for a long period of time. If the network query were asynchronous then the browser would only freeze during actual operations,
|
||||
during network operations it would be free for the user interract with. The browser has even been designed so that
|
||||
a loadfile/loadlist operation saves it's own copy of the current directory, so even if the user hops around like crazy the original
|
||||
open operation will still occur in the correct order (though there's nothing stopping them starting a new operation which will cause
|
||||
random ordering.)
|
||||
|
||||
However, there is one downside to this behaviour. If the parse operation is requested by the browser, then it is
|
||||
possible for the user to change directories while the coroutine is yielded. If you were to resume the coroutine
|
||||
in that situation, then any operations you do are wasted, and unexpected bahaviour could happen.
|
||||
file-browser will automatically detect when it receives a list from an aborted coroutine, so there is no risk
|
||||
of the current list being replaced, but any other logic in your script will continue until `parse` returns.
|
||||
|
||||
To fix this there are two methods available in the state table, the `yield()` method is a wrapper around `coroutine.yield()` that
|
||||
detects when the browser has abandoned the parse, and automatically kills the coroutine by throwing an error.
|
||||
The `is_coroutine_current()` method simply compares if the current coroutine (as returned by `coroutine.running()`) matches the
|
||||
coroutine that the browser is waiting for. Remember this is only a problem when the browser is the source of the request,
|
||||
if the request came from a script-message, or from a loadlist command there are no issues.
|
||||
|
||||
### The List Array
|
||||
|
||||
The list array must be made up of item_tables, which contain details about each item in the directory.
|
||||
Each item has the following members:
|
||||
|
||||
| key | type | required | description |
|
||||
|-------------|-----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| name | string | yes | name of the item, and the string to append after the directory when opening a file/folder |
|
||||
| type | string | yes | determines whether the item is a file ("file") or directory ("dir") |
|
||||
| label | string | no | an alternative string to print to the screen instead of name |
|
||||
| ass | string | no | a string to print to the screen without escaping ass styling - overrides label and name |
|
||||
| path | string | no | opening the item uses this full path instead of appending directory and name |
|
||||
| redirect | bool | no | whether `path` should redirect the browser when opening a directory - default yes (nil counts as true) |
|
||||
| mpv_options | string or table | no | a list of options to be sent to mpv when loading the file - can be in the form `opt1=value1,opt2=value2,...` or a table of string keys and values |
|
||||
|
||||
File-browser expects that `type` and `name` will be set for each item, so leaving these out will probably crash the script.
|
||||
File-browser also assumes that all directories end in a `/` when appending name, and that there will be no backslashes.
|
||||
The API function [`fix_path`](#utility-functions) can be used to ensure that paths conform to file-browser rules.
|
||||
|
||||
Here is an example of a static list table being returned by the `parse` method.
|
||||
This would allow one to specify a custom list of items.
|
||||
|
||||
```lua
|
||||
function parser:parse(directory, state)
|
||||
local list = {
|
||||
{ name = "first/", type = "dir" },
|
||||
{ name = "second/", type = "dir" },
|
||||
{ name = "third/", type = "dir" },
|
||||
{ name = "file%01", type = "file", label = "file1" },
|
||||
{ name = "file2", type = "file", path = "https://youtube.com/video" },
|
||||
}
|
||||
|
||||
return list
|
||||
end
|
||||
```
|
||||
|
||||
### The Opts Table
|
||||
|
||||
The options table allows scripts to better control how they are handled by file-browser.
|
||||
None of these values are required, and the opts table can even left as nil when returning.
|
||||
|
||||
| key | type | description |
|
||||
|-----------------|---------|------------------------------------------------------------------------------------------------------------------------------|
|
||||
| filtered | boolean | if true file-browser will not run the standard filter() function on the list |
|
||||
| sorted | boolean | if true file-browser will not sort the list |
|
||||
| directory | string | changes the browser directory to this - used for redirecting to other locations |
|
||||
| directory_label | string | display this label in the header instead of the actual directory - useful to display encoded paths |
|
||||
| empty_text | string | display this text when the list is empty - can be used for error messages |
|
||||
| selected_index | number | the index of the item on the list to select by default - a.k.a. the cursor position |
|
||||
| id | number | id of the parser that successfully returns a list - set automatically, but can be set manually to take ownership (see defer) |
|
||||
|
||||
The previous static example, but modified so that file browser does not try to filter or re-order the list:
|
||||
|
||||
```lua
|
||||
function parser:parse(directory, state)
|
||||
local list = {
|
||||
{ name = "first/", type = "dir" },
|
||||
{ name = "second/", type = "dir" },
|
||||
{ name = "third/", type = "dir" },
|
||||
{ name = "file%01", type = "file", label = "file1" },
|
||||
{ name = "file2", type = "file", path = "https://youtube.com/video" },
|
||||
}
|
||||
|
||||
return list, { sorted = true, filtered = true }
|
||||
end
|
||||
```
|
||||
|
||||
`id` is used to declare ownership of a page. The name of the parser that has ownership is used for custom-keybinds parser filtering.
|
||||
When using `defer` id will be the id of whichever parser first returned a list.
|
||||
This is the only situation when a parser may want to set id manually.
|
||||
|
||||
## Priority Suggestions
|
||||
|
||||
Below is a table of suggested priority ranges:
|
||||
|
||||
| Range | Suggested Use | Example parsers |
|
||||
|---------|------------------------------------------------------------------------------------------------|------------------------------------------------|
|
||||
| 0-20 | parsers that purely modify the results of other parsers | [m3u-fixer](m3u-browser.lua) |
|
||||
| 21-40 | virtual filesystems which need to link to the results of other parsers | [favourites](favourites.lua) |
|
||||
| 41-50 | to support specific sites or systems which can be inferred from the path | |
|
||||
| 51-80 | limitted support for specific protocols which requires complex parsing to verify compatability | [apache](apache-browser.lua) |
|
||||
| 81-90 | parsers that only need to modify the results of full parsers | [home-label](home-label.lua) |
|
||||
| 91-100 | use for parsers which fully support a non-native protocol with absolutely no overlap | [ftp](ftp-browser.lua), [m3u](m3u-browser.lua) |
|
||||
| 101-109 | replacements for the native file parser or fallbacks for the full parsers | [powershell](powershell.lua) |
|
||||
| 110 | priority of the native file parser - don't use | |
|
||||
| 111+ | fallbacks for native parser - potentially alternatives to the default root | |
|
||||
|
||||
## Keybinds
|
||||
|
||||
Addons have the ability to set custom keybinds using the `keybinds` field in the `parser` table. `keybinds` must be an array of tables, each of which may be in two forms.
|
||||
|
||||
Firstly, the keybind_table may be in the form
|
||||
`{ "key", "name", [function], [flags] }`
|
||||
where the table is an array whose four values corresond to the four arguments for the [mp.add_key_binding](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) API function.
|
||||
|
||||
```lua
|
||||
local function main(keybind, state, co)
|
||||
-- deletes files
|
||||
end
|
||||
|
||||
parser.keybinds = {
|
||||
{ "Alt+DEL", "delete_files", main, {} },
|
||||
}
|
||||
```
|
||||
|
||||
Secondly, the keybind_table may use the same formatting as file-browser's [custom-keybinds](../custom-keybinds.md).
|
||||
Using the array form is equivalent to setting `key`, `name`, `command`, and `flags` of the custom-keybind form, and leaving everything else on the defaults.
|
||||
|
||||
```lua
|
||||
parser.keybinds = {
|
||||
{
|
||||
key = "Alt+DEL",
|
||||
name = "delete_files",
|
||||
command = {"run", "rm", "%F"},
|
||||
filter = "files"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These keybinds are evaluated only once shortly after the addon is loaded, they cannot be modified dynamically during runtime.
|
||||
Keybinds are applied after the default keybinds, but before the custom keybinds. This means that addons can overwrite the
|
||||
default keybinds, but that users can ovewrite addon keybinds. Among addons, those with higher priority numbers have their keybinds loaded before those
|
||||
with lower priority numbers.
|
||||
Remember that a lower priority value is better, they will overwrite already loaded keybinds.
|
||||
Keybind passthrough works the same way, though there is some custom behaviour when it comes to [raw functions](#keybind-functions).
|
||||
|
||||
### Keybind Names
|
||||
|
||||
In either form the naming of the function is different from custom keybinds. Instead of using the form `file_browser/dynamic/custom/[name]`
|
||||
they use the form `file_browser/dynamic/[parser_ID]/[name]`, where `[parser_id]` is a unique string ID for the parser, which can be retrieved using the
|
||||
`parser:get_id()` method.
|
||||
|
||||
### Native Functions vs Command Tables
|
||||
|
||||
There are two ways of specifying the behaviour of a keybind.
|
||||
It can be in command table form, as done when using custom-keybind syntax, and it can be done in
|
||||
native function form, as done when using the `mp.add_key_binding` syntax.
|
||||
However, these two ways of specifying commands are independant of how the overall keybind is defined.
|
||||
What this means is that the command field of the custom-keybinds syntax can be an array, and the
|
||||
3rd value in the array syntax can be a table of mpv commands.
|
||||
|
||||
```lua
|
||||
local function main(keybind, state, co)
|
||||
-- deletes files
|
||||
end
|
||||
|
||||
-- this is a valid keybind table
|
||||
parser.keybinds = {
|
||||
{ "Alt+DEL", "delete_files", {"run", "rm", "%F"}, {} },
|
||||
|
||||
{
|
||||
key = "Alt+DEL",
|
||||
name = "delete_files",
|
||||
command = main
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are some limitations however, not all custom-keybind options are supported when using native functions.
|
||||
The supported options are: `key`, `name`, `condition`, `flags`, `parser`, `passthrough`. The other options can be replicated manually (see below).
|
||||
|
||||
### Keybind Functions
|
||||
|
||||
This section details the use of keybind functions.
|
||||
|
||||
#### Function Call
|
||||
|
||||
If one uses the raw function then the functions are called directly in the form:
|
||||
|
||||
`fn(keybind, state, coroutine)`
|
||||
|
||||
Where `keybind` is the keybind_table of the key being run, `state` is a table of state values at the time of the key press, and `coroutine` is the coroutine object
|
||||
that the keybind is being executed inside.
|
||||
|
||||
The `keybind` table uses the same fields as defined
|
||||
in [custom-keybinds.md](../custom-keybinds.md). Any random extra fields placed in the original
|
||||
`file-browser-keybinds.json` will likely show up as well (this is not guaranteed).
|
||||
Note that even if the array form is used, the `keybind` table will still use the custom-keybind format.
|
||||
|
||||
The entire process of running a keybind is handled with a coroutine, so the addon can safely pause and resume the coroutine at will. The `state` table is provided to
|
||||
allow addons to keep a record of important state values that may be changed during a paused coroutine.
|
||||
|
||||
#### State Table
|
||||
|
||||
The state table contains copies of the following values at the time of the key press.
|
||||
|
||||
| key | description |
|
||||
|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| directory | the current directory |
|
||||
| directory_label | the current directory_label - can (and often will) be `nil` |
|
||||
| list | the current list_table |
|
||||
| selected | index of the currently selected list item |
|
||||
| selection | table of currently selected items (for multi-select) - in the form { index = true, ... } - always available even if the `multiselect` flag is not set |
|
||||
| parser | a copy of the parser object that provided the current directory |
|
||||
|
||||
The following example shows the implementation of the `delete_files` keybind using the state values:
|
||||
|
||||
```lua
|
||||
local fb = require "file-browser" -- see #api-functions and #utility-functions
|
||||
|
||||
local function main(keybind, state, co)
|
||||
for index, item in state.list do
|
||||
if state.selection[index] and item.type == "file" then
|
||||
os.remove( fb.get_full_path(item, state.directory) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.keybinds = {
|
||||
{ "Alt+DEL", "delete_files", main, {} },
|
||||
}
|
||||
```
|
||||
|
||||
#### Passthrough
|
||||
|
||||
If the `passthrough` field of the keybind_table is set to `true` or `false` then file-browser will
|
||||
handle everything. However, if the passthrough field is not set (meaning the bahviour should be automatic)
|
||||
then it is up to the addon to ensure that they are
|
||||
correctly notifying when the operation failed and a passthrough should occur.
|
||||
In order to tell the keybind handler to run the next priority command, the keybind function simply needs to return the value `false`,
|
||||
any other value (including `nil`) will be treated as a successful operation.
|
||||
|
||||
The below example only allows removing files from the `/tmp/` directory and allows other
|
||||
keybinds to run in different directories:
|
||||
|
||||
```lua
|
||||
local fb = require "file-browser" -- see #api-functions and #utility-functions
|
||||
|
||||
local function main(keybind, state, co)
|
||||
if state.directory ~= "/tmp/" then return false end
|
||||
|
||||
for index, item in state.list do
|
||||
if state.selection[index] and item.type == "file" then
|
||||
os.remove( fb.get_full_path(item, state.directory) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parser.keybinds = {
|
||||
{ "Alt+DEL", "delete_files", main, {} },
|
||||
}
|
||||
```
|
||||
|
||||
## The API
|
||||
|
||||
The API is available through a module, which can be loaded with `require "file-browser"`.
|
||||
The API provides a variety of different values and functions for an addon to use
|
||||
in order to make them more powerful.
|
||||
Function definitions are written using Typescript-style type annotations.
|
||||
|
||||
```lua
|
||||
local fb = require "file-browser"
|
||||
|
||||
local parser = {
|
||||
priority = 100,
|
||||
}
|
||||
|
||||
function parser:setup()
|
||||
fb.register_root_item("Example/")
|
||||
end
|
||||
|
||||
return parser
|
||||
```
|
||||
|
||||
### Parser API
|
||||
|
||||
In addition to the standard API there is also an extra parser API that provides
|
||||
several parser specific methods, listed below using `parser:method` instead of `fb.function`.
|
||||
This API is added to the parser object after it is loaded by file-browser,
|
||||
so if a script wants to call them immediately on load they must do so in the `setup` method.
|
||||
All the standard API functions are also available in the parser API.
|
||||
|
||||
```lua
|
||||
local parser = {
|
||||
priority = 100,
|
||||
}
|
||||
|
||||
function parser:setup()
|
||||
-- same operations
|
||||
self.insert_root_item({ name = "Example/", type = "dir" })
|
||||
parser.insert_root_item({ name = "Example/", type = "dir" })
|
||||
end
|
||||
|
||||
-- will not work since the API hasn't been added to the parser yet
|
||||
parser.insert_root_item({ name = "Example/", type = "dir" })
|
||||
|
||||
return parser
|
||||
```
|
||||
|
||||
### General Functions
|
||||
|
||||
#### `fb.API_VERSION: string`
|
||||
|
||||
The current API version in use by file-browser.
|
||||
|
||||
#### `fb.add_default_extension(ext: string): void`
|
||||
|
||||
Adds the given extension to the default extension filter whitelist. Can only be run inside the `setup()` method.
|
||||
|
||||
#### `fb.browse_directory(directory: string, open_browser: bool = true): coroutine`
|
||||
|
||||
Clears the cache and opens the given directory in the browser.
|
||||
If the `open_browser` argument is truthy or `nil` then the browser will be opened
|
||||
if it is currently closed. If `open_browser` is `false` then the directory will
|
||||
be opened in the background.
|
||||
Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle,
|
||||
allowing one to store this value and use it to identify the triggered parse operation.
|
||||
|
||||
This is the equivalent of calling the `browse-directory` script-message.
|
||||
|
||||
#### `fb.insert_root_item(item: item_table, pos?: number): void`
|
||||
|
||||
Add an item_table to the root list at the specified position. If `pos` is nil then append to the end of the root.
|
||||
`item` must be a valid item_table of `type='dir'`.
|
||||
|
||||
#### `fb.register_directory_mapping(directory: string | nil, mapping: string, pattern?: bool): void`
|
||||
|
||||
Creates a directory mapping for the given directory. A directory mapping is a
|
||||
one-way mapping from an external directory string, to an internal directory
|
||||
within file-browser's directory tree. It allows external paths that may not
|
||||
exist within file-browser's tree to be mapped to a location that is.
|
||||
Internally, this is used by file-browser to map the `bd://`, `dvd://`, and `cdda://`
|
||||
protocol paths to their respective device locations in the filesystem.
|
||||
|
||||
Note that as this is still an experimental feature, the exact situations when mappings
|
||||
are resolved is subject to change. Currently, mapping occurs only when
|
||||
receiving a directory from an external source, such as the mpv `path` property,
|
||||
or the `browse-directory` script message.
|
||||
|
||||
`directory` is a string that represents a location within file-browser's file-system.
|
||||
`mapping` is a string that will be replaced by the `directory` string if found in a path:
|
||||
|
||||
```lua
|
||||
fb.register_directory_mapping('/dev/dvd', 'dvd://')
|
||||
fb.resolve_directory_mapping('dvd://1') -- /dev/dvd/1
|
||||
```
|
||||
|
||||
There can only be one `directory` string associated with each unique `mapping` string,
|
||||
but multiple mappings can point to the same directory.
|
||||
If `directory` is set to `nil` then the existing mapping for `mapping` will be removed.
|
||||
If `pattern` is set to true, then `mapping` will be treated as a Lua
|
||||
pattern. Any part of an input path that matches the pattern will be substituted for
|
||||
the `directory` string.
|
||||
|
||||
```lua
|
||||
fb.register_directory_mapping('/dev/dvd', '^dvd://.*', true)
|
||||
fb.resolve_directory_mapping('dvd://1') -- /dev/dvd
|
||||
```
|
||||
|
||||
When `pattern` is falsy, `mapping` is equivalent to `'^'..fb.pattern_escape(mapping)`.
|
||||
Captures in the pattern may be given extra behaviour in the future.
|
||||
|
||||
#### `fb.register_parseable_extension(ext: string): void`
|
||||
|
||||
Register a file extension that the browser will attempt to open, like a directory - for addons which can parse files such
|
||||
as playlist files.
|
||||
|
||||
#### `fb.register_root_item(item: string | item_table, priority?: number): boolean`
|
||||
|
||||
Registers an item to be added to the root and an optional priority value that determines the position relative to other items (default is 100).
|
||||
A lower priority number is better, meaning they will be placed earlier in the list.
|
||||
Only adds the item if it is not already in the root and returns a boolean that specifies whether or not the item was added.
|
||||
Must be called during or after the `parser:setup()` method is run.
|
||||
|
||||
If `item` is a string then a new item_table is created with the values: `{ type = 'dir', name = item }`.
|
||||
If `item` is an item_table then it must be a valid directory item.
|
||||
Use [`fb.fix_path(name, true)`](#fbfix_pathpath-string-is_directory-boolean-string) to ensure the name field is correct.
|
||||
|
||||
This function should be used over the older `fb.insert_root_item`.
|
||||
|
||||
#### `fb.remove_parseable_extension(ext: string): void`
|
||||
|
||||
Remove a file extension that the browser will attempt to open like a directory.
|
||||
|
||||
#### `fb.parse_directory(directory: string, parse?: parse_state_table): (list_table, opts_table) | nil`
|
||||
|
||||
Starts a new scan for the given directory and returns a list_table and opts_table on success and `nil` on failure.
|
||||
Must be called from inside a [coroutine](#coroutines).
|
||||
|
||||
This function allows addons to request the contents of directories from the loaded parsers. There are no protections
|
||||
against infinite recursion, so be careful about calling this from within another parse.
|
||||
|
||||
Do not use the same `parse` table for multiple parses, state values for the two operations may intefere with each other
|
||||
and cause undefined behaviour. If the `parse.source` field is not set then it will be set to `"addon"`.
|
||||
|
||||
Note that this function is for creating new parse operations, if you wish to create virtual directories or modify
|
||||
the results of other parsers then use [`defer`](#parserdeferdirectory-string-list_table-opts_table--nil).
|
||||
|
||||
Also note that every parse operation is expected to have its own unique coroutine. This acts as a unique
|
||||
ID that can be used internally or by other addons. This means that if multiple `parse_directory` operations
|
||||
are run within a single coroutine then file-browser will automatically create a new coroutine for the scan,
|
||||
which hands execution back to the original coroutine upon completion.
|
||||
|
||||
#### `parser:register_root_item(item: string | item_table, priority?: number): boolean`
|
||||
|
||||
A wrapper around [`fb.register_root_item`](#fbregister_root_itemitem-string--item_table-priority-number-boolean)
|
||||
which uses the parser's priority value if `priority` is undefined.
|
||||
|
||||
#### `fb.remove_all_mappings(directory: string): string[]`
|
||||
|
||||
Removes all [directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void)
|
||||
that resolve to the given `directory`. Returns a list of the `mapping` strings
|
||||
that were removed.
|
||||
|
||||
### Advanced Functions
|
||||
|
||||
#### `fb.clear_cache(): void`
|
||||
|
||||
Clears the directory cache. Use this if you are modifying the contents of directories other
|
||||
than the current one to ensure that their contents will be rescanned when next opened.
|
||||
|
||||
#### `fb.coroutine.assert(err?: string): coroutine`
|
||||
|
||||
Throws an error if it is not called from within a coroutine. Returns the currently running coroutine on success.
|
||||
The string argument can be used to throw a custom error string.
|
||||
|
||||
#### `fb.coroutine.callback(time_limit?: number): function`
|
||||
|
||||
Creates and returns a callback function that resumes the current coroutine.
|
||||
This function is designed to help streamline asynchronous operations. The best way to explain is with an example:
|
||||
|
||||
```lua
|
||||
local function execute(args)
|
||||
mp.command_native_async({
|
||||
name = "subprocess",
|
||||
playback_only = false,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true,
|
||||
args = args
|
||||
}, fb.coroutine.callback())
|
||||
|
||||
local _, cmd = coroutine.yield()
|
||||
|
||||
return cmd.status == 0 and cmd.stdout or nil
|
||||
end
|
||||
```
|
||||
|
||||
This function uses the mpv [subprocess](https://mpv.io/manual/master/#command-interface-subprocess)
|
||||
command to execute some system operation. To prevent the whole script (file-browser and all addons) from freezing
|
||||
it uses the [command_native_async](https://mpv.io/manual/master/#lua-scripting-mp-command-native-async(table-[,fn])) command
|
||||
to execute the operation asynchronously and takes a callback function as its second argument.
|
||||
|
||||
`coroutine.callback())` will automatically create a callback function to resume whatever coroutine ran the `execute` function.
|
||||
Any arguments passed into the callback function (by the async function, not by you) will be passed on to the resume;
|
||||
in this case `command_native_async` passes three values into the callback, of which only the second is of interest to me.
|
||||
|
||||
If `time_limit` is set to a number, then a boolean is passed as the first resume argument to the coroutine.
|
||||
If the callback is not run within `time_limit` seconds then the coroutine will be resumed, and the first
|
||||
argument will be `false`. If the callback is run within the time limit then the first argument will be `true`.
|
||||
|
||||
```lua
|
||||
local function execute(args)
|
||||
local t = mp.command_native_async({
|
||||
name = "subprocess",
|
||||
playback_only = false,
|
||||
capture_stdout = true,
|
||||
capture_stderr = true,
|
||||
args = args
|
||||
}, fb.coroutine.callback(10))
|
||||
|
||||
local success, _, cmd = coroutine.yield()
|
||||
if not success then
|
||||
mp.abort_async_command(t)
|
||||
msg.error("command timed out")
|
||||
return nil
|
||||
end
|
||||
|
||||
return cmd.status == 0 and cmd.stdout or nil
|
||||
end
|
||||
```
|
||||
|
||||
The expectation is that the programmer will yield execution before that callback returns. In this example I
|
||||
yield immediately after running the async command.
|
||||
|
||||
If you are doing this during a parse operation you could also substitute `coroutine.yield()` with `parse_state:yield()` to abort the parse if the user changed
|
||||
browser directories during the asynchronous operation.
|
||||
|
||||
If you have no idea what I've been talking about read the [Lua manual on coroutines](https://www.lua.org/manual/5.1/manual.html#2.11).
|
||||
|
||||
#### `fb.coroutine.resume_catch(co: coroutine, ...): (boolean, ...)`
|
||||
|
||||
Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments.
|
||||
If the coroutine throws an error then an error message and stacktrace is printed to the console.
|
||||
All the return values of `coroutine.resume` are caught and returned.
|
||||
|
||||
#### `fb.coroutine.resume_err(co: coroutine, ...): boolean`
|
||||
|
||||
Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments.
|
||||
If the coroutine throws an error then an error message and stacktrace is printed to the console.
|
||||
Returns the success boolean returned by `coroutine.resume`, but drops all other return values.
|
||||
|
||||
#### `fb.coroutine.run(fn: function, ...): void`
|
||||
|
||||
Runs the given function in a new coroutine, passing through any additional arguments.
|
||||
|
||||
#### `fb.coroutine.queue(fn: function, ...): coroutine`
|
||||
|
||||
Runs the given function in a coroutine when the script next goes idle, passing through
|
||||
any additional arguments. The (not yet started) coroutine is returned by the function.
|
||||
|
||||
#### `fb.rescan(): coroutine`
|
||||
|
||||
Rescans the current directory. Equivalent to Ctrl+r without the cache refresh for higher level directories.
|
||||
Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle,
|
||||
allowing one to store this value and use it to identify the triggered parse operation.
|
||||
|
||||
#### `fb.redraw(): void`
|
||||
|
||||
Forces a redraw of the browser UI.
|
||||
|
||||
#### `parser:defer(directory: string): (list_table, opts_table) | nil`
|
||||
|
||||
Forwards the given directory to the next valid parser. For use from within a parse operation.
|
||||
|
||||
The `defer` function is very powerful, and can be used by scripts to create virtual directories, or to modify the results of other parsers.
|
||||
However, due to how much freedom Lua gives coders, it is impossible for file-browser to ensure that parsers are using defer correctly, which can cause unexpected results.
|
||||
The following are a list of recommendations that will increase the compatability with other parsers:
|
||||
|
||||
* Always return the opts table that is returned by defer, this can contain important values for file-browser, as described [above](#the-opts-table).
|
||||
* If required modify values in the existing opts table, don't create a new one.
|
||||
* Respect the `sorted` and `filtered` values in the opts table. This may mean calling `sort` or `filter` manually.
|
||||
* Think about how to handle the `directory_label` field, especially how it might interract with any virtual paths the parser may be maintaining.
|
||||
* Think about what to do if the `directory` field is set.
|
||||
* Think if you want your parser to take full ownership of the results of `defer`, if so consider setting `opts.id = self:get_id()`.
|
||||
* Currently this only affects custom keybind filtering, though it may be changed in the future.
|
||||
|
||||
The [home-label](https://github.com/CogentRedTester/mpv-file-browser/blob/master/addons/home-label.lua)
|
||||
addon provides a good simple example of the safe use of defer. It lets the normal file
|
||||
parser load the home directory, then modifies the directory label.
|
||||
|
||||
```lua
|
||||
local mp = require "mp"
|
||||
local fb = require "file-browser"
|
||||
|
||||
local home = fb.fix_path(mp.command_native({"expand-path", "~/"}), true)
|
||||
|
||||
local home_label = {
|
||||
api_version = '1.0.0',
|
||||
priority = 100
|
||||
}
|
||||
|
||||
function home_label:can_parse(directory)
|
||||
return directory:sub(1, home:len()) == home
|
||||
end
|
||||
|
||||
function home_label:parse(directory, ...)
|
||||
local list, opts = self:defer(directory, ...)
|
||||
|
||||
if (not opts.directory or opts.directory == directory) and not opts.directory_label then
|
||||
opts.directory_label = "~/"..(directory:sub(home:len()+1) or "")
|
||||
end
|
||||
|
||||
return list, opts
|
||||
end
|
||||
|
||||
return home_label
|
||||
```
|
||||
|
||||
### Utility Functions
|
||||
|
||||
#### `fb.ass_escape(str: string, substitute_newline?: true | string): string`
|
||||
|
||||
Returns the `str` string with escaped ass styling codes.
|
||||
The optional 2nd argument allows replacing newlines with the given string, or `'\\n'` if set to `true`.
|
||||
|
||||
#### `fb.copy_table(t: table, depth?: number): table`
|
||||
|
||||
Returns a copy of table `t`.
|
||||
The copy is done recursively to the given `depth`, and any cyclical table references are maintained.
|
||||
Both keys and values are copied. If `depth` is undefined then it defaults to `math.huge` (infinity).
|
||||
Additionally, the original table is stored in the `__original` field of the copy's metatable.
|
||||
The copy behaviour of the metatable itself is subject to change, but currently it is not copied.
|
||||
|
||||
#### `fb.evaluate_string(str: string, chunkname?: string, env?: table, defaults?: bool = true): unknown`
|
||||
|
||||
Loads `str` as a chunk of Lua statement(s) and runs them, returning the result.
|
||||
Errors are propagated to the caller. `chunkname` is used
|
||||
for debug output and error messages.
|
||||
|
||||
Each chunk has a separate global environment table that inherits
|
||||
from the main global table. This means new globals can be created safely,
|
||||
but the default globals can still be accessed. As such, this method
|
||||
cannot and should not be used for security or sandboxing.
|
||||
|
||||
A custom environment table can be provided with the `env` argument.
|
||||
Inheritance from the global table is disabled if `defaults` is `false`.
|
||||
|
||||
Examples:
|
||||
|
||||
```lua
|
||||
fb.evaluate_string('return 5 + 5') -- 10
|
||||
fb.evaluate_string('x = 20 ; return x * x') -- 400
|
||||
|
||||
local code = [[
|
||||
local arr = {1, 2, 3, 4}
|
||||
table.insert(arr, x)
|
||||
return unpack(arr)
|
||||
]]
|
||||
fb.evaluate_string(code, 'test3', {x = 5}) -- 1, 2, 3, 4, 5
|
||||
fb.evaluate_string(code, 'test4', nil, false) -- Lua error: [string "test4"]:2: attempt to index global 'table' (a nil value)
|
||||
|
||||
```
|
||||
|
||||
In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively.
|
||||
Additionally, in mpv v0.38+ the `mp.input` module is available as `input`.
|
||||
This addon API is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input)
|
||||
is installed then user-input will be available in `user_input`.
|
||||
These modules are all unavailable if `defaults` is `false`.
|
||||
|
||||
#### `fb.filter(list: list_table): list_table`
|
||||
|
||||
Iterates through the given list and removes items that don't pass the user set filters
|
||||
(dot files/directories and valid file extensions).
|
||||
Returns the list but does not create a copy; the `list` table is filtered in-place.
|
||||
|
||||
#### `fb.fix_path(path: string, is_directory?: boolean): string`
|
||||
|
||||
Takes a path and returns a file-browser compatible path string.
|
||||
The optional second argument is a boolean that tells the function to format the path to be a
|
||||
directory.
|
||||
|
||||
#### `fb.get_extension(filename: string, def?: any): string | def`
|
||||
|
||||
Returns the file extension for the string `filename`, or `nil` if there is no extension.
|
||||
If `def` is defined then that is returned instead of `nil`.
|
||||
|
||||
The full stop is not included in the extension, so `test.mkv` will return `mkv`.
|
||||
|
||||
#### `fb.get_full_path(item: item_table, directory?: string): string`
|
||||
|
||||
Takes an item table and returns the item's full path assuming it is in the given directory.
|
||||
Takes into account `item.name`/`item.path` fields, etc.
|
||||
If directory is nil then it uses the currently open directory.
|
||||
|
||||
#### `fb.get_protocol(url: string, def?: any): string | def`
|
||||
|
||||
Returns the protocol scheme for the string `url`, or `nil` if there is no scheme.
|
||||
If `def` is defined then that is returned instead of `nil`.
|
||||
|
||||
The `://` is not included, so `https://example.com/test.mkv` will return `https`.
|
||||
|
||||
#### `fb.iterate_opt(opts: string): iterator`
|
||||
|
||||
Takes an options string consisting of a list of items separated by the `root_separators` defined in `file_browser.conf` and
|
||||
returns an iterator function that can be used to iterate over each item in the list.
|
||||
|
||||
```lua
|
||||
local opt = "a,b,zz z" -- root_separators=,
|
||||
for item in fb.iterate_opt(opt) do
|
||||
print(item) -- prints: 'a', 'b', 'zz z'
|
||||
end
|
||||
```
|
||||
|
||||
#### `fb.join_path(p1: string, p2: string): string`
|
||||
|
||||
A wrapper around [`mp.utils.join_path`](https://mpv.io/manual/master/#lua-scripting-utils-join-path(p1,-p2))
|
||||
which treats paths with network protocols as absolute paths.
|
||||
|
||||
#### `fb.pattern_escape(str: string): string`
|
||||
|
||||
Returns `str` with Lua special pattern characters escaped.
|
||||
|
||||
#### `fb_utils.resolve_directory_mapping(path: string): string`
|
||||
|
||||
Takes a `path` string and resolves any
|
||||
[directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void),
|
||||
replacing any substrings that match a mapping with the associated directory.
|
||||
|
||||
Only the first valid mapping is applied, but this behaviour will likely change in
|
||||
the future. Changes to this behaviour will not consitute a major version bump so should not
|
||||
be relied upon.
|
||||
|
||||
#### `fb.sort(list: list_table): list_table`
|
||||
|
||||
Iterates through the given list and sorts the items using file-browser's sorting algorithm.
|
||||
Returns the list but does not create a copy; the `list` table is sorted in-place.
|
||||
|
||||
#### `fb.valid_file(name: string): boolean`
|
||||
|
||||
Tests if the string `name` passes the user set filters for valid files (extensions/dot files/etc).
|
||||
|
||||
#### `fb.valid_dir(name: string): boolean`
|
||||
|
||||
Tests if the string `name` passes the user set filters for valid directories (dot folders/etc).
|
||||
|
||||
### Getters
|
||||
|
||||
These functions allow addons to safely get information from file-browser.
|
||||
All tables returned by these functions are copies sent through the [`fb.copy_table`](#fbcopy_tablet-table-depth-number-table)
|
||||
function to ensure addons can't accidentally break things.
|
||||
|
||||
#### `fb.get_audio_extensions(): table`
|
||||
|
||||
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened
|
||||
as additional audio tracks.
|
||||
All of these are included in `fb.get_extensions`.
|
||||
|
||||
#### `fb.get_current_file(): table`
|
||||
|
||||
A table containing the path of the current open file in the form:
|
||||
`{directory = "/home/me/", name = "bunny.mkv", path = "/home/me/bunny.mkv"}`.
|
||||
|
||||
#### `fb.get_current_parser(): string`
|
||||
|
||||
The unique id of the parser that successfully parsed the current directory.
|
||||
|
||||
#### `fb.get_current_parser_keyname(): string`
|
||||
|
||||
The `keybind_name` of the parser that successfully parsed the current directory.
|
||||
Used for custom-keybind filtering.
|
||||
|
||||
#### `fb.get_directory(): string`
|
||||
|
||||
The current directory open in the browser.
|
||||
|
||||
#### `fb.get_dvd_device(): string`
|
||||
|
||||
The current dvd-device as reported by mpv's `dvd-device` property.
|
||||
Formatted to work with file-browser.
|
||||
|
||||
#### `fb.get_extensions(): table`
|
||||
|
||||
Returns the set of valid extensions after applying the user's whitelist/blacklist options.
|
||||
The table is in the form `{ mkv = true, mp3 = true, ... }`.
|
||||
Sub extensions, audio extensions, and parseable extensions are all included in this set.
|
||||
|
||||
#### `fb.get_list(): list_table`
|
||||
|
||||
The list_table currently open in the browser.
|
||||
|
||||
#### `fb.get_open_status(): boolean`
|
||||
|
||||
Returns true if the browser is currently open and false if not.
|
||||
|
||||
#### `fb.get_opt(name: string): string | number | boolean`
|
||||
|
||||
Returns the script-opt with the given name.
|
||||
|
||||
#### `fb.get_parsers(): table`
|
||||
|
||||
Returns a table of all the loaded parsers/addons.
|
||||
The formatting of this table in undefined, but it should
|
||||
always contain an array of the parsers in order of priority.
|
||||
|
||||
#### `fb.get_parse_state(co?: coroutine): parse_state_table`
|
||||
|
||||
Returns the [parse_state table](#parse-state-table) for the given coroutine.
|
||||
If no coroutine is given then it uses the running coroutine.
|
||||
Every parse operation is guaranteed to have a unique coroutine.
|
||||
|
||||
#### `fb.get_parseable_extensions(): table`
|
||||
|
||||
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are
|
||||
treated as parseable by the browser.
|
||||
All of these are included in `fb.get_extensions`.
|
||||
|
||||
#### `fb.get_root(): list_table`
|
||||
|
||||
Returns the root table.
|
||||
|
||||
#### `fb.get_script_opts(): table`
|
||||
|
||||
The table of script opts set by the user. This currently does not get
|
||||
changed during runtime, but that is not guaranteed for future minor version increments.
|
||||
|
||||
#### `fb.get_selected_index(): number`
|
||||
|
||||
The current index of the cursor.
|
||||
Note that it is possible for the cursor to be outside the bounds of the list;
|
||||
for example when the list is empty this usually returns 1.
|
||||
|
||||
#### `fb.get_selected_item(): item_table | nil`
|
||||
|
||||
Returns the item_table of the currently selected item.
|
||||
If no item is selected (for example an empty list) then returns nil.
|
||||
|
||||
#### `fb.get_state(): table`
|
||||
|
||||
Returns the current state values of the browser.
|
||||
These are not documented and are subject to change at any time,
|
||||
adding a proper getter for anything is a valid request.
|
||||
|
||||
#### `fb.get_sub_extensions(): table`
|
||||
|
||||
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened
|
||||
as additional subtitle tracks.
|
||||
All of these are included in `fb.get_extensions`.
|
||||
|
||||
#### `parser:get_id(): string`
|
||||
|
||||
The unique id of the parser. Used for log messages and various internal functions.
|
||||
|
||||
#### `parser:get_index(): number`
|
||||
|
||||
The index of the parser in order of preference (based on the priority value).
|
||||
`defer` uses this internally.
|
||||
|
||||
### Setters
|
||||
|
||||
#### `fb.set_selected_index(pos: number): number | false`
|
||||
|
||||
Sets the cursor position and returns the new index.
|
||||
If the input is not a number return false, if the input is out of bounds move it in bounds.
|
||||
|
||||
## Examples
|
||||
|
||||
For standard addons that add support for non-native filesystems, but otherwise don't do anything fancy, see [ftp-browser](ftp-browser.lua) and [apache-browser](apache-browser.lua).
|
||||
|
||||
For more simple addons that make a few small modifications to how other parsers are displayed, see [home-label](home-label.lua).
|
||||
|
||||
For more complex addons that maintain their own virtual directory structure, see
|
||||
[favourites](favourites.lua).
|
||||
330
mpv/scripts/file-browser/docs/custom-keybinds.md
Normal file
330
mpv/scripts/file-browser/docs/custom-keybinds.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# Custom Keybinds
|
||||
|
||||
File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item.
|
||||
This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard.
|
||||
|
||||
The feature is disabled by default, but is enabled with the `custom_keybinds` script-opt.
|
||||
Keybinds are declared in the `~~/script-opts/file-browser-keybinds.json` file, the config takes the form of an array of json objects, with the following keys:
|
||||
|
||||
| option | required | default | description |
|
||||
|---------------|----------|------------|--------------------------------------------------------------------------------------------|
|
||||
| key | yes | - | the key to bind the command to - same syntax as input.conf |
|
||||
| command | yes | - | json array of commands and arguments |
|
||||
| name | no | numeric id | name of the script-binding - see [modifying default keybinds](#modifying-default-keybinds) |
|
||||
| condition | no | - | a Lua [expression](#expressions) - the keybind will only run if this evaluates to true |
|
||||
| flags | no | - | flags to send to the mpv add_keybind function - see [here](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) |
|
||||
| filter | no | - | run the command on just a file (`file`) or folder (`dir`) |
|
||||
| parser | no | - | run the command only in directories provided by the specified parser. |
|
||||
| multiselect | no | `false` | command is run on all selected items |
|
||||
| multi-type | no | `repeat` | which multiselect mode to use - `repeat` or `concat` |
|
||||
| delay | no | `0` | time to wait between sending repeated multi commands |
|
||||
| concat-string | no | `' '` (space) | string to insert between items when concatenating multi commands |
|
||||
| passthrough | no | - | force or ban passthrough behaviour - see [passthrough](#passthrough-keybinds) |
|
||||
| api_version | no | - | tie the keybind to a particular [addon API version](./addons.md#api-version), printing warnings and throwing errors if the keybind is used with wrong versions |
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["print-text", "example"],
|
||||
}
|
||||
```
|
||||
|
||||
The command can also be an array of arrays, in order to send multiple commands at once:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP2",
|
||||
"command": [
|
||||
["print-text", "example2"],
|
||||
["show-text", "example2"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Filter should not be included unless one wants to limit what types of list entries the command should be run on.
|
||||
To only run the command for directories use `dir`, to only run the command for files use `file`.
|
||||
|
||||
The parser filter is for filtering keybinds to only work inside directories loaded by specific parsers.
|
||||
There are two parsers in the base script, the default parser for native filesystems is called `file`, while the root parser is called `root`.
|
||||
Other parsers can be supplied by addons, and use the addon's filename with `-browser.lua` or just `.lua` stripped unless otherwise stated.
|
||||
For example `ftp-browser.lua` would have a parser called `ftp`.
|
||||
You can set the filter to match multiple parsers by separating the names with spaces.
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP2",
|
||||
"command": [ ["print-text", "example3"] ],
|
||||
"parser": "ftp file"
|
||||
}
|
||||
```
|
||||
|
||||
The `flags` field is mostly only useful for addons, but can also be useful if one wants a key to be repeatable.
|
||||
In this case the the keybind would look like the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "p",
|
||||
"command": ["print-text", "spam-text"],
|
||||
"flags": { "repeatable": true }
|
||||
}
|
||||
```
|
||||
|
||||
## Codes
|
||||
|
||||
The script will scan every string in the command for the special substitution strings, they are:
|
||||
|
||||
| code | description |
|
||||
|--------|---------------------------------------------------------------------|
|
||||
| `%%` | escape code for `%` |
|
||||
| `%f` | filepath of the selected item |
|
||||
| `%n` | filename of the selected item |
|
||||
| `%p` | currently open directory |
|
||||
| `%q` | currently open directory but preferring the directory label |
|
||||
| `%d` | name of the current directory (characters between the last two '/') |
|
||||
| `%r` | name of the parser for the currently open directory |
|
||||
| `%x` | number of items in the currently open directory |
|
||||
| `%i` | the 1-based index of the selected item in the list |
|
||||
| `%j` | the 1-based index of the item in a multiselection - returns 1 for single selections |
|
||||
|
||||
Additionally, using the uppercase forms of those codes will send the substituted string through the `string.format("%q", str)` function.
|
||||
This adds double quotes around the string and automatically escapes any characters which would break the string encapsulation.
|
||||
This is not necessary for most mpv commands, but can be very useful when sending commands to the OS with the `run` command,
|
||||
or when passing values into [expressions](#conditional-command-condition-command).
|
||||
|
||||
Example of a command to add an audio track:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "Ctrl+a",
|
||||
"command": ["audio-add", "%f"],
|
||||
"filter": "file"
|
||||
}
|
||||
```
|
||||
|
||||
Any commands that contain codes representing specific items (`%f`, `%n`, `%i` etc) will
|
||||
not be run if no item is selected (for example in an empty directory).
|
||||
In these cases [passthrough](#passthrough-keybinds) rules will apply.
|
||||
|
||||
## Multiselect Commands
|
||||
|
||||
When multiple items are selected the command can be run for all items in the order they appear on the screen.
|
||||
This can be controlled by the `multiselect` flag, which takes a boolean value.
|
||||
When not set the flag defaults to `false`.
|
||||
|
||||
There are two different multiselect modes, controlled by the `multi-type` option. There are two options:
|
||||
|
||||
### `repeat`
|
||||
|
||||
The default mode that sends the commands once for each item that is selected.
|
||||
If time is needed between running commands of multiple selected items (for example, due to file handlers) then the `delay` option can be used to set a duration (in seconds) between commands.
|
||||
|
||||
### `concat`
|
||||
|
||||
Run a single command, but replace item specific codes with a concatenated string made from each selected item.
|
||||
For example `["print-text", "%n" ]` would print the name of each item selected separated by `' '` (space).
|
||||
The string inserted between each item is determined by the `concat-string` option, but `' '` is the default.
|
||||
|
||||
## Passthrough Keybinds
|
||||
|
||||
When loading keybinds from the json file file-browser will move down the list and overwrite any existing bindings with the same key.
|
||||
This means the lower an item on the list, the higher preference it has.
|
||||
However, file-browser implements a layered passthrough system for its keybinds; if a keybind is blocked from running by user filters, then the next highest preference command will be sent, continuing until a command is sent or there are no more keybinds.
|
||||
The default dynamic keybinds are considered the lowest priority.
|
||||
|
||||
The `filter`, `parser`, and `condition` options can all trigger passthrough, as well as some [codes](#codes).
|
||||
If a multi-select command is run on multiple items then passthrough will occur if any of the selected items fail the filters.
|
||||
|
||||
Passthrough can be forcibly disabled or enabled using the passthrough option.
|
||||
When set to `true` passthrough will always be activate regardless of the state of the filters.
|
||||
|
||||
## Modifying Default Keybinds
|
||||
|
||||
Since the custom keybinds are applied after the default dynamic keybinds they can be used to overwrite the default bindings.
|
||||
Setting new keys for the existing binds can be done with the `script-binding [binding-name]` command, where `binding-name` is the full name of the keybinding.
|
||||
For this script the names of the dynamic keybinds are in the format `file_browser/dynamic/[name]` where `name` is a unique identifier documented in the [keybinds](README.md#keybinds) table.
|
||||
|
||||
For example to change the scroll buttons from the arrows to the scroll wheel:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"key": "WHEEL_UP",
|
||||
"command": ["script-binding", "file_browser/dynamic/scroll_up"]
|
||||
},
|
||||
{
|
||||
"key": "WHEEL_DOWN",
|
||||
"command": ["script-binding", "file_browser/dynamic/scroll_down"]
|
||||
},
|
||||
{
|
||||
"key": "UP",
|
||||
"command": ["osd-auto", "add", "volume", "2"]
|
||||
},
|
||||
{
|
||||
"key": "DOWN",
|
||||
"command": ["osd-auto", "add", "volume", "-2"]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Custom keybinds can be called using the same method, but users must set the `name` value inside the `file-browser-keybinds.json` file.
|
||||
To avoid conflicts custom keybinds use the format: `file_browser/dynamic/custom/[name]`.
|
||||
|
||||
## Expressions
|
||||
|
||||
Expressions are used to evaluate Lua code into a string that can be used for commands.
|
||||
These behave similarly to those used for [`profile-cond`](https://mpv.io/manual/master/#conditional-auto-profiles)
|
||||
values. In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively.
|
||||
Additionally, in mpv v0.38+ the `mp.input` module is available as `input`.
|
||||
|
||||
The file-browser [addon API](addons/addons.md#the-api) is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input)
|
||||
is installed then user-input API will be available in `user_input`.
|
||||
|
||||
This example only runs the keybind if the browser is in the Windows C drive or if
|
||||
the selected item is a matroska file:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["print-text", "in my C:/ drive!"],
|
||||
"condition": "(%P):find('C:/') == 1"
|
||||
},
|
||||
{
|
||||
"key": "KP2",
|
||||
"command": ["print-text", "Matroska File!"],
|
||||
"condition": "fb.get_extension(%N) == 'mkv'"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
If the `condition` expression contains any item specific codes (`%F`, `%I`, etc) then it will be
|
||||
evaluated on each individual item, otherwise it will evaluated once for the whole keybind.
|
||||
If a code is invalid (for example using `%i` in empty directories) then the expression returns false.
|
||||
|
||||
There are some utility script messages that extend the power of expressions.
|
||||
[`conditional-command`](#conditional-command-condition-command) allows one to specify conditions that
|
||||
can apply to individual items or commands. The tradeoff is that you lose the automated passthrough behaviour.
|
||||
There is also [`evaluate-expressions`](#evaluate-expressions-command) which allows one to evaluate expressions inside commands.
|
||||
|
||||
## Utility Script Messages
|
||||
|
||||
There are a small number of custom script messages defined by file-browser to support custom keybinds.
|
||||
|
||||
### `=> <command...>`
|
||||
|
||||
A basic script message that makes it easier to chain multiple utility script messages together.
|
||||
Any `=>` string will be substituted for `script-message`.
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "=>", "delay-command", "%j * 2", "=>", "evaluate-expressions", "print-text", "!{%j * 2}"],
|
||||
"multiselect": true
|
||||
}
|
||||
```
|
||||
|
||||
### `conditional-command [condition] <command...>`
|
||||
|
||||
Runs the following command only if the condition [expression](#expressions) is `true`.
|
||||
|
||||
This example command will only run if the player is currently paused:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "conditional-command", "mp.get_property_bool('pause')", "print-text", "is paused"],
|
||||
}
|
||||
```
|
||||
|
||||
Custom keybind codes are evaluated before the expressions.
|
||||
|
||||
This example only runs if the currently selected item in the browser has a `.mkv` extension:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "conditional-command", "fb.get_extension(%N) == 'mkv'", "print-text", "a matroska file"],
|
||||
}
|
||||
```
|
||||
|
||||
### `delay-command [delay] <command...>`
|
||||
|
||||
Delays the following command by `[delay]` seconds.
|
||||
Delay is an [expression](#expressions).
|
||||
|
||||
The following example will send the `print-text` command after 5 seconds:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "delay-command", "5", "print-text", "example"],
|
||||
}
|
||||
```
|
||||
|
||||
### `evaluate-expressions <command...>`
|
||||
|
||||
Evaluates embedded Lua expressions in the following command.
|
||||
Expressions have the same behaviour as the [`conditional-command`](#conditional-command-condition-command) script-message.
|
||||
Expressions must be surrounded by `!{}` characters.
|
||||
Additional `!` characters can be placed at the start of the expression to
|
||||
escape the evaluation.
|
||||
|
||||
For example the following keybind will print 3 to the console:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "evaluate-expressions", "print-text", "!{1 + 2}"],
|
||||
}
|
||||
```
|
||||
|
||||
This example replaces all `/` characters in the path with `\`
|
||||
(note that the `\` needs to be escaped twice, once for the json file, and once for the string in the lua expression):
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "evaluate-expressions", "print-text", "!{ string.gsub(%F, '/', '\\\\') }"],
|
||||
}
|
||||
```
|
||||
|
||||
### `run-statement <statement...>`
|
||||
|
||||
Runs the following string a as a Lua statement. This is similar to an [expression](#expressions),
|
||||
but instead of the code evaluating to a value it must run a series of statements. Basically it allows
|
||||
for function bodies to be embedded into custom keybinds. All the same modules are available.
|
||||
If multiple strings are sent to the script-message then they will be concatenated together with newlines.
|
||||
|
||||
The following keybind will use [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) to
|
||||
rename items in file-browser:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["script-message", "run-statement",
|
||||
"assert(user_input, 'install mpv-user-input!')",
|
||||
|
||||
"local line, err = user_input.get_user_input_co({",
|
||||
"id = 'rename-file',",
|
||||
"source = 'custom-keybind',",
|
||||
"request_text = 'rename file:',",
|
||||
"queueable = true,",
|
||||
"default_input = %N,",
|
||||
"cursor_pos = #(%N) - #fb.get_extension(%N, '')",
|
||||
"})",
|
||||
|
||||
"if not line then return end",
|
||||
"os.rename(%F, utils.join_path(%P, line))",
|
||||
|
||||
"fb.rescan()"
|
||||
],
|
||||
"parser": "file",
|
||||
"multiselect": true
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See [here](file-browser-keybinds.json).
|
||||
118
mpv/scripts/file-browser/docs/file-browser-keybinds.json
Normal file
118
mpv/scripts/file-browser/docs/file-browser-keybinds.json
Normal file
@@ -0,0 +1,118 @@
|
||||
[
|
||||
{
|
||||
"key": "KP1",
|
||||
"command": ["print-text", "file: %f"],
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"key": "KP2",
|
||||
"command": ["print-text", "name: %n"],
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"key": "KP3",
|
||||
"command": ["print-text", "open directory: %p"]
|
||||
},
|
||||
{
|
||||
"key": "KP4",
|
||||
"command": ["print-text", "directory name: %d"]
|
||||
},
|
||||
{
|
||||
"key": "KP5",
|
||||
"command": ["print-text", "escape the code: %%f"],
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"key": "KP6",
|
||||
"command": ["print-text", "full filepath via concatenation: %p%n"],
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"key": "KP7",
|
||||
"command": ["print-text", "quote/escape filepath: %F"],
|
||||
"multiselect": true
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"comment": "deletes the currently selected file",
|
||||
"key": "Alt+DEL",
|
||||
"command": ["run", "rm", "%F"],
|
||||
"filter": "file",
|
||||
"multiselect": true,
|
||||
"multi-type": "concat"
|
||||
},
|
||||
{
|
||||
"comment": "opens the currently selected items in a new mpv window",
|
||||
"key": "Ctrl+ENTER",
|
||||
"command": ["run", "mpv", "%F"],
|
||||
"multiselect": true,
|
||||
"multi-type": "concat"
|
||||
},
|
||||
{
|
||||
"key": "Ctrl+c",
|
||||
"command": [
|
||||
["run", "powershell", "-command", "Set-Clipboard", "%F"],
|
||||
["print-text", "copied filepath to clipboard"]
|
||||
],
|
||||
"multiselect": true,
|
||||
"delay": 0.3
|
||||
},
|
||||
{
|
||||
"comment": "Opens the current directory in windows explorer",
|
||||
"key": "Ctrl+o",
|
||||
"command": ["run", "powershell", "-command", "explorer.exe", "(( %P ).TrimEnd('/') -replace '/', '\\' )"],
|
||||
"multiselect": false
|
||||
},
|
||||
{
|
||||
"comment": "Opens the selected directory in windows explorer",
|
||||
"key": "Ctrl+O",
|
||||
"command": ["run", "powershell", "-command", "explorer.exe", "(( %F ).TrimEnd('/') -replace '/', '\\' )"],
|
||||
"filter": "dir",
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"comment": "Opens the current directory in windows explorer and highlights the currently selected file",
|
||||
"key": "Ctrl+O",
|
||||
"command": ["run", "powershell", "-command", "explorer.exe", "'/select,'", "( %F -replace '/', '\\' )"],
|
||||
"filter": "file",
|
||||
"multiselect": true
|
||||
},
|
||||
{
|
||||
"key": "INS",
|
||||
"command": ["run", "powershell", "-command", "Set-Content", "-LiteralPath", "( %P + '/.ordered-chapters.m3u' )", "-Value", "( %N )"],
|
||||
"multiselect": true,
|
||||
"multi-type": "concat",
|
||||
"concat-string": "+ '\n' +"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"key": "WHEEL_UP",
|
||||
"command": ["script-binding", "file_browser/dynamic/scroll_up"]
|
||||
},
|
||||
{
|
||||
"key": "WHEEL_DOWN",
|
||||
"command": ["script-binding", "file_browser/dynamic/scroll_down"]
|
||||
},
|
||||
{
|
||||
"key": "MBTN_LEFT",
|
||||
"command": ["script-binding", "file_browser/dynamic/down_dir"]
|
||||
},
|
||||
{
|
||||
"key": "MBTN_RIGHT",
|
||||
"command": ["script-binding", "file_browser/dynamic/up_dir"]
|
||||
},
|
||||
{
|
||||
"key": "MBTN_MID",
|
||||
"command": ["script-binding", "file_browser/dynamic/play"]
|
||||
},
|
||||
{
|
||||
"key": "UP",
|
||||
"command": ["osd-auto", "add", "volume", "2"]
|
||||
},
|
||||
{
|
||||
"key": "DOWN",
|
||||
"command": ["osd-auto", "add", "volume", "-2"]
|
||||
}
|
||||
]
|
||||
175
mpv/scripts/file-browser/docs/file_browser.conf
Normal file
175
mpv/scripts/file-browser/docs/file_browser.conf
Normal file
@@ -0,0 +1,175 @@
|
||||
#######################################################
|
||||
# This is the default config file for mpv-file-browser
|
||||
# https://github.com/CogentRedTester/mpv-file-browser
|
||||
#######################################################
|
||||
|
||||
# root directories, separated by commas
|
||||
# on linux you will probably want to add `/`,
|
||||
# on windows this should be used to add different drive letters
|
||||
# Examples:
|
||||
# linux: root=~/,/
|
||||
# windows: root=~/,C:/
|
||||
root=~/
|
||||
|
||||
# characters to separate root directories, each character works individually
|
||||
# this is in case one is using directories with strange names
|
||||
root_separators=,;
|
||||
|
||||
# number of entries to show on the screen at once
|
||||
num_entries=20
|
||||
|
||||
# wrap the cursor around the top and bottom of the list
|
||||
wrap=no
|
||||
|
||||
# only show files compatible with mpv in the browser
|
||||
filter_files=yes
|
||||
|
||||
# experimental feature that recurses directories concurrently when appending items to the playlist
|
||||
# this feature has the potential for massive performance improvements when using addons with asynchronous IO
|
||||
concurrent_recursion=no
|
||||
|
||||
# maximum number of recursions that can run concurrently
|
||||
# if this number is too high it risks overflowing the mpv event queue, which will cause some directories to be dropped entirely
|
||||
max_concurrency=16
|
||||
|
||||
# enable custom keybinds
|
||||
# the keybind json file must go in ~~/script-opts
|
||||
custom_keybinds=no
|
||||
|
||||
# file-browser only shows files that are compatible with mpv by default
|
||||
# adding a file extension to this list will add it to the extension whitelist
|
||||
# extensions are separated with the root separators, do not use any spaces
|
||||
extension_whitelist=
|
||||
|
||||
# add file extensions to this list to disable default filetypes
|
||||
# note that this will also override audio/subtitle_extension options below
|
||||
extension_blacklist=
|
||||
|
||||
# files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist
|
||||
# items on this list are automatically added to the extension whitelist
|
||||
audio_extensions=mka,dts,dtshd,dts-hd,truehd,true-hd
|
||||
|
||||
# files with these extensions will be added as additional subtitle tracks for the current file instead of appended to the playlist
|
||||
# items on this list are automatically added to the extension whitelist
|
||||
subtitle_extensions=etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs
|
||||
|
||||
# filter directories or files starting with a period like .config
|
||||
# for linux systems
|
||||
filter_dot_dirs=no
|
||||
filter_dot_files=no
|
||||
|
||||
# substitude forward slashes for backslashes when appending a local file to the playlist
|
||||
# may be useful on windows systems
|
||||
substitute_backslash=no
|
||||
|
||||
# interpret backslashes `\` in paths as forward slashes `/`
|
||||
# this is useful on Windows, which natively uses backslashes.
|
||||
# As backslashes are valid filename characters in Unix systems this could
|
||||
# cause mangled paths, though such filenames are rare.
|
||||
# Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform`
|
||||
# property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`.
|
||||
normalise_backslash=auto
|
||||
|
||||
# this option reverses the behaviour of the alt+ENTER keybind
|
||||
# when disabled the keybind is required to enable autoload for the file
|
||||
# when enabled the keybind disables autoload for the file
|
||||
autoload=no
|
||||
|
||||
# if autoload is triggered by selecting the currently playing file, then
|
||||
# the current file will have it's watch-later config saved before being closed and re-opened
|
||||
# essentially the current file will not be restarted
|
||||
autoload_save_current=yes
|
||||
|
||||
# when opening the browser in idle mode prefer the current working directory over the root
|
||||
# note that the working directory is set as the 'current' directory regardless, so `home` will
|
||||
# move the browser there even if this option is set to false
|
||||
default_to_working_directory=no
|
||||
|
||||
# when moving up a directory do not stop on empty protocol schemes like `ftp://`
|
||||
# e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://`
|
||||
skip_protocol_schemes=yes
|
||||
|
||||
# map optical device paths to their respective file paths,
|
||||
# e.g. mapping bd:// to the value of the bluray-device property
|
||||
map_bd_device=yes
|
||||
map_dvd_device=yes
|
||||
map_cdda_device=yes
|
||||
|
||||
# enables addons
|
||||
addons=no
|
||||
addon_directory=~~/script-modules/file-browser-addons
|
||||
|
||||
# directory to load external modules - currently just user-input-module
|
||||
module_directory=~~/script-modules
|
||||
|
||||
# turn the OSC idle screen off and on when opening and closing the browser
|
||||
# this should only be enabled if file-browser is the only thing controlling the idle-screen,
|
||||
# if multiple sources attempt to control the idle-screen at the same time it can cause unexpected behaviour.
|
||||
toggle_idlescreen=no
|
||||
|
||||
# Set the current open status of the browser in the `file_browser/open` field of the `user-data` property.
|
||||
# This property is only available in mpv v0.36+.
|
||||
set_user_data=yes
|
||||
|
||||
# Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property.
|
||||
# This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically disable this option.
|
||||
set_shared_script_properties=no
|
||||
|
||||
####################################
|
||||
######### style settings ###########
|
||||
####################################
|
||||
|
||||
# force file-browser to use a specific text alignment (default: top-left)
|
||||
# uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3
|
||||
# set to 0 to use the default mpv osd-align options
|
||||
alignment=7
|
||||
|
||||
# The format string used for the header. Uses custom-keybind substitution codes to
|
||||
# dynamically change the contents of the header. See: docs/custom-keybinds.md#codes
|
||||
# e.g. to add file numbers, set this to: {\fnMonospace}[%i/%x]{\fn<font_name_header or blank>} %q\N----------------------------------------------------
|
||||
format_string_header=%q\N----------------------------------------------------
|
||||
|
||||
# The format strings used for the wrappers. Supports custom-keybind substitution codes, and
|
||||
# supports two additional codes: `%<` and `%>` to show the number of items before and after the visible list, respectively.
|
||||
# Setting these options to empty strings will disable the wrappers.
|
||||
format_string_topwrapper=%< item(s) above\N
|
||||
format_string_bottomwrapper=\N%> item(s) remaining
|
||||
|
||||
# allows custom icons be set for the folder and cursor
|
||||
# the `\h` character is a hard space to add padding
|
||||
folder_icon={\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h
|
||||
cursor_icon={\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h
|
||||
|
||||
# set the opacity of fonts in hexadecimal from 00 (opaque) to FF (transparent)
|
||||
font_opacity_selection_marker=99
|
||||
|
||||
# print the header in bold font
|
||||
font_bold_header=yes
|
||||
|
||||
# scale the size of the browser; 2 would double the size, 0.5 would halve it, etc.
|
||||
# the header and wrapper scaling is relative to the base scaling
|
||||
scaling_factor_base=1
|
||||
scaling_factor_header=1.4
|
||||
scaling_factor_wrappers=0.64
|
||||
|
||||
# set custom font names, blank is the default
|
||||
# setting custom fonts for the folder/cursor can fix broken or missing icons
|
||||
font_name_header=
|
||||
font_name_body=
|
||||
font_name_wrappers=
|
||||
font_name_folder=
|
||||
font_name_cursor=
|
||||
|
||||
# set custom font colours
|
||||
# colours are in hexadecimal format in Blue Green Red order
|
||||
# note that this is the opposite order to most RGB colour codes
|
||||
font_colour_header=00ccff
|
||||
font_colour_body=ffffff
|
||||
font_colour_wrappers=00ccff
|
||||
font_colour_cursor=00ccff
|
||||
|
||||
# these are colours applied to list items in different states
|
||||
font_colour_selected=fce788
|
||||
font_colour_multiselect=fcad88
|
||||
font_colour_playing=33ff66
|
||||
font_colour_playing_multiselected=22b547
|
||||
Reference in New Issue
Block a user