style: reconfigured and run the whole codebase through lua formatter
This commit is contained in:
204
.editorconfig
204
.editorconfig
@@ -1,83 +1,167 @@
|
||||
[*.lua]
|
||||
# see https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# see https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||
[*.lua]
|
||||
# [basic]
|
||||
|
||||
# optional space/tab
|
||||
indent_style = tab
|
||||
# if indent_style is space, this is valid
|
||||
indent_size = 4
|
||||
# if indent_style is tab, this is valid
|
||||
tab_width = 4
|
||||
# none/single/double
|
||||
quote_style = single
|
||||
continuation_indent_size = 4
|
||||
|
||||
continuation_indent = 4
|
||||
|
||||
# this mean utf8 length , if this is 'unset' then the line width is no longer checked
|
||||
# this option decides when to chopdown the code
|
||||
max_line_length = 120
|
||||
# crlf/lf/cr/auto
|
||||
|
||||
# optional crlf/lf/cr/auto, if it is 'auto', in windows it is crlf other platforms are lf
|
||||
# in neovim the value 'auto' is not a valid option, please use 'unset'
|
||||
end_of_line = lf
|
||||
detect_end_of_line = false
|
||||
insert_final_newline = true
|
||||
|
||||
# [function]
|
||||
# none/ comma / semicolon / only_kv_colon
|
||||
table_separator_style = comma
|
||||
|
||||
# true/false/only_after_more_indention_statement/only_not_exist_cross_row_expression
|
||||
align_call_args = false
|
||||
align_function_define_params = true
|
||||
remove_expression_list_finish_comma = true
|
||||
# keep/remove/remove_table_only/remove_string_only/unambiguous_remove_string_only
|
||||
#optional keep/never/always/smart
|
||||
trailing_table_separator = smart
|
||||
|
||||
# keep/remove/remove_table_only/remove_string_only
|
||||
call_arg_parentheses = keep
|
||||
|
||||
# [table]
|
||||
detect_end_of_line = false
|
||||
|
||||
# none/comma/semicolon
|
||||
table_separator_style = comma
|
||||
# keep/never/always/smart
|
||||
trailing_table_separator = smart
|
||||
# align equal signs in tables
|
||||
continuous_assign_table_field_align_to_equal_sign = false
|
||||
# if true "local t = { 1, 2, 3 }"
|
||||
keep_one_space_between_table_and_bracket = false
|
||||
|
||||
# [statement]
|
||||
|
||||
align_chained_expression_statement = false
|
||||
max_continuous_line_distance = 1
|
||||
# align equal signs in value assignments
|
||||
continuous_assign_statement_align_to_equal_sign = false
|
||||
if_condition_align_with_each_other = false
|
||||
local_assign_continuation_align_to_first_expression = false
|
||||
statement_inline_comment_space = 1
|
||||
|
||||
# [indentation]
|
||||
|
||||
# labels (e.g.::continue::) will not be intended
|
||||
label_no_indent = false
|
||||
# no indentation for do statement
|
||||
do_statement_no_indent = false
|
||||
# no indentation for conditions of an if statement when on new line
|
||||
if_condition_no_continuation_indent = false
|
||||
if_branch_comments_after_block_no_indent = false
|
||||
# this will check text end with new line
|
||||
insert_final_newline = true
|
||||
|
||||
# [space]
|
||||
space_around_table_field_list = false
|
||||
|
||||
space_before_attribute = false
|
||||
|
||||
# if true, t[#t+1] will not space wrapper '+'
|
||||
table_append_expression_no_space = false
|
||||
long_chain_expression_allow_one_space_after_colon = false
|
||||
remove_empty_header_and_footer_lines_in_function = true
|
||||
space_before_function_open_parenthesis = false
|
||||
|
||||
space_before_function_call_open_parenthesis = false
|
||||
|
||||
space_before_closure_open_parenthesis = false
|
||||
|
||||
# optional always/only_string/only_table/none
|
||||
# or true/false
|
||||
space_before_function_call_single_arg = always
|
||||
|
||||
space_before_open_square_bracket = false
|
||||
# format like this "local t <const> = 1"
|
||||
keep_one_space_between_namedef_and_attribute = false
|
||||
|
||||
# [row_layout]
|
||||
# Each can be: minLine:${n}, keepLine, keepLine:${n}, maxLine:${n}
|
||||
space_inside_function_call_parentheses = false
|
||||
|
||||
keep_line_after_if_statement = keepLine
|
||||
keep_line_after_do_statement = keepLine
|
||||
keep_line_after_while_statement = keepLine
|
||||
keep_line_after_repeat_statement = keepLine
|
||||
keep_line_after_for_statement = keepLine
|
||||
keep_line_after_local_or_assign_statement = keepLine
|
||||
keep_line_after_function_define_statement = keepLine
|
||||
keep_line_after_expression_statement = keepLine
|
||||
space_inside_function_param_list_parentheses = false
|
||||
|
||||
# [diagnostic]
|
||||
# creates a lot of warnings I can't do anything about so disable it is
|
||||
space_inside_square_brackets = false
|
||||
|
||||
enable_check_codestyle = false
|
||||
# like t[#t+1] = 1
|
||||
space_around_table_append_operator = false
|
||||
|
||||
ignore_spaces_inside_function_call = false
|
||||
|
||||
space_before_inline_comment = 1
|
||||
|
||||
# [operator space]
|
||||
space_around_math_operator = true
|
||||
|
||||
space_after_comma = true
|
||||
|
||||
space_after_comma_in_for_statement = true
|
||||
|
||||
# true/false or none/always/no_space_asym
|
||||
space_around_concat_operator = true
|
||||
|
||||
space_around_logical_operator = true
|
||||
|
||||
# true/false or none/always/no_space_asym
|
||||
space_around_assign_operator = true
|
||||
|
||||
# [align]
|
||||
|
||||
align_call_args = false
|
||||
|
||||
align_function_params = false
|
||||
|
||||
align_continuous_assign_statement = false
|
||||
|
||||
align_continuous_rect_table_field = false
|
||||
|
||||
align_continuous_line_space = 2
|
||||
|
||||
align_if_branch = false
|
||||
|
||||
# option none / always / contain_curly/
|
||||
align_array_table = none
|
||||
|
||||
align_continuous_similar_call_args = false
|
||||
|
||||
align_continuous_inline_comment = false
|
||||
|
||||
# option none / always / only_call_stmt
|
||||
align_chain_expr = none
|
||||
|
||||
# [indent]
|
||||
|
||||
never_indent_before_if_condition = false
|
||||
|
||||
never_indent_comment_on_if_branch = true
|
||||
|
||||
keep_indents_on_empty_lines = false
|
||||
|
||||
# [line space]
|
||||
|
||||
# The following configuration supports four expressions
|
||||
# keep
|
||||
# fixed(n)
|
||||
# min(n)
|
||||
# max(n)
|
||||
# for eg. min(2)
|
||||
|
||||
line_space_after_if_statement = keep
|
||||
|
||||
line_space_after_do_statement = keep
|
||||
|
||||
line_space_after_while_statement = keep
|
||||
|
||||
line_space_after_repeat_statement = keep
|
||||
|
||||
line_space_after_for_statement = keep
|
||||
|
||||
line_space_after_local_or_assign_statement = keep
|
||||
|
||||
line_space_after_function_statement = keep
|
||||
|
||||
line_space_after_expression_statement = keep
|
||||
|
||||
line_space_after_comment = keep
|
||||
|
||||
line_space_around_block = fixed(1)
|
||||
|
||||
# [line break]
|
||||
break_all_list_when_line_exceed = false
|
||||
|
||||
auto_collapse_lines = false
|
||||
|
||||
break_before_braces = false
|
||||
|
||||
# [preference]
|
||||
ignore_space_after_colon = false
|
||||
|
||||
remove_call_expression_list_finish_comma = false
|
||||
|
||||
# keep / always / same_line / repalce_with_newline
|
||||
end_statement_with_semicolon = keep
|
||||
|
@@ -16,7 +16,9 @@ function BufferingIndicator:decide_enabled()
|
||||
local player = state.core_idle and not state.eof_reached
|
||||
if self.enabled then
|
||||
if not player or (state.pause and not cache) then self.enabled = false end
|
||||
elseif player and cache and state.uncached_ranges then self.enabled = true end
|
||||
elseif player and cache and state.uncached_ranges then
|
||||
self.enabled = true
|
||||
end
|
||||
end
|
||||
|
||||
function BufferingIndicator:on_prop_pause() self:decide_enabled() end
|
||||
|
@@ -47,7 +47,8 @@ function Button:render()
|
||||
-- Background
|
||||
if is_hover_or_active then
|
||||
ass:rect(self.ax, self.ay, self.bx, self.by, {
|
||||
color = self.active and background or foreground, radius = state.radius,
|
||||
color = self.active and background or foreground,
|
||||
radius = state.radius,
|
||||
opacity = visibility * (self.active and 1 or 0.3),
|
||||
})
|
||||
end
|
||||
@@ -64,8 +65,11 @@ function Button:render()
|
||||
local width, height = math.ceil(badge_width + (badge_font_size / 7) * 2), math.ceil(badge_font_size * 0.93)
|
||||
local bx, by = self.bx - 1, self.by - 1
|
||||
ass:rect(bx - width, by - height, bx, by, {
|
||||
color = foreground, radius = state.radius, opacity = visibility,
|
||||
border = self.active and 0 or 1, border_color = background,
|
||||
color = foreground,
|
||||
radius = state.radius,
|
||||
opacity = visibility,
|
||||
border = self.active and 0 or 1,
|
||||
border_color = background,
|
||||
})
|
||||
ass:txt(bx - width / 2, by - height / 2, 5, self.badge, badge_opts)
|
||||
|
||||
@@ -80,8 +84,11 @@ function Button:render()
|
||||
-- Icon
|
||||
local x, y = round(self.ax + (self.bx - self.ax) / 2), round(self.ay + (self.by - self.ay) / 2)
|
||||
ass:icon(x, y, self.font_size, self.icon, {
|
||||
color = foreground, border = self.active and 0 or options.text_border * state.scale, border_color = background,
|
||||
opacity = visibility, clip = icon_clip,
|
||||
color = foreground,
|
||||
border = self.active and 0 or options.text_border * state.scale,
|
||||
border_color = background,
|
||||
opacity = visibility,
|
||||
clip = icon_clip,
|
||||
})
|
||||
|
||||
return ass
|
||||
|
@@ -57,8 +57,10 @@ function Controls:init_options()
|
||||
local current_item = nil
|
||||
for c in options.controls:gmatch('.') do
|
||||
if not current_item then current_item = {disposition = '', config = ''} end
|
||||
if c == '<' and #current_item.config == 0 then in_disposition = true
|
||||
elseif c == '>' and #current_item.config == 0 then in_disposition = false
|
||||
if c == '<' and #current_item.config == 0 then
|
||||
in_disposition = true
|
||||
elseif c == '>' and #current_item.config == 0 then
|
||||
in_disposition = false
|
||||
elseif c == ',' and not in_disposition then
|
||||
items[#items + 1] = current_item
|
||||
current_item = nil
|
||||
@@ -224,8 +226,11 @@ function Controls:register_badge_updater(badge, element)
|
||||
request_render()
|
||||
end
|
||||
|
||||
if is_external_prop then element['on_external_prop_' .. prop] = function(_, value) handler(prop, value) end
|
||||
else self:observe_mp_property(observable_name, handler) end
|
||||
if is_external_prop then
|
||||
element['on_external_prop_' .. prop] = function(_, value) handler(prop, value) end
|
||||
else
|
||||
self:observe_mp_property(observable_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
function Controls:get_visibility()
|
||||
|
@@ -34,8 +34,11 @@ function Element:init(id, props)
|
||||
self._flash_out_timer = mp.add_timeout(options.flash_duration / 1000, function()
|
||||
local function getTo() return self.proximity end
|
||||
local function onTweenEnd() self.forced_visibility = nil end
|
||||
if self.enabled then self:tween_property('forced_visibility', 1, getTo, onTweenEnd)
|
||||
else onTweenEnd() end
|
||||
if self.enabled then
|
||||
self:tween_property('forced_visibility', 1, getTo, onTweenEnd)
|
||||
else
|
||||
onTweenEnd()
|
||||
end
|
||||
end)
|
||||
self._flash_out_timer:kill()
|
||||
|
||||
|
@@ -43,8 +43,11 @@ function Elements:update_proximities()
|
||||
|
||||
-- If menu is open, all other elements have to be disabled
|
||||
if menu_only then
|
||||
if element.ignores_menu then element:update_proximity()
|
||||
else element:reset_proximity() end
|
||||
if element.ignores_menu then
|
||||
element:update_proximity()
|
||||
else
|
||||
element:reset_proximity()
|
||||
end
|
||||
else
|
||||
element:update_proximity()
|
||||
end
|
||||
|
@@ -64,8 +64,11 @@ function Menu:close(immediate, callback)
|
||||
|
||||
menu.is_closing = true
|
||||
|
||||
if immediate then close()
|
||||
else menu:fadeout(close) end
|
||||
if immediate then
|
||||
close()
|
||||
else
|
||||
menu:fadeout(close)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -155,10 +158,10 @@ function Menu:update(data)
|
||||
local menus_to_serialize = {{new_root, data}}
|
||||
local old_current_id = self.current and self.current.id
|
||||
local menu_props_to_copy = {
|
||||
'title', 'hint', 'keep_open', 'palette', 'on_search', 'search_submenus', 'search_suggestion'
|
||||
'title', 'hint', 'keep_open', 'palette', 'on_search', 'search_submenus', 'search_suggestion',
|
||||
}
|
||||
local item_props_to_copy = itable_join(menu_props_to_copy, {
|
||||
'icon', 'active', 'bold', 'italic', 'muted', 'value', 'separator', 'selectable', 'align'
|
||||
'icon', 'active', 'bold', 'italic', 'muted', 'value', 'separator', 'selectable', 'align',
|
||||
})
|
||||
|
||||
table_assign(new_root, data, itable_join({'type'}, menu_props_to_copy))
|
||||
@@ -189,7 +192,7 @@ function Menu:update(data)
|
||||
-- Update items
|
||||
local first_active_index = nil
|
||||
menu.items = {
|
||||
{title = t('Empty'), value = 'ignore', italic = 'true', muted = 'true', selectable = false, align = 'center'}
|
||||
{title = t('Empty'), value = 'ignore', italic = 'true', muted = 'true', selectable = false, align = 'center'},
|
||||
}
|
||||
|
||||
for i, item_data in ipairs(menu_data.items or {}) do
|
||||
@@ -213,8 +216,11 @@ function Menu:update(data)
|
||||
|
||||
-- Retain old state
|
||||
local old_menu = self.by_id[menu.id]
|
||||
if old_menu then table_assign(menu, old_menu, {'selected_index', 'scroll_y', 'fling', 'search'})
|
||||
else new_menus[#new_menus + 1] = menu end
|
||||
if old_menu then
|
||||
table_assign(menu, old_menu, {'selected_index', 'scroll_y', 'fling', 'search'})
|
||||
else
|
||||
new_menus[#new_menus + 1] = menu
|
||||
end
|
||||
|
||||
if menu.selected_index then self:select_by_offset(0, menu) end
|
||||
|
||||
@@ -403,8 +409,11 @@ end
|
||||
function Menu:scroll_to(pos, menu, fling_options)
|
||||
menu = menu or self.current
|
||||
menu.fling = {
|
||||
y = menu.scroll_y, distance = clamp(-menu.scroll_y, pos - menu.scroll_y, menu.scroll_height - menu.scroll_y),
|
||||
time = mp.get_time(), duration = 0.1, easing = ease_out_sext,
|
||||
y = menu.scroll_y,
|
||||
distance = clamp(-menu.scroll_y, pos - menu.scroll_y, menu.scroll_height - menu.scroll_y),
|
||||
time = mp.get_time(),
|
||||
duration = 0.1,
|
||||
easing = ease_out_sext,
|
||||
}
|
||||
if fling_options then table_assign(menu.fling, fling_options) end
|
||||
request_render()
|
||||
@@ -425,8 +434,11 @@ function Menu:scroll_to_index(index, menu, immediate)
|
||||
menu = menu or self.current
|
||||
if (index and index >= 1 and index <= #menu.items) then
|
||||
local position = round((self.scroll_step * (index - 1)) - ((menu.height - self.scroll_step) / 2))
|
||||
if immediate then self:set_scroll_to(position, menu)
|
||||
else self:scroll_to(position, menu) end
|
||||
if immediate then
|
||||
self:set_scroll_to(position, menu)
|
||||
else
|
||||
self:scroll_to(position, menu)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -500,8 +512,11 @@ end
|
||||
---@param id string
|
||||
function Menu:activate_submenu(id)
|
||||
local submenu = self.by_id[id]
|
||||
if submenu then self:activate_menu(submenu)
|
||||
else msg.error(string.format('Requested submenu id "%s" doesn\'t exist', id)) end
|
||||
if submenu then
|
||||
self:activate_menu(submenu)
|
||||
else
|
||||
msg.error(string.format('Requested submenu id "%s" doesn\'t exist', id))
|
||||
end
|
||||
end
|
||||
|
||||
---@param index? integer
|
||||
@@ -617,8 +632,12 @@ function Menu:handle_cursor_up()
|
||||
local distance = cursor.get_velocity().y / -3
|
||||
if math.abs(distance) > 50 then
|
||||
self.current.fling = {
|
||||
y = self.current.scroll_y, distance = distance, time = cursor.history:head().time,
|
||||
easing = ease_out_quart, duration = 0.5, update_cursor = true,
|
||||
y = self.current.scroll_y,
|
||||
distance = distance,
|
||||
time = cursor.history:head().time,
|
||||
easing = ease_out_quart,
|
||||
duration = 0.5,
|
||||
update_cursor = true,
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -648,9 +667,13 @@ function Menu:select_by_offset(offset, menu)
|
||||
local prev_index = itable_find(menu.items, function(item) return item.selectable ~= false end, index, 1)
|
||||
local next_index = itable_find(menu.items, function(item) return item.selectable ~= false end, index)
|
||||
if prev_index and next_index then
|
||||
if offset == 0 then menu.selected_index = index - prev_index <= next_index - index and prev_index or next_index
|
||||
elseif offset > 0 then menu.selected_index = next_index
|
||||
else menu.selected_index = prev_index end
|
||||
if offset == 0 then
|
||||
menu.selected_index = index - prev_index <= next_index - index and prev_index or next_index
|
||||
elseif offset > 0 then
|
||||
menu.selected_index = next_index
|
||||
else
|
||||
menu.selected_index = prev_index
|
||||
end
|
||||
else
|
||||
menu.selected_index = prev_index or next_index or nil
|
||||
end
|
||||
@@ -752,8 +775,8 @@ function Menu:search_submit(menu)
|
||||
italic = true,
|
||||
align = 'center',
|
||||
selectable = false,
|
||||
muted = true
|
||||
}
|
||||
muted = true,
|
||||
},
|
||||
}
|
||||
self:update_items(self.root.items)
|
||||
end
|
||||
@@ -767,7 +790,9 @@ function Menu:search_submit(menu)
|
||||
else
|
||||
menu.on_search(menu.search.query)
|
||||
end
|
||||
else self:search_internal(menu) end
|
||||
else
|
||||
self:search_internal(menu)
|
||||
end
|
||||
end
|
||||
|
||||
---@param query string
|
||||
@@ -841,11 +866,16 @@ function Menu:search_init(menu)
|
||||
timeout:kill()
|
||||
end
|
||||
menu.search = {
|
||||
query = '', timeout = timeout, min_top = menu.top, max_width = menu.width,
|
||||
query = '',
|
||||
timeout = timeout,
|
||||
min_top = menu.top,
|
||||
max_width = menu.width,
|
||||
source = {
|
||||
width = menu.width, top = menu.top,
|
||||
scroll_y = menu.scroll_y, selected_index = menu.selected_index,
|
||||
items = not menu.on_search and menu.items or nil
|
||||
width = menu.width,
|
||||
top = menu.top,
|
||||
scroll_y = menu.scroll_y,
|
||||
selected_index = menu.selected_index,
|
||||
items = not menu.on_search and menu.items or nil,
|
||||
},
|
||||
}
|
||||
end
|
||||
@@ -860,34 +890,49 @@ end
|
||||
function Menu:key_esc()
|
||||
if self.current.search then
|
||||
if self.current.palette then
|
||||
if self.current.search.query == '' then self:close()
|
||||
else self:search_query_update('') end
|
||||
if self.current.search.query == '' then
|
||||
self:close()
|
||||
else
|
||||
self:search_query_update('')
|
||||
end
|
||||
else
|
||||
self:search_stop()
|
||||
end
|
||||
else self:close() end
|
||||
else
|
||||
self:close()
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:key_bs(info)
|
||||
if info.event ~= 'up' then
|
||||
if self.current.search then self:search_backspace(info.event)
|
||||
elseif info.event ~= 'repeat' then self:back() end
|
||||
if self.current.search then
|
||||
self:search_backspace(info.event)
|
||||
elseif info.event ~= 'repeat' then
|
||||
self:back()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:key_ctrl_enter()
|
||||
if self.current.search then self:search_submit()
|
||||
else self:open_selected_item_preselect() end
|
||||
if self.current.search then
|
||||
self:search_submit()
|
||||
else
|
||||
self:open_selected_item_preselect()
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:key_left()
|
||||
if self.current.search then -- control cursor when it's implemented
|
||||
else self:back() end
|
||||
else
|
||||
self:back()
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:key_right()
|
||||
if self.current.search then -- control cursor when it's implemented
|
||||
else self:open_selected_item_preselect() end
|
||||
else
|
||||
self:open_selected_item_preselect()
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:search_enable_key_bindings()
|
||||
@@ -905,8 +950,11 @@ end
|
||||
|
||||
function Menu:search_ensure_key_bindings()
|
||||
if self.type_to_search then return end
|
||||
if self.current.search then self:search_enable_key_bindings()
|
||||
else self:search_disable_key_bindings() end
|
||||
if self.current.search then
|
||||
self:search_enable_key_bindings()
|
||||
else
|
||||
self:search_disable_key_bindings()
|
||||
end
|
||||
end
|
||||
|
||||
function Menu:search_disable_key_bindings()
|
||||
@@ -942,8 +990,7 @@ function Menu:enable_key_bindings()
|
||||
self:add_key_binding('bs', 'menu-back-alt4', self:create_key_action('key_bs'), {repeatable = true, complex = true})
|
||||
self:add_key_binding('enter', 'menu-select-alt3', self:create_key_action('open_selected_item_preselect'))
|
||||
self:add_key_binding('kp_enter', 'menu-select-alt4', self:create_key_action('open_selected_item_preselect'))
|
||||
self:add_key_binding('ctrl+enter', 'menu-select-ctrl1',
|
||||
self:create_key_action('key_ctrl_enter', {ctrl = true}))
|
||||
self:add_key_binding('ctrl+enter', 'menu-select-ctrl1', self:create_key_action('key_ctrl_enter', {ctrl = true}))
|
||||
self:add_key_binding('alt+enter', 'menu-select-alt1',
|
||||
self:create_key_action('open_selected_item_preselect', {alt = true}))
|
||||
self:add_key_binding('ctrl+kp_enter', 'menu-select-ctrl2',
|
||||
@@ -1040,14 +1087,16 @@ function Menu:render()
|
||||
local start_index = math.floor(menu.scroll_y / self.scroll_step) + 1
|
||||
local end_index = math.ceil((menu.scroll_y + menu.height) / self.scroll_step)
|
||||
local menu_rect = {
|
||||
ax = ax, ay = ay - (draw_title and self.scroll_step or 0) - self.padding,
|
||||
bx = bx, by = by + self.padding
|
||||
ax = ax,
|
||||
ay = ay - (draw_title and self.scroll_step or 0) - self.padding,
|
||||
bx = bx,
|
||||
by = by + self.padding,
|
||||
}
|
||||
local blur_selected_index = is_current and self.mouse_nav
|
||||
|
||||
-- Background
|
||||
ass:rect(menu_rect.ax, menu_rect.ay, menu_rect.bx, menu_rect.by, {
|
||||
color = bg, opacity = menu_opacity * config.opacity.menu, radius = state.radius + self.padding
|
||||
color = bg, opacity = menu_opacity * config.opacity.menu, radius = state.radius + self.padding,
|
||||
})
|
||||
|
||||
if is_parent and get_point_to_rectangle_proximity(cursor, menu_rect) == 0 then
|
||||
@@ -1088,7 +1137,7 @@ function Menu:render()
|
||||
ax = menu_rect.ax + self.padding,
|
||||
ay = item_ay,
|
||||
bx = menu_rect.bx + (item.items and self.gap or -self.padding), -- to bridge the gap with cursor
|
||||
by = item_by
|
||||
by = item_by,
|
||||
}
|
||||
if submenu_is_hovered or get_point_to_rectangle_proximity(cursor, item_rect_hitbox) == 0 then
|
||||
blur_selected_index = false
|
||||
@@ -1117,7 +1166,9 @@ function Menu:render()
|
||||
local highlight_opacity = 0 + (item.active and 0.8 or 0) + (menu.selected_index == index and 0.15 or 0)
|
||||
if not is_submenu and highlight_opacity > 0 then
|
||||
ass:rect(ax + self.padding, item_ay, bx - self.padding, item_by, {
|
||||
radius = state.radius, color = fg, opacity = highlight_opacity * menu_opacity,
|
||||
radius = state.radius,
|
||||
color = fg,
|
||||
opacity = highlight_opacity * menu_opacity,
|
||||
clip = item_clip,
|
||||
})
|
||||
end
|
||||
@@ -1168,8 +1219,13 @@ function Menu:render()
|
||||
title_x, align = content_ax + (title_cut_x - content_ax) / 2, 5
|
||||
end
|
||||
ass:txt(title_x, item_center_y, align, item.ass_safe_title, {
|
||||
size = self.font_size, color = font_color, italic = item.italic, bold = item.bold, wrap = 2,
|
||||
opacity = menu_opacity * (item.muted and 0.5 or 1), clip = clip,
|
||||
size = self.font_size,
|
||||
color = font_color,
|
||||
italic = item.italic,
|
||||
bold = item.bold,
|
||||
wrap = 2,
|
||||
opacity = menu_opacity * (item.muted and 0.5 or 1),
|
||||
clip = clip,
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -1201,8 +1257,10 @@ function Menu:render()
|
||||
end
|
||||
|
||||
ass:icon(rect.ax + icon_size / 2, rect.cy, icon_size, 'search', {
|
||||
color = fg, opacity = icon_opacity,
|
||||
clip = '\\clip(' .. icon_rect.ax .. ',' .. icon_rect.ay .. ',' .. icon_rect.bx .. ',' .. icon_rect.by .. ')'
|
||||
color = fg,
|
||||
opacity = icon_opacity,
|
||||
clip = '\\clip(' ..
|
||||
icon_rect.ax .. ',' .. icon_rect.ay .. ',' .. icon_rect.bx .. ',' .. icon_rect.by .. ')',
|
||||
})
|
||||
|
||||
-- Query/Placeholder
|
||||
@@ -1210,7 +1268,10 @@ function Menu:render()
|
||||
-- Add a ZWNBSP suffix to prevent libass from trimming trailing spaces
|
||||
local query = ass_escape(menu.search.query) .. '\239\187\191'
|
||||
ass:txt(rect.bx, rect.cy, 6, query, {
|
||||
size = self.font_size, color = bgt, wrap = 2, opacity = menu_opacity,
|
||||
size = self.font_size,
|
||||
color = bgt,
|
||||
wrap = 2,
|
||||
opacity = menu_opacity,
|
||||
clip = '\\clip(' .. icon_rect.bx .. ',' .. rect.ay .. ',' .. rect.bx .. ',' .. rect.by .. ')',
|
||||
})
|
||||
else
|
||||
@@ -1218,7 +1279,11 @@ function Menu:render()
|
||||
and menu.ass_safe_title
|
||||
or (requires_submit and t('type & ctrl+enter to search') or t('type to search'))
|
||||
ass:txt(rect.bx, rect.cy, 6, placeholder, {
|
||||
size = self.font_size, italic = true, color = bgt, wrap = 2, opacity = menu_opacity * 0.4,
|
||||
size = self.font_size,
|
||||
italic = true,
|
||||
color = bgt,
|
||||
wrap = 2,
|
||||
opacity = menu_opacity * 0.4,
|
||||
clip = '\\clip(' .. rect.ax .. ',' .. rect.ay .. ',' .. rect.bx .. ',' .. rect.by .. ')',
|
||||
})
|
||||
end
|
||||
@@ -1227,12 +1292,17 @@ function Menu:render()
|
||||
local font_size_half, cursor_thickness = round(self.font_size / 2), round(self.font_size / 14)
|
||||
local cursor_ax, cursor_bx = rect.bx + 1, rect.bx + 1 + cursor_thickness
|
||||
ass:rect(cursor_ax, rect.cy - font_size_half, cursor_bx, rect.cy + font_size_half, {
|
||||
color = fg, opacity = menu_opacity * 0.5,
|
||||
color = fg,
|
||||
opacity = menu_opacity * 0.5,
|
||||
clip = '\\clip(' .. cursor_ax .. ',' .. rect.ay .. ',' .. cursor_bx .. ',' .. rect.by .. ')',
|
||||
})
|
||||
else
|
||||
ass:txt(rect.cx, rect.cy, 5, menu.ass_safe_title, {
|
||||
size = self.font_size, bold = true, color = bgt, wrap = 2, opacity = menu_opacity,
|
||||
size = self.font_size,
|
||||
bold = true,
|
||||
color = bgt,
|
||||
wrap = 2,
|
||||
opacity = menu_opacity,
|
||||
clip = '\\clip(' .. rect.ax .. ',' .. rect.ay .. ',' .. rect.bx .. ',' .. rect.by .. ')',
|
||||
})
|
||||
end
|
||||
|
@@ -127,7 +127,7 @@ function Speed:render()
|
||||
|
||||
-- Background
|
||||
ass:rect(self.ax, self.ay, self.bx, self.by, {
|
||||
color = bg, radius = state.radius, opacity = opacity * config.opacity.speed
|
||||
color = bg, radius = state.radius, opacity = opacity * config.opacity.speed,
|
||||
})
|
||||
|
||||
-- Coordinates
|
||||
@@ -166,7 +166,9 @@ function Speed:render()
|
||||
end
|
||||
|
||||
ass:rect(notch_x - notch_thickness, notch_ay, notch_x + notch_thickness, notch_by, {
|
||||
color = fg, border = 1, border_color = bg,
|
||||
color = fg,
|
||||
border = 1,
|
||||
border_color = bg,
|
||||
opacity = math.min(1.2 - (math.abs((notch_x - ax - half_width) / half_width)), 1) * opacity,
|
||||
})
|
||||
end
|
||||
@@ -186,7 +188,10 @@ function Speed:render()
|
||||
-- Speed value
|
||||
local speed_text = (round(state.speed * 100) / 100) .. 'x'
|
||||
ass:txt(half_x, ay + (notch_ay_big - ay) / 2, 5, speed_text, {
|
||||
size = self.font_size, color = bgt, border = options.text_border * state.scale, border_color = bg,
|
||||
size = self.font_size,
|
||||
color = bgt,
|
||||
border = options.text_border * state.scale,
|
||||
border_color = bg,
|
||||
opacity = opacity,
|
||||
})
|
||||
|
||||
|
@@ -83,8 +83,11 @@ function Timeline:get_time_at_x(x)
|
||||
local fbx = fax + line_width
|
||||
-- time starts 0.5 pixels in
|
||||
x = x - self.ax - 0.5
|
||||
if x > fbx then x = x - line_width
|
||||
elseif x > fax then x = fax end
|
||||
if x > fbx then
|
||||
x = x - line_width
|
||||
elseif x > fax then
|
||||
x = fax
|
||||
end
|
||||
local progress = clamp(0, x / time_width, 1)
|
||||
return state.duration * progress
|
||||
end
|
||||
@@ -133,7 +136,9 @@ function Timeline:on_global_mouse_move()
|
||||
self.pressed.last.x, self.pressed.last.y = cursor.x, cursor.y
|
||||
if state.is_video and math.abs(cursor.get_velocity().x) / self.width * state.duration > 30 then
|
||||
self:set_from_cursor(true)
|
||||
else self:set_from_cursor() end
|
||||
else
|
||||
self:set_from_cursor()
|
||||
end
|
||||
end
|
||||
end
|
||||
function Timeline:handle_wheel_up() mp.commandv('seek', options.timeline_step) end
|
||||
@@ -351,7 +356,7 @@ function Timeline:render()
|
||||
and buffered_playtime < options.buffered_time_threshold then
|
||||
local x, align = fbx + 5, 4
|
||||
local cache_opts = {
|
||||
size = self.font_size * 0.8, opacity = text_opacity * 0.6, border = options.text_border * state.scale
|
||||
size = self.font_size * 0.8, opacity = text_opacity * 0.6, border = options.text_border * state.scale,
|
||||
}
|
||||
local human = round(math.max(buffered_playtime, 0)) .. 's'
|
||||
local width = text_width(human, cache_opts)
|
||||
@@ -411,8 +416,12 @@ function Timeline:render()
|
||||
local ax, ay = (thumb_x - border), (thumb_y - border)
|
||||
local bx, by = (thumb_x + thumb_width + border), (thumb_y + thumb_height + border)
|
||||
ass:rect(ax, ay, bx, by, {
|
||||
color = bg, border = 1, opacity = config.opacity.thumbnail,
|
||||
border_color = fg, border_opacity = 0.08 * config.opacity.thumbnail, radius = state.radius
|
||||
color = bg,
|
||||
border = 1,
|
||||
opacity = config.opacity.thumbnail,
|
||||
border_color = fg,
|
||||
border_opacity = 0.08 * config.opacity.thumbnail,
|
||||
radius = state.radius,
|
||||
})
|
||||
mp.commandv('script-message-to', 'thumbfast', 'thumb', hovered_seconds, thumb_x, thumb_y)
|
||||
self.has_thumbnail, rendered_thumbnail = true, true
|
||||
@@ -421,12 +430,17 @@ function Timeline:render()
|
||||
|
||||
-- Chapter title
|
||||
if #state.chapters > 0 then
|
||||
local _, chapter = itable_find(state.chapters, function(c) return hovered_seconds >= c.time end, #state.chapters, 1)
|
||||
local _, chapter = itable_find(state.chapters, function(c) return hovered_seconds >= c.time end,
|
||||
#state.chapters, 1)
|
||||
if chapter and not chapter.is_end_only then
|
||||
ass:tooltip(tooltip_anchor, chapter.title_wrapped, {
|
||||
size = self.font_size, offset = tooltip_gap, responsive = false, bold = true,
|
||||
size = self.font_size,
|
||||
offset = tooltip_gap,
|
||||
responsive = false,
|
||||
bold = true,
|
||||
width_overwrite = chapter.title_wrapped_width * self.font_size,
|
||||
lines = chapter.title_lines, margin = tooltip_margin,
|
||||
lines = chapter.title_lines,
|
||||
margin = tooltip_margin,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@@ -62,15 +62,19 @@ function TopBar:init()
|
||||
-- Order aligns from right to left
|
||||
self.buttons = {
|
||||
TopBarButton:new('tb_close', {
|
||||
icon = 'close', background = '2311e8', command = 'quit', render_order = self.render_order
|
||||
icon = 'close', background = '2311e8', command = 'quit', render_order = self.render_order,
|
||||
}),
|
||||
TopBarButton:new('tb_max', {
|
||||
icon = 'crop_square', background = '222222', command = get_maximized_command,
|
||||
render_order = self.render_order
|
||||
icon = 'crop_square',
|
||||
background = '222222',
|
||||
command = get_maximized_command,
|
||||
render_order = self.render_order,
|
||||
}),
|
||||
TopBarButton:new('tb_min', {
|
||||
icon = 'minimize', background = '222222', command = 'cycle window-minimized',
|
||||
render_order = self.render_order
|
||||
icon = 'minimize',
|
||||
background = '222222',
|
||||
command = 'cycle window-minimized',
|
||||
render_order = self.render_order,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -117,7 +121,7 @@ function TopBar:decide_titles()
|
||||
longer_title, shorter_title = self.main_title, self.alt_title
|
||||
end
|
||||
|
||||
local escaped_shorter_title = string.gsub(shorter_title --[[@as string]], "[%(%)%.%+%-%*%?%[%]%^%$%%]", "%%%1")
|
||||
local escaped_shorter_title = string.gsub(shorter_title --[[@as string]], '[%(%)%.%+%-%*%?%[%]%^%$%%]', '%%%1')
|
||||
if string.match(longer_title --[[@as string]], escaped_shorter_title) then
|
||||
self.main_title, self.alt_title = longer_title, nil
|
||||
end
|
||||
@@ -208,7 +212,7 @@ function TopBar:render()
|
||||
ax = title_ax,
|
||||
ay = title_ay,
|
||||
bx = round(title_ax + text_width(text, opts) + padding * 2),
|
||||
by = self.by - bg_margin
|
||||
by = self.by - bg_margin,
|
||||
}
|
||||
ass:rect(rect.ax, rect.ay, rect.bx, rect.by, {color = fg, opacity = visibility, radius = state.radius})
|
||||
ass:txt(rect.ax + (rect.bx - rect.ax) / 2, rect.ay + (rect.by - rect.ay) / 2, 5, formatted_text, opts)
|
||||
@@ -226,8 +230,12 @@ function TopBar:render()
|
||||
local main_title = self.show_alt_title and self.alt_title or self.main_title
|
||||
if main_title then
|
||||
local opts = {
|
||||
size = self.font_size, wrap = 2, color = bgt, opacity = visibility,
|
||||
border = options.text_border * state.scale, border_color = bg,
|
||||
size = self.font_size,
|
||||
wrap = 2,
|
||||
color = bgt,
|
||||
opacity = visibility,
|
||||
border = options.text_border * state.scale,
|
||||
border_color = bg,
|
||||
clip = string.format('\\clip(%d, %d, %d, %d)', self.ax, self.ay, max_bx, self.by),
|
||||
}
|
||||
local bx = round(math.min(max_bx, title_ax + text_width(main_title, opts) + padding * 2))
|
||||
@@ -253,8 +261,12 @@ function TopBar:render()
|
||||
local height = font_size * 1.3
|
||||
local by = title_ay + height
|
||||
local opts = {
|
||||
size = font_size, wrap = 2, color = bgt,
|
||||
border = options.text_border * state.scale, border_color = bg, opacity = visibility
|
||||
size = font_size,
|
||||
wrap = 2,
|
||||
color = bgt,
|
||||
border = options.text_border * state.scale,
|
||||
border_color = bg,
|
||||
opacity = visibility,
|
||||
}
|
||||
local bx = round(math.min(max_bx, title_ax + text_width(self.alt_title, opts) + padding * 2))
|
||||
opts.clip = string.format('\\clip(%d, %d, %d, %d)', title_ax, title_ay, bx, by)
|
||||
@@ -271,14 +283,19 @@ function TopBar:render()
|
||||
local height = font_size * 1.3
|
||||
local text = '└ ' .. state.current_chapter.index .. ': ' .. state.current_chapter.title
|
||||
local opts = {
|
||||
size = font_size, italic = true, wrap = 2, color = bgt,
|
||||
border = options.text_border * state.scale, border_color = bg, opacity = visibility * 0.8,
|
||||
size = font_size,
|
||||
italic = true,
|
||||
wrap = 2,
|
||||
color = bgt,
|
||||
border = options.text_border * state.scale,
|
||||
border_color = bg,
|
||||
opacity = visibility * 0.8,
|
||||
}
|
||||
local rect = {
|
||||
ax = title_ax,
|
||||
ay = title_ay,
|
||||
bx = round(math.min(max_bx, title_ax + text_width(text, opts) + padding * 2)),
|
||||
by = title_ay + height
|
||||
by = title_ay + height,
|
||||
}
|
||||
opts.clip = string.format('\\clip(%d, %d, %d, %d)', title_ax, title_ay, rect.bx, rect.by)
|
||||
ass:rect(rect.ax, rect.ay, rect.bx, rect.by, {
|
||||
|
@@ -66,8 +66,10 @@ function VolumeSlider:render()
|
||||
cursor.on_wheel_down = function() self:handle_wheel_down() end
|
||||
cursor.on_wheel_up = function() self:handle_wheel_up() end
|
||||
end
|
||||
if self.pressed then cursor.on_primary_up = function()
|
||||
self.pressed = false end
|
||||
if self.pressed then
|
||||
cursor.on_primary_up = function()
|
||||
self.pressed = false
|
||||
end
|
||||
end
|
||||
|
||||
local ass = assdraw.ass_new()
|
||||
@@ -166,13 +168,17 @@ function VolumeSlider:render()
|
||||
local font_size = round(((width * 0.6) - (#volume_string * (width / 20))) * options.font_scale)
|
||||
if volume_y < self.by - self.spacing then
|
||||
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
||||
size = font_size, color = fgt, opacity = visibility,
|
||||
size = font_size,
|
||||
color = fgt,
|
||||
opacity = visibility,
|
||||
clip = '\\clip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
||||
})
|
||||
end
|
||||
if volume_y > self.by - self.spacing - font_size then
|
||||
ass:txt(self.ax + (width / 2), self.by - self.spacing, 2, volume_string, {
|
||||
size = font_size, color = bgt, opacity = visibility,
|
||||
size = font_size,
|
||||
color = bgt,
|
||||
opacity = visibility,
|
||||
clip = '\\iclip(' .. fg_path.scale .. ', ' .. fg_path.text .. ')',
|
||||
})
|
||||
end
|
||||
@@ -181,7 +187,10 @@ function VolumeSlider:render()
|
||||
if not state.has_audio then
|
||||
local fg_100_path = create_nudged_path(self.border_size, state.radius)
|
||||
local texture_opts = {
|
||||
size = 200, color = 'ffffff', opacity = visibility * 0.1, anchor_x = ax,
|
||||
size = 200,
|
||||
color = 'ffffff',
|
||||
opacity = visibility * 0.1,
|
||||
anchor_x = ax,
|
||||
clip = '\\clip(' .. fg_100_path.scale .. ',' .. fg_100_path.text .. ')',
|
||||
}
|
||||
ass:texture(ax, ay, bx, by, 'a', texture_opts)
|
||||
|
@@ -22,14 +22,20 @@ end
|
||||
|
||||
---@param opts? {submenu?: string; mouse_nav?: boolean; on_close?: string | string[]}
|
||||
function toggle_menu_with_items(opts)
|
||||
if Menu:is_open('menu') then Menu:close()
|
||||
else open_command_menu({type = 'menu', items = get_menu_items(), search_submenus = true}, opts) end
|
||||
if Menu:is_open('menu') then
|
||||
Menu:close()
|
||||
else
|
||||
open_command_menu({type = 'menu', items = get_menu_items(), search_submenus = true}, opts)
|
||||
end
|
||||
end
|
||||
|
||||
---@param options {type: string; title: string; list_prop: string; active_prop?: string; serializer: fun(list: any, active: any): MenuDataItem[]; on_select: fun(value: any); on_move_item?: fun(from_index: integer, to_index: integer, submenu_path: integer[]); on_delete_item?: fun(index: integer, submenu_path: integer[])}
|
||||
function create_self_updating_menu_opener(options)
|
||||
return function()
|
||||
if Menu:is_open(options.type) then Menu:close() return end
|
||||
if Menu:is_open(options.type) then
|
||||
Menu:close()
|
||||
return
|
||||
end
|
||||
local list = mp.get_property_native(options.list_prop)
|
||||
local active = options.active_prop and mp.get_property_native(options.active_prop) or nil
|
||||
local menu
|
||||
@@ -38,14 +44,22 @@ function create_self_updating_menu_opener(options)
|
||||
|
||||
local ignore_initial_list = true
|
||||
local function handle_list_prop_change(name, value)
|
||||
if ignore_initial_list then ignore_initial_list = false
|
||||
else list = value update() end
|
||||
if ignore_initial_list then
|
||||
ignore_initial_list = false
|
||||
else
|
||||
list = value
|
||||
update()
|
||||
end
|
||||
end
|
||||
|
||||
local ignore_initial_active = true
|
||||
local function handle_active_prop_change(name, value)
|
||||
if ignore_initial_active then ignore_initial_active = false
|
||||
else active = value update() end
|
||||
if ignore_initial_active then
|
||||
ignore_initial_active = false
|
||||
else
|
||||
active = value
|
||||
update()
|
||||
end
|
||||
end
|
||||
|
||||
local initial_items, selected_index = options.serializer(list, active)
|
||||
@@ -106,7 +120,8 @@ function create_select_tracklist_type_menu_opener(menu_title, track_type, track_
|
||||
end
|
||||
if track['demux-fps'] then h(string.format('%.5gfps', track['demux-fps'])) end
|
||||
h(track.codec)
|
||||
if track['audio-channels'] then h(t(track['audio-channels'] == 1 and '%s channel' or '%s channels', track['audio-channels'])) end
|
||||
if track['audio-channels'] then h(t(track['audio-channels'] == 1 and '%s channel' or '%s channels',
|
||||
track['audio-channels'])) end
|
||||
if track['demux-samplerate'] then h(string.format('%.3gkHz', track['demux-samplerate'] / 1000)) end
|
||||
if track.forced then h(t('forced')) end
|
||||
if track.default then h(t('default')) end
|
||||
@@ -168,7 +183,7 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
|
||||
|
||||
local files, directories = read_directory(directory.path, {
|
||||
types = opts.allowed_types,
|
||||
hidden = options.show_hidden_files
|
||||
hidden = options.show_hidden_files,
|
||||
})
|
||||
local is_root = not directory.dirname
|
||||
local path_separator = path_separator(directory.path)
|
||||
@@ -222,8 +237,11 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
|
||||
open_drives_menu(function(drive_path)
|
||||
open_file_navigation_menu(drive_path, handle_select, inheritable_options)
|
||||
end, {
|
||||
type = inheritable_options.type, title = inheritable_options.title, selected_path = directory.path,
|
||||
on_open = opts.on_open, on_close = opts.on_close,
|
||||
type = inheritable_options.type,
|
||||
title = inheritable_options.title,
|
||||
selected_path = directory.path,
|
||||
on_open = opts.on_open,
|
||||
on_close = opts.on_close,
|
||||
})
|
||||
return
|
||||
end
|
||||
@@ -252,7 +270,9 @@ function open_file_navigation_menu(directory_path, handle_select, opts)
|
||||
end
|
||||
|
||||
local menu_data = {
|
||||
type = opts.type, title = opts.title or directory.basename .. path_separator, items = items,
|
||||
type = opts.type,
|
||||
title = opts.title or directory.basename .. path_separator,
|
||||
items = items,
|
||||
selected_index = selected_index,
|
||||
}
|
||||
local menu_options = {on_open = opts.on_open, on_close = opts.on_close, on_back = handle_back}
|
||||
@@ -382,7 +402,7 @@ end
|
||||
|
||||
-- Adapted from `stats.lua`
|
||||
function get_input_items()
|
||||
local bindings = mp.get_property_native("input-bindings", {})
|
||||
local bindings = mp.get_property_native('input-bindings', {})
|
||||
local active = {} -- map: key-name -> bind-info
|
||||
local items = {}
|
||||
|
||||
@@ -412,7 +432,7 @@ function get_input_items()
|
||||
selectable = false,
|
||||
align = 'center',
|
||||
italic = true,
|
||||
muted = true
|
||||
}
|
||||
muted = true,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
@@ -52,11 +52,17 @@ local osd_width, osd_height = 100, 100
|
||||
local function utf8_char_bytes(str, i)
|
||||
local char_byte = str:byte(i)
|
||||
local max_bytes = #str - i + 1
|
||||
if char_byte < 0xC0 then return math.min(max_bytes, 1)
|
||||
elseif char_byte < 0xE0 then return math.min(max_bytes, 2)
|
||||
elseif char_byte < 0xF0 then return math.min(max_bytes, 3)
|
||||
elseif char_byte < 0xF8 then return math.min(max_bytes, 4)
|
||||
else return math.min(max_bytes, 1) end
|
||||
if char_byte < 0xC0 then
|
||||
return math.min(max_bytes, 1)
|
||||
elseif char_byte < 0xE0 then
|
||||
return math.min(max_bytes, 2)
|
||||
elseif char_byte < 0xF0 then
|
||||
return math.min(max_bytes, 3)
|
||||
elseif char_byte < 0xF8 then
|
||||
return math.min(max_bytes, 4)
|
||||
else
|
||||
return math.min(max_bytes, 1)
|
||||
end
|
||||
end
|
||||
|
||||
---Creates an iterator for an utf-8 encoded string
|
||||
@@ -98,13 +104,19 @@ end
|
||||
---@param unicode integer
|
||||
---@return string?
|
||||
local function unicode_to_utf8(unicode)
|
||||
if unicode < 0x80 then return string.char(unicode)
|
||||
if unicode < 0x80 then
|
||||
return string.char(unicode)
|
||||
else
|
||||
local byte_count
|
||||
if unicode < 0x800 then byte_count = 2
|
||||
elseif unicode < 0x10000 then byte_count = 3
|
||||
elseif unicode < 0x110000 then byte_count = 4
|
||||
else return end -- too big
|
||||
if unicode < 0x800 then
|
||||
byte_count = 2
|
||||
elseif unicode < 0x10000 then
|
||||
byte_count = 3
|
||||
elseif unicode < 0x110000 then
|
||||
byte_count = 4
|
||||
else
|
||||
return
|
||||
end -- too big
|
||||
|
||||
local res = {}
|
||||
local shift = 2 ^ 6
|
||||
@@ -134,7 +146,7 @@ end)
|
||||
|
||||
local measure_bounds
|
||||
do
|
||||
local text_osd = mp.create_osd_overlay("ass-events")
|
||||
local text_osd = mp.create_osd_overlay('ass-events')
|
||||
text_osd.compute_bounds, text_osd.hidden = true, true
|
||||
|
||||
---@param ass_text string
|
||||
@@ -277,8 +289,11 @@ do
|
||||
local size = math.min(max_size * 0.9, 50)
|
||||
char_count = math.min(math.floor(char_count * max_size / size * 0.8), 100)
|
||||
local enclosing_char, enclosing_width, next_char_count = '|', 0, char_count
|
||||
if measured_char == enclosing_char then enclosing_char = ''
|
||||
else enclosing_width = 2 * character_width(enclosing_char, bold) end
|
||||
if measured_char == enclosing_char then
|
||||
enclosing_char = ''
|
||||
else
|
||||
enclosing_width = 2 * character_width(enclosing_char, bold)
|
||||
end
|
||||
local width_ratio, width, px = nil, nil, nil
|
||||
repeat
|
||||
char_count = next_char_count
|
||||
@@ -304,7 +319,7 @@ end
|
||||
local function character_based_width(text, bold)
|
||||
local max_width = 0
|
||||
local min_px = math.huge
|
||||
for line in tostring(text):gmatch("([^\n]*)\n?") do
|
||||
for line in tostring(text):gmatch('([^\n]*)\n?') do
|
||||
local total_width = 0
|
||||
for _, char in utf8_iter(line) do
|
||||
local width, px = character_width(char, bold)
|
||||
@@ -445,8 +460,11 @@ do
|
||||
end
|
||||
end
|
||||
end
|
||||
if #text_line >= line_start then lines[#lines + 1] = text_line:sub(line_start)
|
||||
elseif text_line == '' then lines[#lines + 1] = '' end
|
||||
if #text_line >= line_start then
|
||||
lines[#lines + 1] = text_line:sub(line_start)
|
||||
elseif text_line == '' then
|
||||
lines[#lines + 1] = ''
|
||||
end
|
||||
end
|
||||
return table.concat(lines, '\n'), #lines
|
||||
end
|
||||
|
@@ -53,8 +53,11 @@ function tween(from, to, setter, duration_or_callback, callback)
|
||||
local is_end = math.abs(to - current) <= cutoff
|
||||
setter(is_end and to or current)
|
||||
request_render()
|
||||
if is_end then finish()
|
||||
else timeout:resume() end
|
||||
if is_end then
|
||||
finish()
|
||||
else
|
||||
timeout:resume()
|
||||
end
|
||||
end
|
||||
|
||||
timeout = mp.add_timeout(state.render_delay, tick)
|
||||
@@ -237,9 +240,13 @@ end
|
||||
---@param path string
|
||||
---@return boolean
|
||||
function is_absolute(path)
|
||||
if path:sub(1, 2) == '\\\\' then return true
|
||||
elseif state.platform == 'windows' then return path:find('^%a+:') ~= nil
|
||||
else return path:sub(1, 1) == '/' end
|
||||
if path:sub(1, 2) == '\\\\' then
|
||||
return true
|
||||
elseif state.platform == 'windows' then
|
||||
return path:find('^%a+:') ~= nil
|
||||
else
|
||||
return path:sub(1, 1) == '/'
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure path is absolute.
|
||||
@@ -287,9 +294,13 @@ function normalize_path(path)
|
||||
path = trim_trailing_separator(path)
|
||||
|
||||
--Deduplication of path separators
|
||||
if is_unc then path = path:gsub('(.\\)\\+', '%1')
|
||||
elseif state.platform == 'windows' then path = path:gsub('\\\\+', '\\')
|
||||
else path = path:gsub('//+', '/') end
|
||||
if is_unc then
|
||||
path = path:gsub('(.\\)\\+', '%1')
|
||||
elseif state.platform == 'windows' then
|
||||
path = path:gsub('\\\\+', '\\')
|
||||
else
|
||||
path = path:gsub('//+', '/')
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
@@ -355,14 +366,16 @@ function read_directory(path, opts)
|
||||
local files, directories = {}, {}
|
||||
|
||||
for _, item in ipairs(items) do
|
||||
if item ~= '.' and item ~= '..' and (opts.hidden or item:sub(1, 1) ~= ".") then
|
||||
if item ~= '.' and item ~= '..' and (opts.hidden or item:sub(1, 1) ~= '.') then
|
||||
local info = utils.file_info(join_path(path, item))
|
||||
if info then
|
||||
if info.is_file then
|
||||
if not opts.types or has_any_extension(item, opts.types) then
|
||||
files[#files + 1] = item
|
||||
end
|
||||
else directories[#directories + 1] = item end
|
||||
else
|
||||
directories[#directories + 1] = item
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -410,7 +423,7 @@ function decide_navigation_in_list(paths, current_index, delta)
|
||||
if state.shuffle then
|
||||
state.shuffle_history = state.shuffle_history or {
|
||||
pos = #state.history,
|
||||
paths = itable_slice(state.history)
|
||||
paths = itable_slice(state.history),
|
||||
}
|
||||
state.shuffle_history.pos = state.shuffle_history.pos + delta
|
||||
local history_path = state.shuffle_history.paths[state.shuffle_history.pos]
|
||||
@@ -442,8 +455,11 @@ function decide_navigation_in_list(paths, current_index, delta)
|
||||
|
||||
local new_index = current_index + delta
|
||||
if mp.get_property_native('loop-playlist') then
|
||||
if new_index > #paths then new_index = new_index % #paths
|
||||
elseif new_index < 1 then new_index = #paths - new_index end
|
||||
if new_index > #paths then
|
||||
new_index = new_index % #paths
|
||||
elseif new_index < 1 then
|
||||
new_index = #paths - new_index
|
||||
end
|
||||
elseif new_index < 1 or new_index > #paths then
|
||||
return
|
||||
end
|
||||
@@ -456,11 +472,14 @@ function navigate_directory(delta)
|
||||
if not state.path or is_protocol(state.path) then return false end
|
||||
local paths, current_index = get_adjacent_files(state.path, {
|
||||
types = config.types.autoload,
|
||||
hidden = options.show_hidden_files
|
||||
hidden = options.show_hidden_files,
|
||||
})
|
||||
if paths and current_index then
|
||||
local _, path = decide_navigation_in_list(paths, current_index, delta)
|
||||
if path then mp.commandv('loadfile', path) return true end
|
||||
if path then
|
||||
mp.commandv('loadfile', path)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -497,9 +516,9 @@ function delete_file(path)
|
||||
]]
|
||||
|
||||
local escaped_path = string.gsub(path, "'", "''")
|
||||
escaped_path = string.gsub(escaped_path, "’", "’’")
|
||||
escaped_path = string.gsub(escaped_path, "%%", "%%%%")
|
||||
ps_code = string.gsub(ps_code, "__path__", escaped_path)
|
||||
escaped_path = string.gsub(escaped_path, '’', '’’')
|
||||
escaped_path = string.gsub(escaped_path, '%%', '%%%%')
|
||||
ps_code = string.gsub(ps_code, '__path__', escaped_path)
|
||||
args = {'powershell', '-NoProfile', '-Command', ps_code}
|
||||
else
|
||||
args = {'cmd', '/C', 'del', path}
|
||||
@@ -524,23 +543,37 @@ end
|
||||
function serialize_chapter_ranges(normalized_chapters)
|
||||
local ranges = {}
|
||||
local simple_ranges = {
|
||||
{name = 'openings', patterns = {
|
||||
{
|
||||
name = 'openings',
|
||||
patterns = {
|
||||
'^op ', '^op$', ' op$',
|
||||
'^opening$', ' opening$'
|
||||
}, requires_next_chapter = true},
|
||||
{name = 'intros', patterns = {
|
||||
'^opening$', ' opening$',
|
||||
},
|
||||
requires_next_chapter = true
|
||||
},
|
||||
{
|
||||
name = 'intros',
|
||||
patterns = {
|
||||
'^intro$', ' intro$',
|
||||
'^avant$', '^prologue$'
|
||||
}, requires_next_chapter = true},
|
||||
{name = 'endings', patterns = {
|
||||
'^avant$', '^prologue$',
|
||||
},
|
||||
requires_next_chapter = true
|
||||
},
|
||||
{
|
||||
name = 'endings',
|
||||
patterns = {
|
||||
'^ed ', '^ed$', ' ed$',
|
||||
'^ending ', '^ending$', ' ending$',
|
||||
}},
|
||||
{name = 'outros', patterns = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name = 'outros',
|
||||
patterns = {
|
||||
'^outro$', ' outro$',
|
||||
'^closing$', '^closing ',
|
||||
'^preview$', '^pv$',
|
||||
}},
|
||||
}
|
||||
},
|
||||
}
|
||||
local sponsor_ranges = {}
|
||||
|
||||
@@ -580,8 +613,10 @@ function serialize_chapter_ranges(normalized_chapters)
|
||||
local end_match = end_chapter.lowercase_title:match('segment end *%(' .. id .. '%)')
|
||||
if end_match then
|
||||
local range = table_assign({
|
||||
start_chapter = chapter, end_chapter = end_chapter,
|
||||
start = chapter.time, ['end'] = end_chapter.time,
|
||||
start_chapter = chapter,
|
||||
end_chapter = end_chapter,
|
||||
start = chapter.time,
|
||||
['end'] = end_chapter.time,
|
||||
}, config.chapter_ranges.ads)
|
||||
ranges[#ranges + 1], sponsor_ranges[#sponsor_ranges + 1] = range, range
|
||||
end_chapter.is_end_only = true
|
||||
@@ -663,10 +698,10 @@ function render()
|
||||
local smaller_side = math.min(display.width, display.height)
|
||||
local center_x, center_y, icon_size = display.width / 2, display.height / 2, math.max(smaller_side / 4, 56)
|
||||
ass:icon(center_x, center_y - icon_size / 4, icon_size, 'not_started', {
|
||||
color = fg, opacity = config.opacity.idle_indicator
|
||||
color = fg, opacity = config.opacity.idle_indicator,
|
||||
})
|
||||
ass:txt(center_x, center_y + icon_size / 2, 8, t('Drop files or URLs to play here'), {
|
||||
size = icon_size / 4, color = fg, opacity = config.opacity.idle_indicator
|
||||
size = icon_size / 4, color = fg, opacity = config.opacity.idle_indicator,
|
||||
})
|
||||
end
|
||||
|
||||
@@ -675,7 +710,7 @@ function render()
|
||||
and not (state.pause and options.pause_indicator == 'static') then
|
||||
local smaller_side = math.min(display.width, display.height)
|
||||
ass:icon(display.width / 2, display.height / 2, smaller_side / 4, 'graphic_eq', {
|
||||
color = fg, opacity = config.opacity.audio_indicator
|
||||
color = fg, opacity = config.opacity.audio_indicator,
|
||||
})
|
||||
end
|
||||
|
||||
|
@@ -24,7 +24,8 @@ defaults = {
|
||||
timeline_step = 5,
|
||||
timeline_cache = true,
|
||||
|
||||
controls = 'menu,gap,subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,gap,space,speed,space,shuffle,loop-playlist,loop-file,gap,prev,items,next,gap,fullscreen',
|
||||
controls =
|
||||
'menu,gap,subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,gap,space,speed,space,shuffle,loop-playlist,loop-file,gap,prev,items,next,gap,fullscreen',
|
||||
controls_size = 32,
|
||||
controls_margin = 8,
|
||||
controls_spacing = 2,
|
||||
@@ -85,8 +86,10 @@ defaults = {
|
||||
buffered_time_threshold = 60,
|
||||
pause_indicator = 'flash',
|
||||
stream_quality_options = '4320,2160,1440,1080,720,480,360,240,144',
|
||||
video_types= '3g2,3gp,asf,avi,f4v,flv,h264,h265,m2ts,m4v,mkv,mov,mp4,mp4v,mpeg,mpg,ogm,ogv,rm,rmvb,ts,vob,webm,wmv,y4m',
|
||||
audio_types= 'aac,ac3,aiff,ape,au,cue,dsf,dts,flac,m4a,mid,midi,mka,mp3,mp4a,oga,ogg,opus,spx,tak,tta,wav,weba,wma,wv',
|
||||
video_types =
|
||||
'3g2,3gp,asf,avi,f4v,flv,h264,h265,m2ts,m4v,mkv,mov,mp4,mp4v,mpeg,mpg,ogm,ogv,rm,rmvb,ts,vob,webm,wmv,y4m',
|
||||
audio_types =
|
||||
'aac,ac3,aiff,ape,au,cue,dsf,dts,flac,m4a,mid,midi,mka,mp3,mp4a,oga,ogg,opus,spx,tak,tta,wav,weba,wma,wv',
|
||||
image_types = 'apng,avif,bmp,gif,j2k,jp2,jfif,jpeg,jpg,jxl,mj2,png,svg,tga,tif,tiff,webp',
|
||||
subtitle_types = 'aqt,ass,gsub,idx,jss,lrc,mks,pgs,pjs,psb,rt,sbv,slt,smi,sub,sup,srt,ssa,ssf,ttxt,txt,usf,vt,vtt',
|
||||
default_directory = '~/',
|
||||
@@ -188,11 +191,23 @@ config = {
|
||||
return ranges
|
||||
end)(),
|
||||
opacity = {
|
||||
timeline = 0.9, position = 1, chapters = 0.8, slider = 0.9, slider_gauge = 1, speed = 0.6,
|
||||
menu = 1, submenu = 0.4, border = 1, title = 1, tooltip = 1, thumbnail = 1, curtain = 0.5,
|
||||
idle_indicator = 0.8, audio_indicator = 0.5
|
||||
timeline = 0.9,
|
||||
position = 1,
|
||||
chapters = 0.8,
|
||||
slider = 0.9,
|
||||
slider_gauge = 1,
|
||||
speed = 0.6,
|
||||
menu = 1,
|
||||
submenu = 0.4,
|
||||
border = 1,
|
||||
title = 1,
|
||||
tooltip = 1,
|
||||
thumbnail = 1,
|
||||
curtain = 0.5,
|
||||
idle_indicator = 0.8,
|
||||
audio_indicator = 0.5,
|
||||
},
|
||||
cursor_leave_fadeout_elements = {'timeline', 'volume', 'top_bar', 'controls'}
|
||||
cursor_leave_fadeout_elements = {'timeline', 'volume', 'top_bar', 'controls'},
|
||||
}
|
||||
-- Adds `{element}_persistency` property with table of flags when the element should be visible (`{paused = true}`)
|
||||
for _, name in ipairs({'timeline', 'controls', 'volume', 'top_bar', 'speed'}) do
|
||||
@@ -221,28 +236,47 @@ function create_default_menu_items()
|
||||
{title = t('Stream quality'), value = 'script-binding uosc/stream-quality'},
|
||||
{title = t('Playlist'), value = 'script-binding uosc/items'},
|
||||
{title = t('Chapters'), value = 'script-binding uosc/chapters'},
|
||||
{title = t('Navigation'), items = {
|
||||
{title = t('Next'), hint = t('playlist or file'), value = 'script-binding uosc/next'},
|
||||
{title = t('Prev'), hint = t('playlist or file'), value = 'script-binding uosc/prev'},
|
||||
{
|
||||
title = t('Navigation'),
|
||||
items = {
|
||||
{
|
||||
title = t('Next'),
|
||||
hint = t('playlist or file'),
|
||||
value =
|
||||
'script-binding uosc/next'
|
||||
},
|
||||
{
|
||||
title = t('Prev'),
|
||||
hint = t('playlist or file'),
|
||||
value =
|
||||
'script-binding uosc/prev'
|
||||
},
|
||||
{title = t('Delete file & Next'), value = 'script-binding uosc/delete-file-next'},
|
||||
{title = t('Delete file & Prev'), value = 'script-binding uosc/delete-file-prev'},
|
||||
{title = t('Delete file & Quit'), value = 'script-binding uosc/delete-file-quit'},
|
||||
{title = t('Open file'), value = 'script-binding uosc/open-file'},
|
||||
},},
|
||||
{title = t('Utils'), items = {
|
||||
{title = t('Aspect ratio'), items = {
|
||||
},
|
||||
},
|
||||
{
|
||||
title = t('Utils'),
|
||||
items = {
|
||||
{
|
||||
title = t('Aspect ratio'),
|
||||
items = {
|
||||
{title = t('Default'), value = 'set video-aspect-override "-1"'},
|
||||
{title = '16:9', value = 'set video-aspect-override "16:9"'},
|
||||
{title = '4:3', value = 'set video-aspect-override "4:3"'},
|
||||
{title = '2.35:1', value = 'set video-aspect-override "2.35:1"'},
|
||||
},},
|
||||
},
|
||||
},
|
||||
{title = t('Audio devices'), value = 'script-binding uosc/audio-device'},
|
||||
{title = t('Editions'), value = 'script-binding uosc/editions'},
|
||||
{title = t('Screenshot'), value = 'async screenshot'},
|
||||
{title = t('Inputs'), value = 'script-binding uosc/inputs'},
|
||||
{title = t('Show in directory'), value = 'script-binding uosc/show-in-directory'},
|
||||
{title = t('Open config folder'), value = 'script-binding uosc/open-config-directory'},
|
||||
},},
|
||||
},
|
||||
},
|
||||
{title = t('Quit'), value = 'quit'},
|
||||
}
|
||||
end
|
||||
@@ -314,8 +348,11 @@ cursor = {
|
||||
-- displays the top bar, so we hardcode cursor position as infinity until
|
||||
-- we receive a first real mouse move event with coordinates other than 0,0.
|
||||
if not cursor.first_real_mouse_move_received then
|
||||
if x > 0 and y > 0 then cursor.first_real_mouse_move_received = true
|
||||
else x, y = math.huge, math.huge end
|
||||
if x > 0 and y > 0 then
|
||||
cursor.first_real_mouse_move_received = true
|
||||
else
|
||||
x, y = math.huge, math.huge
|
||||
end
|
||||
end
|
||||
|
||||
-- Add 0.5 to be in the middle of the pixel
|
||||
@@ -389,7 +426,7 @@ cursor = {
|
||||
if not prev then return false end
|
||||
local end_x, end_y = cursor.x + (cursor.x - prev.x) * 1e10, cursor.y + (cursor.y - prev.y) * 1e10
|
||||
return get_ray_to_rectangle_distance(cursor.x, cursor.y, end_x, end_y, rect)
|
||||
end
|
||||
end,
|
||||
}
|
||||
state = {
|
||||
platform = (function()
|
||||
@@ -457,7 +494,7 @@ state = {
|
||||
margin_right = 0,
|
||||
hidpi_scale = 1,
|
||||
scale = 1,
|
||||
radius = 0
|
||||
radius = 0,
|
||||
}
|
||||
thumbnail = {width = 0, height = 0, disabled = false}
|
||||
external = {} -- Properties set by external scripts
|
||||
@@ -527,18 +564,26 @@ function update_margins()
|
||||
-- margins are normalized to window size
|
||||
local left, right, top, bottom = 0, 0, 0, 0
|
||||
|
||||
if causes_margin(controls) then bottom = (display.height - controls.ay) / display.height
|
||||
elseif causes_margin(timeline) then bottom = (display.height - timeline.ay) / display.height end
|
||||
if causes_margin(controls) then
|
||||
bottom = (display.height - controls.ay) / display.height
|
||||
elseif causes_margin(timeline) then
|
||||
bottom = (display.height - timeline.ay) / display.height
|
||||
end
|
||||
|
||||
if causes_margin(top_bar) then top = top_bar.title_by / display.height end
|
||||
|
||||
if causes_margin(volume) then
|
||||
if options.volume == 'left' then left = volume.bx / display.width
|
||||
elseif options.volume == 'right' then right = volume.ax / display.width end
|
||||
if options.volume == 'left' then
|
||||
left = volume.bx / display.width
|
||||
elseif options.volume == 'right' then
|
||||
right = volume.ax / display.width
|
||||
end
|
||||
end
|
||||
|
||||
if top == state.margin_top and bottom == state.margin_bottom and
|
||||
left == state.margin_left and right == state.margin_right then return end
|
||||
left == state.margin_left and right == state.margin_right then
|
||||
return
|
||||
end
|
||||
|
||||
state.margin_top = top
|
||||
state.margin_bottom = bottom
|
||||
@@ -552,10 +597,16 @@ function update_margins()
|
||||
|
||||
if not options.adjust_osd_margins then return end
|
||||
local osd_margin_y, osd_margin_x, osd_factor_x = 0, 0, display.width / display.height * 720
|
||||
if config.osd_alignment_y == 'bottom' then osd_margin_y = round(bottom * 720)
|
||||
elseif config.osd_alignment_y == 'top' then osd_margin_y = round(top * 720) end
|
||||
if config.osd_alignment_x == 'left' then osd_margin_x = round(left * osd_factor_x)
|
||||
elseif config.osd_alignment_x == 'right' then osd_margin_x = round(right * osd_factor_x) end
|
||||
if config.osd_alignment_y == 'bottom' then
|
||||
osd_margin_y = round(bottom * 720)
|
||||
elseif config.osd_alignment_y == 'top' then
|
||||
osd_margin_y = round(top * 720)
|
||||
end
|
||||
if config.osd_alignment_x == 'left' then
|
||||
osd_margin_x = round(left * osd_factor_x)
|
||||
elseif config.osd_alignment_x == 'right' then
|
||||
osd_margin_x = round(right * osd_factor_x)
|
||||
end
|
||||
mp.set_property_native('osd-margin-y', osd_margin_y + config.osd_margin_y)
|
||||
mp.set_property_native('osd-margin-x', osd_margin_x + config.osd_margin_x)
|
||||
end
|
||||
@@ -576,8 +627,11 @@ end
|
||||
function handle_file_end()
|
||||
local resume = false
|
||||
if not state.loop_file then
|
||||
if state.has_playlist then resume = state.shuffle and navigate_playlist(1)
|
||||
else resume = options.autoload and navigate_directory(1) end
|
||||
if state.has_playlist then
|
||||
resume = state.shuffle and navigate_playlist(1)
|
||||
else
|
||||
resume = options.autoload and navigate_directory(1)
|
||||
end
|
||||
end
|
||||
-- Resume only when navigation happened
|
||||
if resume then mp.command('set pause no') end
|
||||
@@ -592,7 +646,7 @@ function load_file_index_in_current_directory(index)
|
||||
if serialized and serialized.dirname then
|
||||
local files = read_directory(serialized.dirname, {
|
||||
types = config.types.autoload,
|
||||
hidden = options.show_hidden_files
|
||||
hidden = options.show_hidden_files,
|
||||
})
|
||||
|
||||
if not files then return end
|
||||
@@ -645,7 +699,7 @@ if options.click_threshold > 0 then
|
||||
last_down = mp.get_time()
|
||||
if click_timer:is_enabled() then click_timer:kill() else click_timer:resume() end
|
||||
end,
|
||||
},}, 'mouse_movement', 'force')
|
||||
}}, 'mouse_movement', 'force')
|
||||
mp.enable_key_bindings('mouse_movement', 'allow-vo-dragging+allow-hide-cursor')
|
||||
end
|
||||
|
||||
@@ -736,7 +790,9 @@ mp.observe_property('playback-time', 'number', create_state_setter('time', funct
|
||||
if timeout > 0 then
|
||||
file_end_timer.timeout = timeout
|
||||
file_end_timer:resume()
|
||||
else handle_file_end() end
|
||||
else
|
||||
handle_file_end()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -750,9 +806,14 @@ mp.observe_property('track-list', 'native', function(name, value)
|
||||
local types = {sub = 0, image = 0, audio = 0, video = 0}
|
||||
for _, track in ipairs(value) do
|
||||
if track.type == 'video' then
|
||||
if track.image or track.albumart then types.image = types.image + 1
|
||||
else types.video = types.video + 1 end
|
||||
elseif types[track.type] then types[track.type] = types[track.type] + 1 end
|
||||
if track.image or track.albumart then
|
||||
types.image = types.image + 1
|
||||
else
|
||||
types.video = types.video + 1
|
||||
end
|
||||
elseif types[track.type] then
|
||||
types[track.type] = types[track.type] + 1
|
||||
end
|
||||
end
|
||||
set_state('is_audio', types.video == 0 and types.audio > 0)
|
||||
set_state('is_image', types.image > 0 and types.video == 0 and types.audio == 0)
|
||||
@@ -814,7 +875,9 @@ mp.observe_property('demuxer-cache-state', 'native', function(prop, cache_state)
|
||||
if cache_state then
|
||||
cached_ranges, bof, eof = cache_state['seekable-ranges'], cache_state['bof-cached'], cache_state['eof-cached']
|
||||
set_state('cache_underrun', cache_state['underrun'])
|
||||
else cached_ranges = {} end
|
||||
else
|
||||
cached_ranges = {}
|
||||
end
|
||||
|
||||
if not (state.duration and (#cached_ranges > 0 or state.cache == 'yes' or
|
||||
(state.cache == 'auto' and state.is_stream))) then
|
||||
@@ -890,8 +953,11 @@ mp.set_key_bindings({
|
||||
---@param flags nil|string
|
||||
function bind_command(name, callback, flags)
|
||||
mp.add_key_binding(nil, name, function(...)
|
||||
if key_binding_overwrites[name] then mp.command(key_binding_overwrites[name])
|
||||
else callback(...) end
|
||||
if key_binding_overwrites[name] then
|
||||
mp.command(key_binding_overwrites[name])
|
||||
else
|
||||
callback(...)
|
||||
end
|
||||
end, flags)
|
||||
end
|
||||
|
||||
@@ -908,8 +974,11 @@ bind_command('decide-pause-indicator', function() Elements:maybe('pause_indicato
|
||||
bind_command('menu', function() toggle_menu_with_items() end)
|
||||
bind_command('menu-blurred', function() toggle_menu_with_items({mouse_nav = true}) end)
|
||||
bind_command('inputs', function()
|
||||
if Menu:is_open('inputs') then Menu:close()
|
||||
else open_command_menu({type = 'inputs', items = get_input_items(), palette = true}) end
|
||||
if Menu:is_open('inputs') then
|
||||
Menu:close()
|
||||
else
|
||||
open_command_menu({type = 'inputs', items = get_input_items(), palette = true})
|
||||
end
|
||||
end)
|
||||
local track_loaders = {
|
||||
{name = 'subtitles', prop = 'sub', allowed_types = itable_join(config.types.video, config.types.subtitle)},
|
||||
@@ -919,7 +988,10 @@ local track_loaders = {
|
||||
for _, loader in ipairs(track_loaders) do
|
||||
local menu_type = 'load-' .. loader.name
|
||||
bind_command(menu_type, function()
|
||||
if Menu:is_open(menu_type) then Menu:close() return end
|
||||
if Menu:is_open(menu_type) then
|
||||
Menu:close()
|
||||
return
|
||||
end
|
||||
|
||||
local path = state.path
|
||||
if path then
|
||||
@@ -1031,7 +1103,10 @@ bind_command('show-in-directory', function()
|
||||
end
|
||||
end)
|
||||
bind_command('stream-quality', function()
|
||||
if Menu:is_open('stream-quality') then Menu:close() return end
|
||||
if Menu:is_open('stream-quality') then
|
||||
Menu:close()
|
||||
return
|
||||
end
|
||||
|
||||
local ytdl_format = mp.get_property_native('ytdl-format')
|
||||
local items = {}
|
||||
@@ -1067,7 +1142,10 @@ bind_command('stream-quality', function()
|
||||
end)
|
||||
end)
|
||||
bind_command('open-file', function()
|
||||
if Menu:is_open('open-file') then Menu:close() return end
|
||||
if Menu:is_open('open-file') then
|
||||
Menu:close()
|
||||
return
|
||||
end
|
||||
|
||||
local directory
|
||||
local active_file
|
||||
@@ -1153,7 +1231,7 @@ bind_command('delete-file-next', function()
|
||||
if is_local_file then
|
||||
local paths, current_index = get_adjacent_files(state.path, {
|
||||
types = config.types.autoload,
|
||||
hidden = options.show_hidden_files
|
||||
hidden = options.show_hidden_files,
|
||||
})
|
||||
if paths and current_index then
|
||||
local index, path = decide_navigation_in_list(paths, current_index, 1)
|
||||
@@ -1161,8 +1239,11 @@ bind_command('delete-file-next', function()
|
||||
end
|
||||
end
|
||||
|
||||
if next_file then mp.commandv('loadfile', next_file)
|
||||
else mp.commandv('stop') end
|
||||
if next_file then
|
||||
mp.commandv('loadfile', next_file)
|
||||
else
|
||||
mp.commandv('stop')
|
||||
end
|
||||
end
|
||||
|
||||
if is_local_file then delete_file(state.path) end
|
||||
@@ -1186,7 +1267,8 @@ bind_command('audio-device', create_self_updating_menu_opener({
|
||||
local hint = string.match(device.name, ao .. '/(.+)')
|
||||
if not hint then hint = device.name end
|
||||
items[#items + 1] = {
|
||||
title = device.description:sub(1, 7) == 'Default' and t('Default %s', device.description:sub(9)) or t(device.description),
|
||||
title = device.description:sub(1, 7) == 'Default' and t('Default %s', device.description:sub(9)) or
|
||||
t(device.description),
|
||||
hint = hint,
|
||||
active = device.name == current_device,
|
||||
value = device.name,
|
||||
@@ -1295,7 +1377,7 @@ Manager = {
|
||||
---@type table<string, string[]> A map of clients and a list of element ids they disable
|
||||
_disabled_by = {},
|
||||
---@type table<string, boolean>
|
||||
disabled = {}
|
||||
disabled = {},
|
||||
}
|
||||
|
||||
-- Set client and which elements it wishes disabled. To undo just pass an empty `element_ids` for the same `client`.
|
||||
|
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
local example_chapters = {
|
||||
openings = {
|
||||
yes = {
|
||||
@@ -7,8 +5,8 @@ local example_chapters = {
|
||||
'Opening',
|
||||
},
|
||||
no = {
|
||||
'Opening the box'
|
||||
}
|
||||
'Opening the box',
|
||||
},
|
||||
},
|
||||
intros = {
|
||||
yes = {
|
||||
@@ -18,7 +16,7 @@ local example_chapters = {
|
||||
'Prologue',
|
||||
},
|
||||
no = {
|
||||
}
|
||||
},
|
||||
},
|
||||
endings = {
|
||||
yes = {
|
||||
@@ -28,7 +26,7 @@ local example_chapters = {
|
||||
no = {
|
||||
'end of the thread',
|
||||
'trending',
|
||||
}
|
||||
},
|
||||
},
|
||||
outros = {
|
||||
yes = {
|
||||
@@ -38,28 +36,42 @@ local example_chapters = {
|
||||
'PV',
|
||||
},
|
||||
no = {
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local simple_ranges = {
|
||||
{name = 'openings', patterns = {
|
||||
{
|
||||
name = 'openings',
|
||||
patterns = {
|
||||
'^op ', '^op$', ' op$',
|
||||
'^opening$', ' opening$'
|
||||
}, requires_next_chapter = true},
|
||||
{name = 'intros', patterns = {
|
||||
'^opening$', ' opening$',
|
||||
},
|
||||
requires_next_chapter = true
|
||||
},
|
||||
{
|
||||
name = 'intros',
|
||||
patterns = {
|
||||
'^intro$', ' intro$',
|
||||
'^avant$', '^prologue$'
|
||||
}, requires_next_chapter = true},
|
||||
{name = 'endings', patterns = {
|
||||
'^avant$', '^prologue$',
|
||||
},
|
||||
requires_next_chapter = true
|
||||
},
|
||||
{
|
||||
name = 'endings',
|
||||
patterns = {
|
||||
'^ed ', '^ed$', ' ed$',
|
||||
'^ending ', '^ending$', ' ending$',
|
||||
}},
|
||||
{name = 'outros', patterns = {
|
||||
}
|
||||
},
|
||||
{
|
||||
name = 'outros',
|
||||
patterns = {
|
||||
'^outro$', ' outro$',
|
||||
'^closing$', '^closing ',
|
||||
'^preview$', '^pv$',
|
||||
}},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
local function find_any(s, patterns)
|
||||
|
Reference in New Issue
Block a user