├── Makefile ├── README.md ├── luasrc ├── controller │ └── filebrowser.lua ├── model │ └── cbi │ │ └── filebrowser │ │ ├── api.lua │ │ └── settings.lua └── view │ └── filebrowser │ ├── download.htm │ ├── log.htm │ └── status.htm ├── po └── zh_Hans │ └── filebrowser.po ├── preview.png ├── preview2.png └── root ├── etc ├── config │ └── filebrowser ├── init.d │ └── filebrowser └── uci-defaults │ └── luci-app-filebrowser └── usr └── share └── rpcd └── acl.d └── luci-app-filebrowser.json /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018-2020 Lienol 2 | # 3 | # This is free software, licensed under the Apache License, Version 2.0 . 4 | # 5 | # Improve by xiaozhuai 6 | # 7 | 8 | include $(TOPDIR)/rules.mk 9 | 10 | LUCI_TITLE:=LuCI support for FileBrowser 11 | LUCI_PKGARCH:=all 12 | 13 | 14 | include $(TOPDIR)/feeds/luci/luci.mk 15 | 16 | # call BuildPackage - OpenWrt buildroot signature 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # luci-app-filebrowser 2 | 在Lienol的源码基础上改进而来,添加了更多特性和配置项。 3 | 4 | 在OpenWRT中配置filebrowser的LUCI应用 5 | 6 | 此分支适用于OpenWRT 19.*,需要提前安装`luci-compat`包 7 | 8 | 18.06请使用18.06分支 9 | 10 | 由于可执行文件很大,至少32MB,因此ipk中不集成filebrowser的可执行文件。 11 | 12 | 首次运行前,需要手动下载可执行文件,如果你的空间足够大,推荐可执行文件目录配置为`/usr/bin`,否则根据需要放到你认为合适的目录。(路径不能包含空格) 13 | 14 | ![preview.png](preview.png) 15 | 16 | ![preview2.png](preview2.png) 17 | 18 | 19 | # 构建 20 | 21 | Release页有编译好的ipk包,可直接安装,或者可以手动编译 22 | 23 | ``` 24 | git clone https://github.com/xiaozhuai/luci-app-filebrowser package/luci-app-filebrowser 25 | make package/luci-app-filebrowser/compile 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /luasrc/controller/filebrowser.lua: -------------------------------------------------------------------------------- 1 | -- Copyright 2018-2020 Lienol 2 | -- Improve by xiaozhuai 3 | module("luci.controller.filebrowser", package.seeall) 4 | 5 | local http = require "luci.http" 6 | local api = require "luci.model.cbi.filebrowser.api" 7 | 8 | function index() 9 | if not nixio.fs.access("/etc/config/filebrowser") then return end 10 | 11 | entry({"admin", "services"}, firstchild(), "Services", 44).dependent = false 12 | entry({"admin", "services", "filebrowser"}, cbi("filebrowser/settings"), 13 | _("File Browser"), 2).dependent = true 14 | 15 | entry({"admin", "services", "filebrowser", "check"}, call("action_check")).leaf = 16 | true 17 | entry({"admin", "services", "filebrowser", "download"}, call("action_download")).leaf = 18 | true 19 | entry({"admin", "services", "filebrowser", "status"}, call("act_status")).leaf = 20 | true 21 | entry({"admin", "services", "filebrowser", "get_log"}, call("get_log")).leaf = 22 | true 23 | entry({"admin", "services", "filebrowser", "clear_log"}, call("clear_log")).leaf = 24 | true 25 | end 26 | 27 | local function http_write_json(content) 28 | http.prepare_content("application/json") 29 | http.write_json(content or {code = 1}) 30 | end 31 | 32 | function act_status() 33 | local e = {} 34 | e.status = luci.sys.call("ps -w | grep -v grep | grep 'filebrowser -a' >/dev/null") == 0 35 | http_write_json(e) 36 | end 37 | 38 | function action_check() 39 | local json = api.to_check() 40 | http_write_json(json) 41 | end 42 | 43 | function action_download() 44 | local json = nil 45 | local task = http.formvalue("task") 46 | if task == "extract" then 47 | json = api.to_extract(http.formvalue("file")) 48 | elseif task == "move" then 49 | json = api.to_move(http.formvalue("file")) 50 | else 51 | json = api.to_download(http.formvalue("url")) 52 | end 53 | http_write_json(json) 54 | end 55 | 56 | function get_log() 57 | luci.http.write(luci.sys.exec("[ -f '/var/log/filebrowser.log' ] && cat /var/log/filebrowser.log")) 58 | end 59 | function clear_log() luci.sys.call("echo '' > /var/log/filebrowser.log") end 60 | -------------------------------------------------------------------------------- /luasrc/model/cbi/filebrowser/api.lua: -------------------------------------------------------------------------------- 1 | local fs = require "nixio.fs" 2 | local sys = require "luci.sys" 3 | local uci = require"luci.model.uci".cursor() 4 | local util = require "luci.util" 5 | local i18n = require "luci.i18n" 6 | 7 | module("luci.model.cbi.filebrowser.api", package.seeall) 8 | 9 | local appname = "filebrowser" 10 | local api_url = 11 | "https://api.github.com/repos/filebrowser/filebrowser/releases/latest" 12 | 13 | local wget = "/usr/bin/wget" 14 | local wget_args = { 15 | "--no-check-certificate", "--quiet", "--timeout=10", "--tries=2" 16 | } 17 | local command_timeout = 300 18 | 19 | local LEDE_BOARD = nil 20 | local DISTRIB_TARGET = nil 21 | 22 | function uci_get_type(type, config, default) 23 | value = uci:get_first(appname, type, config, default) or sys.exec( 24 | "echo -n `uci -q get " .. appname .. ".@" .. type .. "[0]." .. 25 | config .. "`") 26 | if (value == nil or value == "") and (default and default ~= "") then 27 | value = default 28 | end 29 | return value 30 | end 31 | 32 | local function _unpack(t, i) 33 | i = i or 1 34 | if t[i] ~= nil then return t[i], _unpack(t, i + 1) end 35 | end 36 | 37 | local function exec(cmd, args, writer, timeout) 38 | local os = require "os" 39 | local nixio = require "nixio" 40 | 41 | local fdi, fdo = nixio.pipe() 42 | local pid = nixio.fork() 43 | 44 | if pid > 0 then 45 | fdo:close() 46 | 47 | if writer or timeout then 48 | local starttime = os.time() 49 | while true do 50 | if timeout and os.difftime(os.time(), starttime) >= timeout then 51 | nixio.kill(pid, nixio.const.SIGTERM) 52 | return 1 53 | end 54 | 55 | if writer then 56 | local buffer = fdi:read(2048) 57 | if buffer and #buffer > 0 then 58 | writer(buffer) 59 | end 60 | end 61 | 62 | local wpid, stat, code = nixio.waitpid(pid, "nohang") 63 | 64 | if wpid and stat == "exited" then return code end 65 | 66 | if not writer and timeout then nixio.nanosleep(1) end 67 | end 68 | else 69 | local wpid, stat, code = nixio.waitpid(pid) 70 | return wpid and stat == "exited" and code 71 | end 72 | elseif pid == 0 then 73 | nixio.dup(fdo, nixio.stdout) 74 | fdi:close() 75 | fdo:close() 76 | nixio.exece(cmd, args, nil) 77 | nixio.stdout:close() 78 | os.exit(1) 79 | end 80 | end 81 | 82 | local function compare_versions(ver1, comp, ver2) 83 | local table = table 84 | 85 | local av1 = util.split(ver1, "[%.%-]", nil, true) 86 | local av2 = util.split(ver2, "[%.%-]", nil, true) 87 | 88 | local max = table.getn(av1) 89 | local n2 = table.getn(av2) 90 | if (max < n2) then max = n2 end 91 | 92 | for i = 1, max, 1 do 93 | local s1 = av1[i] or "" 94 | local s2 = av2[i] or "" 95 | 96 | if comp == "~=" and (s1 ~= s2) then return true end 97 | if (comp == "<" or comp == "<=") and (s1 < s2) then return true end 98 | if (comp == ">" or comp == ">=") and (s1 > s2) then return true end 99 | if (s1 ~= s2) then return false end 100 | end 101 | 102 | return not (comp == "<" or comp == ">") 103 | end 104 | 105 | local function auto_get_arch() 106 | local arch = nixio.uname().machine or "" 107 | if fs.access("/usr/lib/os-release") then 108 | LEDE_BOARD = sys.exec( 109 | "echo -n `grep 'LEDE_BOARD' /usr/lib/os-release | awk -F '[\\042\\047]' '{print $2}'`") 110 | end 111 | if fs.access("/etc/openwrt_release") then 112 | DISTRIB_TARGET = sys.exec( 113 | "echo -n `grep 'DISTRIB_TARGET' /etc/openwrt_release | awk -F '[\\042\\047]' '{print $2}'`") 114 | end 115 | 116 | if arch == "mips" then 117 | if LEDE_BOARD and LEDE_BOARD ~= "" then 118 | if string.match(LEDE_BOARD, "ramips") == "ramips" then 119 | arch = "ramips" 120 | else 121 | arch = sys.exec("echo '" .. LEDE_BOARD .. 122 | "' | grep -oE 'ramips|ar71xx'") 123 | end 124 | elseif DISTRIB_TARGET and DISTRIB_TARGET ~= "" then 125 | if string.match(DISTRIB_TARGET, "ramips") == "ramips" then 126 | arch = "ramips" 127 | else 128 | arch = sys.exec("echo '" .. DISTRIB_TARGET .. 129 | "' | grep -oE 'ramips|ar71xx'") 130 | end 131 | end 132 | end 133 | 134 | return util.trim(arch) 135 | end 136 | 137 | local function get_file_info(arch) 138 | local file_tree = "" 139 | local sub_version = "" 140 | 141 | if arch == "x86_64" then 142 | file_tree = "amd64" 143 | elseif arch == "aarch64" then 144 | file_tree = "arm64" 145 | elseif arch == "ramips" then 146 | file_tree = "mipsle" 147 | elseif arch == "ar71xx" then 148 | file_tree = "mips" 149 | elseif arch:match("^i[%d]86$") then 150 | file_tree = "386" 151 | elseif arch:match("^armv[5-8]") then 152 | file_tree = "armv" 153 | sub_version = arch:match("[5-8]") 154 | if LEDE_BOARD and string.match(LEDE_BOARD, "bcm53xx") == "bcm53xx" then 155 | sub_version = "5" 156 | elseif DISTRIB_TARGET and string.match(DISTRIB_TARGET, "bcm53xx") == 157 | "bcm53xx" then 158 | sub_version = "5" 159 | end 160 | sub_version = "5" 161 | end 162 | 163 | return file_tree, sub_version 164 | end 165 | 166 | local function get_api_json(url) 167 | local jsonc = require "luci.jsonc" 168 | 169 | local output = {} 170 | -- exec(wget, { "-O-", url, _unpack(wget_args) }, 171 | -- function(chunk) output[#output + 1] = chunk end) 172 | -- local json_content = util.trim(table.concat(output)) 173 | 174 | local json_content = luci.sys.exec(wget .. 175 | " --no-check-certificate --timeout=10 -t 1 -O- " .. 176 | url) 177 | 178 | if json_content == "" then return {} end 179 | 180 | return jsonc.parse(json_content) or {} 181 | end 182 | 183 | function get_version() return uci_get_type("global", "version", "0") end 184 | 185 | function to_check(arch) 186 | if not arch or arch == "" then arch = auto_get_arch() end 187 | 188 | local file_tree, sub_version = get_file_info(arch) 189 | 190 | if file_tree == "" then 191 | return { 192 | code = 1, 193 | error = i18n.translate( 194 | "Can't determine ARCH, or ARCH not supported.") 195 | } 196 | end 197 | 198 | local json = get_api_json(api_url) 199 | 200 | if json.tag_name == nil then 201 | return { 202 | code = 1, 203 | error = i18n.translate("Get remote version info failed.") 204 | } 205 | end 206 | 207 | local remote_version = json.tag_name:match("[^v]+") 208 | 209 | local needs_update = compare_versions(get_version(), "<", remote_version) 210 | local html_url, download_url 211 | 212 | if needs_update then 213 | html_url = json.html_url 214 | for _, v in ipairs(json.assets) do 215 | if v.name and v.name:match("linux%-" .. file_tree .. sub_version) then 216 | download_url = v.browser_download_url 217 | break 218 | end 219 | end 220 | end 221 | 222 | if needs_update and not download_url then 223 | return { 224 | code = 1, 225 | version = remote_version, 226 | html_url = html_url, 227 | error = i18n.translate( 228 | "New version found, but failed to get new version download url.") 229 | } 230 | end 231 | 232 | return { 233 | code = 0, 234 | update = needs_update, 235 | version = remote_version, 236 | url = {html = html_url, download = download_url} 237 | } 238 | end 239 | 240 | function to_download(url) 241 | if not url or url == "" then 242 | return {code = 1, error = i18n.translate("Download url is required.")} 243 | end 244 | 245 | sys.call("/bin/rm -f /tmp/filebrowser_download.*") 246 | 247 | local tmp_file = util.trim(util.exec( 248 | "mktemp -u -t filebrowser_download.XXXXXX")) 249 | 250 | local result = exec(wget, {"-O", tmp_file, url, _unpack(wget_args)}, nil, 251 | command_timeout) == 0 252 | 253 | if not result then 254 | exec("/bin/rm", {"-f", tmp_file}) 255 | return { 256 | code = 1, 257 | error = i18n.translatef("File download failed or timed out: %s", url) 258 | } 259 | end 260 | 261 | return {code = 0, file = tmp_file} 262 | end 263 | 264 | function to_extract(file, subfix) 265 | if not file or file == "" or not fs.access(file) then 266 | return {code = 1, error = i18n.translate("File path required.")} 267 | end 268 | 269 | sys.call("/bin/rm -rf /tmp/filebrowser_extract.*") 270 | local tmp_dir = util.trim(util.exec( 271 | "mktemp -d -t filebrowser_extract.XXXXXX")) 272 | 273 | local output = {} 274 | exec("/bin/tar", {"-C", tmp_dir, "-zxvf", file}, 275 | function(chunk) output[#output + 1] = chunk end) 276 | 277 | local files = util.split(table.concat(output)) 278 | 279 | exec("/bin/rm", {"-f", file}) 280 | 281 | if not new_file then 282 | for _, f in pairs(files) do 283 | if f:match("filebrowser") then 284 | new_file = tmp_dir .. "/" .. util.trim(f) 285 | break 286 | end 287 | end 288 | end 289 | 290 | if not new_file then 291 | exec("/bin/rm", {"-rf", tmp_dir}) 292 | return { 293 | code = 1, 294 | error = i18n.translatef("Can't find client in file: %s", file) 295 | } 296 | end 297 | 298 | return {code = 0, file = new_file} 299 | end 300 | 301 | function to_move(file) 302 | if not file or file == "" or not fs.access(file) then 303 | sys.call("/bin/rm -rf /tmp/filebrowser_extract.*") 304 | return {code = 1, error = i18n.translate("Client file is required.")} 305 | end 306 | local executable_directory = 307 | uci_get_type("global", "executable_directory", "/tmp") 308 | luci.sys.exec("mkdir -p " .. executable_directory) 309 | local client_path = executable_directory .. "/" .. appname 310 | local client_path_bak 311 | 312 | if fs.access(client_path) then 313 | client_path_bak = "/tmp/" .. appname .. ".bak" 314 | exec("/bin/mv", {"-f", client_path, client_path_bak}) 315 | end 316 | 317 | local result = exec("/bin/mv", {"-f", file, client_path}, nil, 318 | command_timeout) == 0 319 | 320 | if not result or not fs.access(client_path) then 321 | if client_path_bak then 322 | exec("/bin/mv", {"-f", client_path_bak, client_path}) 323 | end 324 | return { 325 | code = 1, 326 | error = i18n.translatef("Can't move new file to path: %s", 327 | client_path) 328 | } 329 | end 330 | 331 | exec("/bin/chmod", {"755", client_path}) 332 | 333 | if client_path_bak then exec("/bin/rm", {"-f", client_path_bak}) end 334 | 335 | sys.call("/bin/rm -rf /tmp/filebrowser_extract.*") 336 | 337 | return {code = 0} 338 | end 339 | -------------------------------------------------------------------------------- /luasrc/model/cbi/filebrowser/settings.lua: -------------------------------------------------------------------------------- 1 | m = Map("filebrowser", translate("FileBrowser"), translate( 2 | "File explorer is software that creates your own cloud that you can install on a server, point it to a path, and then access your files through a beautiful web interface. You have many features available!")) 3 | m:append(Template("filebrowser/status")) 4 | 5 | s = m:section(TypedSection, "global", translate("Global Settings")) 6 | s.anonymous = true 7 | s.addremove = false 8 | 9 | o = s:option(Flag, "enable", translate("Enable")) 10 | o.rmempty = false 11 | 12 | o = s:option(Value, "address", translate("Listen address")) 13 | o.default = "0.0.0.0" 14 | o.rmempty = false 15 | 16 | o = s:option(Value, "port", translate("Listen port")) 17 | o.datatype = "port" 18 | o.default = 8088 19 | o.rmempty = false 20 | 21 | o = s:option(Value, "database", translate("Database path")) 22 | o.default = "/etc/filebrowser.db" 23 | o.rmempty = false 24 | 25 | o = s:option(Value, "username", translate("Initial username")) 26 | o.default = "admin" 27 | o.rmempty = false 28 | 29 | o = s:option(Value, "password", translate("Initial password")) 30 | o.default = "admin" 31 | o.rmempty = false 32 | 33 | o = s:option(Value, "ssl_cert", translate("SSL cert")) 34 | o.default = "" 35 | 36 | o = s:option(Value, "ssl_key", translate("SSL key")) 37 | o.default = "" 38 | 39 | o = s:option(Value, "root_path", translate("Root path"), translate( 40 | "Point to a path to access your files in the web interface, default is /root")) 41 | o.default = "/root" 42 | o.rmempty = false 43 | 44 | o = s:option(Value, "executable_directory", translate("Executable directory"), 45 | translate( 46 | "The file size is large, requiring at least 32M space. It is recommended to insert a usb flash drive or hard disk, or use it in the tmp directory
For example, /mnt/sda1
For example, /tmp")) 47 | o.default = "/tmp" 48 | o.rmempty = false 49 | 50 | o = s:option(Button, "_download", translate("Manually download"), translate( 51 | "Make sure you have enough space.
Be sure to fill out the executable storage directory the first time you run it, and then save the application. Then manually download, otherwise can not use!")) 52 | o.template = "filebrowser/download" 53 | o.inputstyle = "apply" 54 | o.btnclick = "downloadClick(this);" 55 | o.id = "download_btn" 56 | 57 | m:append(Template("filebrowser/log")) 58 | 59 | return m 60 | -------------------------------------------------------------------------------- /luasrc/view/filebrowser/download.htm: -------------------------------------------------------------------------------- 1 | <% 2 | local dsp = require "luci.dispatcher" 3 | -%> 4 | 5 | 155 | 156 | <%+cbi/valueheader%> 157 | <% if self:cfgvalue(section) ~= false then %> 158 | " type="button"<%= 159 | attr("name", cbid) .. 160 | attr("id", self.id or cbid) .. 161 | attr("value", self.inputtitle or self.title) .. 162 | ifattr(self.btnclick, "onclick", self.btnclick) .. 163 | ifattr(self.placeholder, "placeholder") 164 | %> /> 165 | 166 | <% else %> 167 | - 168 | <% end %> 169 | <%+cbi/valuefooter%> 170 | -------------------------------------------------------------------------------- /luasrc/view/filebrowser/log.htm: -------------------------------------------------------------------------------- 1 | 25 |
26 | 27 | <%:Logs%> 28 | 29 | 30 | 31 |
32 | -------------------------------------------------------------------------------- /luasrc/view/filebrowser/status.htm: -------------------------------------------------------------------------------- 1 | <% 2 | local dsp = require "luci.dispatcher" 3 | -%> 4 | 5 |
6 | <%:Running Status%> 7 |
8 |
9 | 10 |

<%:Collecting data...%>

11 |
12 |
13 |
14 | 15 | 39 | -------------------------------------------------------------------------------- /po/zh_Hans/filebrowser.po: -------------------------------------------------------------------------------- 1 | msgid "File Browser" 2 | msgstr "文件浏览器" 3 | 4 | msgid "File explorer is software that creates your own cloud that you can install on a server, point it to a path, and then access your files through a beautiful web interface. You have many features available!" 5 | msgstr "文件浏览器是一种创建你自己的云的软件,你可以在服务器上安装它,将它指向一个路径,然后通过一个漂亮的web界面访问你的文件。您有许多可用的特性!" 6 | 7 | msgid "RUNNING" 8 | msgstr "运行中" 9 | 10 | msgid "NOT RUNNING" 11 | msgstr "未运行" 12 | 13 | msgid "Enter interface" 14 | msgstr "进入界面" 15 | 16 | msgid "Global Settings" 17 | msgstr "全局设置" 18 | 19 | msgid "Enable" 20 | msgstr "启用" 21 | 22 | msgid "Listen address" 23 | msgstr "监听地址" 24 | 25 | msgid "Listen port" 26 | msgstr "监听端口" 27 | 28 | msgid "Initial username" 29 | msgstr "初始账户" 30 | 31 | msgid "Initial password" 32 | msgstr "初始密码" 33 | 34 | msgid "SSL cert" 35 | msgstr "SSL 证书" 36 | 37 | msgid "SSL key" 38 | msgstr "SSL 私钥" 39 | 40 | msgid "Database path" 41 | msgstr "数据库路径" 42 | 43 | msgid "Root path" 44 | msgstr "指向路径" 45 | 46 | msgid "Point to a path to access your files in the web interface, default is /root" 47 | msgstr "指向一个路径,可在web界面访问你的文件,默认为 /root" 48 | 49 | msgid "Executable directory" 50 | msgstr "可执行文件存放目录" 51 | 52 | msgid "The file size is large, requiring at least 32M space. It is recommended to insert a usb flash drive or hard disk, or use it in the tmp directory
For example, /mnt/sda1
For example, /tmp" 53 | msgstr "文件较大,至少需要32M空间。建议插入U盘或硬盘,或放入tmp目录里使用
例如:/mnt/sda1
例如:/tmp" 54 | 55 | msgid "Manually download" 56 | msgstr "手动下载" 57 | 58 | msgid "Make sure you have enough space.
Be sure to fill out the executable storage directory the first time you run it, and then save the application. Then manually download, otherwise can not use!" 59 | msgstr "请确保具有足够的空间。
第一次运行务必填好项目存放目录,然后保存应用。再手动下载,否则无法使用!" 60 | 61 | msgid "Logs" 62 | msgstr "日志" 63 | 64 | msgid "Clear logs" 65 | msgstr "清空日志" 66 | 67 | msgid "It is the latest version" 68 | msgstr "已是最新版本" 69 | 70 | msgid "Download successful" 71 | msgstr "下载成功" 72 | 73 | msgid "Click to download" 74 | msgstr "点击下载" 75 | 76 | msgid "Updating..." 77 | msgstr "更新中" 78 | 79 | msgid "Unexpected error" 80 | msgstr "意外错误" 81 | 82 | msgid "Download, are you sure to close?" 83 | msgstr "正在下载,你确认要关闭吗?" 84 | 85 | msgid "Downloading..." 86 | msgstr "下载中" 87 | 88 | msgid "Unpacking..." 89 | msgstr "解压中" 90 | 91 | msgid "Moving..." 92 | msgstr "移动中" 93 | 94 | msgid "The latest version:" 95 | msgstr "最新版本:" 96 | 97 | msgid "Can't determine ARCH, or ARCH not supported." 98 | msgstr "无法确认ARCH架构,或是不支持。" 99 | 100 | msgid "Get remote version info failed." 101 | msgstr "获取远程版本信息失败。" 102 | 103 | msgid "New version found, but failed to get new version download url." 104 | msgstr "发现新版本,但未能获得新版本的下载地址。" 105 | 106 | msgid "Download url is required." 107 | msgstr "请指定下载地址。" 108 | 109 | msgid "File download failed or timed out: %s" 110 | msgstr "文件下载失败或超时:%s" 111 | 112 | msgid "File path required." 113 | msgstr "请指定文件路径。" 114 | 115 | msgid "Can't find client in file: %s" 116 | msgstr "无法在文件中找到客户端:%s" 117 | 118 | msgid "Client file is required." 119 | msgstr "请指定客户端文件。" 120 | 121 | msgid "The client file is not suitable for current device." 122 | msgstr "客户端文件不适合当前设备。" 123 | 124 | msgid "Can't move new file to path: %s" 125 | msgstr "无法移动新文件到:%s" 126 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaozhuai/luci-app-filebrowser/54659c9d1193200e90bacb25d890d683a30399a8/preview.png -------------------------------------------------------------------------------- /preview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaozhuai/luci-app-filebrowser/54659c9d1193200e90bacb25d890d683a30399a8/preview2.png -------------------------------------------------------------------------------- /root/etc/config/filebrowser: -------------------------------------------------------------------------------- 1 | 2 | config global 3 | option address '0.0.0.0' 4 | option port '8088' 5 | option database '/etc/filebrowser.db' 6 | option username 'admin' 7 | option password 'admin' 8 | option ssl_cert '' 9 | option ssl_key '' 10 | option root_path '/root' 11 | option executable_directory '/tmp' 12 | option enable '0' 13 | 14 | -------------------------------------------------------------------------------- /root/etc/init.d/filebrowser: -------------------------------------------------------------------------------- 1 | #!/bin/sh /etc/rc.common 2 | # Copyright (C) 2018-2020 Lienol 3 | # Improve by xiaozhuai 4 | 5 | START=99 6 | 7 | LOG_PATH="/var/log/filebrowser.log" 8 | 9 | echolog() { 10 | echo -e "$(date "+%Y-%m-%d %H:%M:%S"): $1" >> $LOG_PATH 11 | } 12 | 13 | config_t_get() { 14 | local index=0 15 | [ -n "$4" ] && index=$4 16 | local ret=$(uci get filebrowser.@$1[$index].$2 2>/dev/null) 17 | echo ${ret:=$3} 18 | } 19 | start() { 20 | ENABLED=$(config_t_get global enable 0) 21 | [ "$ENABLED" = "0" ] && return 22 | ADDRESS=$(config_t_get global address 0.0.0.0) 23 | PORT=$(config_t_get global port 8088) 24 | DATABASE=$(config_t_get global database /etc/filebrowser.db) 25 | USERNAME=$(config_t_get global username admin) 26 | PASSWORD=$(config_t_get global password admin) 27 | SSL_CERT=$(config_t_get global ssl_cert) 28 | SSL_KEY=$(config_t_get global ssl_key) 29 | ROOT_PATH=$(config_t_get global root_path /root) 30 | executable_directory=$(config_t_get global executable_directory /tmp) 31 | [ ! -f "$executable_directory/filebrowser" ] && echolog "$executable_directory/filebrowser not exists, please download first" && exit 32 | 33 | SSL_PARAMS="" 34 | [ -n "$SSL_CERT" ] && [ -n "$SSL_KEY" ] && SSL_PARAMS="-t $SSL_CERT -k $SSL_KEY" 35 | PASSWORD="$($executable_directory/filebrowser hash "$PASSWORD")" 36 | $executable_directory/filebrowser -a $ADDRESS -p $PORT -r $ROOT_PATH -d "$DATABASE" --username $USERNAME --password $PASSWORD $SSL_PARAMS -l $LOG_PATH >/dev/null 2>&1 & 37 | } 38 | 39 | stop() { 40 | ps -w | grep -v "grep" | grep "$executable_directory/filebrowser -a" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & 41 | rm -rf $LOG_PATH 42 | } 43 | 44 | restart() { 45 | stop 46 | sleep 1 47 | start 48 | } 49 | -------------------------------------------------------------------------------- /root/etc/uci-defaults/luci-app-filebrowser: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | uci -q batch <<-EOF >/dev/null 4 | delete ucitrack.@filebrowser[-1] 5 | add ucitrack filebrowser 6 | set ucitrack.@filebrowser[-1].init=filebrowser 7 | commit ucitrack 8 | EOF 9 | 10 | rm -f /tmp/luci-indexcache 11 | exit 0 12 | -------------------------------------------------------------------------------- /root/usr/share/rpcd/acl.d/luci-app-filebrowser.json: -------------------------------------------------------------------------------- 1 | { 2 | "luci-app-filebrowser": { 3 | "description": "Grant UCI access for luci-app-filebrowser", 4 | "read": { 5 | "uci": [ "filebrowser" ] 6 | }, 7 | "write": { 8 | "uci": [ "filebrowser" ] 9 | } 10 | } 11 | } 12 | --------------------------------------------------------------------------------