diff --git a/applications/luci-app-chinesesubfinder/luasrc/model/cbi/chinesesubfinder.lua b/applications/luci-app-chinesesubfinder/luasrc/model/cbi/chinesesubfinder.lua index bef9881..48ae2ba 100644 --- a/applications/luci-app-chinesesubfinder/luasrc/model/cbi/chinesesubfinder.lua +++ b/applications/luci-app-chinesesubfinder/luasrc/model/cbi/chinesesubfinder.lua @@ -48,7 +48,7 @@ for _, val in pairs(paths) do end o.default = default_path -o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") +o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") o.datatype = "string" return m diff --git a/applications/luci-app-codeserver/Makefile b/applications/luci-app-codeserver/Makefile new file mode 100644 index 0000000..6ae2bca --- /dev/null +++ b/applications/luci-app-codeserver/Makefile @@ -0,0 +1,18 @@ + + +include $(TOPDIR)/rules.mk + +PKG_VERSION:=1.0.0-20221114 +PKG_RELEASE:= + +LUCI_TITLE:=LuCI support for CodeServer +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+docker +luci-lib-taskd + +define Package/luci-app-codeserver/conffiles +/etc/config/codeserver +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-codeserver/luasrc/controller/codeserver.lua b/applications/luci-app-codeserver/luasrc/controller/codeserver.lua new file mode 100755 index 0000000..24643bf --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/controller/codeserver.lua @@ -0,0 +1,9 @@ + +module("luci.controller.codeserver", package.seeall) + +function index() + entry({"admin", "services", "codeserver"}, alias("admin", "services", "codeserver", "config"), _("CodeServer"), 30).dependent = true + entry({"admin", "services", "codeserver", "config"}, cbi("codeserver/config"), _("Config"), 10).leaf = true + entry({"admin", "services", "codeserver", "tool"}, form("codeserver/tool"), _("Tool"), 30).leaf = true + entry({"admin", "services", "codeserver", "console"}, form("codeserver/console"), _("Console"), 50).leaf = true +end diff --git a/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/config.lua b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/config.lua new file mode 100644 index 0000000..e5cfb8b --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/config.lua @@ -0,0 +1,64 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local taskd = require "luci.model.tasks" +local codeserver_model = require "luci.model.codeserver" +local m, s, o + +m = taskd.docker_map("codeserver", "codeserver", "/usr/libexec/istorec/codeserver.sh", + translate("CodeServer"), + translate("CodeServer is a web version of VSCode.") + .. translate("Official website:") .. ' https://coder.com/') + +s = m:section(SimpleSection, translate("Service Status"), translate("CodeServer status:")) +s:append(Template("codeserver/status")) + +s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:")) +s.addremove=false +s.anonymous=true + +o = s:option(Value, "http_port", translate("HTTP Port").."*") +o.default = "8082" +o.datatype = "string" + +o = s:option(Value, "image_name", translate("Image").."*") +o.rmempty = false +o.datatype = "string" +o:value("lscr.io/linuxserver/code-server:latest", "lscr.io/linuxserver/code-server:latest") +o:value("lscr.io/linuxserver/code-server:4.8.3", "lscr.io/linuxserver/code-server:4.8.3") +o.default = "lscr.io/linuxserver/code-server:latest" + +local blocks = codeserver_model.blocks() +local home = codeserver_model.home() + +o = s:option(Value, "config_path", translate("Config path").."*") +o.rmempty = false +o.datatype = "string" + +local paths, default_path = codeserver_model.find_paths(blocks, home, "Configs") +for _, val in pairs(paths) do + o:value(val, val) +end +o.default = default_path + +o = s:option(Value, "env_password", "PASSWORD") +o.password = true +o.datatype = "string" + +o = s:option(Value, "env_hashed_password", "HASHED_PASSWORD") +o.datatype = "string" +o.password = true + +o = s:option(Value, "env_sudo_password", "SUDO_PASSWORD") +o.password = true +o.datatype = "string" + +o = s:option(Value, "env_sudo_password_hash", "SUDO_PASSWORD_HASH") +o.password = true +o.datatype = "string" + +o = s:option(Value, "env_proxy_domain", "PROXY_DOMAIN") +o.datatype = "string" + +return m diff --git a/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/console.lua b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/console.lua new file mode 100644 index 0000000..0ad9e8b --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/console.lua @@ -0,0 +1,110 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + + +require "luci.util" + +local docker = require "luci.model.docker" +local dk = docker.new() + +local container_name = "codeserver" + +local m, s, o +local images, networks, container_info, res + +res = dk.containers:inspect({name = container_name}) +if res.code < 300 then + container_info = res.body +else + return +end + +m=SimpleForm("Console", "", translate("Only works in LAN")) +m.submit = false +m.reset = false + +local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil +local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil + +if cmd_docker and cmd_ttyd and container_info.State.Status == "running" then + local cmd = "/bin/bash" + local uid + + s = m:section(SimpleSection) + + o = s:option(Value, "command", translate("Command")) + o:value("/bin/sh", "/bin/sh") + o:value("/bin/ash", "/bin/ash") + o:value("/bin/bash", "/bin/bash") + o.default = "/bin/bash" + o.forcewrite = true + o.write = function(self, section, value) + cmd = value + end + + o = s:option(Value, "uid", translate("UID")) + o.forcewrite = true + o.write = function(self, section, value) + uid = value + end + + o = s:option(Button, "connect") + o.render = function(self, section, scope) + self.inputstyle = "add" + self.title = " " + self.inputtitle = translate("Connect") + Button.render(self, section, scope) + end + o.write = function(self, section) + local cmd_docker = luci.util.exec("command -v docker"):match("^.+docker") or nil + local cmd_ttyd = luci.util.exec("command -v ttyd"):match("^.+ttyd") or nil + + if not cmd_docker or not cmd_ttyd or cmd_docker:match("^%s+$") or cmd_ttyd:match("^%s+$")then + return + end + + local pid = luci.util.trim(luci.util.exec("netstat -lnpt | grep :7682 | grep ttyd | tr -s ' ' | cut -d ' ' -f7 | cut -d'/' -f1")) + if pid and pid ~= "" then + luci.util.exec("kill -9 " .. pid) + end + + local hosts + local uci = require "luci.model.uci".cursor() + local remote = uci:get_bool("dockerd", "globals", "remote_endpoint") or false + local host = nil + local port = nil + local socket = nil + + if remote then + host = uci:get("dockerd", "globals", "remote_host") or nil + port = uci:get("dockerd", "globals", "remote_port") or nil + else + socket = uci:get("dockerd", "globals", "socket_path") or "/var/run/docker.sock" + end + + if remote and host and port then + hosts = host .. ':'.. port + elseif socket then + hosts = socket + else + return + end + + if uid and uid ~= "" then + uid = "-u " .. uid + else + uid = "" + end + + local start_cmd = string.format('%s -d 2 --once -p 7682 %s -H "unix://%s" exec -it %s %s %s&', cmd_ttyd, cmd_docker, hosts, uid, container_name, cmd) + + os.execute(start_cmd) + + o = s:option(DummyValue, "console") + o.container_id = container_id + o.template = "codeserver/console" + end +end + +return m diff --git a/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/tool.lua b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/tool.lua new file mode 100644 index 0000000..b917db8 --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/model/cbi/codeserver/tool.lua @@ -0,0 +1,56 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local http = require 'luci.http' + +m=SimpleForm("Tools") +m.submit = false +m.reset = false + +s = m:section(SimpleSection) + +o = s:option(Value, "action", translate("Action").."*") +o.rmempty = false +o.datatype = "string" +o:value("git-config", "git-config") +o.default = "git-config" + +local data = {} +o = s:option(Value, "username", "user.name") +o.datatype = "string" +o.placeholder = "username" +o:depends("action", "git-config") + +o = s:option(Value, "email", "user.email") +o.datatype = "string" +o.placeholder = "email@address" +o:depends("action", "git-config") + +local t=Template("codeserver/tool") +m:append(t) + +local btn_do = s:option(Button, "_do") +btn_do.render = function(self, section, scope) + self.inputstyle = "add" + self.title = " " + self.inputtitle = translate("Execute") + Button.render(self, section, scope) +end + +btn_do.write = function(self, section, value) + local action = m:get(section, "action") + if action == "git-config" then + local user = m:get(section, "username") + local email = m:get(section, "email") + if user ~= nil and email ~= nil then + local cmd = string.format("/usr/libexec/istorec/codeserver.sh %s %s %s", action, user, email) + cmd = "/etc/init.d/tasks task_add codeserver " .. luci.util.shellquote(cmd) .. " >/dev/null 2>&1" + os.execute(cmd) + t.show_log_taskid = "codeserver" + end + end +end + +return m + diff --git a/applications/luci-app-codeserver/luasrc/model/codeserver.lua b/applications/luci-app-codeserver/luasrc/model/codeserver.lua new file mode 100644 index 0000000..d476ae9 --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/model/codeserver.lua @@ -0,0 +1,54 @@ +local util = require "luci.util" +local jsonc = require "luci.jsonc" + +local codeserver = {} + +codeserver.blocks = function() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj["blockdevices"]) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + -- fsize > 1G + vals[#vals+1] = val["mountpoint"] + end + end + end + return vals +end + +codeserver.home = function() + local uci = require "luci.model.uci".cursor() + local home_dirs = {} + home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root") + home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs") + home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public") + home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches") + return home_dirs +end + +codeserver.find_paths = function(blocks, home_dirs, path_name) + local default_path = '' + local configs = {} + + default_path = home_dirs[path_name] .. "/CodeServer" + if #blocks == 0 then + table.insert(configs, default_path) + else + for _, val in pairs(blocks) do + table.insert(configs, val .. "/" .. path_name .. "/CodeServer") + end + local without_conf_dir = "/root/" .. path_name .. "/CodeServer" + if default_path == without_conf_dir then + default_path = configs[1] + end + end + + return configs, default_path +end + +return codeserver diff --git a/applications/luci-app-codeserver/luasrc/view/codeserver/console.htm b/applications/luci-app-codeserver/luasrc/view/codeserver/console.htm new file mode 100644 index 0000000..0a1e052 --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/view/codeserver/console.htm @@ -0,0 +1,10 @@ +
+ +
+ diff --git a/applications/luci-app-codeserver/luasrc/view/codeserver/status.htm b/applications/luci-app-codeserver/luasrc/view/codeserver/status.htm new file mode 100644 index 0000000..effa0c1 --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/view/codeserver/status.htm @@ -0,0 +1,31 @@ +<% +local util = require "luci.util" +local container_status = util.trim(util.exec("/usr/libexec/istorec/codeserver.sh status")) +local container_install = (string.len(container_status) > 0) +local container_running = container_status == "running" +-%> +
+ +
+ <% if container_running then %> + + <% else %> + + <% end %> +
+
+<% +if container_running then + local port=util.trim(util.exec("/usr/libexec/istorec/codeserver.sh port")) + if port == "" then + port="8443" + end +-%> +
+ +
+ + +
+
+<% end %> diff --git a/applications/luci-app-codeserver/luasrc/view/codeserver/tool.htm b/applications/luci-app-codeserver/luasrc/view/codeserver/tool.htm new file mode 100644 index 0000000..8ab8bdc --- /dev/null +++ b/applications/luci-app-codeserver/luasrc/view/codeserver/tool.htm @@ -0,0 +1,11 @@ +<%+tasks/embed%> + + + diff --git a/applications/luci-app-codeserver/po/zh-cn/codeserver.po b/applications/luci-app-codeserver/po/zh-cn/codeserver.po new file mode 100644 index 0000000..a349a80 --- /dev/null +++ b/applications/luci-app-codeserver/po/zh-cn/codeserver.po @@ -0,0 +1,45 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Official website:" +msgstr "官方网站:" + +msgid "CodeServer is a web version of VSCode." +msgstr "CodeServer 就一个在线版本的 VSCode,可以在线开发。" + +msgid "Config path" +msgstr "配置文件路径" + +msgid "HTTP Port" +msgstr "HTTP 端口" + +msgid "Service Status" +msgstr "服务状态" + +msgid "CodeServer status:" +msgstr "CodeServer 的状态信息如下:" + +msgid "Setup" +msgstr "安装配置" + +msgid "The following parameters will only take effect during installation or upgrade:" +msgstr "以下参数只在安装或者升级时才会生效:" + +msgid "Status" +msgstr "状态" + +msgid "CodeServer is running" +msgstr "CodeServer 运行中" + +msgid "CodeServer is not running" +msgstr "CodeServer 未运行" + +msgid "Open CodeServer" +msgstr "打开 CodeServer" + +msgid "Console" +msgstr "控制台" + +msgid "Only works in LAN" +msgstr "只在内网环境下工作。" + diff --git a/applications/luci-app-codeserver/root/etc/config/codeserver b/applications/luci-app-codeserver/root/etc/config/codeserver new file mode 100644 index 0000000..9a4c1f1 --- /dev/null +++ b/applications/luci-app-codeserver/root/etc/config/codeserver @@ -0,0 +1,10 @@ +config main + option 'http_port' '8082' + option 'image_name' 'lscr.io/linuxserver/code-server:latest' + option 'config_path' '' + option 'env_password' '' + option 'env_hashed_password' '' + option 'env_sudo_password' '' + option 'env_sudo_password_hash' '' + option 'env_proxy_domain' '' + diff --git a/applications/luci-app-codeserver/root/usr/libexec/istorec/codeserver.sh b/applications/luci-app-codeserver/root/usr/libexec/istorec/codeserver.sh new file mode 100755 index 0000000..59669c6 --- /dev/null +++ b/applications/luci-app-codeserver/root/usr/libexec/istorec/codeserver.sh @@ -0,0 +1,90 @@ +#!/bin/sh +# Author Xiaobao(xiaobao@linkease.com) + +ACTION=${1} +shift 1 + +do_install() { + local http_port=`uci get codeserver.@main[0].http_port 2>/dev/null` + local image_name=`uci get codeserver.@main[0].image_name 2>/dev/null` + local config=`uci get codeserver.@main[0].config_path 2>/dev/null` + local env_password=`uci get codeserver.@main[0].env_password 2>/dev/null` + local env_hashed_password=`uci get codeserver.@main[0].env_hashed_password 2>/dev/null` + local env_sudo_password=`uci get codeserver.@main[0].env_sudo_password 2>/dev/null` + local env_sudo_password_hash=`uci get codeserver.@main[0].env_sudo_password_hash 2>/dev/null` + local env_proxy_domain=`uci get codeserver.@main[0].env_proxy_domain 2>/dev/null` + + [ -z "$image_name" ] && image_name="lscr.io/linuxserver/code-server:latest" + echo "docker pull ${image_name}" + docker pull ${image_name} + docker rm -f codeserver + + if [ -z "$config" ]; then + echo "config path is empty!" + exit 1 + fi + + [ -z "$http_port" ] && http_port=8082 + + local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" \ + --dns=172.17.0.1 \ + -e DEFAULT_WORKSPACE=/config/workspace \ + -p $http_port:8443 " + + local tz="`cat /tmp/TZ`" + [ -z "$tz" ] || cmd="$cmd -e TZ=$tz" + + [ -z "$env_password" ] || cmd="$cmd -e \"PASSWORD=$env_password\"" + [ -z "$env_hashed_password" ] || cmd="$cmd -e \"HASHED_PASSWORD=$env_hashed_password\"" + [ -z "$env_sudo_password" ] || cmd="$cmd -e \"SUDO_PASSWORD=$env_sudo_password\"" + [ -z "$env_sudo_password_hash" ] || cmd="$cmd -e \"SUDO_PASSWORD_HASH=$env_sudo_password_hash\"" + [ -z "$env_proxy_domain" ] || cmd="$cmd -e \"PROXY_DOMAIN=$env_proxy_domain\"" + + cmd="$cmd -v /mnt:/mnt" + mountpoint -q /mnt && cmd="$cmd:rslave" + cmd="$cmd --name codeserver \"$image_name\"" + + echo "$cmd" + eval "$cmd" +} + +usage() { + echo "usage: $0 sub-command" + echo "where sub-command is one of:" + echo " install Install the codeserver" + echo " upgrade Upgrade the codeserver" + echo " rm/start/stop/restart Remove/Start/Stop/Restart the codeserver" + echo " status CodeServer status" + echo " port CodeServer port" +} + +case ${ACTION} in + "install") + do_install + ;; + "upgrade") + do_install + ;; + "rm") + docker rm -f codeserver + ;; + "start" | "stop" | "restart") + docker ${ACTION} codeserver + ;; + "status") + docker ps --all -f 'name=codeserver' --format '{{.State}}' + ;; + "port") + docker ps --all -f 'name=codeserver' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://' + ;; + "git-config") + docker exec codeserver git config --global user.name "${1}" + docker exec codeserver git config --global user.email "${2}" + echo "git config --global user.name ${1}" + echo "git config --global user.email ${2}" + ;; + *) + usage + exit 1 + ;; +esac diff --git a/applications/luci-app-emby/luasrc/model/cbi/emby.lua b/applications/luci-app-emby/luasrc/model/cbi/emby.lua index 442e826..cf0cfaf 100644 --- a/applications/luci-app-emby/luasrc/model/cbi/emby.lua +++ b/applications/luci-app-emby/luasrc/model/cbi/emby.lua @@ -48,7 +48,7 @@ for _, val in pairs(paths) do end o.default = default_path -o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") +o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") o.datatype = "string" o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space")) diff --git a/applications/luci-app-gogs/Makefile b/applications/luci-app-gogs/Makefile new file mode 100644 index 0000000..1f1bd00 --- /dev/null +++ b/applications/luci-app-gogs/Makefile @@ -0,0 +1,18 @@ + + +include $(TOPDIR)/rules.mk + +PKG_VERSION:=1.0.0-20221114 +PKG_RELEASE:= + +LUCI_TITLE:=LuCI support for Emby +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+docker +luci-lib-taskd + +define Package/luci-app-emby/conffiles +/etc/config/emby +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-gogs/luasrc/controller/gogs.lua b/applications/luci-app-gogs/luasrc/controller/gogs.lua new file mode 100755 index 0000000..2dcbbdc --- /dev/null +++ b/applications/luci-app-gogs/luasrc/controller/gogs.lua @@ -0,0 +1,7 @@ + +module("luci.controller.gogs", package.seeall) + +function index() + entry({"admin", "services", "gogs"}, alias("admin", "services", "gogs", "config"), _("Gogs"), 30).dependent = true + entry({"admin", "services", "gogs", "config"}, cbi("gogs")) +end diff --git a/applications/luci-app-gogs/luasrc/model/cbi/gogs.lua b/applications/luci-app-gogs/luasrc/model/cbi/gogs.lua new file mode 100644 index 0000000..be679a4 --- /dev/null +++ b/applications/luci-app-gogs/luasrc/model/cbi/gogs.lua @@ -0,0 +1,51 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local taskd = require "luci.model.tasks" +local gogs_model = require "luci.model.gogs" +local m, s, o + +m = taskd.docker_map("gogs", "gogs", "/usr/libexec/istorec/gogs.sh", + translate("Gogs"), + translate("Gogs is a painless self-hosted Git service.") + .. translate("Official website:") .. ' https://gogs.io/') + +s = m:section(SimpleSection, translate("Service Status"), translate("Gogs status:")) +s:append(Template("gogs/status")) + +s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:")) +s.addremove=false +s.anonymous=true + +o = s:option(Value, "http_port", translate("HTTP Port").."*") +o.default = "3001" +o.datatype = "string" +o.rmempty = false + +o = s:option(Value, "ssh_port", translate("SSH Port").."*") +o.default = "3022" +o.datatype = "string" +o.rmempty = false + +o = s:option(Value, "image_name", translate("Image").."*") +o.rmempty = false +o.datatype = "string" +o:value("gogs/gogs:latest", "gogs/gogs:latest") +o:value("gogs/gogs:0.12", "gogs/gogs:0.12") +o.default = "gogs/gogs:latest" + +local blocks = gogs_model.blocks() +local home = gogs_model.home() + +o = s:option(Value, "config_path", translate("Config path").."*") +o.rmempty = false +o.datatype = "string" + +local paths, default_path = gogs_model.find_paths(blocks, home, "Configs") +for _, val in pairs(paths) do + o:value(val, val) +end +o.default = default_path + +return m diff --git a/applications/luci-app-gogs/luasrc/model/gogs.lua b/applications/luci-app-gogs/luasrc/model/gogs.lua new file mode 100644 index 0000000..d49601a --- /dev/null +++ b/applications/luci-app-gogs/luasrc/model/gogs.lua @@ -0,0 +1,54 @@ +local util = require "luci.util" +local jsonc = require "luci.jsonc" + +local gogs = {} + +gogs.blocks = function() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj["blockdevices"]) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + -- fsize > 1G + vals[#vals+1] = val["mountpoint"] + end + end + end + return vals +end + +gogs.home = function() + local uci = require "luci.model.uci".cursor() + local home_dirs = {} + home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root") + home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs") + home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public") + home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches") + return home_dirs +end + +gogs.find_paths = function(blocks, home_dirs, path_name) + local default_path = '' + local configs = {} + + default_path = home_dirs[path_name] .. "/Gogs" + if #blocks == 0 then + table.insert(configs, default_path) + else + for _, val in pairs(blocks) do + table.insert(configs, val .. "/" .. path_name .. "/Gogs") + end + local without_conf_dir = "/root/" .. path_name .. "/Gogs" + if default_path == without_conf_dir then + default_path = configs[1] + end + end + + return configs, default_path +end + +return gogs diff --git a/applications/luci-app-gogs/luasrc/view/gogs/status.htm b/applications/luci-app-gogs/luasrc/view/gogs/status.htm new file mode 100644 index 0000000..da476fa --- /dev/null +++ b/applications/luci-app-gogs/luasrc/view/gogs/status.htm @@ -0,0 +1,31 @@ +<% +local util = require "luci.util" +local container_status = util.trim(util.exec("/usr/libexec/istorec/gogs.sh status")) +local container_install = (string.len(container_status) > 0) +local container_running = container_status == "running" +-%> +
+ +
+ <% if container_running then %> + + <% else %> + + <% end %> +
+
+<% +if container_running then + local port=util.trim(util.exec("/usr/libexec/istorec/gogs.sh port")) + if port == "" then + port="3001" + end +-%> +
+ +
+ + +
+
+<% end %> diff --git a/applications/luci-app-gogs/po/zh-cn/gogs.po b/applications/luci-app-gogs/po/zh-cn/gogs.po new file mode 100644 index 0000000..76b41cf --- /dev/null +++ b/applications/luci-app-gogs/po/zh-cn/gogs.po @@ -0,0 +1,42 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Official website:" +msgstr "官方网站:" + +msgid "Gogs is a painless self-hosted Git service." +msgstr "Gogs 是一个轻松易用的 Git 服务。" + +msgid "Config path" +msgstr "配置文件路径" + +msgid "HTTP Port" +msgstr "HTTP 端口" + +msgid "SSH Port" +msgstr "SSH 端口" + +msgid "Service Status" +msgstr "服务状态" + +msgid "Gogs status:" +msgstr "Gogs 的状态信息如下:" + +msgid "Setup" +msgstr "安装配置" + +msgid "The following parameters will only take effect during installation or upgrade:" +msgstr "以下参数只在安装或者升级时才会生效:" + +msgid "Status" +msgstr "状态" + +msgid "Gogs is running" +msgstr "Gogs 运行中" + +msgid "Gogs is not running" +msgstr "Gogs 未运行" + +msgid "Open Gogs" +msgstr "打开 Gogs" + diff --git a/applications/luci-app-gogs/root/etc/config/gogs b/applications/luci-app-gogs/root/etc/config/gogs new file mode 100644 index 0000000..a111b5b --- /dev/null +++ b/applications/luci-app-gogs/root/etc/config/gogs @@ -0,0 +1,6 @@ +config main + option 'http_port' '3001' + option 'ssh_port' '3022' + option 'image_name' 'gogs/gogs:latest' + option 'config_path' '' + diff --git a/applications/luci-app-gogs/root/usr/libexec/istorec/gogs.sh b/applications/luci-app-gogs/root/usr/libexec/istorec/gogs.sh new file mode 100755 index 0000000..d9cf4f9 --- /dev/null +++ b/applications/luci-app-gogs/root/usr/libexec/istorec/gogs.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# Author Xiaobao(xiaobao@linkease.com) + +ACTION=${1} +shift 1 + +do_install() { + local http_port=`uci get gogs.@main[0].http_port 2>/dev/null` + local ssh_port=`uci get gogs.@main[0].ssh_port 2>/dev/null` + local image_name=`uci get gogs.@main[0].image_name 2>/dev/null` + local config=`uci get gogs.@main[0].config_path 2>/dev/null` + + [ -z "$image_name" ] && image_name="gogs/gogs:latest" + echo "docker pull ${image_name}" + docker pull ${image_name} + docker rm -f gogs + + if [ -z "$config" ]; then + echo "config path is empty!" + exit 1 + fi + + if [ -z "$http_port" ]; then + http_port=3001 + fi + if [ -z "$ssh_port" ]; then + ssh_port=3022 + fi + + local cmd="docker run --restart=unless-stopped -d -v \"$config:/data\" \ + --dns=172.17.0.1 \ + -p $http_port:3000 \ + -p $ssh_port:22 " + + local tz="`cat /tmp/TZ`" + [ -z "$tz" ] || cmd="$cmd -e TZ=$tz" + + cmd="$cmd -v /mnt:/mnt" + mountpoint -q /mnt && cmd="$cmd:rslave" + cmd="$cmd --name gogs \"$image_name\"" + + echo "$cmd" + eval "$cmd" +} + +usage() { + echo "usage: $0 sub-command" + echo "where sub-command is one of:" + echo " install Install the gogs" + echo " upgrade Upgrade the gogs" + echo " rm/start/stop/restart Remove/Start/Stop/Restart the gogs" + echo " status Gogs status" + echo " port Gogs port" +} + +case ${ACTION} in + "install") + do_install + ;; + "upgrade") + do_install + ;; + "rm") + docker rm -f gogs + ;; + "start" | "stop" | "restart") + docker ${ACTION} gogs + ;; + "status") + docker ps --all -f 'name=gogs' --format '{{.State}}' + ;; + "port") + local http_port=`uci get gogs.@main[0].http_port 2>/dev/null` + echo $http_port + ;; + *) + usage + exit 1 + ;; +esac diff --git a/applications/luci-app-jellyfin/luasrc/model/cbi/jellyfin.lua b/applications/luci-app-jellyfin/luasrc/model/cbi/jellyfin.lua index 10fa318..7e016fa 100644 --- a/applications/luci-app-jellyfin/luasrc/model/cbi/jellyfin.lua +++ b/applications/luci-app-jellyfin/luasrc/model/cbi/jellyfin.lua @@ -40,7 +40,7 @@ for _, val in pairs(paths) do end o.default = default_path -o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") +o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") o.datatype = "string" o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space")) diff --git a/applications/luci-app-penpot/Makefile b/applications/luci-app-penpot/Makefile new file mode 100644 index 0000000..1778fb5 --- /dev/null +++ b/applications/luci-app-penpot/Makefile @@ -0,0 +1,18 @@ + + +include $(TOPDIR)/rules.mk + +PKG_VERSION:=1.0.0-20221114 +PKG_RELEASE:= + +LUCI_TITLE:=LuCI support for Penpot +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+docker +luci-lib-taskd docker-compose + +define Package/luci-app-penpot/conffiles +/etc/config/penpot +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-penpot/luasrc/controller/penpot.lua b/applications/luci-app-penpot/luasrc/controller/penpot.lua new file mode 100755 index 0000000..23358c9 --- /dev/null +++ b/applications/luci-app-penpot/luasrc/controller/penpot.lua @@ -0,0 +1,8 @@ + +module("luci.controller.penpot", package.seeall) + +function index() + entry({"admin", "services", "penpot"}, alias("admin", "services", "penpot", "config"), _("Penpot"), 30).dependent = true + entry({"admin", "services", "penpot", "config"}, cbi("penpot/config"), _("Config"), 10).leaf = true + entry({"admin", "services", "penpot", "tool"}, form("penpot/tool"), _("Tool"), 30).leaf = true +end diff --git a/applications/luci-app-penpot/luasrc/model/cbi/penpot/config.lua b/applications/luci-app-penpot/luasrc/model/cbi/penpot/config.lua new file mode 100644 index 0000000..61c5669 --- /dev/null +++ b/applications/luci-app-penpot/luasrc/model/cbi/penpot/config.lua @@ -0,0 +1,63 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local taskd = require "luci.model.tasks" +local penpot_model = require "luci.model.penpot" +local m, s, o + +m = taskd.docker_map("penpot", "penpot", "/usr/libexec/istorec/penpot.sh", + translate("Penpot"), + translate("Penpot is the first Open Source design and prototyping platform meant for cross-domain teams.") + .. translate("Official website:") .. ' https://penpot.app/') + +s = m:section(SimpleSection, translate("Service Status"), translate("Penpot status:")) +s:append(Template("penpot/status")) + +s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:")) +s.addremove=false +s.anonymous=true + +o = s:option(Value, "http_port", translate("HTTP Port").."*") +o.default = "9001" +o.datatype = "string" + +local blocks = penpot_model.blocks() +local home = penpot_model.home() + +o = s:option(Value, "config_path", translate("Config path").."*", translate("Manually edit template at") .. " /root/usr/share/penpot") +o.rmempty = false +o.datatype = "string" + +local paths, default_path = penpot_model.find_paths(blocks, home, "Configs") +for _, val in pairs(paths) do + o:value(val, val) +end +o.default = default_path + +o = s:option(Value, "public_uri", "PUBLIC_URI") +o.datatype = "string" + +o = s:option(Value, "redis_uri", "REDIS_URI") +o.datatype = "string" + +o = s:option(Value, "db_uri", "DB_URI") +o.datatype = "string" + +o = s:option(Value, "db_name", "DB_NAME") +o.datatype = "string" + +o = s:option(Value, "db_username", "DB_USERNAME") +o.datatype = "string" + +o = s:option(Value, "db_password", "DB_PASSWORD") +o.password = true +o.datatype = "string" + +o = s:option(Value, "smtp_default_from", "SMTP_DEFAULT_FROM") +o.datatype = "string" + +o = s:option(Value, "smtp_default_reply_to", "SMTP_DEFAULT_REPLY_TO") +o.datatype = "string" + +return m diff --git a/applications/luci-app-penpot/luasrc/model/cbi/penpot/tool.lua b/applications/luci-app-penpot/luasrc/model/cbi/penpot/tool.lua new file mode 100644 index 0000000..1f5d0d4 --- /dev/null +++ b/applications/luci-app-penpot/luasrc/model/cbi/penpot/tool.lua @@ -0,0 +1,62 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local http = require 'luci.http' + +m=SimpleForm("Tools") +m.submit = false +m.reset = false + +s = m:section(SimpleSection) + +o = s:option(Value, "action", translate("Action").."*") +o.rmempty = false +o.datatype = "string" +o:value("create-user", "create-user") +o.default = "create-user" + +local data = {} +o = s:option(Value, "email", "Email") +o.datatype = "string" +o.placeholder = "email@address" +o:depends("action", "create-user") + +o = s:option(Value, "password", "Password") +o.password = true +o.datatype = "string" +o:depends("action", "create-user") + +o = s:option(Value, "fullname", "Your Full Name") +o.datatype = "string" +o.placeholder = "Full Name" +o:depends("action", "create-user") + +local t=Template("penpot/tool") +m:append(t) + +local btn_do = s:option(Button, "_do") +btn_do.render = function(self, section, scope) + self.inputstyle = "add" + self.title = " " + self.inputtitle = translate("Execute") + Button.render(self, section, scope) +end + +btn_do.write = function(self, section, value) + local action = m:get(section, "action") + if action == "create-user" then + local email = m:get(section, "email") + local password = m:get(section, "password") + local fullname = m:get(section, "fullname") + if email ~= nil and password ~= nil and fullname ~= nil then + local cmd = string.format("/usr/libexec/istorec/penpot.sh %s %s %s %s", action, email, password, fullname) + cmd = "/etc/init.d/tasks task_add penpot " .. luci.util.shellquote(cmd) .. " >/dev/null 2>&1" + os.execute(cmd) + t.show_log_taskid = "penpot" + end + end +end + +return m + diff --git a/applications/luci-app-penpot/luasrc/model/penpot.lua b/applications/luci-app-penpot/luasrc/model/penpot.lua new file mode 100644 index 0000000..5f17590 --- /dev/null +++ b/applications/luci-app-penpot/luasrc/model/penpot.lua @@ -0,0 +1,54 @@ +local util = require "luci.util" +local jsonc = require "luci.jsonc" + +local penpot = {} + +penpot.blocks = function() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj["blockdevices"]) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + -- fsize > 1G + vals[#vals+1] = val["mountpoint"] + end + end + end + return vals +end + +penpot.home = function() + local uci = require "luci.model.uci".cursor() + local home_dirs = {} + home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root") + home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs") + home_dirs["Public"] = uci:get_first("quickstart", "main", "dl_dir", home_dirs["main_dir"].."/Public") + home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches") + return home_dirs +end + +penpot.find_paths = function(blocks, home_dirs, path_name) + local default_path = '' + local configs = {} + + default_path = home_dirs[path_name] .. "/Penpot" + if #blocks == 0 then + table.insert(configs, default_path) + else + for _, val in pairs(blocks) do + table.insert(configs, val .. "/" .. path_name .. "/Penpot") + end + local without_conf_dir = "/root/" .. path_name .. "/Penpot" + if default_path == without_conf_dir then + default_path = configs[1] + end + end + + return configs, default_path +end + +return penpot diff --git a/applications/luci-app-penpot/luasrc/view/penpot/status.htm b/applications/luci-app-penpot/luasrc/view/penpot/status.htm new file mode 100644 index 0000000..2485945 --- /dev/null +++ b/applications/luci-app-penpot/luasrc/view/penpot/status.htm @@ -0,0 +1,31 @@ +<% +local util = require "luci.util" +local container_status = util.trim(util.exec("/usr/libexec/istorec/penpot.sh status")) +local container_install = (string.len(container_status) > 0) +local container_running = container_status == "running" +-%> +
+ +
+ <% if container_running then %> + + <% else %> + + <% end %> +
+
+<% +if container_running then + local port=util.trim(util.exec("/usr/libexec/istorec/penpot.sh port")) + if port == "" then + port="9001" + end +-%> +
+ +
+ + +
+
+<% end %> diff --git a/applications/luci-app-penpot/luasrc/view/penpot/tool.htm b/applications/luci-app-penpot/luasrc/view/penpot/tool.htm new file mode 100644 index 0000000..8ab8bdc --- /dev/null +++ b/applications/luci-app-penpot/luasrc/view/penpot/tool.htm @@ -0,0 +1,11 @@ +<%+tasks/embed%> + + + diff --git a/applications/luci-app-penpot/po/zh-cn/penpot.po b/applications/luci-app-penpot/po/zh-cn/penpot.po new file mode 100644 index 0000000..613c8aa --- /dev/null +++ b/applications/luci-app-penpot/po/zh-cn/penpot.po @@ -0,0 +1,44 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Official website:" +msgstr "官方网站:" + +msgid "Penpot is the first Open Source design and prototyping platform meant for cross-domain teams." +msgstr "Penpot 是第一个开源的便于团队协作的在线设计平台。" + +msgid "Config path" +msgstr "配置文件路径" + +msgid "HTTP Port" +msgstr "HTTP 端口" + +msgid "Service Status" +msgstr "服务状态" + +msgid "Penpot status:" +msgstr "Penpot 的状态信息如下:" + +msgid "Setup" +msgstr "安装配置" + +msgid "The following parameters will only take effect during installation or upgrade:" +msgstr "以下参数只在安装或者升级时才会生效:" + +msgid "Status" +msgstr "状态" + +msgid "Penpot is running" +msgstr "Penpot 运行中" + +msgid "Penpot is not running" +msgstr "Penpot 未运行" + +msgid "Open Penpot" +msgstr "打开 Penpot" + +msgid "Console" +msgstr "控制台" + +msgid "Manually edit template at" +msgstr "可以手动手改配置文件的模板,路径在:" diff --git a/applications/luci-app-penpot/root/etc/config/penpot b/applications/luci-app-penpot/root/etc/config/penpot new file mode 100644 index 0000000..54ed72b --- /dev/null +++ b/applications/luci-app-penpot/root/etc/config/penpot @@ -0,0 +1,12 @@ +config main + option 'http_port' '9001' + option 'config_path' '' + option 'public_uri' 'http://localhost:9001' + option 'redis_uri' 'redis://penpot-redis/0' + option 'db_uri' 'postgresql://penpot-postgres/penpot' + option 'db_name' 'penpot' + option 'db_username' 'penpot' + option 'db_password' 'penpot' + option 'smtp_default_from' 'no-reply@example.com' + option 'smtp_default_reply_to' 'no-reply@example.com' + diff --git a/applications/luci-app-penpot/root/usr/libexec/istorec/penpot.sh b/applications/luci-app-penpot/root/usr/libexec/istorec/penpot.sh new file mode 100755 index 0000000..2676380 --- /dev/null +++ b/applications/luci-app-penpot/root/usr/libexec/istorec/penpot.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# Author Xiaobao(xiaobao@linkease.com) + +ACTION=${1} +shift 1 + +do_install() { + local config=`uci get penpot.@main[0].config_path 2>/dev/null` + if [ -z "$config" ]; then + echo "config path is empty!" + exit 1 + fi + mkdir -p $config + + lua /usr/libexec/istorec/penpot_template.lua penpot /usr/share/penpot/config.template.env $config/config.env + RET=$? + if [ ! "$RET" = "0" ]; then + echo "convert config.env failed" + exit 1 + fi + + lua /usr/libexec/istorec/penpot_template.lua penpot /usr/share/penpot/docker-compose.template.yaml $config/docker-compose.yaml + RET=$? + if [ ! "$RET" = "0" ]; then + echo "convert config.env failed" + exit 1 + fi + + cd $config + docker-compose down + docker-compose up -d + echo "Wait 120 to intialize" + sleep 120 + echo "Now you should create a user manually" +} + +usage() { + echo "usage: $0 sub-command" + echo "where sub-command is one of:" + echo " install Install the penpot" + echo " upgrade Upgrade the penpot" + echo " rm/start/stop/restart Remove/Start/Stop/Restart the penpot" + echo " status Penpot status" + echo " port Penpot port" +} + +case ${ACTION} in + "install") + do_install + ;; + "upgrade") + do_install + ;; + "rm") + local config=`uci get penpot.@main[0].config_path 2>/dev/null` + cd $config && docker-compose down + ;; + "start" | "stop" | "restart") + local config=`uci get penpot.@main[0].config_path 2>/dev/null` + cd $config && docker-compose ${ACTION} + ;; + "status") + docker ps --all -f 'name=penpot_penpot-frontend_1' --format '{{.State}}' + ;; + "port") + http_port=`uci get penpot.@main[0].http_port 2>/dev/null` + echo $http_port + ;; + "create-user") + echo docker exec -ti penpot_penpot-backend_1 ./manage.sh create-profile -u "${1}" -p "${2}" -n "${3}" + docker exec -ti penpot_penpot-backend_1 ./manage.sh create-profile -u "${1}" -p "${2}" -n "${3}" + ;; + *) + usage + exit 1 + ;; +esac diff --git a/applications/luci-app-penpot/root/usr/libexec/istorec/penpot_template.lua b/applications/luci-app-penpot/root/usr/libexec/istorec/penpot_template.lua new file mode 100644 index 0000000..564b086 --- /dev/null +++ b/applications/luci-app-penpot/root/usr/libexec/istorec/penpot_template.lua @@ -0,0 +1,96 @@ +local util = require "luci.util" +local tparser = require "luci.template.parser" +local uci = require "luci.model.uci" +local nixio = require "nixio" + +local tostring, pairs, loadstring = tostring, pairs, loadstring +local setmetatable, loadfile = setmetatable, loadfile +local getfenv, setfenv, rawget = getfenv, setfenv, rawget +local assert, type, error = assert, type, error + +local default_ctx = {tostring = tostring} + +local from_string = function(template) + return Template(default_ctx, nil, template) +end + +local from_file = function(template_file) + return Template(default_ctx, template_file) +end + +-- Template class +Template = util.class() + +-- Constructor - Reads and compiles the template on-demand +function Template.__init__(self, viewns, name, template) + if name then + self.name = name + else + self.name = "[string]" + end + + -- Create a new namespace for this template + self.viewns = viewns + + -- Compile template + local err + local sourcefile + + if name then + sourcefile = name + self.template, _, err = tparser.parse(sourcefile) + else + sourcefile = "[string]" + self.template, _, err = tparser.parse_string(template) + end + + -- If we have no valid template throw error, otherwise cache the template + if not self.template then + error("Failed to load template '" .. self.name .. "'.\n" .. + "Error while parsing template '" .. sourcefile .. "':\n" .. + (err or "Unknown syntax error")) + end +end + +-- Renders a template +function Template.render(self, scope) + + -- Put our predefined objects in the scope of the template + setfenv(self.template, setmetatable({}, {__index = + function(tbl, key) + return rawget(tbl, key) or self.viewns[key] or scope[key] + end})) + + -- Now finally render the thing + local stat, err = util.copcall(self.template) + if not stat then + error("Failed to execute template '" .. self.name .. "'.\n" .. + "A runtime error occurred: " .. tostring(err or "(nil)")) + end +end + +if #arg == 3 then + local cur = uci.cursor() + local configs = {} + cur:foreach(arg[1], "main", function(s) + for k, v in pairs(s) do + configs[k] = v + end + end) + if not nixio.fs.access(arg[2]) then + print(arg[2] .. " not found") + os.exit(10) + end + local target = io.open(arg[3], "w") + if not target then + print(arg[3] .. " can not write") + end + configs.write = function(data) + target:write(data) + end + from_file(arg[2]):render(configs) + target:close() +else + print("penpot_template.lua [appname] [template-in] [template-out]") +end + diff --git a/applications/luci-app-penpot/root/usr/share/penpot/config.template.env b/applications/luci-app-penpot/root/usr/share/penpot/config.template.env new file mode 100644 index 0000000..c5e2b44 --- /dev/null +++ b/applications/luci-app-penpot/root/usr/share/penpot/config.template.env @@ -0,0 +1,96 @@ +## Should be set to the public domain where penpot is going to be served. +## +## NOTE: If you are going to serve it under different domain than +## 'localhost' without HTTPS, consider setting the +## `disable-secure-session-cookies' flag on the 'PENPOT_FLAGS' +## setting. + +PENPOT_PUBLIC_URI=<%=public_uri%> + +## Feature flags. +PENPOT_FLAGS=enable-registration enable-login disable-email-verification disable-secure-session-cookies + +## Temporal workaround because of bad builtin default + +PENPOT_HTTP_SERVER_HOST=0.0.0.0 + +## Standard database connection parameters (only postgresql is supported): + +PENPOT_DATABASE_URI=<%=db_uri%> +PENPOT_DATABASE_USERNAME=<%=db_username%> +PENPOT_DATABASE_PASSWORD=<%=db_password%> + +## Redis is used for the websockets notifications. + +PENPOT_REDIS_URI=<%=redis_uri%> + +## By default, files uploaded by users are stored in local +## filesystem. But it can be configured to store in AWS S3. + +PENPOT_ASSETS_STORAGE_BACKEND=assets-fs +PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets + +## Telemetry. When enabled, a periodical process will send anonymous +## data about this instance. Telemetry data will enable us to learn on +## how the application is used, based on real scenarios. If you want +## to help us, please leave it enabled. + +PENPOT_TELEMETRY_ENABLED=true + +## Email sending configuration. By default, emails are printed in the +## console, but for production usage is recommended to setup a real +## SMTP provider. Emails are used to confirm user registrations. + +PENPOT_SMTP_DEFAULT_FROM=<%=smtp_default_from%> +PENPOT_SMTP_DEFAULT_REPLY_TO=<%=smtp_default_reply_to%> +# PENPOT_SMTP_HOST= +# PENPOT_SMTP_PORT= +# PENPOT_SMTP_USERNAME= +# PENPOT_SMTP_PASSWORD= +# PENPOT_SMTP_TLS=true +# PENPOT_SMTP_SSL=false + +## Comma separated list of allowed domains to register. Empty to allow +## all. + +# PENPOT_REGISTRATION_DOMAIN_WHITELIST="" + +## Authentication providers + +## Google + +# PENPOT_GOOGLE_CLIENT_ID= +# PENPOT_GOOGLE_CLIENT_SECRET= + +## GitHub + +# PENPOT_GITHUB_CLIENT_ID= +# PENPOT_GITHUB_CLIENT_SECRET= + +## GitLab + +# PENPOT_GITLAB_BASE_URI=https://gitlab.com +# PENPOT_GITLAB_CLIENT_ID= +# PENPOT_GITLAB_CLIENT_SECRET= + +## OpenID Connect (since 1.5.0) + +# PENPOT_OIDC_BASE_URI= +# PENPOT_OIDC_CLIENT_ID= +# PENPOT_OIDC_CLIENT_SECRET= + +## LDAP +## +## NOTE: to enable ldap, you will need to put 'enable-login-with-ldap' +## on the 'PENPOT_FLAGS' environment variable. + +# PENPOT_LDAP_HOST=ldap +# PENPOT_LDAP_PORT=10389 +# PENPOT_LDAP_SSL=false +# PENPOT_LDAP_STARTTLS=false +# PENPOT_LDAP_BASE_DN=ou=people,dc=planetexpress,dc=com +# PENPOT_LDAP_BIND_DN=cn=admin,dc=planetexpress,dc=com +# PENPOT_LDAP_BIND_PASSWORD=GoodNewsEveryone +# PENPOT_LDAP_ATTRS_USERNAME=uid +# PENPOT_LDAP_ATTRS_EMAIL=mail +# PENPOT_LDAP_ATTRS_FULLNAME=cn diff --git a/applications/luci-app-penpot/root/usr/share/penpot/docker-compose.template.yaml b/applications/luci-app-penpot/root/usr/share/penpot/docker-compose.template.yaml new file mode 100644 index 0000000..d0461ec --- /dev/null +++ b/applications/luci-app-penpot/root/usr/share/penpot/docker-compose.template.yaml @@ -0,0 +1,73 @@ +--- +version: "3.5" + +networks: + penpot: + +services: + penpot-frontend: + image: "penpotapp/frontend:latest" + ports: + - <%=http_port%>:80 + + volumes: + - <%=config_path%>/data/asserts:/opt/data + + env_file: + - config.env + + depends_on: + - penpot-backend + - penpot-exporter + + networks: + - penpot + + penpot-backend: + image: "penpotapp/backend:latest" + volumes: + - <%=config_path%>/data/asserts:/opt/data + + depends_on: + - penpot-postgres + - penpot-redis + + env_file: + - config.env + + networks: + - penpot + + penpot-exporter: + image: "penpotapp/exporter:latest" + env_file: + - config.env + environment: + # Don't touch it; this uses internal docker network to + # communicate with the frontend. + - PENPOT_PUBLIC_URI=http://penpot-frontend + networks: + - penpot + + penpot-postgres: + image: "postgres:14" + restart: always + stop_signal: SIGINT + + environment: + - POSTGRES_INITDB_ARGS=--data-checksums + - POSTGRES_DB=<%=db_name%> + - POSTGRES_USER=<%=db_username%> + - POSTGRES_PASSWORD=<%=db_password%> + + volumes: + - <%=config_path%>/data/postgres:/var/lib/postgresql/data + + networks: + - penpot + + penpot-redis: + image: redis:7 + restart: always + networks: + - penpot diff --git a/applications/luci-app-plex/luasrc/model/cbi/plex.lua b/applications/luci-app-plex/luasrc/model/cbi/plex.lua index b24c9b6..a9c7ed1 100644 --- a/applications/luci-app-plex/luasrc/model/cbi/plex.lua +++ b/applications/luci-app-plex/luasrc/model/cbi/plex.lua @@ -50,7 +50,7 @@ for _, val in pairs(paths) do end o.default = default_path -o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") +o = s:option(Value, "media_path", translate("Media path"), translate("Not required, all disk is mounted in") .. " /mnt") o.datatype = "string" o = s:option(Value, "cache_path", translate("Transcode cache path"), translate("Default use 'transcodes' in 'config path' if not set, please make sure there has enough space")) diff --git a/applications/luci-app-unifi/Makefile b/applications/luci-app-unifi/Makefile new file mode 100644 index 0000000..c4bca79 --- /dev/null +++ b/applications/luci-app-unifi/Makefile @@ -0,0 +1,18 @@ + + +include $(TOPDIR)/rules.mk + +PKG_VERSION:=1.0.0-20221114 +PKG_RELEASE:= + +LUCI_TITLE:=LuCI support for UnifiController +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+docker +luci-lib-taskd + +define Package/luci-app-unifi/conffiles +/etc/config/unifi +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-unifi/luasrc/controller/unifi.lua b/applications/luci-app-unifi/luasrc/controller/unifi.lua new file mode 100755 index 0000000..002c41c --- /dev/null +++ b/applications/luci-app-unifi/luasrc/controller/unifi.lua @@ -0,0 +1,7 @@ + +module("luci.controller.unifi", package.seeall) + +function index() + entry({"admin", "services", "unifi"}, alias("admin", "services", "unifi", "config"), _("UnifiController"), 30).dependent = true + entry({"admin", "services", "unifi", "config"}, cbi("unifi")) +end diff --git a/applications/luci-app-unifi/luasrc/model/cbi/unifi.lua b/applications/luci-app-unifi/luasrc/model/cbi/unifi.lua new file mode 100644 index 0000000..ea53ec0 --- /dev/null +++ b/applications/luci-app-unifi/luasrc/model/cbi/unifi.lua @@ -0,0 +1,49 @@ +--[[ +LuCI - Lua Configuration Interface +]]-- + +local taskd = require "luci.model.tasks" +local unifi_model = require "luci.model.unifi" +local m, s, o + +m = taskd.docker_map("unifi", "unifi", "/usr/libexec/istorec/unifi.sh", + translate("UnifiController"), + translate("UnifiController ubnt.") + .. translate("Official website:") .. ' https://www.ui.com/') + +s = m:section(SimpleSection, translate("Service Status"), translate("UnifiController status:")) +s:append(Template("unifi/status")) + +s = m:section(TypedSection, "main", translate("Setup"), translate("The following parameters will only take effect during installation or upgrade:")) +s.addremove=false +s.anonymous=true + +o = s:option(Flag, "hostnet", translate("Host network"), translate("UnifiController running in host network, for DLNA application, port is always 8096 if enabled")) +o.default = 0 +o.rmempty = false + +o = s:option(Value, "http_port", translate("HTTPS Port").."*") +o.default = "8083" +o.datatype = "string" +o:depends("hostnet", 0) + +o = s:option(Value, "image_name", translate("Image").."*") +o.rmempty = false +o.datatype = "string" +o:value("lscr.io/linuxserver/unifi-controller:latest", "lscr.io/linuxserver/unifi-controller:latest") +o.default = "lscr.io/linuxserver/unifi-controller:latest" + +local blocks = unifi_model.blocks() +local home = unifi_model.home() + +o = s:option(Value, "config_path", translate("Config path").."*") +o.rmempty = false +o.datatype = "string" + +local paths, default_path = unifi_model.find_paths(blocks, home, "Configs") +for _, val in pairs(paths) do + o:value(val, val) +end +o.default = default_path + +return m diff --git a/applications/luci-app-unifi/luasrc/model/unifi.lua b/applications/luci-app-unifi/luasrc/model/unifi.lua new file mode 100644 index 0000000..0847022 --- /dev/null +++ b/applications/luci-app-unifi/luasrc/model/unifi.lua @@ -0,0 +1,53 @@ +local util = require "luci.util" +local jsonc = require "luci.jsonc" + +local unifi = {} + +unifi.blocks = function() + local f = io.popen("lsblk -s -f -b -o NAME,FSSIZE,MOUNTPOINT --json", "r") + local vals = {} + if f then + local ret = f:read("*all") + f:close() + local obj = jsonc.parse(ret) + for _, val in pairs(obj["blockdevices"]) do + local fsize = val["fssize"] + if fsize ~= nil and string.len(fsize) > 10 and val["mountpoint"] then + -- fsize > 1G + vals[#vals+1] = val["mountpoint"] + end + end + end + return vals +end + +unifi.home = function() + local uci = require "luci.model.uci".cursor() + local home_dirs = {} + home_dirs["main_dir"] = uci:get_first("quickstart", "main", "main_dir", "/root") + home_dirs["Configs"] = uci:get_first("quickstart", "main", "conf_dir", home_dirs["main_dir"].."/Configs") + home_dirs["Caches"] = uci:get_first("quickstart", "main", "tmp_dir", home_dirs["main_dir"].."/Caches") + return home_dirs +end + +unifi.find_paths = function(blocks, home_dirs, path_name) + local default_path = '' + local configs = {} + + default_path = home_dirs[path_name] .. "/UnifiController" + if #blocks == 0 then + table.insert(configs, default_path) + else + for _, val in pairs(blocks) do + table.insert(configs, val .. "/" .. path_name .. "/UnifiController") + end + local without_conf_dir = "/root/" .. path_name .. "/UnifiController" + if default_path == without_conf_dir then + default_path = configs[1] + end + end + + return configs, default_path +end + +return unifi diff --git a/applications/luci-app-unifi/luasrc/view/unifi/status.htm b/applications/luci-app-unifi/luasrc/view/unifi/status.htm new file mode 100644 index 0000000..61ebb67 --- /dev/null +++ b/applications/luci-app-unifi/luasrc/view/unifi/status.htm @@ -0,0 +1,31 @@ +<% +local util = require "luci.util" +local container_status = util.trim(util.exec("/usr/libexec/istorec/unifi.sh status")) +local container_install = (string.len(container_status) > 0) +local container_running = container_status == "running" +-%> +
+ +
+ <% if container_running then %> + + <% else %> + + <% end %> +
+
+<% +if container_running then + local port=util.trim(util.exec("/usr/libexec/istorec/unifi.sh port")) + if port == "" then + port="8083" + end +-%> +
+ +
+ + +
+
+<% end %> diff --git a/applications/luci-app-unifi/po/zh-cn/unifi.po b/applications/luci-app-unifi/po/zh-cn/unifi.po new file mode 100644 index 0000000..b74fa19 --- /dev/null +++ b/applications/luci-app-unifi/po/zh-cn/unifi.po @@ -0,0 +1,41 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Official website:" +msgstr "官方网站:" + +msgid "UnifiController ubnt." +msgstr "Ubnt AC 控制器。" + +msgid "Config path" +msgstr "配置文件路径" + +msgid "HTTPS Port" +msgstr "HTTPS 端口" + +msgid "Service Status" +msgstr "服务状态" + +msgid "UnifiController status:" +msgstr "UnifiController 的状态信息如下:" + +msgid "Setup" +msgstr "安装配置" + +msgid "The following parameters will only take effect during installation or upgrade:" +msgstr "以下参数只在安装或者升级时才会生效:" + +msgid "Status" +msgstr "状态" + +msgid "UnifiController is running" +msgstr "UnifiController 运行中" + +msgid "UnifiController is not running" +msgstr "UnifiController 未运行" + +msgid "Open UnifiController" +msgstr "打开 UnifiController" + +msgid "Not required, all disk is mounted in" +msgstr "可不填,所有硬盘都在" diff --git a/applications/luci-app-unifi/root/etc/config/unifi b/applications/luci-app-unifi/root/etc/config/unifi new file mode 100644 index 0000000..d1333f0 --- /dev/null +++ b/applications/luci-app-unifi/root/etc/config/unifi @@ -0,0 +1,6 @@ +config main + option 'hostnet' '0' + option 'http_port' '8083' + option 'image_name' 'lscr.io/linuxserver/unifi-controller:latest' + option 'config_path' '' + diff --git a/applications/luci-app-unifi/root/usr/libexec/istorec/unifi.sh b/applications/luci-app-unifi/root/usr/libexec/istorec/unifi.sh new file mode 100755 index 0000000..d4cce34 --- /dev/null +++ b/applications/luci-app-unifi/root/usr/libexec/istorec/unifi.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# Author Xiaobao(xiaobao@linkease.com) + +ACTION=${1} +shift 1 + +do_install() { + local hostnet=`uci get unifi.@main[0].hostnet 2>/dev/null` + local http_port=`uci get unifi.@main[0].http_port 2>/dev/null` + local image_name=`uci get unifi.@main[0].image_name 2>/dev/null` + local config=`uci get unifi.@main[0].config_path 2>/dev/null` + + [ -z "$image_name" ] && image_name="lscr.io/linuxserver/unifi-controller:latest" + echo "docker pull ${image_name}" + docker pull ${image_name} + docker rm -f unifi + + if [ -z "$config" ]; then + echo "config path is empty!" + exit 1 + fi + + [ -z "$http_port" ] && http_port=8083 + + local cmd="docker run --restart=unless-stopped -d -v \"$config:/config\" " + + if [ "$hostnet" = 1 ]; then + cmd="$cmd\ + --dns=127.0.0.1 \ + --network=host " + else + cmd="$cmd\ + --dns=172.17.0.1 \ + -p 3478:3478/udp \ + -p 10001:10001/udp \ + -p 8080:8080 \ + -p $http_port:8443 " + fi + + local tz="`cat /tmp/TZ`" + [ -z "$tz" ] || cmd="$cmd -e TZ=$tz" + + cmd="$cmd -v /mnt:/mnt" + mountpoint -q /mnt && cmd="$cmd:rslave" + cmd="$cmd --name unifi \"$image_name\"" + + echo "$cmd" + eval "$cmd" +} + +usage() { + echo "usage: $0 sub-command" + echo "where sub-command is one of:" + echo " install Install the unifi" + echo " upgrade Upgrade the unifi" + echo " rm/start/stop/restart Remove/Start/Stop/Restart the unifi" + echo " status UnifiController status" + echo " port UnifiController port" +} + +case ${ACTION} in + "install") + do_install + ;; + "upgrade") + do_install + ;; + "rm") + docker rm -f unifi + ;; + "start" | "stop" | "restart") + docker ${ACTION} unifi + ;; + "status") + docker ps --all -f 'name=unifi' --format '{{.State}}' + ;; + "port") + http_port=`uci get unifi.@main[0].http_port 2>/dev/null` + echo $http_port + ;; + *) + usage + exit 1 + ;; +esac