diff --git a/README.md b/README.md
index feec8c3481..4de920d856 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,8 @@ luci-app-ssr-plus-jo source: [Leo-Jo/luci-app-ssr-plus-jo](https://github.com/Le
openwrt-udpspeeder source: [pexcn/openwrt-udpspeeder](https://github.com/pexcn/openwrt-udpspeeder).
luci-app-onliner source: [rufengsuixing/luci-app-onliner](https://github.com/rufengsuixing/luci-app-onliner).
luci-app-dockerman source: [lisaac/luci-app-dockerman](https://github.com/lisaac/luci-app-dockerman).
-luci-lib-docker source: [luci-lib-docker](https://github.com/lisaac/luci-lib-docker).
+luci-lib-docker source: [luci-lib-docker](https://github.com/lisaac/luci-lib-docker).
+openwrt-iptvhelper source: [riverscn/openwrt-iptvhelper](https://github.com/riverscn/openwrt-iptvhelper).
# License
### [GPL v3](https://www.gnu.org/licenses/gpl-3.0.html).
diff --git a/package/ctcgfw/iptvhelper/Makefile b/package/ctcgfw/iptvhelper/Makefile
new file mode 100644
index 0000000000..7ecad4eedd
--- /dev/null
+++ b/package/ctcgfw/iptvhelper/Makefile
@@ -0,0 +1,50 @@
+# Copyright 2019 Shun Li
+# Licensed to the public under the GNU General Public License v3.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=iptvhelper
+PKG_VERSION:=0.1.1
+PKG_RELEASE:=1
+PKG_MAINTAINER:=Shun Li
+PKG_LICENSE:=GPL-3.0
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/iptvhelper
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Routing and Redirection
+ DEPENDS:= \
+ +ipset \
+ +iptables
+ TITLE:=Scripts for configure IPTV easily
+ MAINTAINER:=Shun Li
+ PKGARCH:=all
+endef
+
+define Package/iptvhelper/description
+Scripts for configure IPTV easily
+endef
+
+define Package/iptvhelper/conffiles
+/etc/config/iptvhelper
+/etc/firewall.iptvhelper
+endef
+
+define Build/Compile
+endef
+
+define Package/iptvhelper/postinst
+#!/bin/sh
+endef
+
+define Package/iptvhelper/postrm
+#!/bin/sh
+endef
+
+define Package/iptvhelper/install
+$(CP) ./files/* $(1)
+endef
+
+$(eval $(call BuildPackage,iptvhelper))
\ No newline at end of file
diff --git a/package/ctcgfw/iptvhelper/files/etc/config/iptvhelper b/package/ctcgfw/iptvhelper/files/etc/config/iptvhelper
new file mode 100644
index 0000000000..bad77043cd
--- /dev/null
+++ b/package/ctcgfw/iptvhelper/files/etc/config/iptvhelper
@@ -0,0 +1,8 @@
+config tvbox 'default'
+ option disabled '1'
+ option respawn '1'
+ option mac '00:00:00:00:00:00'
+ option ipset '1'
+ option dns_redir '1'
+
+
diff --git a/package/ctcgfw/iptvhelper/files/etc/firewall.iptvhelper b/package/ctcgfw/iptvhelper/files/etc/firewall.iptvhelper
new file mode 100755
index 0000000000..edf6ad7f6c
--- /dev/null
+++ b/package/ctcgfw/iptvhelper/files/etc/firewall.iptvhelper
@@ -0,0 +1,2 @@
+#!/bin/sh
+test -s "/etc/init.d/iptvhelper" && /etc/init.d/iptvhelper reload
\ No newline at end of file
diff --git a/package/ctcgfw/iptvhelper/files/etc/init.d/iptvhelper b/package/ctcgfw/iptvhelper/files/etc/init.d/iptvhelper
new file mode 100755
index 0000000000..e189cda15d
--- /dev/null
+++ b/package/ctcgfw/iptvhelper/files/etc/init.d/iptvhelper
@@ -0,0 +1,127 @@
+#!/bin/sh /etc/rc.common
+# Copyright 2019 Shun Li
+# Licensed to the public under the GNU General Public License v3.
+
+START=95
+USE_PROCD=1
+
+_ipt() {
+ cmd="$(echo "$@" | sed 's|-A|-D|g;s|-I|-D|g')"
+ while iptables $cmd &>/dev/null; do
+ :
+ done
+ iptables $@
+}
+
+destroy_iptv_ipset() {
+ for ip_set in $(ipset list | awk '/iptvhelper/ {print $2}'); do ipset destroy $ip_set; done
+}
+
+clear_iptv_rules() {
+ iptables-save --counters | grep -v "iptvhelper-rule" | iptables-restore --counters
+}
+
+append_arg() {
+ local cfg="$1"
+ local var="$2"
+ local opt="$3"
+ local def="$4"
+ local val
+
+ config_get val "$cfg" "$var"
+ [ -n "$val" -o -n "$def" ] && procd_append_param command $opt "${val:-$def}"
+}
+
+append_bool() {
+ local cfg="$1"
+ local var="$2"
+ local opt="$3"
+ local def="$4"
+ local val
+
+ config_get_bool val "$cfg" "$var" "$def"
+ [ "$val" = 1 ] && procd_append_param command "$opt"
+}
+
+start_instance() {
+ local cfg="$1"
+ local aux
+
+ config_get_bool aux "$cfg" 'disabled' '0'
+ [ "$aux" = 1 ] && return 1
+
+ logger "iptvhelper.$cfg: instance starting"
+
+ local IPTV_MAC
+ local IPTV_DNS_REDIR
+ local IPTV_IPSET
+
+ config_get IPTV_MAC $cfg mac
+ config_get IPTV_DNS_REDIR $cfg dns_redir
+ config_get IPTV_IPSET $cfg ipset
+ logger "iptvhelper.$cfg: topbox mac=$IPTV_MAC"
+
+ if [[ $IPTV_DNS_REDIR == '1' ]]; then
+ logger "iptvhelper.$cfg: topbox DNS redierct enabled"
+ _ipt -t nat -A PREROUTING -m mac --mac-source $IPTV_MAC -m comment --comment "iptvhelper-rule" -p udp --dport 53 -j REDIRECT --to-ports 53
+ fi
+
+ if [[ $IPTV_IPSET='1' ]]; then
+ logger "iptvhelper.$cfg: topbox ipset enabled"
+ if ! ipset -q list iptvhelper_$cfg >/dev/null; then
+ ipset create iptvhelper_$cfg nethash
+ fi
+ _ipt -t nat -I PREROUTING -m mac --mac-source $IPTV_MAC -m comment --comment "iptvhelper-rule" -m set ! --match-set iptvhelper_$cfg dst -m conntrack --ctstate NEW -j LOG --log-prefix "iptvhelper.$cfg:"
+ procd_open_instance
+ procd_set_param command /usr/sbin/iptvhelper.sh $cfg
+ config_get_bool aux "$cfg" 'respawn' '0'
+ [ "$aux" = 1 ] && procd_set_param respawn
+ procd_set_param pidfile /var/run/iptvhelper_$cfg.pid
+ procd_close_instance
+ fi
+}
+
+service_triggers() {
+ procd_add_reload_trigger "iptvhelper"
+}
+
+start_service() {
+ logger "iptvhelper: starting"
+ echo "iptvhelper: starting"
+ config_load iptvhelper
+ config_foreach start_instance tvbox
+ if uci -q show firewall >/dev/null; then
+ if ! uci -q get firewall.iptvhelper >/dev/null; then
+ uci -q batch <<-EOF >/dev/null
+ set firewall.iptvhelper=include
+ set firewall.iptvhelper.type='script'
+ set firewall.iptvhelper.path='/etc/firewall.iptvhelper'
+ set firewall.iptvhelper.family='any'
+ set firewall.iptvhelper.reload='1'
+ commit firewall
+ EOF
+ fi
+ fi
+}
+
+stop_service() {
+ if uci -q show firewall >/dev/null; then
+ if uci -q get firewall.iptvhelper >/dev/null; then
+ uci delete firewall.iptvhelper
+ uci commit firewall
+ fi
+ fi
+ for pid in $(ps | grep -v awk | awk '/iptvhelper.sh/ {print $1}'); do kill -9 $pid; done
+ for pid in $(ps | grep -v awk | awk '/logread -e iptvhelper/ {print $1}'); do kill -9 $pid; done
+ clear_iptv_rules
+ destroy_iptv_ipset
+ logger "iptvhelper: stopped"
+ echo "iptvhelper: stopped"
+}
+
+reload_service() {
+ logger "iptvhelper: reloading"
+ echo "iptvhelper: reloading"
+ stop
+ start
+}
diff --git a/package/ctcgfw/iptvhelper/files/usr/sbin/iptvhelper.sh b/package/ctcgfw/iptvhelper/files/usr/sbin/iptvhelper.sh
new file mode 100755
index 0000000000..ca746b63cb
--- /dev/null
+++ b/package/ctcgfw/iptvhelper/files/usr/sbin/iptvhelper.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# Copyright 2019 Shun Li
+# Licensed to the public under the GNU General Public License v3.
+
+add_to_set() {
+ local ip=$1
+ local cfg=$2
+ local subnet=$ip/24
+ ping -W1 -c1 $ip &>/dev/null && return
+ if ! ipset -q test iptvhelper_$cfg $subnet; then
+ ipset add iptvhelper_$cfg $subnet
+ echo added $subnet to set iptvhelper_$cfg
+ fi
+}
+
+echo $1
+
+logread -e "iptvhelper\.$1" -f |
+ while read line; do
+ ip=$(echo "$line" | sed -r 's|.*DST=([0-9.]+).*|\1|')
+ echo requested $ip
+ add_to_set $ip $1 &
+ done
diff --git a/package/ctcgfw/luci-app-iptvhelper/Makefile b/package/ctcgfw/luci-app-iptvhelper/Makefile
new file mode 100644
index 0000000000..17ccaf2a55
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/Makefile
@@ -0,0 +1,19 @@
+# Copyright 2019 Shun Li
+# Licensed to the public under the GNU General Public License v3.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=luci-app-iptvhelper
+PKG_VERSION:=0.1.1
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=Shun Li
+PKG_LICENSE:=GPL-3.0
+
+LUCI_TITLE:=LuCI support for iptvhelper
+LUCI_DEPENDS:=+luci-compat +iptvhelper
+LUCI_PKGARCH:=all
+
+include $(TOPDIR)/feeds/luci/luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
\ No newline at end of file
diff --git a/package/ctcgfw/luci-app-iptvhelper/luasrc/controller/iptvhelper.lua b/package/ctcgfw/luci-app-iptvhelper/luasrc/controller/iptvhelper.lua
new file mode 100644
index 0000000000..8290207e41
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/luasrc/controller/iptvhelper.lua
@@ -0,0 +1,14 @@
+-- Copyright 2019 Shun Li
+-- Licensed to the public under the GNU General Public License v3.
+
+module("luci.controller.iptvhelper", package.seeall)
+
+function index()
+ if not nixio.fs.access("/etc/config/iptvhelper") then
+ return
+ end
+
+ local page = entry({"admin", "services", "iptvhelper"}, cbi("iptvhelper"), _("IPTV Helper"))
+ page.dependent = true
+
+end
\ No newline at end of file
diff --git a/package/ctcgfw/luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua b/package/ctcgfw/luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua
new file mode 100644
index 0000000000..e4a106b05a
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua
@@ -0,0 +1,34 @@
+-- Copyright 2019 Shun Li
+-- Licensed to the public under the GNU General Public License v3.
+
+local sys = require "luci.sys"
+
+m = Map("iptvhelper", translate("IPTV Helper"), translate("Help you configure IPTV easily. Github"))
+
+s = m:section(TypedSection, "tvbox", translate("IPTV topbox parameters"))
+s.addremove = true
+s.anonymous = false
+
+enable=s:option(Flag, "disabled", translate("Enabled"))
+enable.enabled = "0"
+enable.disabled = "1"
+enable.default = "1"
+enable.rmempty = false
+respawn=s:option(Flag, "respawn", translate("Respawn"))
+respawn.default = false
+ipset=s:option(Flag, "ipset", translate("Create ipset"),
+ translate("You can use it in mwan3."))
+ipset.default = true
+dns_redir=s:option(Flag, "dns_redir", translate("Redirect topbox's DNS"),
+ translate("You may need it to jailbreak your topbox."))
+dns_redir.default = false
+
+host = s:option(Value, "mac", translate("Topbox MAC Address"),
+ translate("It is usually on the bottom side of topbox."))
+host.rmempty = false
+host.datatype = "macaddr"
+sys.net.mac_hints(function(mac, name)
+ host:value(mac, "%s (%s)" %{ mac, name })
+end)
+
+return m
\ No newline at end of file
diff --git a/package/ctcgfw/luci-app-iptvhelper/po/templates/iptvhelper.pot b/package/ctcgfw/luci-app-iptvhelper/po/templates/iptvhelper.pot
new file mode 100644
index 0000000000..808b51ba8b
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/po/templates/iptvhelper.pot
@@ -0,0 +1,49 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:19
+msgid "Create ipset"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:12
+msgid "Enabled"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:6
+msgid ""
+"Help you configure IPTV easily. Github"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/controller/iptvhelper.lua:11
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:6
+msgid "IPTV Helper"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:8
+msgid "IPTV topbox parameters"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:27
+msgid "It is usually on the bottom side of topbox."
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:22
+msgid "Redirect topbox's DNS"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:17
+msgid "Respawn"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:26
+msgid "Topbox MAC Address"
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:20
+msgid "You can use it in mwan3."
+msgstr ""
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:23
+msgid "You may need it to jailbreak your topbox."
+msgstr ""
diff --git a/package/ctcgfw/luci-app-iptvhelper/po/zh-cn/iptvhelper.po b/package/ctcgfw/luci-app-iptvhelper/po/zh-cn/iptvhelper.po
new file mode 100644
index 0000000000..04f74b8fe4
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/po/zh-cn/iptvhelper.po
@@ -0,0 +1,50 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:19
+msgid "Create ipset"
+msgstr "创建 ipset"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:12
+msgid "Enabled"
+msgstr "启用"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:6
+msgid ""
+"Help you configure IPTV easily. Github"
+msgstr "帮助你轻松配置IPTV。Github"
+
+#: luci-app-iptvhelper/luasrc/controller/iptvhelper.lua:11
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:6
+msgid "IPTV Helper"
+msgstr "IPTV 帮手"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:8
+msgid "IPTV topbox parameters"
+msgstr "IPTV 机顶盒参数"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:27
+msgid "It is usually on the bottom side of topbox."
+msgstr "它通常贴在机顶盒的底部"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:22
+msgid "Redirect topbox's DNS"
+msgstr "重定向机顶盒的DNS"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:17
+msgid "Respawn"
+msgstr "进程守护"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:26
+msgid "Topbox MAC Address"
+msgstr "机顶盒MAC地址"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:20
+msgid "You can use it in mwan3."
+msgstr "你可以在mwan3中使用它"
+
+#: luci-app-iptvhelper/luasrc/model/cbi/iptvhelper.lua:23
+msgid "You may need it to jailbreak your topbox."
+msgstr "想要破解机顶盒可能会用到它"
diff --git a/package/ctcgfw/luci-app-iptvhelper/root/etc/uci-defaults/40_iptvhelper b/package/ctcgfw/luci-app-iptvhelper/root/etc/uci-defaults/40_iptvhelper
new file mode 100755
index 0000000000..8ee6587be0
--- /dev/null
+++ b/package/ctcgfw/luci-app-iptvhelper/root/etc/uci-defaults/40_iptvhelper
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# needed for "Save and Apply" to restart iptvhelper
+uci -q batch <<-EOF >/dev/null
+ delete ucitrack.@iptvhelper[-1]
+ add ucitrack iptvhelper
+ set ucitrack.@iptvhelper[-1].init="iptvhelper"
+ commit ucitrack
+EOF
+
+rm -f /tmp/luci-indexcache
+exit 0
\ No newline at end of file