diff --git a/applications/luci-app-plex/Makefile b/applications/luci-app-plex/Makefile
new file mode 100644
index 0000000..851ae7c
--- /dev/null
+++ b/applications/luci-app-plex/Makefile
@@ -0,0 +1,18 @@
+
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=1.0.0-20221106
+PKG_RELEASE:=
+
+LUCI_TITLE:=LuCI support for Plex
+LUCI_PKGARCH:=all
+LUCI_DEPENDS:=+docker +luci-lib-taskd
+
+define Package/luci-app-plex/conffiles
+/etc/config/plex
+endef
+
+include $(TOPDIR)/feeds/luci/luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-plex/luasrc/controller/plex.lua b/applications/luci-app-plex/luasrc/controller/plex.lua
new file mode 100755
index 0000000..23a6e6a
--- /dev/null
+++ b/applications/luci-app-plex/luasrc/controller/plex.lua
@@ -0,0 +1,7 @@
+
+module("luci.controller.heimdall", package.seeall)
+
+function index()
+ entry({"admin", "services", "heimdall"}, alias("admin", "services", "heimdall", "config"), _("Heimdall"), 30).dependent = true
+ entry({"admin", "services", "heimdall", "config"}, cbi("heimdall"))
+end
diff --git a/applications/luci-app-plex/luasrc/model/cbi/plex.lua b/applications/luci-app-plex/luasrc/model/cbi/plex.lua
new file mode 100644
index 0000000..2d4ac86
--- /dev/null
+++ b/applications/luci-app-plex/luasrc/model/cbi/plex.lua
@@ -0,0 +1,44 @@
+--[[
+LuCI - Lua Configuration Interface
+]]--
+
+local taskd = require "luci.model.tasks"
+local m, s, o
+
+m = taskd.docker_map("plex", "plex", "/usr/libexec/istorec/plex.sh",
+ translate("Plex"),
+ translate("Plex is an elegant solution to organise all your web applications.")
+ .. translate("Official website:") .. ' https://www.plex.tv/')
+
+s = m:section(SimpleSection, translate("Service Status"), translate("Plex status:"))
+s:append(Template("plex/status"))
+
+s = m:section(TypedSection, "plex", 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("Plex running in host network, for DLNA application, port is always 32400 if enabled"))
+o.default = 0
+o.rmempty = false
+
+o = s:option(Value, "claim_token", translate("Plex Claim").."*")
+o.rmempty = false
+o.datatype = "string"
+
+o = s:option(Value, "port", translate("Port").."*")
+o.rmempty = false
+o.default = "32400"
+o.datatype = "port"
+o:depends("hostnet", 0)
+
+o = s:option(Value, "config_path", translate("Config path").."*")
+o.rmempty = false
+o.datatype = "string"
+
+o = s:option(Value, "media_path", translate("Media path"))
+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"))
+o.datatype = "string"
+
+return m
diff --git a/applications/luci-app-plex/luasrc/model/plex.lua b/applications/luci-app-plex/luasrc/model/plex.lua
new file mode 100644
index 0000000..80335bc
--- /dev/null
+++ b/applications/luci-app-plex/luasrc/model/plex.lua
@@ -0,0 +1,23 @@
+local util = require "luci.util"
+local jsonc = require "luci.jsonc"
+
+local plex_model = {}
+
+plex_model.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
+
diff --git a/applications/luci-app-plex/luasrc/view/plex/status.htm b/applications/luci-app-plex/luasrc/view/plex/status.htm
new file mode 100644
index 0000000..b5afa1b
--- /dev/null
+++ b/applications/luci-app-plex/luasrc/view/plex/status.htm
@@ -0,0 +1,31 @@
+<%
+local util = require "luci.util"
+local container_status = util.trim(util.exec("/usr/libexec/istorec/plex.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/plex.sh port"))
+ if port == "" then
+ port="32400"
+ end
+-%>
+
+<% end %>
diff --git a/applications/luci-app-plex/po/zh-cn/plex.po b/applications/luci-app-plex/po/zh-cn/plex.po
new file mode 100644
index 0000000..ccd5049
--- /dev/null
+++ b/applications/luci-app-plex/po/zh-cn/plex.po
@@ -0,0 +1,41 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid "Official website:"
+msgstr "官方网站:"
+
+msgid "Plex is an streaming media service and a client–server media player platform, made by Plex, Inc."
+msgstr "Plex 是一个多媒体串流平台。"
+
+msgid "Config path"
+msgstr "配置文件路径"
+
+msgid "Port"
+msgstr "端口"
+
+msgid "HTTP Port"
+msgstr "HTTP 端口"
+
+msgid "Service Status"
+msgstr "服务状态"
+
+msgid "Plex status:"
+msgstr "Plex 的状态信息如下:"
+
+msgid "Setup"
+msgstr "安装配置"
+
+msgid "The following parameters will only take effect during installation or upgrade:"
+msgstr "以下参数只在安装或者升级时才会生效:"
+
+msgid "Status"
+msgstr "状态"
+
+msgid "Plex is running"
+msgstr "Plex 运行中"
+
+msgid "Plex is not running"
+msgstr "Plex 未运行"
+
+msgid "Open Plex"
+msgstr "打开 Plex"
diff --git a/applications/luci-app-plex/root/etc/config/plex b/applications/luci-app-plex/root/etc/config/plex
new file mode 100644
index 0000000..554dbd2
--- /dev/null
+++ b/applications/luci-app-plex/root/etc/config/plex
@@ -0,0 +1,4 @@
+config heimdall
+ option 'http_port' '8088'
+ option 'https_port' '8089'
+ option 'config_path' '/root/heimdall/config'
diff --git a/applications/luci-app-plex/root/usr/libexec/istorec/plex.sh b/applications/luci-app-plex/root/usr/libexec/istorec/plex.sh
new file mode 100755
index 0000000..07c53b5
--- /dev/null
+++ b/applications/luci-app-plex/root/usr/libexec/istorec/plex.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+# Author Xiaobao(xiaobao@linkease.com)
+
+ACTION=${1}
+shift 1
+
+do_install() {
+ local hostnet=`uci get plex.@plex[0].hostnet 2>/dev/null`
+ local claim_token==`uci get plex.@plex[0].claim_token 2>/dev/null`
+ local port=`uci get plex.@plex[0].port 2>/dev/null`
+ local image_name=`uci get plex.@plex[0].image_name 2>/dev/null`
+ local config=`uci get plex.@plex[0].config_path 2>/dev/null`
+ local media=`uci get plex.@plex[0].media_path 2>/dev/null`
+ local cache=`uci get plex.@plex[0].cache_path 2>/dev/null`
+
+ [-z "$image_name" ] && image_name="plexinc/pms-docker:latest"
+ echo "docker pull ${image_name}"
+ docker pull ${image_name}
+ docker rm -f plex
+
+ if [ -z "$config" ]; then
+ echo "config path is empty!"
+ exit 1
+ fi
+
+ [ -z "$port" ] && port=32400
+
+ local cmd="docker run --restart=unless-stopped -d -e PLEX_CLAIM="$claim_token" -v \"$config:/config\" "
+
+ if [ -d /dev/dri ]; then
+ cmd="$cmd\
+ --device /dev/dri:/dev/dri \
+ --privileged "
+ fi
+
+ if [ "$hostnet" = 1 ]; then
+ cmd="$cmd\
+ --dns=127.0.0.1 \
+ --network=host "
+ else
+ cmd="$cmd\
+ --dns=172.17.0.1 \
+ -p 3005:3005/tcp \
+ -p 8324:8324/tcp \
+ -p 32469:32469/tcp \
+ -p 1900:1900/udp \
+ -p 32410:32410/udp \
+ -p 32412:32412/udp \
+ -p 32413:32413/udp \
+ -p 32414:32414/udp \
+ -p $port:32400 "
+ fi
+
+ local tz="`cat /tmp/TZ`"
+ [ -z "$tz" ] || cmd="$cmd -e TZ=$tz"
+
+ [ -z "$cache" ] || cmd="$cmd -v \"$cache:/config/transcodes\""
+ [ -z "$media" ] || cmd="$cmd -v \"$media:/media\""
+
+ cmd="$cmd -v /mnt:/mnt"
+ mountpoint -q /mnt && cmd="$cmd:rslave"
+ cmd="$cmd --name plex \"$IMAGE_NAME\""
+
+ echo "$cmd"
+ eval "$cmd"
+}
+
+usage() {
+ echo "usage: $0 sub-command"
+ echo "where sub-command is one of:"
+ echo " install Install the plex"
+ echo " upgrade Upgrade the plex"
+ echo " rm/start/stop/restart Remove/Start/Stop/Restart the plex"
+ echo " status Heimdall status"
+ echo " port Heimdall port"
+}
+
+case ${ACTION} in
+ "install")
+ do_install
+ ;;
+ "upgrade")
+ do_install
+ ;;
+ "rm")
+ docker rm -f plex
+ ;;
+ "start" | "stop" | "restart")
+ docker ${ACTION} plex
+ ;;
+ "status")
+ docker ps --all -f 'name=plex' --format '{{.State}}'
+ ;;
+ "port")
+ docker ps --all -f 'name=plex' --format '{{.Ports}}' | grep -om1 '0.0.0.0:[0-9]*' | sed 's/0.0.0.0://'
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac