fb.lua (6839B)
1 local mp = require 'mp' 2 local msg = require 'mp.msg' 3 local utils = require 'mp.utils' 4 5 local o = require 'modules.options' 6 local g = require 'modules.globals' 7 local fb_utils = require 'modules.utils' 8 local ass = require 'modules.ass' 9 local directory_movement = require 'modules.navigation.directory-movement' 10 local scanning = require 'modules.navigation.scanning' 11 local controls = require 'modules.controls' 12 13 ---@class FbAPI: fb_utils 14 local fb = setmetatable({}, { __index = setmetatable({}, { __index = fb_utils }) }) 15 package.loaded["file-browser"] = setmetatable({}, { __index = fb }) 16 17 --these functions we'll provide as-is 18 fb.redraw = ass.update_ass 19 fb.browse_directory = controls.browse_directory 20 21 ---Clears the directory cache. 22 ---@return thread 23 function fb.rescan() 24 return scanning.rescan() 25 end 26 27 ---@async 28 ---@return thread 29 function fb.rescan_await() 30 local co = scanning.rescan(nil, fb_utils.coroutine.callback()) 31 coroutine.yield() 32 return co 33 end 34 35 ---@param directories? string[] 36 function fb.clear_cache(directories) 37 if directories then 38 mp.commandv('script-message-to', mp.get_script_name(), 'cache/clear', utils.format_json(directories)) 39 else 40 mp.commandv('script-message-to', mp.get_script_name(), 'cache/clear') 41 end 42 end 43 44 ---A wrapper around scan_directory for addon API. 45 ---@async 46 ---@param directory string 47 ---@param parse_state ParseStateTemplate 48 ---@return Item[]|nil 49 ---@return Opts 50 function fb.parse_directory(directory, parse_state) 51 if not parse_state then parse_state = { source = "addon" } 52 elseif not parse_state.source then parse_state.source = "addon" end 53 return scanning.scan_directory(directory, parse_state) 54 end 55 56 ---Register file extensions which can be opened by the browser. 57 ---@param ext string 58 function fb.register_parseable_extension(ext) 59 g.parseable_extensions[string.lower(ext)] = true 60 end 61 62 ---Deregister file extensions which can be opened by the browser. 63 ---@param ext string 64 function fb.remove_parseable_extension(ext) 65 g.parseable_extensions[string.lower(ext)] = nil 66 end 67 68 ---Add a compatible extension to show through the filter, only applies if run during the setup() method. 69 ---@param ext string 70 function fb.add_default_extension(ext) 71 table.insert(g.compatible_file_extensions, ext) 72 end 73 74 ---Add item to root at position pos. 75 ---@param item Item 76 ---@param pos? number 77 function fb.insert_root_item(item, pos) 78 msg.debug("adding item to root", item.label or item.name, pos) 79 item.ass = item.ass or fb.ass_escape(item.label or item.name) 80 item.type = "dir" 81 table.insert(g.root, pos or (#g.root + 1), item) 82 end 83 84 ---Add a new mapping to the given directory. 85 ---@param directory string 86 ---@param mapping string 87 ---@param pattern? boolean 88 ---@return string 89 function fb.register_directory_mapping(directory, mapping, pattern) 90 if not pattern then mapping = '^'..fb_utils.pattern_escape(mapping) end 91 g.directory_mappings[mapping] = directory 92 msg.verbose('registering directory alias', mapping, directory) 93 94 directory_movement.set_current_file(g.current_file.original_path) 95 return mapping 96 end 97 98 ---Remove all directory mappings that map to the given directory. 99 ---@param directory string 100 ---@return string[] 101 function fb.remove_all_mappings(directory) 102 local removed = {} 103 for mapping, target in pairs(g.directory_mappings) do 104 if target == directory then 105 g.directory_mappings[mapping] = nil 106 table.insert(removed, mapping) 107 end 108 end 109 return removed 110 end 111 112 ---A newer API for adding items to the root. 113 ---Only adds the item if the same item does not already exist in the root. 114 ---@param item Item|string 115 ---@param priority? number Specifies the insertion location, a lower priority 116 --- is placed higher in the list and the default is 100. 117 ---@return boolean 118 function fb.register_root_item(item, priority) 119 msg.verbose('registering root item:', utils.to_string(item)) 120 if type(item) == 'string' then 121 item = {name = item, type = 'dir'} 122 end 123 124 -- if the item is already in the list then do nothing 125 if fb.list.some(g.root, function(r) 126 return fb.get_full_path(r, '') == fb.get_full_path(item, '') 127 end) then return false end 128 129 ---@type table<Item,number> 130 local priorities = {} 131 132 priorities[item] = priority 133 for i, v in ipairs(g.root) do 134 if (priorities[v] or 100) > (priority or 100) then 135 fb.insert_root_item(item, i) 136 return true 137 end 138 end 139 fb.insert_root_item(item) 140 return true 141 end 142 143 --providing getter and setter functions so that addons can't modify things directly 144 145 146 ---@param key string 147 ---@return boolean|string|number 148 function fb.get_opt(key) return o[key] end 149 150 function fb.get_script_opts() return fb.copy_table(o) end 151 function fb.get_platform() return g.PLATFORM end 152 function fb.get_extensions() return fb.copy_table(g.extensions) end 153 function fb.get_sub_extensions() return fb.copy_table(g.sub_extensions) end 154 function fb.get_audio_extensions() return fb.copy_table(g.audio_extensions) end 155 function fb.get_parseable_extensions() return fb.copy_table(g.parseable_extensions) end 156 function fb.get_state() return fb.copy_table(g.state) end 157 function fb.get_parsers() return fb.copy_table(g.parsers) end 158 function fb.get_root() return fb.copy_table(g.root) end 159 function fb.get_directory() return g.state.directory end 160 function fb.get_list() return fb.copy_table(g.state.list) end 161 function fb.get_current_file() return fb.copy_table(g.current_file) end 162 function fb.get_current_parser() return g.state.parser:get_id() end 163 function fb.get_current_parser_keyname() return g.state.parser.keybind_name or g.state.parser.name end 164 function fb.get_selected_index() return g.state.selected end 165 function fb.get_selected_item() return fb.copy_table(g.state.list[g.state.selected]) end 166 function fb.get_open_status() return not g.state.hidden end 167 function fb.get_parse_state(co) return g.parse_states[co or coroutine.running() or ""] end 168 function fb.get_history() return fb.copy_table(g.history.list) end 169 function fb.get_history_index() return g.history.position end 170 171 ---@deprecated 172 ---@return string|nil 173 function fb.get_dvd_device() 174 local dvd_device = mp.get_property('dvd-device') 175 if not dvd_device or dvd_device == '' then return nil end 176 return fb_utils.fix_path(dvd_device, true) 177 end 178 179 ---@param str string 180 function fb.set_empty_text(str) 181 g.state.empty_text = str 182 fb.redraw() 183 end 184 185 ---@param index number 186 ---@return number|false 187 function fb.set_selected_index(index) 188 if type(index) ~= "number" then return false end 189 if index < 1 then index = 1 end 190 if index > #g.state.list then index = #g.state.list end 191 g.state.selected = index 192 fb.redraw() 193 return index 194 end 195 196 fb.set_history_index = directory_movement.goto_history 197 198 return fb