package ctcgfw: sync

This commit is contained in:
CN_SZTL 2020-02-07 22:10:39 +08:00
parent e0244ad58a
commit 94655b05d3
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
65 changed files with 1636 additions and 755 deletions

View File

@ -43,4 +43,4 @@ define Package/$(PKG_NAME)/install
po2lmo ./po/pl/diskman.po $(1)/usr/lib/lua/luci/i18n/diskman.pl.lmo
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -1 +1 @@
e2fsprogs parted smartmontools blkid
e2fsprogs parted smartmontools blkid mdadm btrfs-progs util-linux mergerfs snapraid

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
require "luci.util"
@ -29,6 +24,7 @@ function index()
entry({"admin", "system", "diskman"}, alias("admin", "system", "diskman", "disks"), _("Disk Man"), 55)
entry({"admin", "system", "diskman", "disks"}, form("diskman/disks"), nil).leaf = true
entry({"admin", "system", "diskman", "partition"}, form("diskman/partition"), nil).leaf = true
entry({"admin", "system", "diskman", "btrfs"}, form("diskman/btrfs"), nil).leaf = true
entry({"admin", "system", "diskman", "get_disk_info"}, call("get_disk_info"), nil).leaf = true
entry({"admin", "system", "diskman", "mk_p_table"}, call("mk_p_table"), nil).leaf = true
entry({"admin", "system", "diskman", "smartdetail"}, call("smart_detail"), nil).leaf = true

View File

@ -0,0 +1,210 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
]]--
require "luci.util"
require("luci.tools.webadmin")
local dm = require "luci.model.diskman"
local uuid = arg[1]
if not uuid then luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) end
-- mount subv=/ to tempfs
mount_point = "/tmp/.btrfs_tmp"
nixio.fs.mkdirr(mount_point)
luci.util.exec(dm.command.umount .. " "..mount_point .. " >/dev/null 2>&1")
luci.util.exec(dm.command.mount .. " -t btrfs -o subvol=/ UUID="..uuid.." "..mount_point)
m = SimpleForm("btrfs", translate("Btrfs"), translate("Manage Btrfs"))
m.template = "diskman/cbi/xsimpleform"
m.redirect = luci.dispatcher.build_url("admin/system/diskman")
m.submit = false
m.reset = false
-- info
local btrfs_info = dm.get_btrfs_info(mount_point)
local table_btrfs_info = m:section(Table, {btrfs_info}, translate("Btrfs Info"))
table_btrfs_info:option(DummyValue, "uuid", translate("UUID"))
table_btrfs_info:option(DummyValue, "members", translate("Members"))
table_btrfs_info:option(DummyValue, "data_raid_level", translate("Data"))
table_btrfs_info:option(DummyValue, "metadata_raid_lavel", translate("Metadata"))
table_btrfs_info:option(DummyValue, "size_formated", translate("Size"))
table_btrfs_info:option(DummyValue, "used_formated", translate("Used"))
table_btrfs_info:option(DummyValue, "free_formated", translate("Free Space"))
table_btrfs_info:option(DummyValue, "usage", translate("Usage"))
local v_btrfs_label = table_btrfs_info:option(Value, "label", translate("Label"))
local value_btrfs_label = ""
v_btrfs_label.write = function(self, section, value)
value_btrfs_label = value or ""
end
local btn_update_label = table_btrfs_info:option(Button, "_update_label")
btn_update_label.inputtitle = translate("Update")
btn_update_label.inputstyle = "edit"
btn_update_label.write = function(self, section, value)
local cmd = dm.command.btrfs .. " filesystem label " .. mount_point .. " " .. value_btrfs_label
local res = luci.util.exec(cmd)
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
end
-- subvolume
local subvolume_list = dm.get_btrfs_subv(mount_point)
subvolume_list["_"] = { ID = 0 }
table_subvolume = m:section(Table, subvolume_list, translate("SubVolumes"))
table_subvolume:option(DummyValue, "id", translate("ID"))
table_subvolume:option(DummyValue, "top_level", translate("Top Level"))
table_subvolume:option(DummyValue, "uuid", translate("UUID"))
table_subvolume:option(DummyValue, "otime", translate("Otime"))
table_subvolume:option(DummyValue, "snapshots", translate("Snapshots"))
local v_path = table_subvolume:option(Value, "path", translate("Path"))
v_path.forcewrite = true
v_path.render = function(self, section, scope)
if subvolume_list[section].ID == 0 then
self.template = "cbi/value"
self.placeholder = "/my_subvolume"
self.forcewrite = true
Value.render(self, section, scope)
else
self.template = "cbi/dvalue"
DummyValue.render(self, section, scope)
end
end
local value_path
v_path.write = function(self, section, value)
value_path = value
end
local btn_set_default = table_subvolume:option(Button, "_subv_set_default", translate("Set Default"))
btn_set_default.forcewrite = true
btn_set_default.inputstyle = "edit"
btn_set_default.template = "diskman/cbi/disabled_button"
btn_set_default.render = function(self, section, scope)
if subvolume_list[section].default_subvolume then
self.view_disabled = true
self.inputtitle = translate("Set Default")
elseif subvolume_list[section].ID == 0 then
self.template = "cbi/dvalue"
else
self.inputtitle = translate("Set Default")
self.view_disabled = false
end
Button.render(self, section, scope)
end
btn_set_default.write = function(self, section, value)
local cmd
if value == translate("Set Default") then
cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point..subvolume_list[section].path
else
cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point.."/"
end
local res = luci.util.exec(cmd.. " 2>&1")
if res and (res:match("ERR") or res:match("not enough arguments")) then
m.errmessage = res
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
end
end
local btn_remove = table_subvolume:option(Button, "_subv_remove")
btn_remove.template = "diskman/cbi/disabled_button"
btn_remove.forcewrite = true
btn_remove.render = function(self, section, scope)
if subvolume_list[section].ID == 0 then
btn_remove.inputtitle = translate("Create")
btn_remove.inputstyle = "add"
self.view_disabled = false
elseif subvolume_list[section].path == "/" or subvolume_list[section].default_subvolume then
btn_remove.inputtitle = translate("Delete")
btn_remove.inputstyle = "remove"
self.view_disabled = true
else
btn_remove.inputtitle = translate("Delete")
btn_remove.inputstyle = "remove"
self.view_disabled = false
end
Button.render(self, section, scope)
end
btn_remove.write = function(self, section, value)
local cmd
if value == translate("Delete") then
cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. subvolume_list[section].path
elseif value == translate("Create") then
if value_path and value_path:match("^/") then
cmd = dm.command.btrfs .. " subvolume create " .. mount_point .. value_path
else
m.errmessage = translate("Please input Subvolume Path, Subvolume must start with '/'")
return
end
end
local res = luci.util.exec(cmd.. " 2>&1")
if res and (res:match("ERR") or res:match("not enough arguments")) then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
end
end
-- snapshot
-- local snapshot_list = dm.get_btrfs_subv(mount_point, 1)
-- table_snapshot = m:section(Table, snapshot_list, translate("Snapshots"))
-- table_snapshot:option(DummyValue, "id", translate("ID"))
-- table_snapshot:option(DummyValue, "top_level", translate("Top Level"))
-- table_snapshot:option(DummyValue, "uuid", translate("UUID"))
-- table_snapshot:option(DummyValue, "otime", translate("Otime"))
-- table_snapshot:option(DummyValue, "path", translate("Path"))
-- local snp_remove = table_snapshot:option(Button, "_snp_remove")
-- snp_remove.inputtitle = translate("Delete")
-- snp_remove.inputstyle = "remove"
-- snp_remove.write = function(self, section, value)
-- local cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. snapshot_list[section].path
-- local res = luci.util.exec(cmd.. " 2>&1")
-- if res and (res:match("ERR") or res:match("not enough arguments")) then
-- m.errmessage = luci.util.pcdata(res)
-- else
-- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
-- end
-- end
-- new snapshots
local s_snapshot = m:section(SimpleSection, translate("New Snapshot"))
local value_sorce, value_dest, value_readonly
local v_sorce = s_snapshot:option(Value, "_source", translate("Source Path"), translate("The source path for create the snapshot"))
v_sorce.placeholder = "/data"
v_sorce.forcewrite = true
v_sorce.write = function(self, section, value)
value_sorce = value
end
local v_readonly = s_snapshot:option(Flag, "_readonly", translate("Readonly"), translate("The path where you want to store the snapshot"))
v_readonly.forcewrite = true
v_readonly.rmempty = false
v_readonly.disabled = 0
v_readonly.enabled = 1
v_readonly.default = 1
v_readonly.write = function(self, section, value)
value_readonly = value
end
local v_dest = s_snapshot:option(Value, "_dest", translate("Destination Path (optional)"))
v_dest.forcewrite = true
v_dest.placeholder = "/.snapshot/202002051538"
v_dest.write = function(self, section, value)
value_dest = value
end
local btn_snp_create = s_snapshot:option(Button, "_snp_create")
btn_snp_create.title = " "
btn_snp_create.inputtitle = translate("New Snapshot")
btn_snp_create.inputstyle = "add"
btn_snp_create.write = function(self, section, value)
if value_sorce and value_sorce:match("^/") then
if not value_dest then value_dest = "/.snapshot"..value_sorce.."/"..os.date("%Y%m%d%H%M%S") end
nixio.fs.mkdirr(mount_point..value_dest:match("(.-)[^/]+$"))
local cmd = dm.command.btrfs .. " subvolume snapshot" .. (value_readonly == 1 and " -r " or " ") .. mount_point..value_sorce .. " " .. mount_point..value_dest
local res = luci.util.exec(cmd .. " 2>&1")
if res and (res:match("ERR") or res:match("not enough arguments")) then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid))
end
else
m.errmessage = translate("Please input Source Path of snapshot, Source Path must start with '/'")
end
end
return m

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
require "luci.util"
@ -67,17 +62,23 @@ if dm.command.mdadm then
r:option(DummyValue, "status", translate("Status"))
r:option(DummyValue, "members_str", translate("Members"))
r:option(DummyValue, "active", translate("Active"))
-- local redit = r:option(Button, "rpartition")
-- redit.inputstyle = "edit"
-- redit.inputtitle = "Edit"
-- redit.write = function(self, section)
-- local url = luci.dispatcher.build_url("admin/system/diskman/partition")
-- url = url .. "/" .. raid_devices[section].path:match("/dev/(.+)")
-- luci.http.redirect(url)
-- end
r.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s")
end
end
-- btrfs devices
if dm.command.btrfs then
btrfs_devices = dm.list_btrfs_devices()
if next(btrfs_devices) ~= nil then
local table_btrfs = m:section(Table, btrfs_devices, translate("Btrfs"))
table_btrfs:option(DummyValue, "uuid", translate("UUID"))
table_btrfs:option(DummyValue, "label", translate("Label"))
table_btrfs:option(DummyValue, "members", translate("Members"))
-- sieze is error, since there is RAID
-- table_btrfs:option(DummyValue, "size_formated", translate("Size"))
table_btrfs:option(DummyValue, "used_formated", translate("Usage"))
table_btrfs.extedit = luci.dispatcher.build_url("admin/system/diskman/btrfs/%s")
end
end
--tabs
@ -95,12 +96,12 @@ if dm.command.mdadm then
local r = m:section(SimpleSection, translate("RAID Creation"))
r.template="diskman/cbi/xnullsection"
r.config = "raid"
local r_name = r:option(Value, "_name", translate("Raid Name"))
local r_name = r:option(Value, "_rname", translate("Raid Name"))
r_name.placeholder = "/dev/md0"
r_name.write = function(self, section, value)
rname = value
end
local r_level = r:option(ListValue, "_level", translate("Raid Level"))
local r_level = r:option(ListValue, "_rlevel", translate("Raid Level"))
local valid_raid = luci.util.exec("lsmod | grep md_mod")
if valid_raid:match("linear") then
r_level:value("linear", "Linear")
@ -121,7 +122,7 @@ if dm.command.mdadm then
r_level.write = function(self, section, value)
rlevel = value
end
local r_member = r:option(DynamicList, "_member", translate("Raid Member"))
local r_member = r:option(DynamicList, "_rmember", translate("Raid Member"))
for dev, info in pairs(disks) do
if not info.inuse and #info.partitions == 0 then
r_member:value(info.path, info.path.. " ".. info.size_formated)
@ -135,7 +136,7 @@ if dm.command.mdadm then
r_member.write = function(self, section, value)
rmembers = value
end
local r_create = r:option(Button, "_create")
local r_create = r:option(Button, "_rcreate")
r_create.render = function(self, section, scope)
self.title = " "
self.inputtitle = translate("Create Raid")
@ -145,8 +146,8 @@ if dm.command.mdadm then
r_create.write = function(self, section, value)
-- mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/sdb6 /dev/sdc5
local res = dm.create_raid(rname, rlevel, rmembers)
if res:match("^ERR") then
m.errmessage = translate(res)
if res and res:match("^ERR") then
m.errmessage = luci.util.pcdata(res)
return
end
dm.gen_mdadm_config()
@ -201,11 +202,17 @@ v_mount_option.render = function(self, section, scope)
self.template = "cbi/dvalue"
local mp = mount_point[section].mount_options
mount_point[section].mount_options = nil
local length = 0
for k in mp:gmatch("([^,]+)") do
mount_point[section].mount_options = mount_point[section].mount_options and mount_point[section].mount_options .. "," or ""
if #mount_point[section].mount_options > 50 then mount_point[section].mount_options = mount_point[section].mount_options.. " " end
mount_point[section].mount_options= mount_point[section].mount_options.. k
mount_point[section].mount_options = mount_point[section].mount_options and (mount_point[section].mount_options .. ",") or ""
if length > 20 then
mount_point[section].mount_options = mount_point[section].mount_options.. " <br>"
length = 0
end
mount_point[section].mount_options = mount_point[section].mount_options .. k
length = length + #k
end
self.rawhtml = true
-- mount_point[section].mount_options = #mount_point[section].mount_options > 50 and mount_point[section].mount_options:sub(1,50) .. "..." or mount_point[section].mount_options
DummyValue.render(self, section, scope)
end
@ -244,22 +251,67 @@ btn_umount.write = function(self, section, value)
local res
if value == translate("Mount") then
luci.util.exec("mkdir -p ".. _mount_point.mount_point)
res = luci.util.exec("mount ".. _mount_point.device .. (_mount_point.fs and (" -t ".. _mount_point.fs )or "") .. (_mount_point.mount_options and (" -o " .. _mount_point.mount_options.. " ") or " ").._mount_point.mount_point .. " 2>&1")
res = luci.util.exec(dm.command.mount .. " ".. _mount_point.device .. (_mount_point.fs and (" -t ".. _mount_point.fs )or "") .. (_mount_point.mount_options and (" -o " .. _mount_point.mount_options.. " ") or " ").._mount_point.mount_point .. " 2>&1")
elseif value == translate("Umount") then
res = luci.util.exec("umount "..mount_point[section].mount_point .. " 2>&1")
res = luci.util.exec(dm.command.umount .. " "..mount_point[section].mount_point .. " 2>&1")
end
if res:match("^mount:") then
if res:match("^mount:") or res:match("^umount:") then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
end
end
-- -- btrfs
-- btrfs
if dm.command.btrfs then
local blabel, bmembers, blevel
tab_section.tabs.btrfs = translate("Btrfs")
local btrfs_devices = {}
local table_btrfs = m:section(Table, btrfs_devices, translate("Btrfs"))
table_btrfs.config = "btrfs"
local r = m:section(SimpleSection, translate("Multiple Devices Btrfs Creation"))
r.template="diskman/cbi/xnullsection"
r.config = "btrfs"
local btrfs_label = r:option(Value, "_blabel", translate("Btrfs Label"))
btrfs_label.write = function(self, section, value)
blabel = value
end
local btrfs_level = r:option(ListValue, "_blevel", translate("Btrfs Raid Level"))
btrfs_level:value("single", "Single")
btrfs_level:value("raid0", "Raid 0")
btrfs_level:value("raid1", "Raid 1")
btrfs_level:value("raid10", "Raid 10")
btrfs_level.write = function(self, section, value)
blevel = value
end
local btrfs_member = r:option(DynamicList, "_bmember", translate("Btrfs Member"))
for dev, info in pairs(disks) do
if not info.inuse and #info.partitions == 0 then
btrfs_member:value(info.path, info.path.. " ".. info.size_formated)
end
for i, v in ipairs(info.partitions) do
if not v.inuse then
btrfs_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated)
end
end
end
btrfs_member.write = function(self, section, value)
bmembers = value
end
local btrfs_create = r:option(Button, "_bcreate")
btrfs_create.render = function(self, section, scope)
self.title = " "
self.inputtitle = translate("Create Btrfs")
self.inputstyle = "add"
Button.render(self, section, scope)
end
btrfs_create.write = function(self, section, value)
-- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb
local res = dm.create_btrfs(blabel, blevel, bmembers)
if res and res:match("^ERR") then
m.errmessage = luci.util.pcdata(res)
return
end
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman"))
end
end
return m

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
require "luci.util"
@ -37,10 +32,11 @@ s:option(DummyValue, "path", translate("Path"))
s:option(DummyValue, "model", translate("Model"))
s:option(DummyValue, "sn", translate("Serial Number"))
s:option(DummyValue, "size_formated", translate("Size"))
s:option(DummyValue, "sec_size", translate("Sector Size "))
s:option(DummyValue, "sec_size", translate("Sector Size"))
local dv_p_table = s:option(ListValue, "p_table", translate("Partition Table"))
dv_p_table.render = function(self, section, scope)
if not disk_info.p_table:match("Raid") and (#disk_info.partitions == 0 or (#disk_info.partitions == 1 and disk_info.partitions[1].number == -1)) then
-- create table only if not used by raid and no partitions on disk
if not disk_info.p_table:match("Raid") and (#disk_info.partitions == 0 or (#disk_info.partitions == 1 and disk_info.partitions[1].number == -1) or (disk_info.p_table:match("LOOP") and not disk_info.partitions[1].inuse)) then
self:value(disk_info.p_table, disk_info.p_table)
self:value("GPT", "GPT")
self:value("MBR", "MBR")
@ -100,7 +96,7 @@ btn_eject.forcewrite = true
btn_eject.write = function(self, section, value)
for i, p in ipairs(disk_info.partitions) do
if p.mount_point ~= "-" then
m.errmessage = p.name .. "is in use! please unmount it first!"
m.errmessage = p.name .. translate("is in use! please unmount it first!")
return
end
end
@ -160,7 +156,9 @@ if not disk_info.p_table:match("Raid") then
if disk_info.p_table == "MBR" then
s_partition_table:option(DummyValue, "type", translate("Type"))
end
s_partition_table:option(DummyValue, "useage", translate("Useage"))
s_partition_table:option(DummyValue, "used_formated", translate("Used"))
s_partition_table:option(DummyValue, "free_formated", translate("Free Space"))
s_partition_table:option(DummyValue, "usage", translate("Usage"))
s_partition_table:option(DummyValue, "mount_point", translate("Mount Point"))
local val_fs = s_partition_table:option(Value, "fs", translate("File System"))
val_fs.forcewrite = true
@ -211,18 +209,21 @@ if not disk_info.p_table:match("Raid") then
btn_format.write = function(self, section, value)
local partition_name = "/dev/".. disk_info.partitions[section].name
if not nixio.fs.access(partition_name) then
m.errmessage = "Partition NOT found!"
m.errmessage = translate("Partition NOT found!")
return
end
local fs = disk_info.partitions[section]._fs
if not format_cmd[fs] then
m.errmessage = "Filesystem NOT support!"
m.errmessage = translate("Filesystem NOT support!")
return
end
local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name
-- luci.util.perror(cmd)
local res = luci.sys.exec(cmd)
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
local res = luci.util.exec(cmd .. " 2>&1")
if res and res:lower():match("error+") then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
end
end
local btn_action = s_partition_table:option(Button, "_action")
@ -250,7 +251,6 @@ if not disk_info.p_table:match("Raid") then
Button.render(self, section, scope)
end
btn_action.write = function(self, section, value)
-- luci.util.perror(value)
if value == translate("New") then
local start_sec = disk_info.partitions[section]._sec_start and tonumber(disk_info.partitions[section]._sec_start) or tonumber(disk_info.partitions[section].sec_start)
local end_sec = disk_info.partitions[section]._sec_end
@ -267,7 +267,7 @@ if not disk_info.p_table:match("Raid") then
start_sec = start_sec .. "s"
end
else
m.errmessage = "Invalid Start Sector!"
m.errmessage = translate("Invalid Start Sector!")
return
end
-- support +size format for End sector
@ -286,7 +286,7 @@ if not disk_info.p_table:match("Raid") then
elseif tonumber(end_sec) then
end_sec = end_sec .. "s"
else
m.errmessage = "Invalid End Sector!"
m.errmessage = translate("Invalid End Sector!")
return
end
local part_type = "primary"
@ -305,9 +305,9 @@ if not disk_info.p_table:match("Raid") then
-- partiton
local cmd = dm.command.parted .. " -s -a optimal /dev/" .. dev .. " mkpart " .. part_type .." " .. start_sec .. " " .. end_sec
local res = luci.util.exec(cmd)
if res:match("Error.+") then
m.errmessage = res
local res = luci.util.exec(cmd .. " 2>&1")
if res and res:lower():match("error+") then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
end
@ -315,13 +315,13 @@ if not disk_info.p_table:match("Raid") then
-- remove partition
local number = tostring(disk_info.partitions[section].number)
if (not number) or (number == "") then
m.errmessage = "Partition not exists!"
m.errmessage = translate("Partition not exists!")
return
end
local cmd = dm.command.parted .. " -s /dev/" .. dev .. " rm " .. number
local res = luci.util.exec(cmd)
if res:match("Error.+") then
m.errmessage = res
local res = luci.util.exec(cmd .. " 2>&1")
if res and res:lower():match("error+") then
m.errmessage = luci.util.pcdata(res)
else
luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev))
end

View File

@ -1,17 +1,12 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-diskman>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
]]--
require "luci.util"
local ver = require "luci.version"
local CMD = {"parted", "mdadm", "blkid", "smartctl", "df", "sgdisk", "btrfs"}
local CMD = {"parted", "mdadm", "blkid", "smartctl", "df", "sgdisk", "btrfs", "mergerfs", "snapraid"}
local d = {command ={}}
for _, cmd in ipairs(CMD) do
@ -19,6 +14,9 @@ for _, cmd in ipairs(CMD) do
d.command[cmd] = command:match("^.+"..cmd) or nil
end
d.command.mount = nixio.fs.access("/usr/bin/mount") and "/usr/bin/mount" or "/bin/mount"
d.command.umount = nixio.fs.access("/usr/bin/umount") and "/usr/bin/umount" or "/bin/umount"
local mounts = nixio.fs.readfile("/proc/mounts") or ""
local swaps = nixio.fs.readfile("/proc/swaps") or ""
local df = luci.sys.exec(d.command.df) or ""
@ -142,11 +140,16 @@ local get_mount_point = function(partition)
end
local get_partition_useage = function(partition)
-- return used, free, usage
local get_partition_usage = function(partition)
if not nixio.fs.access("/dev/"..partition) then return false end
local useage = df:match("\n/dev/" .. partition .. "%s+%d+%s+%d+%s+%d+%s+([0-9]+)%%%s")
useage = useage and (useage .. "%") or false
return useage
local used, free, usage = df:match("\n/dev/" .. partition .. "%s+%d+%s+(%d+)%s+(%d+)%s+(%d+)%%%s-")
usage = usage and (usage .. "%") or "-"
used = used and (tonumber(used) * 1024) or 0
free = free and (tonumber(free) * 1024) or 0
return used, free, usage
end
local get_parted_info = function(device)
@ -195,7 +198,15 @@ local get_parted_info = function(device)
partition_temp["sec_start"] = partition_temp["sec_start"] and partition_temp["sec_start"]:sub(1,-2)
partition_temp["sec_end"] = partition_temp["sec_end"] and partition_temp["sec_end"]:sub(1,-2)
partition_temp["mount_point"] = partition_temp["name"]~="-" and get_mount_point(partition_temp["name"]) or "-"
partition_temp["useage"] = partition_temp["mount_point"]~="-" and get_partition_useage(partition_temp["name"]) or "-"
if partition_temp["mount_point"]~="-" then
partition_temp["used"], partition_temp["free"], partition_temp["usage"] = get_partition_usage(partition_temp["name"])
partition_temp["used_formated"] = partition_temp["used"] and byte_format(partition_temp["used"]) or "-"
partition_temp["free_formated"] = partition_temp["free"] and byte_format(partition_temp["free"]) or "-"
else
partition_temp["used"], partition_temp["free"], partition_temp["usage"] = 0,0,"-"
partition_temp["used_formated"] = "-"
partition_temp["free_formated"] = "-"
end
-- if disk_temp["p_table"] == "MBR" and (partition_temp["number"] < 4) and (partition_temp["number"] > 0) then
-- local real_size_sec = tonumber(nixio.fs.readfile("/sys/block/"..device.."/"..partition_temp["name"].."/size")) * tonumber(disk_temp.phy_sec)
-- if real_size_sec ~= partition_temp["size"] then
@ -288,8 +299,8 @@ d.get_disk_info = function(device, wakeup)
{
path, model, sn, size, size_mounted, flags, type, temp, p_table, logic_sec, phy_sec, sec_size, sata_ver, rota_rate, status, health,
partitions = {
1 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, useage },
2 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, useage },
1 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated},
2 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated},
...
}
--raid devices only
@ -537,4 +548,178 @@ d.gen_mdadm_config = function()
luci.util.exec("/etc/init.d/mdadm enable")
end
-- list btrfs filesystem device
-- {uuid={uuid, label, members, size, used}...}
d.list_btrfs_devices = function()
local btrfs_device = {}
if not d.command.btrfs then return btrfs_device end
local line, _uuid
for _, line in ipairs(luci.util.execl(d.command.btrfs .. " filesystem show -d --raw"))
do
local label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^%s]+)")
if label and uuid then
_uuid = uuid
local _label = label:match("^'([^']+)'")
btrfs_device[_uuid] = {label = _label or label, uuid = uuid}
-- table.insert(btrfs_device, {label = label, uuid = uuid})
end
local used = line:match("Total devices[%w%s]+used%s+(%d+)$")
if used then
btrfs_device[_uuid]["used"] = tonumber(used)
btrfs_device[_uuid]["used_formated"] = byte_format(tonumber(used))
end
local size, device = line:match("devid[%w.%s]+size%s+(%d+)[%w.%s]+path%s+([^%s]+)$")
if size and device then
btrfs_device[_uuid]["size"] = btrfs_device[_uuid]["size"] and btrfs_device[_uuid]["size"] + tonumber(size) or tonumber(size)
btrfs_device[_uuid]["size_formated"] = byte_format(btrfs_device[_uuid]["size"])
btrfs_device[_uuid]["members"] = btrfs_device[_uuid]["members"] and btrfs_device[_uuid]["members"]..", "..device or device
end
end
return btrfs_device
end
d.create_btrfs = function(blabel, blevel, bmembers)
-- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb
if not d.command.btrfs or type(bmembers) ~= "table" or next(bmembers) == nil then return "ERR no btrfs support or no members" end
local label = blabel and " -L " .. blabel or ""
local cmd = "mkfs.btrfs -f " .. label .. " -d " .. blevel .. " " .. table.concat(bmembers, " ")
return luci.util.exec(cmd)
end
-- get btrfs info
-- {uuid, label, members, data_raid_level,metadata_raid_lavel, size, used, size_formated, used_formated, free, free_formated, usage}
d.get_btrfs_info = function(m_point)
local btrfs_info = {}
if not m_point or not d.command.btrfs then return btrfs_info end
local cmd = d.command.btrfs .. " filesystem show --raw " .. m_point
local _, line, uuid, _label, members
for _, line in ipairs(luci.util.execl(cmd)) do
if not uuid and not _label then
_label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^s]+)")
else
local mb = line:match("%s+devid.+path%s+([^%s]+)")
if mb then
members = members and (members .. ", ".. mb) or mb
end
end
end
if not _label or not uuid then return btrfs_info end
local label = _label:match("^'([^']+)'")
cmd = d.command.btrfs .. " filesystem usage -b " .. m_point
local used, free, data_raid_level, metadata_raid_lavel
for _, line in ipairs(luci.util.execl(cmd)) do
if not used then
used = line:match("^%s+Used:%s+(%d+)")
elseif not free then
free = line:match("^%s+Free %(estimated%):%s+(%d+)")
elseif not data_raid_level then
data_raid_level = line:match("^Data,%s-(%w+)")
elseif not metadata_raid_lavel then
metadata_raid_lavel = line:match("^Metadata,%s-(%w+)")
end
end
if used and free and data_raid_level and metadata_raid_lavel then
used = tonumber(used)
free = tonumber(free)
btrfs_info = {
uuid = uuid,
label = label,
data_raid_level = data_raid_level,
metadata_raid_lavel = metadata_raid_lavel,
used = used,
free = free,
size = used + free,
size_formated = byte_format(used + free),
used_formated = byte_format(used),
free_formated = byte_format(free),
members = members,
usage = string.format("%.2f",(used / (free+used) * 100)) .. "%"
}
end
return btrfs_info
end
-- get btrfs subvolume
-- {id={id, gen, top_level, path, snapshots, otime, default_subvolume}...}
d.get_btrfs_subv = function(m_point, snapshot)
local subvolume = {}
if not m_point or not d.command.btrfs then return subvolume end
-- get default subvolume
local cmd = d.command.btrfs .. " subvolume get-default " .. m_point
local res = luci.util.exec(cmd)
local default_subvolume_id = res:match("^ID%s+([^%s]+)")
-- get the root subvolume
if not snapshot then
local _, line, section_snap, _uuid, _otime, _id, _snap
cmd = d.command.btrfs .. " subvolume show ".. m_point
for _, line in ipairs(luci.util.execl(cmd)) do
if not section_snap then
if not _uuid then
_uuid = line:match("^%s-UUID:%s+([^%s]+)")
elseif not _otime then
_otime = line:match("^%s+Creation time:%s+(.+)")
elseif not _id then
_id = line:match("^%s+Subvolume ID:%s+([^%s]+)")
elseif line:match("^%s+(Snapshot%(s%):)") then
section_snap = true
end
else
local snapshot = line:match("^%s+(.+)")
if snapshot then
_snap = _snap and (_snap ..", /".. snapshot) or ("/"..snapshot)
end
end
end
if _uuid and _otime and _id then
subvolume["0".._id] = {id = _id , uuid = _uuid, otime = _otime, snapshots = _snap, path = "/"}
if default_subvolume_id == _id then
subvolume["0".._id].default_subvolume = 1
end
end
end
-- get subvolume of btrfs
cmd = d.command.btrfs .. " subvolume list -gcu" .. (snapshot and "s " or " ") .. m_point
for _, line in ipairs(luci.util.execl(cmd)) do
-- ID 259 gen 11 top level 258 uuid 26ae0c59-199a-cc4d-bd58-644eb4f65d33 path 1a/2b'
local id, gen, top_level, uuid, path, otime, otime2
if snapshot then
id, gen, top_level, otime, otime2, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+otime%s+([^%s]+)%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$")
else
id, gen, top_level, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$")
end
if id and gen and top_level and uuid and path then
subvolume[id] = {id = id, gen = gen, top_level = top_level, otime = (otime and otime or "") .." ".. (otime2 and otime2 or ""), uuid = uuid, path = '/'.. path}
if not snapshot then
-- use btrfs subv show to get snapshots
local show_cmd = d.command.btrfs .. " subvolume show "..m_point.."/"..path
local __, line_show, section_snap
for __, line_show in ipairs(luci.util.execl(show_cmd)) do
if not section_snap then
local create_time = line_show:match("^%s+Creation time:%s+(.+)")
if create_time then
subvolume[id]["otime"] = create_time
elseif line_show:match("^%s+(Snapshot%(s%):)") then
section_snap = "true"
end
else
local snapshot = line_show:match("^%s+(.+)")
subvolume[id]["snapshots"] = subvolume[id]["snapshots"] and (subvolume[id]["snapshots"] .. ", /".. snapshot) or ("/"..snapshot)
end
end
end
end
end
if subvolume[default_subvolume_id] then
subvolume[default_subvolume_id].default_subvolume = 1
end
-- if m_point == "/tmp/.btrfs_tmp" then
-- luci.util.exec("umount " .. m_point)
-- end
return subvolume
end
return d

View File

@ -61,7 +61,7 @@ msgstr "Sektor początkowy"
msgid "End Sector"
msgstr "Sektor końcowy"
msgid "Useage"
msgid "Usage"
msgstr "Użycie"
msgid "Model"
@ -126,3 +126,66 @@ msgstr "Informacja o partycjach"
msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector"
msgstr "Sektory wyrównywane są do wielokrotności 2048, sektor końcowy można podać jako rozmiar w postaci +size{b,k,m,g,t}"
msgid "Multiple Devices Btrfs Creation"
msgstr "Kreator urządzeń Btrfs"
msgid "Label"
msgstr "Etykieta"
msgid "Btrfs Label"
msgstr "Etykieta Btrfs"
msgid "Btrfs Raid Level"
msgstr "Poziom Raid Btrfs"
msgid "Btrfs Member"
msgstr "Członek Btrfs"
msgid "Create Btrfs"
msgstr "Utwórz Btrfs"
msgid "New Snapshot"
msgstr "Nowy obraz"
msgid "SubVolumes"
msgstr "SubVolumes"
msgid "Top Level"
msgstr "Top Level"
msgid "Manage Btrfs"
msgstr "Zarządzaj Btrfs"
msgid "Otime"
msgstr "Otime"
msgid "Snapshots"
msgstr "Obrazy"
msgid "Set Default"
msgstr "Ustaw domyślnie"
msgid "Source Path"
msgstr "Ścieżka źródłowa"
msgid "Readonly"
msgstr "Tylko do odczytu"
msgid "Delete"
msgstr "Usuń"
msgid "Create"
msgstr "Utwórz"
msgid "Destination Path (optional)"
msgstr "Ścieżka docelowa (opcjonalnie)"
msgid "Metadata"
msgstr "Metadata"
msgid "Data"
msgstr "Data"
msgid "Btrfs Info"
msgstr "Informacja o Btrfs"

View File

@ -2,7 +2,7 @@ msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "DiskMan"
msgstr "DiskMan磁盘管理"
msgstr "DiskMan 磁盘管理"
msgid "Manage Disks over LuCI."
msgstr "通过LuCI管理磁盘"
@ -61,8 +61,14 @@ msgstr "起始扇区"
msgid "End Sector"
msgstr "中止扇区"
msgid "Useage"
msgstr "使用情况"
msgid "Usage"
msgstr "用量"
msgid "Used"
msgstr "已使用"
msgid "Free Space"
msgstr "空闲空间"
msgid "Model"
msgstr "主机型号"
@ -126,3 +132,96 @@ msgstr "分区信息"
msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector"
msgstr "默认2048扇区对齐【中止扇区】支持 +容量{b,k,m,g,t} 格式,例:+500m +10g +1t"
msgid "Multiple Devices Btrfs Creation"
msgstr "Btrfs 阵列创建"
msgid "Label"
msgstr "卷标"
msgid "Btrfs Label"
msgstr "Btrfs 卷标"
msgid "Btrfs Raid Level"
msgstr "Btrfs Raid 级别"
msgid "Btrfs Member"
msgstr "Btrfs 整列成员"
msgid "Create Btrfs"
msgstr "创建 Btrfs"
msgid "New Snapshot"
msgstr "新建快照"
msgid "SubVolumes"
msgstr "子卷"
msgid "Top Level"
msgstr "父ID"
msgid "Manage Btrfs"
msgstr "Btrfs 管理"
msgid "Otime"
msgstr "创建时间"
msgid "Snapshots"
msgstr "快照"
msgid "Set Default"
msgstr "默认子卷"
msgid "Source Path"
msgstr "源目录"
msgid "Readonly"
msgstr "只读"
msgid "Delete"
msgstr "删除"
msgid "Create"
msgstr "创建"
msgid "Destination Path (optional)"
msgstr "目标目录(可选)"
msgid "Metadata"
msgstr "元数据"
msgid "Data"
msgstr "数据"
msgid "Btrfs Info"
msgstr "Btrfs 信息"
msgid "The source path for create the snapshot"
msgstr "创建快照的源数据目录"
msgid "The path where you want to store the snapshot"
msgstr "存放快照数据目录"
msgid "Please input Source Path of snapshot, Source Path must start with '/'"
msgstr "请输入快照源路径,源路径必须以'/'开头"
msgid "Please input Subvolume Path, Subvolume must start with '/'"
msgstr "请输入子卷路径,子卷路径必须以'/'开头"
msgid "is in use! please unmount it first!"
msgstr "正在被使用!请先卸载!"
msgid "Partition NOT found!"
msgstr "分区未找到!"
msgid "Filesystem NOT support!"
msgstr "文件系统不支持!"
msgid "Invalid Start Sector!"
msgstr "无效的起始扇区!"
msgid "Invalid End Sector"
msgstr "无效的终止扇区!"
msgid "Partition not exists!"
msgstr "分区不存在!"

View File

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-dockerman
PKG_VERSION:=v0.1.9
PKG_VERSION:=v0.2
PKG_RELEASE:=beta
PKG_MAINTAINER:=lisaac <https://github.com/lisaac/luci-app-dockerman>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
local docker = require "luci.model.docker"

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
@ -94,7 +89,7 @@ container_selecter.default = 0
container_id = c_table:option(DummyValue, "_id", translate("ID"))
container_id.width="10%"
container_name = c_table:option(DummyValue, "_name", translate("Name"))
container_name = c_table:option(DummyValue, "_name", translate("Container Name"))
container_name.width="20%"
container_name.template="docker/cbi/dummyvalue"
container_name.href = function (self, section)

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
@ -62,7 +57,7 @@ network_selecter.render = function(self, section, scope)
Flag.render(self, section, scope)
end
network_name = network_table:option(DummyValue, "_name", translate("Name"))
network_name = network_table:option(DummyValue, "_name", translate("Network Name"))
network_driver = network_table:option(DummyValue, "_driver", translate("Driver"))
network_interface = network_table:option(DummyValue, "_interface", translate("Parent Interface"))
network_subnet = network_table:option(DummyValue, "_subnet", translate("Subnet"))

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
@ -55,6 +50,8 @@ if cmd_line and cmd_line:match("^docker.+") then
key = "port"
elseif key == "e" then
key = "env"
elseif key == "dns" then
key = "dns"
elseif key == "net" then
key = "network"
elseif key == "cpu-shares" then
@ -69,7 +66,7 @@ if cmd_line and cmd_line:match("^docker.+") then
end
--key=value
if val then
if key == "mount" or key == "link" or key == "env" or key == "port" or key == "device" or key == "tmpfs" then
if key == "mount" or key == "link" or key == "env" or key == "dns" or key == "port" or key == "device" or key == "tmpfs" then
if not default_config[key] then default_config[key] = {} end
table.insert( default_config[key], val )
else
@ -81,7 +78,7 @@ if cmd_line and cmd_line:match("^docker.+") then
cursor = 1
-- value
elseif key and type(key) == "string" and cursor == 1 then
if key == "mount" or key == "link" or key == "env" or key == "port" or key == "device" or key == "tmpfs" then
if key == "mount" or key == "link" or key == "env" or key == "dns" or key == "port" or key == "device" or key == "tmpfs" then
if not default_config[key] then default_config[key] = {} end
table.insert( default_config[key], w )
else
@ -119,6 +116,7 @@ elseif cmd_line and cmd_line:match("^duplicate/[^/]+$") then
default_config.ip = default_config.network and default_config.network ~= "bridge" and default_config.network ~= "host" and default_config.network ~= "null" and create_body.NetworkingConfig.EndpointsConfig[default_config.network].IPAMConfig and create_body.NetworkingConfig.EndpointsConfig[default_config.network].IPAMConfig.IPv4Address or nil
default_config.link = create_body.HostConfig.Links
default_config.env = create_body.Env
default_config.dns = create_body.HostConfig.Dns
default_config.mount = create_body.HostConfig.Binds
if create_body.HostConfig.PortBindings and type(create_body.HostConfig.PortBindings) == "table" then
@ -183,12 +181,6 @@ d.disabled = 0
d.enabled = 1
d.default = default_config.tty and 1 or 0
d = s:option(Flag, "_force_pull", translate("Always pull image first"))
d.rmempty = true
d.disabled = 0
d.enabled = 1
d.default = 0
d = s:option(Value, "image", translate("Docker Image"))
d.rmempty = true
d.default = default_config.image or nil
@ -198,6 +190,12 @@ for _, v in ipairs (images) do
end
end
d = s:option(Flag, "_force_pull", translate("Always pull image first"))
d.rmempty = true
d.disabled = 0
d.enabled = 1
d.default = 0
d = s:option(Flag, "privileged", translate("Privileged"))
d.rmempty = true
d.disabled = 0
@ -222,11 +220,6 @@ d_ip.datatype="ip4addr"
d_ip:depends("network", "nil")
d_ip.default = default_config.ip or nil
d = s:option(Value, "user", translate("User"))
d.placeholder = "1000:1000"
d.rmempty = true
d.default = default_config.user or nil
d = s:option(DynamicList, "link", translate("Links with other containers"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "container_name:alias"
@ -234,19 +227,30 @@ d.rmempty = true
d:depends("network", "bridge")
d.default = default_config.link or nil
d = s:option(DynamicList, "env", translate("Environmental Variable"))
d = s:option(DynamicList, "dns", translate("Set custom DNS servers"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "8.8.8.8"
d.rmempty = true
d.default = default_config.dns or nil
d = s:option(Value, "user", translate("User(-u)"), translate("The user that commands are run as inside the container.(format: name|uid[:group|gid])"))
d.placeholder = "1000:1000"
d.rmempty = true
d.default = default_config.user or nil
d = s:option(DynamicList, "env", translate("Environmental Variable(-e)"), translate("Set environment variables to inside the container"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "TZ=Asia/Shanghai"
d.rmempty = true
d.default = default_config.env or nil
d = s:option(DynamicList, "mount", translate("Bind Mount"))
d = s:option(DynamicList, "mount", translate("Bind Mount(-v)"), translate("Bind mount a volume"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "/media:/media:slave"
d.rmempty = true
d.default = default_config.mount or nil
local d_ports = s:option(DynamicList, "port", translate("Exposed Ports"))
local d_ports = s:option(DynamicList, "port", translate("Exposed Ports(-p)"), translate("Publish container's port(s) to the host"))
d_ports.template = "docker/cbi/xdynlist"
d_ports.placeholder = "2200:22/tcp"
d_ports.rmempty = true
@ -263,6 +267,20 @@ d.disabled = 0
d.enabled = 1
d.default = default_config.advance or 0
d = s:option(DynamicList, "device", translate("Device(--device)"), translate("Add host device to the container"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "/dev/sda:/dev/xvdc:rwm"
d.rmempty = true
d:depends("advance", 1)
d.default = default_config.device or nil
d = s:option(DynamicList, "tmpfs", translate("Tmpfs(--tmpfs)"), translate("Mount tmpfs directory"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "/run:rw,noexec,nosuid,size=65536k"
d.rmempty = true
d:depends("advance", 1)
d.default = default_config.tmpfs or nil
d = s:option(Value, "cpus", translate("CPUs"), translate("Number of CPUs. Number is a fractional number. 0.000 means no limit."))
d.placeholder = "1.5"
d.rmempty = true
@ -270,7 +288,7 @@ d:depends("advance", 1)
d.datatype="ufloat"
d.default = default_config.cpus or nil
d = s:option(Value, "cpushares", translate("CPU Shares Weight"), translate("CPU shares (relative weight, if 0 is set, the system will ignore the value and use the default of 1024."))
d = s:option(Value, "cpushares", translate("CPU Shares Weight"), translate("CPU shares relative weight, if 0 is set, the system will ignore the value and use the default of 1024."))
d.placeholder = "1024"
d.rmempty = true
d:depends("advance", 1)
@ -290,19 +308,6 @@ d:depends("advance", 1)
d.datatype="uinteger"
d.default = default_config.blkioweight or nil
d = s:option(DynamicList, "device", translate("Device"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "/dev/sda:/dev/xvdc:rwm"
d.rmempty = true
d:depends("advance", 1)
d.default = default_config.device or nil
d = s:option(DynamicList, "tmpfs", translate("Tmpfs"), translate("Mount tmpfs filesystems"))
d.template = "docker/cbi/xdynlist"
d.placeholder = "/run:rw,noexec,nosuid,size=65536k"
d.rmempty = true
d:depends("advance", 1)
d.default = default_config.tmpfs or nil
for _, v in ipairs (networks) do
if v.Name then
@ -325,7 +330,7 @@ end
m.handle = function(self, state, data)
if state ~= FORM_VALID then return end
local tmp
local name = data.name
local name = data.name or ("luci_" .. os.date("%Y%m%d%H%M%S"))
local tty = type(data.tty) == "number" and (data.tty == 1 and true or false) or default_config.tty or false
local interactive = type(data.interactive) == "number" and (data.interactive == 1 and true or false) or default_config.interactive or false
local image = data.image
@ -336,6 +341,7 @@ m.handle = function(self, state, data)
local privileged = type(data.privileged) == "number" and (data.privileged == 1 and true or false) or default_config.privileged or false
local restart = data.restart
local env = data.env
local dns = data.dns
local network = data.network
local ip = (network ~= "bridge" and network ~= "host" and network ~= "none") and data.ip or nil
local mount = data.mount
@ -366,12 +372,13 @@ m.handle = function(self, state, data)
if h and c then
t['PathOnHost'] = h
t['PathInContainer'] = c
t['CgroupPermissions'] = p or nil
t['CgroupPermissions'] = p or "rwm"
else
local _,_, h, c = v:find("(.-):(.+)")
if h and c then
t['PathOnHost'] = h
t['PathInContainer'] = c
t['CgroupPermissions'] = "rwm"
end
end
if next(t) ~= nil then
@ -425,8 +432,8 @@ m.handle = function(self, state, data)
create_body.Image = image
create_body.ExposedPorts = (next(exposedports) ~= nil) and exposedports or nil
create_body.HostConfig = create_body.HostConfig or {}
create_body.HostConfig.Dns = dns
create_body.HostConfig.Binds = (#mount ~= 0) and mount or nil
create_body.HostConfig.NetworkMode = network
create_body.HostConfig.RestartPolicy = { Name = restart, MaximumRetryCount = 0 }
create_body.HostConfig.Privileged = privileged and true or false
create_body.HostConfig.PortBindings = (next(portbindings) ~= nil) and portbindings or nil
@ -434,8 +441,14 @@ m.handle = function(self, state, data)
create_body.HostConfig.CpuShares = tonumber(cpushares)
create_body.HostConfig.NanoCPUs = tonumber(cpus) * 10 ^ 9
create_body.HostConfig.BlkioWeight = tonumber(blkioweight)
if create_body.HostConfig.NetworkMode ~= network then
-- network mode changed, need to clear duplicate config
create_body.NetworkingConfig = nil
end
create_body.HostConfig.NetworkMode = network
if ip then
if create_body.NetworkingConfig and create_body.NetworkingConfig.EndpointsConfig and type(create_body.NetworkingConfig.EndpointsConfig) == "table" then
-- ip + duplicate config
for k, v in pairs (create_body.NetworkingConfig.EndpointsConfig) do
if k == network and v.IPAMConfig and v.IPAMConfig.IPv4Address then
v.IPAMConfig.IPv4Address = ip
@ -445,18 +458,16 @@ m.handle = function(self, state, data)
break
end
else
-- ip + no duplicate config
create_body.NetworkingConfig = { EndpointsConfig = { [network] = { IPAMConfig = { IPv4Address = ip } } } }
end
elseif not create_body.NetworkingConfig then
-- no ip + no duplicate config
create_body.NetworkingConfig = nil
end
if next(tmpfs) ~= nil then
create_body["HostConfig"]["Tmpfs"] = tmpfs
end
if next(device) ~= nil then
create_body["HostConfig"]["Devices"] = device
end
create_body["HostConfig"]["Tmpfs"] = (next(tmpfs) ~= nil) and tmpfs or nil
create_body["HostConfig"]["Devices"] = (next(device) ~= nil) and device or nil
if network == "bridge" and next(link) ~= nil then
create_body["HostConfig"]["Links"] = link

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
@ -87,7 +82,7 @@ s = m:section(NamedSection, "local", "section", translate("Setting"))
socket_path = s:option(Value, "socket_path", translate("Socket Path"))
status_path = s:option(Value, "status_path", translate("Action Status Tempfile Path"), translate("Where you want to save the docker status file"))
debug = s:option(Flag, "debug", translate("Enable Debug"), translate("For debug, It shows all docker API actions of luci-app-docker in Debug Tempfile Path"))
debug = s:option(Flag, "debug", translate("Enable Debug"), translate("For debug, It shows all docker API actions of luci-app-dockerman in Debug Tempfile Path"))
debug.enabled="true"
debug.disabled="false"
debug_path = s:option(Value, "debug_path", translate("Debug Tempfile Path"), translate("Where you want to save the debug tempfile"))

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"

View File

@ -1,11 +1,6 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2019 lisaac <lisaac.cn@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
Copyright 2019 lisaac <https://github.com/lisaac/luci-app-dockerman>
]]--
require "luci.util"
@ -231,4 +226,4 @@ _docker.clear_status=function(self)
nixio.fs.remove(self.options.status_path)
end
return _docker
return _docker

View File

@ -1,17 +1,3 @@
<%#
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
$Id$
-%>
<% if self.title == translate("Docker Events") then %>
<%+header%>
<% end %>

View File

@ -81,6 +81,10 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
.img-con {
margin: 1rem;
min-width: 4rem;
max-width: 4rem;
min-height: 4rem;
max-height: 4rem;
}
.block h4 {
@ -123,7 +127,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
<div class="block pure-g">
<div class="pure-u-2-5">
<div class="img-con">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<svg role="img" viewBox="0 0 24 24">
<title>Docker icon</title>
<path
d="M4.82 17.275c-.684 0-1.304-.56-1.304-1.24s.56-1.243 1.305-1.243c.748 0 1.31.56 1.31 1.242s-.622 1.24-1.305 1.24zm16.012-6.763c-.135-.992-.75-1.8-1.56-2.42l-.315-.25-.254.31c-.494.56-.69 1.553-.63 2.295.06.562.24 1.12.554 1.554-.254.13-.568.25-.81.377-.57.187-1.124.25-1.68.25H.097l-.06.37c-.12 1.182.06 2.42.562 3.54l.244.435v.06c1.5 2.483 4.17 3.6 7.078 3.6 5.594 0 10.182-2.42 12.357-7.633 1.425.062 2.864-.31 3.54-1.676l.18-.31-.3-.187c-.81-.494-1.92-.56-2.85-.31l-.018.002zm-8.008-.992h-2.428v2.42h2.43V9.518l-.002.003zm0-3.043h-2.428v2.42h2.43V6.48l-.002-.003zm0-3.104h-2.428v2.42h2.43v-2.42h-.002zm2.97 6.147H13.38v2.42h2.42V9.518l-.007.003zm-8.998 0H4.383v2.42h2.422V9.518l-.01.003zm3.03 0h-2.4v2.42H9.84V9.518l-.015.003zm-6.03 0H1.4v2.42h2.428V9.518l-.03.003zm6.03-3.043h-2.4v2.42H9.84V6.48l-.015-.003zm-3.045 0H4.387v2.42H6.8V6.48l-.016-.003z" />
@ -145,7 +149,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
<div class="block pure-g">
<div class="pure-u-2-5">
<div class="img-con">
<svg id="icon-hub" viewBox="0 0 42 38" stroke-width="2" fill-rule="nonzero" width="100%" height="100%">
<svg id="icon-hub" viewBox="0 -4 42 50" stroke-width="2" fill-rule="nonzero" width="100%" height="100%">
<path
d="M37.176371,36.2324812 C37.1920117,36.8041095 36.7372743,37.270685 36.1684891,37.270685 L3.74335204,37.2703476 C3.17827583,37.2703476 2.72400056,36.8091818 2.72400056,36.2397767 L2.72400056,19.6131383 C1.4312007,18.4881431 0.662551336,16.8884326 0.662551336,15.1618249 L0.664207893,14.69503 C0.63774183,14.4532127 0.650524255,14.2942438 0.711604827,14.1238231 L5.10793246,1.20935468 C5.24853286,0.797020623 5.63848594,0.511627907 6.06681069,0.511627907 L34.0728364,0.511627907 C34.5091607,0.511627907 34.889927,0.793578201 35.0316653,1.20921034 L39.4428567,14.1234095 C39.4871296,14.273204 39.5020782,14.4249444 39.4884726,14.5493649 L39.4884726,15.1505835 C39.4884726,16.9959517 38.6190601,18.6883031 37.1764746,19.7563084 L37.176371,36.2324812 Z M35.1376208,35.209311 L35.1376208,20.7057152 C34.7023924,20.8097593 34.271333,20.8633641 33.8336069,20.8633641 C32.0046019,20.8633641 30.3013756,19.9547008 29.2437221,18.4771538 C28.1860473,19.954695 26.4828515,20.8633641 24.6538444,20.8633641 C22.824803,20.8633641 21.1216155,19.9547157 20.0639591,18.4771544 C19.0062842,19.9546953 17.3030887,20.8633641 15.4740818,20.8633641 C13.6450404,20.8633641 11.9418529,19.9547157 10.8841965,18.4771544 C9.82652161,19.9546953 8.12332608,20.8633641 6.29431919,20.8633641 C5.76735555,20.8633641 5.24095778,20.7883418 4.73973398,20.644674 L4.73973398,35.209311 L35.1376208,35.209311 Z M30.2720226,15.6557626 C30.5154632,17.4501192 32.0503909,18.8018554 33.845083,18.8018554 C35.7286794,18.8018554 37.285413,17.3395134 37.4474599,15.4751932 L30.2280765,15.4751932 C30.2470638,15.532987 30.2617919,15.5932958 30.2720226,15.6557626 Z M21.0484306,15.4751932 C21.0674179,15.532987 21.0821459,15.5932958 21.0923767,15.6557626 C21.3358173,17.4501192 22.8707449,18.8018554 24.665437,18.8018554 C26.4601001,18.8018554 27.9950169,17.4501481 28.2378191,15.6611556 C28.2451225,15.5981318 28.2590045,15.5358056 28.2787375,15.4751932 L21.0484306,15.4751932 Z M11.9238102,15.6557626 C12.1672508,17.4501192 13.7021785,18.8018554 15.4968705,18.8018554 C17.2915336,18.8018554 18.8264505,17.4501481 19.0692526,15.6611556 C19.0765561,15.5981318 19.0904381,15.5358056 19.110171,15.4751932 L11.8798641,15.4751932 C11.8988514,15.532987 11.9135795,15.5932958 11.9238102,15.6557626 Z M6.31682805,18.8018317 C8.11149114,18.8018317 9.64640798,17.4501244 9.88921012,15.6611319 C9.89651357,15.5981081 9.91039559,15.5357819 9.93012856,15.4751696 L2.70318796,15.4751696 C2.86612006,17.3346852 4.42809696,18.8018317 6.31682805,18.8018317 Z M3.09670082,13.4139924 L37.04257,13.4139924 L33.3489482,2.57204736 L6.80119239,2.57204736 L3.09670082,13.4139924 Z"
id="Fill-1"></path>
@ -169,12 +173,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
<div class="block pure-g">
<div class="pure-u-2-5">
<div class="img-con">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="48.723px" height="48.723px" viewBox="0 0 48.723 48.723"
style="enable-background:new 0 0 48.723 48.723;" xml:space="preserve">
<g>
<g id="_x33_8_89_">
<g>
<svg version="1.1" x="0px" y="0px" width="100%" height="100%" viewBox="0 0 48.723 48.723" xml:space="preserve">
<path d="M7.452,24.152h3.435v5.701h0.633c0.001,0,0.001,0,0.002,0h0.636v-5.701h3.51v-1.059h17.124v1.104h3.178v5.656h0.619
c0,0,0,0,0.002,0h0.619v-5.656h3.736v-0.856c0-0.012,0.006-0.021,0.006-0.032c0-0.072,0-0.143,0-0.215h5.721v-1.316h-5.721
c0-0.054,0-0.108,0-0.164c0-0.011-0.006-0.021-0.006-0.032v-0.832h-8.154v1.028h-7.911v-2.652h-0.689c-0.001,0-0.001,0-0.002,0
@ -188,10 +187,6 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
<path
d="M29.491,30.994v12.684h6.895v2.611h5.205v-2.611h7.133V30.994H29.491z M46.774,41.729H31.44v-8.783h15.334V41.729z" />
<rect x="33.584" y="46.338" width="10.809" height="0.537" />
</g>
</g>
</g>
</svg>
</div>
</div>
@ -210,8 +205,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
<div class="block pure-g">
<div class="pure-u-2-5">
<div class="img-con">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 55 55" style="enable-background:new 0 0 55 55;" xml:space="preserve">
<svg x="0px" y="0px" viewBox="0 0 55 55" style="enable-background:new 0 0 55 55;" xml:space="preserve">
<path
d="M52.354,8.51C51.196,4.22,42.577,0,27.5,0C12.423,0,3.803,4.22,2.646,8.51C2.562,8.657,2.5,8.818,2.5,9v0.5V21v0.5V22v11
v0.5V34v12c0,0.162,0.043,0.315,0.117,0.451C3.798,51.346,14.364,55,27.5,55c13.106,0,23.655-3.639,24.875-8.516

View File

@ -3,7 +3,7 @@
function resolv_container(op) {
let s = document.getElementById(op + '-status');
if (!s) return;
let cmd_line = prompt("Plese input <docker create/run> command line:", "");
let cmd_line = prompt("<%:Plese input <docker create/run> command line:%>", "");
if (cmd_line == null || cmd_line == "") {
s.innerHTML = "<font color='red'>Canceled</font>";
return;
@ -12,12 +12,9 @@
s.innerHTML = "<font color='red'>Command line Error</font>";
return;
}
let re = /\/admin\/docker\/newcontainer\//
let p = window.location.href
let path = p.split(re)
window.location.href = path[0] + "/admin/docker/newcontainer/" + encodeURI(cmd_line)
window.location.href = "/cgi-bin/luci/admin/docker/newcontainer/" + encodeURI(cmd_line)
}
</script>
<input type="button" class="cbi-button cbi-button-apply" value="Command line" onclick="resolv_container('<%=self.option%>')" />
<input type="button" class="cbi-button cbi-button-apply" value="<%:Command line%>" onclick="resolv_container('<%=self.option%>')" />
<span id="<%=self.option%>-status"></span>
<%+cbi/valuefooter%>

View File

@ -58,8 +58,8 @@ msgstr "重启策略"
msgid "Update"
msgstr "更新"
msgid "Device"
msgstr "设备"
msgid "Device(--device)"
msgstr "设备(--device)"
msgid "Mount/Volume"
msgstr "挂载/存储卷"
@ -103,26 +103,20 @@ msgstr "CPU数量数字是小数0.000表示没有限制。"
msgid "CPU Shares Weight"
msgstr "CPU份额权重"
msgid ""
"CPU shares relative weight, if 0 is set, the system will ignore the value and use the default of 1024."
msgstr ""
"CPU份额相对权重如果设置为0则系统将忽略该值并使用默认值1024。"
msgid "CPU shares relative weight, if 0 is set, the system will ignore the value and use the default of 1024."
msgstr "CPU份额相对权重如果设置为0则系统将忽略该值并使用默认值1024。"
msgid "Memory"
msgstr "内存"
msgid ""
"Memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M."
msgstr ""
"内存限制 (格式: <容量>[<单位>]). 数字是一个正整数。单位可以是bkm或g之一。最小为4M。"
msgid "Memory limit (format: <number>[<unit>]). Number is a positive integer. Unit can be one of b, k, m, or g. Minimum is 4M."
msgstr "内存限制 (格式: <容量>[<单位>]). 数字是一个正整数。单位可以是bkm或g之一。最小为4M。"
msgid "Block IO Weight"
msgstr "IO 权重"
msgid ""
"Block IO weight (relative weight) accepts a weight value between 10 and 1000."
msgstr ""
"IO 权重相对权重接受10到1000之间的权重值。"
msgid "Block IO weight (relative weight) accepts a weight value between 10 and 1000."
msgstr "IO 权重 (相对权重) 接受10到1000之间的权重值。"
msgid "Container Logs"
msgstr "容器日志"
@ -151,8 +145,8 @@ msgstr "解析命令行"
msgid "Docker Image"
msgstr "Docker 镜像"
msgid "User"
msgstr "用户"
msgid "User(-u)"
msgstr "用户(-u)"
msgid "New Container"
msgstr "新容器"
@ -167,22 +161,22 @@ msgid "Always pull image first"
msgstr "始终先拉取镜像"
msgid "Privileged"
msgstr "特权模式(Privileged)"
msgstr "特权模式(--privileged)"
msgid "IPv4 Address"
msgstr "IPv4 地址"
msgid "Links with other containers"
msgstr "与其他容器的链接(Links)"
msgstr "与其他容器的链接(--link)"
msgid "Environmental Variable"
msgstr "环境变量(Env)"
msgid "Environmental Variable(-e)"
msgstr "环境变量(-e)"
msgid "Bind Mount"
msgid "Bind Mount(-v)"
msgstr "挂载(-v)"
msgid "Exposed Ports"
msgstr "暴露端口"
msgid "Exposed Ports(-p)"
msgstr "暴露端口(-p)"
msgid "Run command"
msgstr "运行命令"
@ -190,8 +184,8 @@ msgstr "运行命令"
msgid "Advance"
msgstr "高级"
msgid "Mount tmpfs filesystems"
msgstr "挂载tmpfs文件系统"
msgid "Mount tmpfs directory"
msgstr "挂载tmpfs到容器内部目录"
msgid "New Network"
msgstr "新网络"
@ -259,8 +253,8 @@ msgstr "保存docker status文件的位置"
msgid "Enable Debug"
msgstr "启用调试"
msgid "For debug, It shows all docker API actions of luci-app-docker in Debug Tempfile Path"
msgstr "用于调试它在调试临时文件路径中显示luci-app-docker的所有docker API操作"
msgid "For debug, It shows all docker API actions of luci-app-dockermab in Debug Tempfile Path"
msgstr "用于调试,它在调试临时文件路径中显示 luci-app-dockermab 的所有docker API操作"
msgid "Debug Tempfile Path"
msgstr "调试临时文件路径"
@ -296,4 +290,37 @@ msgid "Pull Image"
msgstr "拉取镜像"
msgid "Pull"
msgstr "拉取"
msgstr "拉取"
msgid "Command line"
msgstr "输入命令行"
msgid "Plese input <docker create/run> command line:"
msgstr "请输入 docker run/create ... 命令行:"
msgid "Network Name"
msgstr "网络名"
msgid "Set custom DNS servers"
msgstr "自定义 DNS 服务器"
msgid "The user that commands are run as inside the container.(format: name|uid[:group|gid])"
msgstr "容器内部执行命令的用户(组), 格式: UID:GID"
msgid "Set environment variables to inside the container"
msgstr "容器内部环境变量"
msgid "Bind mount a volume"
msgstr "绑定挂载"
msgid "Publish container's port(s) to the host"
msgstr "将容器的端口发布到宿主"
msgid "Add host device to the container"
msgstr "添加宿主设备到容器内部"
msgid "Device"
msgstr "设备"
msgid "Finish Time"
msgstr "结束时间"

View File

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-openclash
PKG_VERSION:=0.36.2
PKG_VERSION:=0.36.4
PKG_RELEASE:=beta
PKG_MAINTAINER:=vernesong <https://github.com/vernesong/OpenClash>
@ -14,7 +14,7 @@ define Package/$(PKG_NAME)
SUBMENU:=3. Applications
TITLE:=LuCI support for clash
PKGARCH:=all
DEPENDS:=+iptables +dnsmasq-full +coreutils +coreutils-nohup +bash +wget
DEPENDS:=+iptables +dnsmasq-full +coreutils +coreutils-nohup +bash +curl +jsonfilter +ca-certificates
MAINTAINER:=vernesong
endef
@ -48,6 +48,7 @@ if [ -f "/etc/config/openclash" ]; then
cp "/etc/config/openclash_custom_rules.list" "/tmp/openclash_custom_rules.list.bak" >/dev/null 2>&1
cp "/etc/config/openclash_custom_hosts.list" "/tmp/openclash_custom_hosts.list.bak" >/dev/null 2>&1
cp "/etc/config/openclash_custom_fake_black.conf" "/tmp/openclash_custom_fake_black.conf.bak" >/dev/null 2>&1
cp "/etc/openclash/history" "/tmp/openclash_history.bak" >/dev/null 2>&1
fi
if [ -f "/etc/openclash/custom/openclash_custom_rules.list" ]; then
cp "/etc/openclash/custom/openclash_custom_rules.list" "/tmp/openclash_custom_rules.list.bak" >/dev/null 2>&1
@ -76,6 +77,7 @@ if [ -f "/tmp/openclash.bak" ]; then
mv "/tmp/openclash_custom_rules.list.bak" "/etc/openclash/custom/openclash_custom_rules.list" >/dev/null 2>&1
mv "/tmp/openclash_custom_hosts.list.bak" "/etc/openclash/custom/openclash_custom_hosts.list" >/dev/null 2>&1
mv "/tmp/openclash_custom_fake_black.conf.bak" "/etc/openclash/custom/openclash_custom_fake_black.conf" >/dev/null 2>&1
mv "/tmp/openclash_history.bak" "/etc/openclash/history" >/dev/null 2>&1
fi
if [ -f "/tmp/config.yaml" ]; then
mv "/tmp/config.yaml" "/etc/openclash/config/config.yaml" >/dev/null 2>&1
@ -113,6 +115,7 @@ fi
mv "/etc/openclash/config" "/tmp/openclash_config" >/dev/null 2>&1
mv "/etc/openclash/proxy_provider" "/tmp/openclash_proxy_provider" >/dev/null 2>&1
mv "/etc/openclash/game_rules" "/tmp/openclash_game_rules" >/dev/null 2>&1
mv "/etc/openclash/history" "/tmp/openclash_history.bak" >/dev/null 2>&1
cp "/etc/config/openclash" "/tmp/openclash.bak" >/dev/null 2>&1
cp "/etc/config/openclash_custom_rules.list" "/tmp/openclash_custom_rules.list.bak" >/dev/null 2>&1
cp "/etc/config/openclash_custom_hosts.list" "/tmp/openclash_custom_hosts.list.bak" >/dev/null 2>&1
@ -129,6 +132,7 @@ if [ -f "/etc/openclash/clash" ]; then
rm -rf /etc/openclash/backup >/dev/null 2>&1
rm -rf /etc/openclash/proxy_provider >/dev/null 2>&1
rm -rf /etc/openclash/game_rules >/dev/null 2>&1
rm -rf /etc/openclash/history >/dev/null 2>&1
else
rm -rf /etc/openclash >/dev/null 2>&1
fi

View File

@ -165,7 +165,7 @@ yml_check()
awk '/^proxy-provider:/,/^Proxy Group:/{print}' "$3" | sed '/^Proxy Group:/d' >/tmp/backprovider.yaml 2>/dev/null
sed -i '/^Proxy Group:/i\proxy-provider-tag' "$3" 2>/dev/null
sed -i '/^proxy-provider:/,/proxy-provider-tag/d' "$3" 2>/dev/null
sed -i '/^Rule:/i\proxy-provider:' "$3" 2>/dev/null
sed -i '/^Proxy:/i\proxy-provider:' "$3" 2>/dev/null
sed -i '/^proxy-provider:/d' /tmp/backprovider.yaml 2>/dev/null
sed -i '/proxy-provider:/r/tmp/backprovider.yaml' "$3" 2>/dev/null
rm -rf /tmp/backprovider.yaml 2>/dev/null
@ -506,11 +506,16 @@ yml_game_rule_get()
local section="$1"
config_get_bool "enabled" "$section" "enabled" "1"
config_get "group" "$section" "group" ""
config_get "config" "$section" "config" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$group" ]; then
return
fi
@ -523,18 +528,21 @@ yml_game_group_get()
local section="$1"
config_get_bool "enabled" "$section" "enabled" "1"
config_get "group" "$section" "group" ""
config_get "config" "$section" "config" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$group" ]; then
return
fi
if [ -z "$(grep "^ \{0,\}- name: $group" "$GROUP_FILE")" ]; then
/usr/share/openclash/yml_groups_set.sh "$group"
fi
/usr/share/openclash/yml_groups_set.sh "$group"
}
yml_game_custom()
@ -611,6 +619,7 @@ else
cp $BACKUP_FILE $CONFIG_FILE
fi
fi
CONFIG_NAME=$(echo $CONFIG_FILE |awk -F '/' '{print $5}' 2>/dev/null)
enable=$(uci get openclash.config.enable 2>/dev/null)
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
@ -628,6 +637,10 @@ if [ "$enable" -eq 1 ] && [ -f "$CONFIG_FILE" ]; then
en_mode_tun="1"
en_mode="fake-ip"
fi
if [ "$en_mode" = "redir-host-tun" ]; then
en_mode_tun="1"
en_mode="redir-host"
fi
if [ "$en_mode" = "redir-host-vpn" ]; then
en_mode_tun="2"
en_mode="redir-host"
@ -647,6 +660,7 @@ if [ "$enable" -eq 1 ] && [ -f "$CONFIG_FILE" ]; then
socks_port=$(uci get openclash.config.socks_port 2>/dev/null)
enable_redirect_dns=$(uci get openclash.config.enable_redirect_dns 2>/dev/null)
lan_ip=$(uci get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null)
wan_ip4=$(ubus call network.interface.wan status 2>/dev/null | grep \"address\" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 2>/dev/null)
lan_ip6=$(uci get network.lan.ip6addr 2>/dev/null)
direct_dns=$(uci get openclash.config.direct_dns 2>/dev/null)
disable_masq_cache=$(uci get openclash.config.disable_masq_cache 2>/dev/null)
@ -688,13 +702,14 @@ if [ "$enable" -eq 1 ] && [ -f "$CONFIG_FILE" ]; then
nohup $CLASH -d "$CLASH_CONFIG" -f "$CONFIG_FILE" >> $LOG_FILE 2>&1 &
#检测proxy_provider配置文件状态
echo "第六步: 等待主程序下载代理集..." >$START_LOG
yml_proxy_provider_check "$PROXY_PROVIDER_FILE"
rm -rf /tmp/yaml_* 2>/dev/null
echo "第步: 设置控制面板..." >$START_LOG
echo "第步: 设置控制面板..." >$START_LOG
ln -s /usr/share/openclash/yacd /www/openclash 2>/dev/null
echo "第步: 设置 OpenClash 防火墙规则..." >$START_LOG
echo "第步: 设置 OpenClash 防火墙规则..." >$START_LOG
if [ -z "$(uci get firewall.openclash 2>/dev/null)" ] || [ -z "$(uci get ucitrack.@openclash[-1].init 2>/dev/null)" ]; then
uci delete ucitrack.@openclash[-1] >/dev/null 2>&1
uci add ucitrack openclash >/dev/null 2>&1
@ -717,13 +732,8 @@ mkdir -p /var/etc
cat > "/var/etc/openclash.include" <<-EOF
/etc/init.d/openclash restart
EOF
if [ "$en_mode_tun" != "2" ]; then
if [ -z "$en_mode_tun" ]; then
iptables -t nat -N openclash
if [ "$en_mode_tun" = "1" ]; then
iptables -t nat -A openclash -d 198.18.0.0/16 -j RETURN
fi
iptables -t nat -A openclash -d 0.0.0.0/8 -j RETURN
iptables -t nat -A openclash -d 10.0.0.0/8 -j RETURN
iptables -t nat -A openclash -d 127.0.0.0/8 -j RETURN
@ -732,29 +742,21 @@ EOF
iptables -t nat -A openclash -d 192.168.0.0/16 -j RETURN
iptables -t nat -A openclash -d 224.0.0.0/4 -j RETURN
iptables -t nat -A openclash -d 240.0.0.0/4 -j RETURN
if [ ! -z "$wan_ip4" ]; then
iptables -t nat -A openclash -d "$wan_ip4" -j RETURN
fi
iptables -t nat -A openclash -p tcp -j REDIRECT --to-ports "$proxy_port"
if [ -z "$(iptables -nvL zone_lan_prerouting -t nat)" ]; then
iptables -t nat -A PREROUTING -p tcp -j openclash
else
iptables -t nat -A zone_lan_prerouting -p tcp -j openclash
fi
iptables -t nat -A PREROUTING -p tcp -j openclash
iptables -t nat -A OUTPUT -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
if [ "$en_mode_tun" != 1 ]; then
iptables -t nat -A OUTPUT -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
fi
if [ "$ipv6_enable" -eq 1 ]; then
ip6tables -t nat -N openclash
ip6tables -t nat -A openclash -p tcp -j REDIRECT --to-ports "$proxy_port"
if [ -z "$(ip6tables -nvL zone_lan_prerouting -t nat)" ]; then
ip6tables -t nat -A PREROUTING -p tcp -j openclash
else
ip6tables -t nat -A zone_lan_prerouting -p tcp -j openclash
fi
ip6tables -t nat -A PREROUTING -p tcp -j openclash
fi
else
#TUN2模式
#TUN模式
ipset create localnetwork hash:net
ipset add localnetwork 127.0.0.0/8
ipset add localnetwork 10.0.0.0/8
@ -763,10 +765,15 @@ EOF
ipset add localnetwork 224.0.0.0/4
ipset add localnetwork 240.0.0.0/4
ipset add localnetwork 172.16.0.0/12
ipset add localnetwork "$wan_ip4"
#启动TUN
if [ "$en_mode_tun" = "2" ]; then
ip tuntap add user root mode tun clash0
ip link set clash0 up
ip route replace default dev clash0 table "$PROXY_ROUTE_TABLE"
elif [ "$en_mode_tun" = "1" ]; then
ip route replace default dev utun table "$PROXY_ROUTE_TABLE"
fi
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
#设置防火墙
iptables -t mangle -N openclash
@ -776,10 +783,12 @@ EOF
iptables -t mangle -I OUTPUT -j openclash
iptables -t mangle -I PREROUTING -m set ! --match-set localnetwork dst -j MARK --set-mark "$PROXY_FWMARK"
#ipv6
ip6tables -t mangle -I PREROUTING -j MARK --set-mark "$PROXY_FWMARK"
if [ "$ipv6_enable" -eq 1 ]; then
ip6tables -t mangle -I PREROUTING -j MARK --set-mark "$PROXY_FWMARK"
fi
fi
echo "第步: 重启 Dnsmasq 程序..." >$START_LOG
echo "第步: 重启 Dnsmasq 程序..." >$START_LOG
if [ "$(iptables -t nat -nL PREROUTING --line-number |grep dpt:53 |wc -l)" -gt 2 ]; then
echo "发现53端口被劫持如连接异常请将OpenClash设置为劫持53端口程序的上游DNS服务器" >$START_LOG
echo "${LOGTIME} Warring: OpenClash May Can Not Take Over DNS, Please Use OpenClash for Upstream DNS Resolve Server" >> $LOG_FILE
@ -789,15 +798,17 @@ EOF
fake_block "$en_mode" "$direct_dns"
/etc/init.d/dnsmasq restart >/dev/null 2>&1
if pidof clash >/dev/null; then
echo "第步: 添加 OpenClash 计划任务,启动进程守护程序..." >$START_LOG
echo "第步: 添加 OpenClash 计划任务,启动进程守护程序..." >$START_LOG
add_cron
if [ -z "$(uci get dhcp.lan.dhcpv6 2>/dev/null)" ]; then
echo "OpenClash 启动成功,请等待服务器上线!" >$START_LOG
echo "${LOGTIME} OpenClash Start Successful" >> $LOG_FILE
/usr/share/openclash/openclash_history_set.sh
sleep 5
else
echo "OpenClash 启动成功检测到您启用了IPV6的DHCP服务可能会造成连接异常" >$START_LOG
echo "${LOGTIME} OpenClash Start Successful, Please Note That Network May Abnormal With IPV6's DHCP Server" >> $LOG_FILE
/usr/share/openclash/openclash_history_set.sh
sleep 10
fi
echo "" >$START_LOG
@ -817,12 +828,14 @@ EOF
if [ -z "$(uci get dhcp.lan.dhcpv6 2>/dev/null)" ]; then
echo "OpenClash 使用备份规则启动成功,请更新、检查变动的规则后重试!" >$START_LOG
echo "${LOGTIME} OpenClash Start Successful With Backup Rules Config, Please Check Or Update Other Rules And Retry" >> $LOG_FILE
/usr/share/openclash/openclash_history_set.sh
sleep 10
else
echo "OpenClash 使用备份规则启动成功,请更新、检查变动的规则后重试!" >$START_LOG
echo "${LOGTIME} OpenClash Start Successful With Backup Rules Config, Please Check Or Update Other Rules And Retry" >> $LOG_FILE
sleep 10
echo "OpenClash 启动成功检测到您启用了IPV6的DHCP服务可能会造成连接异常" >$START_LOG
/usr/share/openclash/openclash_history_set.sh
sleep 5
echo "检测到您启用了IPV6的DHCP服务可能会造成连接异常" >$START_LOG
echo "${LOGTIME} OpenClash Start Successful, Please Note That Network May Abnormal With IPV6's DHCP Server" >> $LOG_FILE
sleep 10
fi
@ -871,12 +884,14 @@ fi
stop()
{
echo "OpenClash 开始关闭..." >$START_LOG
echo "第一步: 删除 OpenClash 防火墙规则..." >$START_LOG
echo "第一步: 备份当前节点状态..." >$START_LOG
/usr/share/openclash/openclash_history_get.sh
echo "第二步: 删除 OpenClash 防火墙规则..." >$START_LOG
rm -rf /var/etc/openclash.include 2>/dev/null
#ipv4
iptables -t nat -F openclash >/dev/null 2>&1
iptables -t nat -D PREROUTING -p tcp -j openclash >/dev/null 2>&1
iptables -t nat -D zone_lan_prerouting -p tcp -j openclash >/dev/null 2>&1
iptables -t nat -X openclash >/dev/null 2>&1
out_lines=$(iptables -nvL OUTPUT -t nat |sed 1,2d |sed -n '/198.18.0.0\/16/=' 2>/dev/null |sort -rn)
@ -887,13 +902,13 @@ stop()
#ipv6
ip6tables -t nat -F openclash >/dev/null 2>&1
ip6tables -t nat -D PREROUTING -p tcp -j openclash >/dev/null 2>&1
ip6tables -t nat -D zone_lan_prerouting -p tcp -j openclash >/dev/null 2>&1
ip6tables -t nat -X openclash >/dev/null 2>&1
#TUN
ip link set dev clash0 down >/dev/null 2>&1
ip tuntap del clash0 mode tun >/dev/null 2>&1
ip route del default dev clash0 table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip route del default dev utun table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
iptables -t mangle -D OUTPUT -j openclash >/dev/null 2>&1
@ -903,23 +918,23 @@ stop()
iptables -t mangle -X openclash >/dev/null 2>&1
ipset destroy localnetwork >/dev/null 2>&1
echo "第步: 关闭 OpenClash 守护程序..." >$START_LOG
echo "第步: 关闭 OpenClash 守护程序..." >$START_LOG
watchdog_pids=$(ps |grep openclash_watchdog.sh |grep -v grep |awk '{print $1}' 2>/dev/null)
for watchdog_pid in $watchdog_pids; do
kill -9 "$watchdog_pid" >/dev/null 2>&1
done
echo "第步: 关闭 Clash 主程序..." >$START_LOG
echo "第步: 关闭 Clash 主程序..." >$START_LOG
kill -9 "$(pidof clash|sed 's/$//g')" 2>/dev/null
echo "第步: 重启 Dnsmasq 程序..." >$START_LOG
echo "第步: 重启 Dnsmasq 程序..." >$START_LOG
dns_port=$(uci get openclash.config.dns_port 2>/dev/null)
redirect_dns=$(uci get openclash.config.redirect_dns 2>/dev/null)
masq_cache=$(uci get openclash.config.masq_cache 2>/dev/null)
revert_dns "$redirect_dns" "$masq_cache" "$dns_port"
/etc/init.d/dnsmasq restart >/dev/null 2>&1
echo "第步:删除 OpenClash 残留文件..." >$START_LOG
echo "第步:删除 OpenClash 残留文件..." >$START_LOG
enable=$(uci get openclash.config.enable 2>/dev/null)
if [ "$enable" -eq 0 ]; then
rm -rf $LOG_FILE 2>/dev/null
@ -943,4 +958,4 @@ restart()
{
stop
start
}
}

View File

@ -460,8 +460,7 @@ Rule:
# (HKMTMedia)
# > 愛奇藝台灣站
- DOMAIN-SUFFIX,iqiyi.com,HKMTMedia
- DOMAIN-SUFFIX,71.am,HKMTMedia
- DOMAIN,cache.video.iqiyi.com,HKMTMedia
# > bilibili
- DOMAIN-SUFFIX,bilibili.com,HKMTMedia
- DOMAIN,upos-hz-mirrorakam.akamaized.net,HKMTMedia

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,14 @@ local uci = require "luci.model.uci".cursor()
m = Map(openclash, translate("Game Rules and Groups"))
m.pageaction = false
m.description=translate("注意事项:<br/>游戏模式为测试功能不保证可用性。使用的内核由comzyh修改<br/>项目地址https://github.com/comzyh/clash <br/>使用步骤:<br/>1、在《服务器与策略组管理》页面创建您准备使用的游戏策略组和游戏节点节点添加时必须选择要加入的策略组策略组类型建议:FallBack游戏节点必须支持UDP<br/>2、在此页面的游戏规则列表下载您要使用的游戏规则<br/>3、在此页面上方设置您已下载的游戏规则的对应策略组并保存设置<br/>4、替换内核下载地址https://github.com/vernesong/OpenClash/releases/tag/TUN<br/>5、在《全局设置》-《常规设置》-《运行模式》中选择游戏模式并启动")
m.description=translate("注意事项:<br/>游戏代理为测试功能不保证可用性。其中游戏模式使用的内核由comzyh修改 \
<br/>https://github.com/comzyh/clash <br/>使 \
<br/>1使:FallBackUDP \
<br/>2使 \
<br/>3 \
<br/>4https://github.com/Dreamacro/clash/releases/tag/TUN \
<br/>https://github.com/vernesong/OpenClash/releases/tag/TUN \
<br/>5--TUN模式")
function IsRuleFile(e)
@ -20,7 +27,21 @@ local e=string.lower(string.sub(e,-6,-1))
return e==".rules"
end
SYS.call("awk -F ',' '{print $1}' /etc/openclash/game_rules.list > /tmp/rules_name 2>/dev/null")
function IsYamlFile(e)
e=e or""
local e=string.lower(string.sub(e,-5,-1))
return e == ".yaml"
end
function IsYmlFile(e)
e=e or""
local e=string.lower(string.sub(e,-4,-1))
return e == ".yml"
end
if not NXFS.access("/tmp/rules_name") then
SYS.call("awk -F ',' '{print $1}' /etc/openclash/game_rules.list > /tmp/rules_name 2>/dev/null")
end
file = io.open("/tmp/rules_name", "r");
-- [[ Edit Game Rule ]] --
@ -39,6 +60,21 @@ o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "1"
end
---- config
o = s:option(ListValue, "config", translate("Config File"))
o:value("all", translate("Use For All Config File"))
local e,a={}
for t,f in ipairs(fs.glob("/etc/openclash/config/*"))do
a=fs.stat(f)
if a then
e[t]={}
e[t].name=fs.basename(f)
if IsYamlFile(e[t].name) or IsYmlFile(e[t].name) then
o:value(e[t].name)
end
end
end
---- rule name
o = s:option(DynamicList, "rule_name", translate("Game Rule's Name"))
local e,a={}
@ -69,9 +105,8 @@ o:value("REJECT")
o.rmempty = true
---- Rules List
local e={},a,o,t
a=nixio.fs.access("/tmp/rules_name")
if a then
local e={},o,t
if NXFS.access("/tmp/rules_name") then
for o in file:lines() do
table.insert(e,o)
end

View File

@ -48,6 +48,7 @@ o = s:taboption("settings", ListValue, "en_mode", font_red..bold_on..translate("
o.description = translate("Select Mode For OpenClash Work, Network Error Try Flush DNS Cache")
o:value("redir-host", translate("redir-host"))
o:value("fake-ip", translate("fake-ip"))
o:value("redir-host-tun", translate("redir-host(tun mode)"))
o:value("fake-ip-tun", translate("fake-ip(tun mode)"))
o:value("redir-host-vpn", translate("redir-host-vpn(game mode)"))
o:value("fake-ip-vpn", translate("fake-ip-vpn(game mode)"))

View File

@ -132,9 +132,6 @@
<div style="display: flex;">
<div style="width: 51%">
<h3>IP 地址</h3>
<p>
<span class="ip-title">IP&nbsp;&nbsp;&nbsp;登录设备:</span><span class="ip-result" id="ip-webrtc"></span> <span class="ip-geo" id="ip-webrtc-cz88"></span>
</p>
<p>
<span class="ip-title">IPIP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;国内:</span><span class="ip-result" id="ip-ipipnet"></span> <span class="ip-geo" id="ip-ipipnet-geo"></span>
</p>
@ -159,9 +156,6 @@
<p>
<span class="ip-state_title">GitHub:</span><span id="http-github"></span>
</p>
<p>
<span class="ip-state_title">Facebook:</span><span id="http-facebook"></span>
</p>
<p>
<span class="ip-state_title">YouTube:</span><span id="http-youtube"></span>
</p>
@ -180,7 +174,6 @@
window.open(url2);
}
const $$ = document;
$$.getElementById('ip-webrtc').innerHTML = '查询中...';
$$.getElementById('ip-pcol').innerHTML = '查询中...';
$$.getElementById('ip-ipify').innerHTML = '查询中...';
$$.getElementById('ip-ipipnet').innerHTML = '查询中...';
@ -220,23 +213,6 @@
//$$.getElementById(elID).innerHTML = `${resp.data.country} ${resp.data.regionName} ${resp.data.city} ${resp.data.isp}`;
})
},
getWebrtcIP: () => {
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
let pc = new RTCPeerConnection({ iceServers: [] }),
noop = () => { };
pc.createDataChannel('');
pc.createOffer(pc.setLocalDescription.bind(pc), noop);
pc.onicecandidate = (ice) => {
if (!ice || !ice.candidate || !ice.candidate.candidate) {
$$.getElementById('ip-webrtc').innerHTML = '没有查询到 IP';
return;
}
let ip = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/.exec(ice.candidate.candidate)[1];
$$.getElementById('ip-webrtc').innerHTML = ip;
IP.parseIPIpip(ip, 'ip-webrtc-cz88');
pc.onicecandidate = noop;
};
},
getIpipnetIP: () => {
IP.get(`https://myip.ipip.net/?z=${random}`, 'text')
.then((resp) => {
@ -267,7 +243,6 @@
$$.getElementById('http-baidu').innerHTML = '<span class="ip-checking">检测中...</span>';
$$.getElementById('http-163').innerHTML = '<span class="ip-checking">检测中...</span>';
$$.getElementById('http-github').innerHTML = '<span class="ip-checking">检测中...</span>';
$$.getElementById('http-facebook').innerHTML = '<span class="ip-checking">检测中...</span>';
$$.getElementById('http-youtube').innerHTML = '<span class="ip-checking">检测中...</span>';
let HTTP = {
checker: (domain, cbElID) => {
@ -293,7 +268,6 @@
HTTP.checker('www.baidu.com', 'http-baidu');
HTTP.checker('s1.music.126.net/style', 'http-163');
HTTP.checker('github.com', 'http-github');
HTTP.checker('www.facebook.com', 'http-facebook');
HTTP.checker('www.youtube.com', 'http-youtube');
}
};
@ -301,7 +275,6 @@
HTTP.runcheck();
IP.getIpipnetIP();
IP.getIpifyIP();
IP.getWebrtcIP();
function getPcolIP(data){
let pcisp = data.addr.split(' ');
@ -334,7 +307,6 @@
HTTP.runcheck();
IP.getIpipnetIP();
IP.getIpifyIP();
IP.getWebrtcIP();
function getPcolIP(data){
let pcisp = data.addr.split(' ');

View File

@ -55,6 +55,10 @@
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Redir-Host兼容模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';
}
else if ( status.mode == "redir-host-tun\n" )
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Redir-HostTUN模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';
}
else if ( status.mode == "fake-ip-tun\n" )
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Fake-IPTUN模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';
@ -86,6 +90,10 @@
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Redir-Host兼容模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';
}
else if ( status.mode == "redir-host-tun\n" )
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Redir-HostTUN模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';
}
else if ( status.mode == "fake-ip-tun\n" )
{
mode.innerHTML = status.clash ? "<b><font color=green><%: Fake-IPTUN模式 %></font></b>" : '<b><font color=red><%:NOT RUNNING%></font></b>';

View File

@ -3,7 +3,7 @@ CKTIME=$(date "+%Y-%m-%d-%H")
LAST_OPVER="/tmp/clash_last_version"
version_url="https://raw.githubusercontent.com/vernesong/OpenClash/master/core_version"
if [ "$CKTIME" != "$(grep "CheckTime" $LAST_OPVER 2>/dev/null |awk -F ':' '{print $2}')" ]; then
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 "$version_url" -O $LAST_OPVER
curl -sL -m 10 --retry 2 "$version_url" -o $LAST_OPVER >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l $LAST_OPVER 2>/dev/null |awk '{print int($5)}')" -gt 0 ]; then
echo "CheckTime:$CKTIME" >>$LAST_OPVER
else

View File

@ -16,12 +16,12 @@ config_download()
{
if [ "$URL_TYPE" == "v2rayn" ]; then
subscribe_url=`echo $subscribe_url |sed 's/{/%7B/g;s/}/%7D/g;s/:/%3A/g;s/\"/%22/g;s/,/%2C/g;s/?/%3F/g;s/=/%3D/g;s/&/%26/g;s/\//%2F/g'`
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://tgbot.lbyczf.com/v2rayn2clash?url="$subscribe_url" -O /tmp/config.yaml
curl -sL -m 10 --retry 2 https://tgbot.lbyczf.com/v2rayn2clash?url="$subscribe_url" -o /tmp/config.yaml >/dev/null 2>&1
elif [ "$URL_TYPE" == "surge" ]; then
subscribe_url=`echo $subscribe_url |sed 's/{/%7B/g;s/}/%7D/g;s/:/%3A/g;s/\"/%22/g;s/,/%2C/g;s/?/%3F/g;s/=/%3D/g;s/&/%26/g;s/\//%2F/g'`
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://tgbot.lbyczf.com/surge2clash?url="$subscribe_url" -O /tmp/config.yaml
curl -sL -m 10 --retry 2 https://tgbot.lbyczf.com/surge2clash?url="$subscribe_url" -o /tmp/config.yaml >/dev/null 2>&1
else
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 "$subscribe_url" -O /tmp/config.yaml
curl -sL -m 10 --retry 2 "$subscribe_url" -o /tmp/config.yaml >/dev/null 2>&1
fi
}

View File

@ -11,7 +11,7 @@ CPU_MODEL=$(uci get openclash.config.core_version 2>/dev/null)
if [ "$(/etc/openclash/clash -v 2>/dev/null |awk -F ' ' '{print $2}')" != "$(sed -n 1p /tmp/clash_last_version 2>/dev/null)" ] || [ -z "$(/etc/openclash/clash -v 2>/dev/null |awk -F ' ' '{print $2}')" ] || [ ! -f /etc/openclash/clash ]; then
if [ "$CPU_MODEL" != 0 ]; then
echo "开始下载 OpenClash 内核..." >$START_LOG
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=5 https://github.com/vernesong/OpenClash/releases/download/Clash/clash-"$CPU_MODEL".tar.gz -O /tmp/clash.tar.gz
curl -sL -m 10 --retry 2 https://github.com/vernesong/OpenClash/releases/download/Clash/clash-"$CPU_MODEL".tar.gz -o /tmp/clash.tar.gz >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l /tmp/clash.tar.gz |awk '{print int($5/1024)}')" -ne 0 ]; then
tar zxvf /tmp/clash.tar.gz -C /tmp >/dev/null 2>&1\
&& rm -rf /tmp/clash.tar.gz >/dev/null 2>&1\

View File

@ -12,7 +12,7 @@
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
LOG_FILE="/tmp/openclash.log"
echo "开始下载【$RULE_FILE_NAME】规则..." >$START_LOG
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://raw.githubusercontent.com/FQrabbit/SSTap-Rule/master/rules/"$DOWNLOAD_PATH" -O "$TMP_RULE_DIR"
curl -sL -m 10 --retry 2 https://raw.githubusercontent.com/FQrabbit/SSTap-Rule/master/rules/"$DOWNLOAD_PATH" -o "$TMP_RULE_DIR" >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l $TMP_RULE_DIR |awk '{print $5}')" -ne 0 ]; then
echo "$RULE_FILE_NAME】规则下载成功,检查规则版本是否更新..." >$START_LOG
cmp -s $TMP_RULE_DIR $RULE_FILE_DIR

View File

@ -0,0 +1,17 @@
#!/bin/sh
CURL_GROUP_CACHE="/tmp/openclash_history_gorup.json"
CURL_NOW_CACHE="/tmp/openclash_history_now.json"
CURL_CACHE="/tmp/openclash_history_curl.json"
HISTORY_PATH="/etc/openclash/history"
SECRET=$(uci get openclash.config.dashboard_password 2>/dev/null)
LAN_IP=$(uci get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null)
PORT=$(uci get openclash.config.cn_port 2>/dev/null)
curl -w %{http_code}"\n" -H "Authorization: Bearer ${SECRET}" -H "Content-Type:application/json" -X GET http://"$LAN_IP":"$PORT"/proxies > "$CURL_CACHE" 2>/dev/null
if [ "$(sed -n '$p' "$CURL_CACHE")" -eq "200" ]; then
cat "$CURL_CACHE" |jsonfilter -e '@["proxies"][@.type="Selector"]["name"]' > "$CURL_GROUP_CACHE" 2>/dev/null
cat "$CURL_CACHE" |jsonfilter -e '@["proxies"][@.type="Selector"]["now"]' > "$CURL_NOW_CACHE" 2>/dev/null
awk 'NR==FNR{a[i]=$0;i++}NR>FNR{print a[j]"#*#"$0;j++}' "$CURL_GROUP_CACHE" "$CURL_NOW_CACHE" > "$HISTORY_PATH" 2>/dev/null
fi
rm -rf /tmp/openclash_history_* 2>/dev/null

View File

@ -0,0 +1,15 @@
#!/bin/sh
HISTORY_PATH="/etc/openclash/history"
SECRET=$(uci get openclash.config.dashboard_password 2>/dev/null)
LAN_IP=$(uci get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null)
PORT=$(uci get openclash.config.cn_port 2>/dev/null)
if [ ! -z "$(grep "#*#" "$HISTORY_PATH")" ]; then
cat $HISTORY_PATH |while read line
do
GORUP_NAME=$(echo $line |awk -F '#*#' '{print $1}')
NOW_NAME=$(echo $line |awk -F '#*#' '{print $3}')
curl -H "Authorization: Bearer ${SECRET}" -H "Content-Type:application/json" -X PUT -d '{"name":"'"$NOW_NAME"'"}' http://"$LAN_IP":"$PORT"/proxies/"$GORUP_NAME" >/dev/null 2>&1
done
fi

View File

@ -3,7 +3,7 @@
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
LOG_FILE="/tmp/openclash.log"
echo "开始下载 GEOIP 数据库..." >$START_LOG
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://static.clash.to/GeoIP2/GeoIP2-Country.mmdb -O /tmp/Country.mmdb
curl -sL -m 10 --retry 2 https://static.clash.to/GeoIP2/GeoIP2-Country.mmdb -o /tmp/Country.mmdb >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l /tmp/Country.mmdb |awk '{print int($5/1024)}')" -ne 0 ]; then
echo "GEOIP 数据库下载成功,检查数据库版本是否更新..." >$START_LOG
cmp -s /tmp/Country.mmdb /etc/openclash/Country.mmdb

View File

@ -6,13 +6,13 @@
rule_source=$(uci get openclash.config.rule_source 2>/dev/null)
echo "开始下载使用中的第三方规则..." >$START_LOG
if [ "$rule_source" = "lhie1" ]; then
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://raw.githubusercontent.com/lhie1/Rules/master/Clash/Rule.yml -O /tmp/rules.yaml
curl -sL -m 10 --retry 2 https://raw.githubusercontent.com/lhie1/Rules/master/Clash/Rule.yml -o /tmp/rules.yaml >/dev/null 2>&1
sed -i '1i Rule:' /tmp/rules.yaml
elif [ "$rule_source" = "ConnersHua" ]; then
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://raw.githubusercontent.com/ConnersHua/Profiles/master/Clash/Pro.yaml -O /tmp/rules.yaml
curl -sL -m 10 --retry 2 https://raw.githubusercontent.com/ConnersHua/Profiles/master/Clash/Pro.yaml -o /tmp/rules.yaml >/dev/null 2>&1
sed -i -n '/^Rule:/,$p' /tmp/rules.yaml
elif [ "$rule_source" = "ConnersHua_return" ]; then
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 https://raw.githubusercontent.com/ConnersHua/Profiles/master/Clash/BacktoCN.yaml -O /tmp/rules.yaml
curl -sL -m 10 --retry 2 https://raw.githubusercontent.com/ConnersHua/Profiles/master/Clash/BacktoCN.yaml -o /tmp/rules.yaml >/dev/null 2>&1
sed -i -n '/^Rule:/,$p' /tmp/rules.yaml
fi
if [ "$?" -eq "0" ] && [ "$rule_source" != 0 ] && [ "$(ls -l /tmp/rules.yaml |awk '{print int($5/1024)}')" -ne 0 ]; then

View File

@ -10,7 +10,7 @@ LAST_OPVER="/tmp/openclash_last_version"
LAST_VER=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g")
if [ "$(sed -n 1p /etc/openclash/openclash_version 2>/dev/null)" != "$(sed -n 1p $LAST_OPVER 2>/dev/null)" ] && [ -f "$LAST_OPVER" ]; then
echo "开始下载 OpenClash-$LAST_VER ..." >$START_LOG
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=5 https://github.com/vernesong/OpenClash/releases/download/v"$LAST_VER"/luci-app-openclash_"$LAST_VER"_all.ipk -O /tmp/openclash.ipk
curl -sL -m 10 --retry 5 https://github.com/vernesong/OpenClash/releases/download/v"$LAST_VER"/luci-app-openclash_"$LAST_VER"_all.ipk -o /tmp/openclash.ipk >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l /tmp/openclash.ipk |awk '{print int($5/1024)}')" -ne 0 ]; then
echo "OpenClash-$LAST_VER 下载成功,开始更新,更新过程请不要刷新页面和进行其他操作..." >$START_LOG
cat > /tmp/openclash_update.sh <<"EOF"

View File

@ -3,7 +3,7 @@ CKTIME=$(date "+%Y-%m-%d-%H")
LAST_OPVER="/tmp/openclash_last_version"
version_url="https://raw.githubusercontent.com/vernesong/OpenClash/master/version"
if [ "$CKTIME" != "$(grep "CheckTime" $LAST_OPVER 2>/dev/null |awk -F ':' '{print $2}')" ]; then
wget-ssl --no-check-certificate --quiet --timeout=10 --tries=2 "$version_url" -O $LAST_OPVER
curl -sL -m 10 --retry 2 "$version_url" -o $LAST_OPVER >/dev/null 2>&1
if [ "$?" -eq "0" ] && [ "$(ls -l $LAST_OPVER 2>/dev/null |awk '{print int($5)}')" -gt 0 ]; then
if [ "$(sed -n 1p /etc/openclash/openclash_version 2>/dev/null)" = "$(sed -n 1p $LAST_OPVER 2>/dev/null)" ]; then
sed -i "/^https:/i\CheckTime:${CKTIME}" "$LAST_OPVER" 2>/dev/null

View File

@ -19,6 +19,8 @@ if [ "$enable" -eq 1 ]; then
CONFIG_FILE=$(uci get openclash.config.config_path 2>/dev/null)
echo "${LOGTIME} Watchdog: Clash Core Problem, Restart." >> $LOG_FILE
nohup $CLASH -d "$CLASH_CONFIG" -f "$CONFIG_FILE" >> $LOG_FILE 2>&1 &
sleep 3
/usr/share/openclash/openclash_history_set.sh
else
echo "${LOGTIME} Watchdog: Already Restart 3 Times With Clash Core Problem, Auto-Exit." >> $LOG_FILE
exit 0
@ -28,11 +30,23 @@ if [ "$enable" -eq 1 ]; then
fi
fi
## Porxy history
/usr/share/openclash/openclash_history_get.sh
## Log File Size Manage:
LOGSIZE=`ls -l /tmp/openclash.log |awk '{print int($5/1024)}'`
if [ "$LOGSIZE" -gt 90 ]; then
echo "$LOGTIME Watchdog: Size Limit, Clean Up All Log Records." > $LOG_FILE
fi
## 端口转发重启
last_line=$(iptables -t nat -nL PREROUTING --line-number |awk '{print $1}' 2>/dev/null |awk 'END {print}' |sed -n '$p')
op_line=$(iptables -t nat -nL PREROUTING --line-number |grep "openclash" 2>/dev/null |awk '{print $1}' 2>/dev/null |head -1)
if [ "$last_line" -ne "$op_line" ]; then
iptables -t nat -D PREROUTING -p tcp -j openclash
iptables -t nat -A PREROUTING -p tcp -j openclash
echo "$LOGTIME Watchdog: Reset Firewall For Enabling Redirect." >>$LOG_FILE
fi
## DNS转发劫持
if [ "$enable_redirect_dns" != "0" ]; then

View File

@ -6,6 +6,7 @@ status=$(ps|grep -c /usr/share/openclash/yml_groups_set.sh)
START_LOG="/tmp/openclash_start.log"
GROUP_FILE="/tmp/yaml_groups.yaml"
CONFIG_GROUP_FILE="/tmp/yaml_group.yaml"
CFG_FILE="/etc/config/openclash"
servers_update=$(uci get openclash.config.servers_update 2>/dev/null)
CONFIG_FILE=$(uci get openclash.config.config_path 2>/dev/null)
@ -35,6 +36,7 @@ yml_servers_add()
local section="$1"
config_get_bool "enabled" "$section" "enabled" "1"
config_get "config" "$section" "config" ""
config_get "name" "$section" "name" ""
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
@ -43,8 +45,9 @@ yml_servers_add()
if [ "$enabled" = "0" ]; then
return
else
config_get "name" "$section" "name" ""
config_list_foreach "$section" "groups" set_groups "$name" "$2"
if [ -z "$3" ]; then
config_list_foreach "$section" "groups" set_groups "$name" "$2"
fi
if [ ! -z "$if_game_group" ] && [ -z "$(grep -F $name /tmp/yaml_proxy.yaml)" ]; then
/usr/share/openclash/yml_proxys_set.sh "$name" "proxy"
@ -83,6 +86,7 @@ set_proxy_provider()
local section="$1"
config_get_bool "enabled" "$section" "enabled" "1"
config_get "config" "$section" "config" ""
config_get "name" "$section" "name" ""
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
@ -91,8 +95,9 @@ set_proxy_provider()
if [ "$enabled" = "0" ]; then
return
else
config_get "name" "$section" "name" ""
config_list_foreach "$section" "groups" set_provider_groups "$name" "$2"
if [ -z "$3" ]; then
config_list_foreach "$section" "groups" set_provider_groups "$name" "$2"
fi
if [ ! -z "$if_game_group" ] && [ -z "$(grep "^ \{0,\}$name" /tmp/yaml_proxy_provider.yaml)" ]; then
/usr/share/openclash/yml_proxys_set.sh "$name" "proxy-provider"
@ -146,6 +151,13 @@ yml_groups_set()
return
fi
#游戏策略组存在时判断节点是否存在
if [ ! -z "$if_game_group" ] && [ ! -z "$(grep "^ \{0,\}- name: $if_game_group" "$CONFIG_GROUP_FILE")" ]; then
config_foreach yml_servers_add "servers" "$name" "check" #加入服务器节点
config_foreach set_proxy_provider "proxy-provider" "$group_name" "check" #加入代理集
return
fi
echo "正在写入【$type】-【$name】策略组到配置文件【$CONFIG_NAME】..." >$START_LOG
echo "- name: $name" >>$GROUP_FILE
@ -168,9 +180,8 @@ yml_groups_set()
config_foreach yml_servers_add "servers" "$name" #加入服务器节点
echo " use: $group_name" >>$GROUP_FILE
config_foreach set_proxy_provider "proxy-provider" "$group_name" #加入代理集
if [ "$set_group" -eq 1 ]; then
sed -i "/^ \{0,\}proxies: ${group_name}/c\ proxies:" $GROUP_FILE
else
@ -184,10 +195,10 @@ yml_groups_set()
fi
[ ! -z "$test_url" ] && {
echo " url: $test_url" >>$GROUP_FILE
echo " url: $test_url" >>$GROUP_FILE
}
[ ! -z "$test_interval" ] && {
echo " interval: \"$test_interval\"" >>$GROUP_FILE
echo " interval: \"$test_interval\"" >>$GROUP_FILE
}
}
@ -208,6 +219,7 @@ if [ "$create_config" = "0" ] || [ "$servers_if_update" = "1" ] || [ ! -z "$if_g
echo "Proxy Group:" >$GROUP_FILE
else
echo "开始加入游戏策略组【$if_game_group】的信息..." >$START_LOG
rm -rf $GROUP_FILE
fi
config_load "openclash"
config_foreach yml_groups_set "groups"

View File

@ -301,7 +301,7 @@ rm -rf /tmp/Proxy_Provider
config_load "openclash"
config_foreach yml_proxy_provider_set "proxy-provider"
sed -i "s/^ \{0,\}/ - /" /tmp/Proxy_Provider 2>/dev/null #添加参数
if [ "$(grep "-" /tmp/Proxy_Provider |wc -l)" -eq 0 ]; then
if [ "$(grep "-" /tmp/Proxy_Provider 2>/dev/null |wc -l)" -eq 0 ]; then
rm -rf $PROXY_PROVIDER_FILE
rm -rf /tmp/Proxy_Provider
fi
@ -665,9 +665,9 @@ echo "" >$START_LOG
if [ -z "$if_game_proxy" ]; then
rm -rf $SERVER_FILE 2>/dev/null
rm -rf $PROXY_PROVIDER_FILE 2>/dev/null
rm -rf /tmp/yaml_groups.yaml 2>/dev/null
fi
rm -rf /tmp/Proxy_Server 2>/dev/null
rm -rf /tmp/yaml_groups.yaml 2>/dev/null
rm -rf /tmp/Proxy_Provider 2>/dev/null
uci set openclash.config.enable=1 2>/dev/null
[ "$(uci get openclash.config.servers_if_update)" == "0" ] && [ -z "$if_game_proxy" ] && /etc/init.d/openclash restart >/dev/null 2>&1

View File

@ -95,6 +95,9 @@ msgstr "Redir-Host兼容模式"
msgid "fake-ip"
msgstr "Fake-IP增强模式"
msgid "redir-host(tun mode)"
msgstr "Redir-HostTUN模式【依赖kmod-tun】"
msgid "fake-ip(tun mode)"
msgstr "Fake-IPTUN模式【依赖kmod-tun】"

View File

@ -11,14 +11,16 @@ PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Server \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_haproxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_udpspeeder \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_udp2raw-tunnel \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_privoxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs\
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs-server\
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks\
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-client\
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-server\
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_v2ray-plugin
@ -33,10 +35,10 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
bool "Include V2ray"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
bool "Include Trojan"
default n
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun
bool "Include Kcptun"
@ -48,7 +50,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Server
bool "Include Shadowsocks Server"
default n
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks
bool "Include ShadowsocksR Socks and Tunnel"
@ -56,51 +58,59 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks
bool "Include Shadowsocks Socks and Tunnel"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy
bool "dnscrypt-proxy-full"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder
bool "dnsforwarder"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS
bool "chinadns"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_haproxy
bool "haproxy"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_privoxy
bool "privoxy http local"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs
bool "simple-obfs-local"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs-server
bool "simple-obfs-server"
default n
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks
bool "Include ipt2socks"
default n
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy
bool "Include dnscrypt-proxy-full"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder
bool "Include dnsforwarder"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS
bool "Include chinadns"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_haproxy
bool "Include haproxy"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_privoxy
bool "Include privoxy http local"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs
bool "Include simple-obfsl"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs-server
bool "Include simple-obfs-server"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_udpspeeder
bool "Include udpspeeder"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_udp2raw-tunnel
bool "Include udp2raw-tunnel"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-client
bool "GoQuiet-client"
default n
bool "Include GoQuiet-client"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-server
bool "GoQuiet-server"
default n
bool "Include GoQuiet-server"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_v2ray-plugin
bool "v2ray-plugin"
default n
bool "Include v2ray-plugin"
default y
endef
define Package/luci-app-ssr-plus-Jo
@ -112,20 +122,22 @@ define Package/luci-app-ssr-plus-Jo
DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +bash +pdnsd-alt +curl +wget +unzip \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks:shadowsocks-libev-ss-redir \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \
+PACKAGE_$(PKG_NAME)_INCLUDE_Kcptun:kcptun-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server:shadowsocksr-libev-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Server:shadowsocks-libev-ss-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks:shadowsocksr-libev-ssr-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks:shadowsocks-libev-ss-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks:ipt2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy:dnscrypt-proxy-full \
+PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder:dnsforwarder \
+PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS:openwrt_chinadns \
+PACKAGE_$(PKG_NAME)_INCLUDE_haproxy:haproxy \
+PACKAGE_$(PKG_NAME)_INCLUDE_privoxy:privoxy \
+PACKAGE_$(PKG_NAME)_INCLUDE_udpspeeder:speederv2-tunnel \
+PACKAGE_$(PKG_NAME)_INCLUDE_udp2raw-tunnel:udp2raw-tunnel \
+PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs:simple-obfs \
+PACKAGE_$(PKG_NAME)_INCLUDE_simple-obfs-server:simple-obfs-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks:ipt2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-client:gq-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_GoQuiet-server:gq-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_v2ray-plugin:v2ray-plugin

View File

@ -11,8 +11,8 @@ LUCI_TITLE:=LuCI support for UnblockNeteaseMusic
LUCI_DEPENDS:=+bash +busybox +coreutils-nohup +curl +dnsmasq-full +ipset +libopenssl +node
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-unblockneteasemusic
PKG_VERSION:=2.6
PKG_RELEASE:=3
PKG_VERSION:=2.7
PKG_RELEASE:=1
PKG_MAINTAINER:=[CTCGFW]Project-OpenWrt

View File

@ -12,10 +12,11 @@ function index()
entry({"admin", "services", "unblockneteasemusic"},firstchild(), _("解除网易云音乐播放限制"), 50).dependent = false
entry({"admin", "services", "unblockneteasemusic", "general"},cbi("unblockneteasemusic"), _("基本设定"), 1)
entry({"admin", "services", "unblockneteasemusic", "upgrade_core"},form("unblockneteasemusic_upcore"), _("更新核心"), 2).leaf = true
entry({"admin", "services", "unblockneteasemusic", "upgrade"},form("unblockneteasemusic_upgrade"), _("更新组件"), 2).leaf = true
entry({"admin", "services", "unblockneteasemusic", "log"},form("unblockneteasemusiclog"), _("日志"), 3)
entry({"admin", "services", "unblockneteasemusic", "status"},call("act_status")).leaf=true
entry({"admin", "services", "unblockneteasemusic", "update_luci"},call("act_update_luci"))
entry({"admin", "services", "unblockneteasemusic", "update_core"},call("act_update_core"))
end
@ -26,21 +27,49 @@ function act_status()
luci.http.write_json(e)
end
function update_core()
cloud_ver=luci.sys.exec("curl -s 'https://github.com/nondanee/UnblockNeteaseMusic/commits/master' |tr -d '\n' |grep -Eo 'commit\/[0-9a-z]+' |sed -n 1p |sed 's#commit/##g'")
cloud_ver_mini=luci.sys.exec("curl -s 'https://github.com/nondanee/UnblockNeteaseMusic/commits/master' |tr -d '\n' |grep -Eo 'BtnGroup-item.> [0-9a-z]+' |sed -n 1p |sed 's#BtnGroup-item.> ##g'")
if not cloud_ver or not cloud_ver_mini then
function update_luci()
luci_cloud_ver=luci.sys.exec("curl -s 'https://github.com/project-openwrt/luci-app-unblockneteasemusic/releases/latest'| grep -Eo '[0-9\.]+\-[0-9]+'")
if not luci_cloud_ver then
return "1"
else
local_ver=luci.sys.exec("cat '/usr/share/unblockneteasemusic/local_ver'")
if not local_ver or (local_ver ~= cloud_ver) then
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_successfully")
luci.sys.call("/bin/bash /usr/share/unblockneteasemusic/update_core.sh luci_update")
if not nixio.fs.access("/usr/share/unblockneteasemusic/update_successfully") then
luci_local_ver=luci.sys.exec("opkg info 'luci-app-unblockneteasemusic' |sed -n '2p' |tr -d 'Version: '")
if not luci_local_ver or (luci_local_ver ~= luci_cloud_ver) then
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_luci_successfully")
luci.sys.call("/bin/bash /usr/share/unblockneteasemusic/update.sh update_luci")
if not nixio.fs.access("/usr/share/unblockneteasemusic/update_luci_successfully") then
return "2"
else
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_successfully")
return cloud_ver_mini
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_luci_successfully")
return luci_cloud_ver
end
else
return "0"
end
end
end
function act_update_luci()
luci.http.prepare_content("application/json")
luci.http.write_json({
ret = update_luci();
})
end
function update_core()
core_cloud_ver=luci.sys.exec("curl -s 'https://github.com/nondanee/UnblockNeteaseMusic/commits/master' |tr -d '\n' |grep -Eo 'commit\/[0-9a-z]+' |sed -n 1p |sed 's#commit/##g'")
core_cloud_ver_mini=luci.sys.exec("curl -s 'https://github.com/nondanee/UnblockNeteaseMusic/commits/master' |tr -d '\n' |grep -Eo 'BtnGroup-item.> [0-9a-z]+' |sed -n 1p |sed 's#BtnGroup-item.> ##g'")
if not core_cloud_ver or not core_cloud_ver_mini then
return "1"
else
core_local_ver=luci.sys.exec("cat '/usr/share/unblockneteasemusic/core_local_ver'")
if not core_local_ver or (core_local_ver ~= core_cloud_ver) then
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_core_successfully")
luci.sys.call("/bin/bash /usr/share/unblockneteasemusic/update.sh update_core_from_luci")
if not nixio.fs.access("/usr/share/unblockneteasemusic/update_core_successfully") then
return "2"
else
luci.sys.call("rm -f /usr/share/unblockneteasemusic/update_core_successfully")
return core_cloud_ver_mini
end
else
return "0"
@ -53,4 +82,4 @@ function act_update_core()
luci.http.write_json({
ret = update_core();
})
end
end

View File

@ -48,7 +48,7 @@ hijack = s:option(ListValue, "hijack_ways", translate("劫持方法"))
hijack:value("dont_hijack", translate("不开启劫持"))
hijack:value("use_ipset", translate("使用IPSet劫持"))
hijack:value("use_hosts", translate("使用Hosts劫持"))
hijack.description = translate("如果使用Hosts劫持主实例的HTTP/HTTPS端口将被锁定为80/443")
hijack.description = translate("如果使用Hosts劫持程序监听的HTTP/HTTPS端口将被锁定为80/443")
hijack.default = "dont_hijack"
hijack.rmempty = false
@ -103,7 +103,7 @@ pub_access.rmempty = false
pub_access:depends("advanced_mode", 1)
strict_mode = s:option(Flag, "strict_mode", translate("启用严格模式"))
strict_mode.description = translate("若将服务部署到公网,则强烈建议使用严格模式,此模式下仅放行网易云音乐所属域名的请求;注意:该模式下只能使用PAC方式进行代理")
strict_mode.description = translate("若将服务部署到公网,则强烈建议使用严格模式,此模式下仅放行网易云音乐所属域名的请求;注意:该模式下不能使用全局代理")
strict_mode.default = 0
strict_mode.rmempty = false
strict_mode:depends("advanced_mode", 1)
@ -112,7 +112,6 @@ netease_server_ip = s:option(Value, "netease_server_ip", translate("网易云服
netease_server_ip.description = translate("通过 ping music.163.com 即可获得IP地址仅限填写一个")
netease_server_ip.placeholder = "59.111.181.38"
netease_server_ip.datatype = "ipaddr"
netease_server_ip:depends("set_netease_server_ip", 1)
netease_server_ip:depends("advanced_mode", 1)
proxy_server_ip = s:option(Value, "proxy_server_ip", translate("代理服务器地址"))
@ -121,4 +120,16 @@ proxy_server_ip.placeholder = "http(s)://host:port"
proxy_server_ip.datatype = "string"
proxy_server_ip:depends("advanced_mode", 1)
self_issue_cert_crt = s:option(Value, "self_issue_cert_crt", translate("自签发证书公钥位置"))
self_issue_cert_crt.description = translate("[公钥] 默认使用UnblockNeteaseMusic项目提供的CA证书您可以指定为您自己的证书")
self_issue_cert_crt.placeholder = "/usr/share/unblockneteasemusic/core/server.crt"
self_issue_cert_crt.datatype = "file"
self_issue_cert_crt:depends("advanced_mode", 1)
self_issue_cert_key = s:option(Value, "self_issue_cert_key", translate("自签发证书私钥位置"))
self_issue_cert_key.description = translate("[私钥] 默认使用UnblockNeteaseMusic项目提供的CA证书您可以指定为您自己的证书")
self_issue_cert_key.placeholder = "/usr/share/unblockneteasemusic/core/server.key"
self_issue_cert_key.datatype = "file"
self_issue_cert_key:depends("advanced_mode", 1)
return mp

View File

@ -4,6 +4,12 @@ m = SimpleForm("Version")
m.reset = false
m.submit = false
up_core=m:field(DummyValue,"update_luci",translate("更新LuCI"))
up_core.rawhtml = true
up_core.template = "unblockneteasemusic/update_luci"
up_core.value = translate("未检查")
up_core.description = "更新完毕后请手动刷新该界面"
up_core=m:field(DummyValue,"update_core",translate("更新主程序"))
up_core.rawhtml = true
up_core.template = "unblockneteasemusic/update_core"

View File

@ -0,0 +1,36 @@
<%+cbi/valueheader%>
<script type="text/javascript">//<![CDATA[
function act_update_luci(btn,dataname)
{
btn.disabled = true;
btn.value = '<%:正在更新LuCI...%> ';
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "unblockneteasemusic","update_luci")%>',
status.ret,
function(x,status)
{
var s = document.getElementById(dataname+'-status');
if (s)
{
if(status.ret=="0")
s.innerHTML ="<font color='green'>"+"<%:当前已是最新版本%>"+"</font>";
else if (status.ret=="1")
s.innerHTML ="<font color='red'>"+"<%:无法检测最新版本%>"+"</font>";
else if(status.ret=="2")
s.innerHTML ="<font color='red'>"+"<%:更新失败,请稍后重试%>"+"</font>";
else
s.innerHTML ="<font color='green'>"+"<%:更新成功,当前版本号:%>"+status.ret+"</font>";
}
btn.disabled = false;
btn.value = '<%:点此更新LuCI%>';
}
);
return false;
}
//]]></script>
<input type="button" class="cbi-button cbi-input-reload" value="<%:点此更新LuCI%> " onclick="return act_update_luci(this,'<%=self.option%>')" />
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
<%+cbi/valuefooter%>

View File

@ -17,3 +17,5 @@ config unblockneteasemusic
option strict_mode '0'
option netease_server_ip '59.111.181.38'
option proxy_server_ip ''
option self_issue_cert_crt '/usr/share/unblockneteasemusic/core/server.crt'
option self_issue_cert_key '/usr/share/unblockneteasemusic/core/server.key'

View File

@ -31,46 +31,49 @@ netease_server_ip="$(uci get unblockneteasemusic.@unblockneteasemusic[0].netease
proxy_server_ip="$(uci get unblockneteasemusic.@unblockneteasemusic[0].proxy_server_ip 2>"/dev/null")"
[ -n "${proxy_server_ip}" ] && proxy_server_ip="-u ${proxy_server_ip}"
self_issue_cert_crt="$(uci get unblockneteasemusic.@unblockneteasemusic[0].self_issue_cert_crt 2>"/dev/null")"
self_issue_cert_key="$(uci get unblockneteasemusic.@unblockneteasemusic[0].self_issue_cert_key 2>"/dev/null")"
set_ipset(){
if [ "${set_type}" = "start" ]; then
mkdir -p "/tmp/dnsmasq.d"
rm -f "/tmp/dnsmasq.d/dnsmasq-unblockneteasemusic.conf"
cat <<-EOF > "/tmp/dnsmasq.d/dnsmasq-unblockneteasemusic.conf"
dhcp-option=252,http://${lan_addr}:${http_port}/proxy.pac
ipset=/.music.163.com/music
ipset=/interface.music.163.com/music
ipset=/interface3.music.163.com/music
ipset=/apm.music.163.com/music
ipset=/apm3.music.163.com/music
ipset=/.music.163.com/neteasemusic
ipset=/interface.music.163.com/neteasemusic
ipset=/interface3.music.163.com/neteasemusic
ipset=/apm.music.163.com/neteasemusic
ipset=/apm3.music.163.com/neteasemusic
EOF
/etc/init.d/dnsmasq restart > "/dev/null" 2>&1
/etc/init.d/dnsmasq reload > "/dev/null" 2>&1
if ! ipset list music > "/dev/null"; then ipset create music hash:ip; fi
if ! ipset list "neteasemusic" > "/dev/null"; then ipset create "neteasemusic" hash:ip; fi
curl -s "http://httpdns.n.netease.com/httpdns/v2/d?domain=music.163.com,interface.music.163.com,interface3.music.163.com,apm.music.163.com,apm3.music.163.com,clientlog.music.163.com,clientlog3.music.163.com" |grep -Eo '[0-9]+?\.[0-9]+?\.[0-9]+?\.[0-9]+?' |sort |uniq |awk '{print "ipset add music "$1}' |bash > "/dev/null" 2>&1
iptables -t nat -N cloud_music
iptables -t nat -A cloud_music -d 0.0.0.0/8 -j RETURN
iptables -t nat -A cloud_music -d 10.0.0.0/8 -j RETURN
iptables -t nat -A cloud_music -d 127.0.0.0/8 -j RETURN
iptables -t nat -A cloud_music -d 169.254.0.0/16 -j RETURN
iptables -t nat -A cloud_music -d 172.16.0.0/12 -j RETURN
iptables -t nat -A cloud_music -d 192.168.0.0/16 -j RETURN
iptables -t nat -A cloud_music -d 224.0.0.0/4 -j RETURN
iptables -t nat -A cloud_music -d 240.0.0.0/4 -j RETURN
iptables -t nat -A cloud_music -p tcp --dport 80 -j REDIRECT --to-ports "${http_port}"
iptables -t nat -A cloud_music -p tcp --dport 443 -j REDIRECT --to-ports "${https_port}"
iptables -t nat -I PREROUTING -p tcp -m set --match-set music dst -j cloud_music
iptables -t nat -N "netease_cloud_music"
iptables -t nat -A "netease_cloud_music" -d "0.0.0.0/8" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "10.0.0.0/8" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "127.0.0.0/8" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "169.254.0.0/16" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "172.16.0.0/12" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "192.168.0.0/16" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "224.0.0.0/4" -j RETURN
iptables -t nat -A "netease_cloud_music" -d "240.0.0.0/4" -j RETURN
iptables -t nat -A "netease_cloud_music" -p tcp --dport 80 -j REDIRECT --to-ports "${http_port}"
iptables -t nat -A "netease_cloud_music" -p tcp --dport 443 -j REDIRECT --to-ports "${https_port}"
iptables -t nat -I PREROUTING -p tcp -m set --match-set "neteasemusic" dst -j "netease_cloud_music"
mkdir -p /var/etc
mkdir -p "/var/etc/"
echo -e "/etc/init.d/unblockneteasemusic restart" > "/var/etc/unblockneteasemusic.include"
elif [ "${set_type}" = "stop" ]; then
iptables -t nat -D PREROUTING -p tcp -m set --match-set music dst -j cloud_music
iptables -t nat -F cloud_music
iptables -t nat -X cloud_music
ipset destroy music
iptables -t nat -D PREROUTING -p tcp -m set --match-set "neteasemusic" dst -j "netease_cloud_music"
iptables -t nat -F "netease_cloud_music"
iptables -t nat -X "netease_cloud_music"
ipset destroy "neteasemusic"
echo "" > "/var/etc/unblockneteasemusic.include"
rm -f "/tmp/dnsmasq.d/dnsmasq-unblockneteasemusic.conf"
/etc/init.d/dnsmasq restart > "/dev/null" 2>&1
/etc/init.d/dnsmasq reload > "/dev/null" 2>&1
fi
}
@ -87,14 +90,14 @@ address=/apm.music.163.com/${lan_addr}
address=/apm3.music.163.com/${lan_addr}
address=/music.httpdns.c.163.com/0.0.0.0
EOF
/etc/init.d/dnsmasq restart > "/dev/null" 2>&1
/etc/init.d/dnsmasq reload > "/dev/null" 2>&1
ip route add 223.252.199.10 dev lo
ip route add "223.252.199.10" dev lo
elif [ "${set_type}" = "stop" ]; then
rm -f "/tmp/dnsmasq.d/dnsmasq-unblockneteasemusic.conf"
/etc/init.d/dnsmasq restart > "/dev/null" 2>&1
/etc/init.d/dnsmasq reload > "/dev/null" 2>&1
ip route del 223.252.199.10
ip route del "223.252.199.10"
fi
}
@ -103,7 +106,7 @@ set_ports(){
iptables -I INPUT -p tcp --dport "${http_port}" -j ACCEPT
iptables -I INPUT -p tcp --dport "${https_port}" -j ACCEPT
mkdir -p /var/etc
mkdir -p "/var/etc/"
echo -e "/etc/init.d/unblockneteasemusic restart" > "/var/etc/unblockneteasemusic.include"
elif [ "${set_type}" = "stop" ]; then
iptables -D INPUT -p tcp --dport "${http_port}" -j ACCEPT
@ -119,7 +122,7 @@ start()
[ "${enable}" -ne "1" ] && exit 0
[ ! -e "/usr/share/unblockneteasemusic/core/app.js" ] && rm -f "/usr/share/unblockneteasemusic/local_ver" && bash "/usr/share/unblockneteasemusic/update_core.sh"
[ ! -e "/usr/share/unblockneteasemusic/core/app.js" ] && rm -f "/usr/share/unblockneteasemusic/local_ver" && bash "/usr/share/unblockneteasemusic/update.sh" "update_core_non_restart"
[ ! -e "/usr/share/unblockneteasemusic/core/app.js" ] && echo "Core Not Found, please download it before starting." >> "/tmp/unblockneteasemusic.log" && exit 1
if [ "${music_source}" = "qq" ];then
@ -133,6 +136,9 @@ start()
sed -i -e "1i const key = '${youtube_key}'" "/usr/share/unblockneteasemusic/core/provider/youtube.js"
fi
[ -f "${self_issue_cert_crt}" ] && { [ "${self_issue_cert_crt}" != "/usr/share/unblockneteasemusic/core/server.crt" ] && ln -sf "${self_issue_cert_crt}" "/usr/share/unblockneteasemusic/core/server.crt"; }
[ -f "${self_issue_cert_key}" ] && { [ "${self_issue_cert_key}" != "/usr/share/unblockneteasemusic/core/server.key" ] && ln -sf "${self_issue_cert_key}" "/usr/share/unblockneteasemusic/core/server.key"; }
[ "${hijack_ways}" = "use_hosts" ] && { http_port="80"; https_port="443"; }
if [ "${music_source}" = "default" ]; then
nohup node "/usr/share/unblockneteasemusic/core/app.js" -a "${addr}" -p "${http_port}":"${https_port}" -e "${endpoint_url}" ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >> "/tmp/unblockneteasemusic.log" 2>&1 &
@ -150,7 +156,7 @@ start()
[ "*$(uci get unblockneteasemusic.@unblockneteasemusic[0].pub_access 2>"/dev/null")*" = "*1*" ] && set_ports > "/dev/null" 2>&1
sed -i '/unblockneteasemusic/d' /etc/crontabs/root
[ "${auto_update}" -eq "1" ] && echo "0 ${update_time} * * * /usr/share/unblockneteasemusic/update_core.sh" >> "/etc/crontabs/root"
[ "${auto_update}" -eq "1" ] && echo "0 ${update_time} * * * /usr/share/unblockneteasemusic/update.sh update_core" >> "/etc/crontabs/root"
echo "*/5 * * * * /usr/share/unblockneteasemusic/log_check.sh" >> "/etc/crontabs/root"
/etc/init.d/cron restart > "/dev/null" 2>&1
}
@ -163,7 +169,7 @@ stop()
/etc/init.d/cron restart > "/dev/null" 2>&1
sed -i '/unblockneteasemusic/d' "/etc/sysupgrade.conf"
[ "${keep_core_when_upgrade}" -eq 1 ] && { echo "/usr/share/unblockneteasemusic/core/" >> "/etc/sysupgrade.conf"; echo "/usr/share/unblockneteasemusic/local_ver" >> "/etc/sysupgrade.conf"; }
[ "${keep_core_when_upgrade}" -eq "1" ] && { echo "/usr/share/unblockneteasemusic/core/" >> "/etc/sysupgrade.conf"; echo "/usr/share/unblockneteasemusic/local_ver" >> "/etc/sysupgrade.conf"; }
rm -f "/tmp/unblockneteasemusic.log"

View File

@ -0,0 +1,120 @@
#!/bin/bash
# Created By [CTCGFW]Project OpenWRT
# https://github.com/project-openwrt
function check_core_if_already_running(){
running_tasks="$(ps |grep "unblockneteasemusic" |grep "update" |grep "core" |grep -v "grep" |awk '{print $1}' |wc -l)"
[ "${running_tasks}" -gt "2" ] && echo -e "\nA task is already running." >>/tmp/unblockneteasemusic.log && exit 2
}
function check_luci_if_already_running(){
running_tasks="$(ps |grep "unblockneteasemusic" |grep "update" |grep "update_luci" |grep -v "grep" |awk '{print $1}' |wc -l)"
[ "${running_tasks}" -gt "2" ] && echo -e "\nA task is already running." >>/tmp/unblockneteasemusic.log && exit 2
}
function clean_log(){
echo "" > /tmp/unblockneteasemusic.log
}
function check_luci_latest_version(){
luci_latest_ver="$(curl -s 'https://github.com/project-openwrt/luci-app-unblockneteasemusic/releases/latest'| grep -Eo '[0-9\.]+\-[0-9]+')"
[ -z "${luci_latest_ver}" ] && echo -e "\nFailed to check latest LuCI version, please try again later." >>/tmp/unblockneteasemusic.log && exit 1
if [ "$(opkg info 'luci-app-unblockneteasemusic' |sed -n '2p' |tr -d 'Version: ')" != "${luci_latest_ver}" ]; then
clean_log
echo -e "Local LuCI version: $(opkg info 'luci-app-unblockneteasemusic' |sed -n '2p' |tr -d 'Version: '), cloud LuCI version: ${luci_latest_ver}." >>/tmp/unblockneteasemusic.log
update_luci
else
echo -e "\nLocal LuCI version: $(opkg info 'luci-app-unblockneteasemusic' |sed -n '2p' |tr -d 'Version: '), cloud LuCI version: ${luci_latest_ver}." >>/tmp/unblockneteasemusic.log
echo -e "You're already using the latest LuCI version." >>/tmp/unblockneteasemusic.log
exit 3
fi
}
function update_luci(){
echo -e "Updating LuCI..." >>/tmp/unblockneteasemusic.log
mkdir -p "/tmp" >/dev/null 2>&1
curl -sL "https://github.com/project-openwrt/luci-app-unblockneteasemusic/releases/download/v${luci_latest_ver}/luci-app-unblockneteasemusic_${luci_latest_ver}_all.ipk" -o "/tmp/luci-app-unblockneteasemusic_${luci_latest_ver}_all.ipk" >/dev/null 2>&1
opkg install "/tmp/luci-app-unblockneteasemusic_${luci_latest_ver}_all.ipk"
rm -f "/tmp/luci-app-unblockneteasemusic_${luci_latest_ver}_all.ipk"
rm -rf "/tmp/luci-indexcache" "/tmp/luci-modulecache"
if [ "$(opkg info 'luci-app-unblockneteasemusic' |sed -n '2p' |tr -d 'Version: ')" != "$1" ]; then
echo -e "Failed to update LuCI." >>/tmp/unblockneteasemusic.log
exit 1
else
touch "/usr/share/unblockneteasemusic/update_luci_successfully"
fi
echo -e "Succeeded in updating LuCI." >/tmp/unblockneteasemusic.log
echo -e "Current LuCI version: ${luci_latest_ver}.\n" >>/tmp/unblockneteasemusic.log
}
function check_core_latest_version(){
core_latest_ver="$(curl -s https://github.com/nondanee/UnblockNeteaseMusic/commits/master |tr -d '\n' |grep -Eo 'commit\/[0-9a-z]+' |sed -n 1p |sed 's#commit/##g')"
[ -z "${core_latest_ver}" ] && echo -e "\nFailed to check latest core version, please try again later." >>/tmp/unblockneteasemusic.log && exit 1
if [ ! -e "/usr/share/unblockneteasemusic/core_local_ver" ]; then
clean_log
echo -e "Local version: NOT FOUND, cloud version: ${core_latest_ver}." >>/tmp/unblockneteasemusic.log
update_core
else
if [ "$(cat /usr/share/unblockneteasemusic/core_local_ver)" != "${core_latest_ver}" ]; then
clean_log
echo -e "Local core version: $(cat /usr/share/unblockneteasemusic/core_local_ver 2>/dev/null), cloud core version: ${core_latest_ver}." >>/tmp/unblockneteasemusic.log
update_core
else
echo -e "\nLocal core version: $(cat /usr/share/unblockneteasemusic/core_local_ver 2>/dev/null), cloud core version: ${core_latest_ver}." >>/tmp/unblockneteasemusic.log
echo -e "You're already using the latest core version." >>/tmp/unblockneteasemusic.log
exit 3
fi
fi
}
function update_core(){
echo -e "Updating core..." >>/tmp/unblockneteasemusic.log
mkdir -p "/usr/share/unblockneteasemusic/core" >/dev/null 2>&1
rm -rf /usr/share/unblockneteasemusic/core/* >/dev/null 2>&1
curl -sL "https://github.com/nondanee/UnblockNeteaseMusic/archive/master.tar.gz" -o "/usr/share/unblockneteasemusic/core/core.tar.gz" >/dev/null 2>&1
tar -zxf "/usr/share/unblockneteasemusic/core/core.tar.gz" -C "/usr/share/unblockneteasemusic/core/" >/dev/null 2>&1
mv /usr/share/unblockneteasemusic/core/UnblockNeteaseMusic-master/* "/usr/share/unblockneteasemusic/core/"
rm -rf "/usr/share/unblockneteasemusic/core/core.tar.gz" "/usr/share/unblockneteasemusic/core/UnblockNeteaseMusic-master" >/dev/null 2>&1
if [ ! -e "/usr/share/unblockneteasemusic/core/app.js" ]; then
echo -e "Failed to download core." >>/tmp/unblockneteasemusic.log
exit 1
else
[ "${update_core_from_luci}" == "y" ] && touch "/usr/share/unblockneteasemusic/update_core_successfully"
echo -e "${core_latest_ver}" > /usr/share/unblockneteasemusic/core_local_ver
[ "${non_restart}" != "y" ] && /etc/init.d/unblockneteasemusic restart
fi
echo -e "Succeeded in updating core." >/tmp/unblockneteasemusic.log
echo -e "Current core version: ${core_latest_ver}.\n" >>/tmp/unblockneteasemusic.log
}
case "$1" in
"update_luci")
check_luci_if_already_running
check_luci_latest_version
;;
"update_core")
check_core_if_already_running
check_core_latest_version
;;
"update_core_non_restart")
non_restart="y"
check_core_if_already_running
check_core_latest_version
;;
"update_core_from_luci")
update_core_from_luci="y"
check_core_if_already_running
check_core_latest_version
;;
*)
echo -e "Usage: ./update.sh {update_luci|update_core}"
;;
esac

View File

@ -1,64 +0,0 @@
#!/bin/bash
# Created By [CTCGFW]Project OpenWRT
# https://github.com/project-openwrt
function check_if_already_running(){
running_tasks="$(ps |grep "unblockneteasemusic" |grep "update_core" |grep -v "grep" |awk '{print $1}' |wc -l)"
[ "${running_tasks}" -gt "2" ] && echo -e "\nA task is already running." >>/tmp/unblockneteasemusic.log && exit 2
}
function clean_log(){
echo "" > /tmp/unblockneteasemusic.log
}
function check_latest_version(){
latest_ver="$(curl -s https://github.com/nondanee/UnblockNeteaseMusic/commits/master |tr -d '\n' |grep -Eo 'commit\/[0-9a-z]+' |sed -n 1p |sed 's#commit/##g')"
[ -z "${latest_ver}" ] && echo -e "\nFailed to check latest version, please try again later." >>/tmp/unblockneteasemusic.log && exit 1
if [ ! -e "/usr/share/unblockneteasemusic/local_ver" ]; then
clean_log
echo -e "Local version: NOT FOUND, cloud version: ${latest_ver}." >>/tmp/unblockneteasemusic.log
update_core
else
if [ "$(cat /usr/share/unblockneteasemusic/local_ver)" != "${latest_ver}" ]; then
clean_log
echo -e "Local version: $(cat /usr/share/unblockneteasemusic/local_ver 2>/dev/null), cloud version: ${latest_ver}." >>/tmp/unblockneteasemusic.log
update_core
else
echo -e "\nLocal version: $(cat /usr/share/unblockneteasemusic/local_ver 2>/dev/null), cloud version: ${latest_ver}." >>/tmp/unblockneteasemusic.log
echo -e "You're already using the latest version." >>/tmp/unblockneteasemusic.log
exit 3
fi
fi
}
function update_core(){
echo -e "Updating core..." >>/tmp/unblockneteasemusic.log
mkdir -p "/usr/share/unblockneteasemusic/core" >/dev/null 2>&1
rm -rf /usr/share/unblockneteasemusic/core/* >/dev/null 2>&1
curl -L "https://github.com/nondanee/UnblockNeteaseMusic/archive/master.tar.gz" -o "/usr/share/unblockneteasemusic/core/core.tar.gz" >/dev/null 2>&1
tar -zxf "/usr/share/unblockneteasemusic/core/core.tar.gz" -C "/usr/share/unblockneteasemusic/core/" >/dev/null 2>&1
mv /usr/share/unblockneteasemusic/core/UnblockNeteaseMusic-master/* "/usr/share/unblockneteasemusic/core/"
rm -rf "/usr/share/unblockneteasemusic/core/core.tar.gz" "/usr/share/unblockneteasemusic/core/UnblockNeteaseMusic-master" >/dev/null 2>&1
if [ ! -e "/usr/share/unblockneteasemusic/core/app.js" ]; then
echo -e "Failed to download core." >>/tmp/unblockneteasemusic.log
exit 1
else
[ "${luci_update}" == "y" ] && touch "/usr/share/unblockneteasemusic/update_successfully"
echo -e "${latest_ver}" > /usr/share/unblockneteasemusic/local_ver
/etc/init.d/unblockneteasemusic restart
fi
echo -e "Succeeded in updating core." >/tmp/unblockneteasemusic.log
echo -e "Current version: ${latest_ver}.\n" >>/tmp/unblockneteasemusic.log
}
function main(){
check_if_already_running
check_latest_version
}
[ "$1" == "luci_update" ] && luci_update="y"
main

View File

@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Argon Theme
LUCI_DEPENDS:=
PKG_VERSION:=2.0
PKG_RELEASE:=20200131
PKG_VERSION:=2.1
PKG_RELEASE:=20200206
include $(TOPDIR)/feeds/luci/luci.mk

View File

@ -25,7 +25,7 @@
*/
@import url("custom.css?v=1");
/*
* Icon Css and Fonts
* Icon Css and Fonts
*/
@font-face {
font-family: 'argon';
@ -356,9 +356,10 @@ button,
select,
input,
.cbi-dropdown {
line-height: 1.5rem;
height: 2.5rem;
padding: 0.625rem 0.75rem;
margin: 0.25rem 0;
margin: 0.25rem 0.1rem;
color: #8898aa;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
@ -607,11 +608,23 @@ header .fill .status * {
margin-bottom: 1em;
padding: 1rem;
border: 0;
border-radius: 0 !important;
border-radius: 0.375rem !important;
background-color: #fff;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 2px 0 rgba(0, 0, 0, 0.12);
text-shadow: 1px 1px rgba(0, 0, 0, 0.1);
}
.alert.error,
.alert-message.error {
background-color: #ffd600;
}
.alert h4,
.alert-message h4 {
padding: 0rem 1.5rem 0.75rem 0rem;
}
.alert .btn,
.alert-message .btn {
height: auto;
}
.alert-message > h4 {
font-size: 110%;
font-weight: bold;
@ -1532,10 +1545,13 @@ body:not(.Interfaces) .cbi-rowstyle-2:first-child {
.cbi-dropdown > ul.preview {
display: none;
}
.cbi-dropdown > ul.preview li {
.cbi-button-apply > ul.preview {
display: none;
}
.cbi-button-apply > ul.preview li {
color: #fff;
}
.cbi-dropdown > ul:first-child li {
.cbi-button-apply > ul:first-child li {
color: #fff;
}
.cbi-dropdown > .open {
@ -2264,18 +2280,24 @@ input[name="nslookup"] {
.node-main-login .main .main-right #maincontent .container .alert-message.error {
position: absolute;
color: #fff;
width: calc(100% - 4rem);
width: calc(100% - 2rem);
background-color: #f0ad4e;
border-color: #eea236;
box-sizing: border-box;
margin-top: 8rem;
border-radius: 5px;
padding: 1rem 2rem;
margin-top: -7rem;
border-radius: 5px !important;
padding: 1rem 2rem 0.5rem 2rem;
text-align: center;
}
.node-main-login .main .main-right #maincontent .container .alert-message.error p {
color: #fff;
}
.node-main-login .main .main-right #maincontent .container .alert-message.error h4 {
font-size: 1rem;
}
.node-main-login .main .main-right #maincontent .container .alert-message.error .btn {
height: auto;
}
.node-main-login .main .main-right #maincontent .container .cbi-map h2 {
width: 120px;
height: 120px;

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@
@import url("custom.css?v=1");
/*
* Icon Css and Fonts
* Icon Css and Fonts
*/
@font-face {
font-family: 'argon';
@ -417,9 +417,10 @@ button,
select,
input,
.cbi-dropdown {
line-height: 1.5rem;
height: 2.5rem;
padding: .625rem .75rem;
margin: 0.25rem 0;
margin: 0.25rem 0.1rem;
color: #8898aa;
border: 1px solid #dee2e6;
@ -714,10 +715,22 @@ header {
margin-bottom: 1em;
padding: 1rem;
border: 0;
border-radius: 0 !important;
border-radius: 0.375rem !important;
background-color: #fff;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .16), 0 0 2px 0 rgba(0, 0, 0, .12);
text-shadow: 1px 1px rgba(0, 0, 0, .1);
&.error{
background-color: #ffd600;
}
h4{
padding: 0rem 1.5rem 0.75rem 0rem;
}
.btn{
height: auto;
}
}
.alert-message>h4 {
@ -1809,13 +1822,17 @@ body:not(.Interfaces) .cbi-rowstyle-2:first-child {
.cbi-dropdown>ul.preview {
display: none;
}
.cbi-button-apply>ul.preview {
display: none;
li {
color: #fff;
}
}
.cbi-dropdown>ul:first-child {
.cbi-button-apply>ul:first-child {
li {
color: #fff;
}
@ -2679,17 +2696,23 @@ input[name="nslookup"] {
&.error {
position: absolute;
color: #fff;
width: calc(100% - 4rem);
width: calc(100% - 2rem);
background-color: #f0ad4e;
border-color: #eea236;
box-sizing: border-box;
margin-top: 8rem;
border-radius: 5px;
padding: 1rem 2rem;
margin-top: -7rem;
border-radius: 5px !important;
padding: 1rem 2rem 0.5rem 2rem;
text-align: center;
p{
color: #fff;
}
h4{
font-size: 1rem;
}
.btn{
height: auto;
}
}
}

View File

@ -1,21 +1,24 @@
/**
* Material is a clean HTML5 theme for LuCI. It is based on luci-theme-bootstrap and MUI
* Argon is a clean HTML5 theme for LuCI. It is based on luci-theme-material and Argon Template
*
* luci-theme-material
* Copyright 2015 Lutty Yang <lutty@wcan.in>
* luci-theme-argon
* Copyright 2019 Jerrykuku <jerrykuku@qq.com>
*
* Have a bug? Please create an issue here on GitHub!
* https://github.com/LuttyYang/luci-theme-material/issues
* Have a bug? Please create an issue here on GitHub!
* https://github.com/jerrykuku/luci-theme-argon/issues
*
* luci-theme-bootstrap:
* Copyright 2008 Steven Barth <steven@midlink.org>
* Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
* Copyright 2012 David Menting <david@nut-bolt.nl>
* luci-theme-material:
* Copyright 2015 Lutty Yang <lutty@wcan.in>
* https://github.com/LuttyYang/luci-theme-material/
*
* MUI:
* https://github.com/muicss/mui
* Agron Theme
* https://demos.creative-tim.com/argon-dashboard/index.html
*
* Licensed to the public under the Apache License 2.0
* Login background
* https://unsplash.com/
* Font generate by Icomoon<icomoon.io>
*
* Licensed to the public under the Apache License 2.0
*/
document.addEventListener('luci-loaded', function(ev) {

View File

@ -16,27 +16,11 @@
Licensed to the public under the Apache License 2.0
-%>
<%
local ver = require "luci.version"
local disp = require "luci.dispatcher"
local request = disp.context.path
local category = request[1]
local tree = disp.node()
local categories = disp.node_childs(tree)
%>
<% local ver = require "luci.version" %>
</div>
<footer class="mobile-hide">
<a href="https://github.com/openwrt/luci">Powered by <%= ver.luciname %> (<%= ver.luciversion %>)</a> / <%= ver.distversion %>
<% if #categories > 1 then %>
<ul class="breadcrumb pull-right" id="modemenu">
<% for i, r in ipairs(categories) do %>
<li<% if request[1] == r then %> class="active"<%end%>>
<a href="<%=controller%>/<%=r%>/"><%=striptags(translate(tree.nodes[r].title))%></a>
<span class="divider">|</span>
</li>
<% end %>
</ul>
<% end %>
<ul class="breadcrumb pull-right" id="modemenu" style="display:none"></ul>
</footer>
</div>
</div>
@ -44,8 +28,8 @@
// thanks for Jo-Philipp Wich <jow@openwrt.org>
var luciLocation = <%= luci.http.write_json(luci.dispatcher.context.path) %>;
</script>
<script src="<%=media%>/js/jquery.min.js?v=git-20.029.45734-adbbd5c"></script>
<script src="<%=media%>/js/script.js?v=git-20.029.45734-adbbd5c"></script>
<script src="<%=media%>/js/jquery.min.js"></script>
<script src="<%=media%>/js/script.js"></script>
</body>
</html>

View File

@ -17,146 +17,24 @@
-%>
<%
local sys = require "luci.sys"
local sys = require "luci.sys"
local util = require "luci.util"
local http = require "luci.http"
local disp = require "luci.dispatcher"
local fs = require "nixio.fs"
local nutil = require "nixio.util"
local boardinfo = util.ubus("system", "board")
local request = disp.context.path
local request2 = disp.context.request
local category = request[1]
local cattree = category and disp.node(category)
local leaf = request2[#request2]
local tree = disp.node()
local node = disp.context.dispatched
local categories = disp.node_childs(tree)
local c = tree
local i, r
-- tag all nodes leading to this page
for i, r in ipairs(request) do
if c.nodes and c.nodes[r] then
c = c.nodes[r]
c._menu_selected = true
end
end
local fs = require "nixio.fs"
local nutil = require "nixio.util"
-- send as HTML5
http.prepare_content("text/html")
local function nodeurl(prefix, name, query)
local u = url(prefix, name)
if query then
u = u .. http.build_querystring(query)
end
return pcdata(u)
end
local function render_tabmenu(prefix, node, level)
if not level then
level = 1
end
local childs = disp.node_childs(node)
if #childs > 0 then
if level > 2 then
write('<ul class="tabs">')
end
local selected_node
local selected_name
local i, v
for i, v in ipairs(childs) do
local nnode = node.nodes[v]
if nnode._menu_selected then
selected_node = nnode
selected_name = v
end
if level > 2 then
write('<li class="tabmenu-item-%s %s"><a href="%s">%s</a></li>' %{
v, (nnode._menu_selected or (node.leaf and v == leaf)) and 'active' or '',
nodeurl(prefix, v, nnode.query),
striptags(translate(nnode.title))
})
end
end
if level > 2 then
write('</ul>')
end
if selected_node then
render_tabmenu(prefix .. "/" .. selected_name, selected_node, level + 1)
end
end
end
local function render_submenu(prefix, node)
local childs = disp.node_childs(node)
if #childs > 0 then
write('<ul class="slide-menu">')
for i, r in ipairs(childs) do
local nnode = node.nodes[r]
local title = striptags(translate(nnode.title))
write('<li><a data-title="%s" href="%s">%s</a></li>' %{
title,
nodeurl(prefix, r, nnode.query),
title
})
end
write('</ul>')
end
end
local function render_topmenu()
local childs = disp.node_childs(cattree)
if #childs > 0 then
write('<ul class="nav">')
for i, r in ipairs(childs) do
local nnode = cattree.nodes[r]
local grandchildren = disp.node_childs(nnode)
if #grandchildren > 0 then
local title = striptags(translate(nnode.title))
local en_title = pcdata(striptags(string.gsub(nnode.title," ","_")))
write('<li class="slide"><a class="menu" data-title="%s" href="#">%s</a>' %{
en_title,
title
})
render_submenu(category .. "/" .. r, nnode)
write('</li>')
else
local title = striptags(translate(nnode.title))
local en_title = pcdata(striptags(nnode.title))
write('<li class="lg"><a class="logout" data-title="%s" href="%s">%s</a></li>' %{
en_title,
nodeurl(category, r, nnode.query),
title
})
end
end
write('</ul>')
end
end
math.randomseed(os.time())
math.randomseed(os.time())
function glob(...)
local iter, code, msg = fs.glob(...)
if iter then
@ -167,16 +45,21 @@
end
local bgcount = 0
for f in ipairs(glob("/www/luci-static/material/img/*")) do
for f in ipairs(glob("/www/luci-static/argon/img/*")) do
bgcount = bgcount + 1
end
-%>
<!DOCTYPE html>
<html lang="<%=luci.i18n.context.lang%>">
<head>
<meta charset="utf-8">
<title><%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI</title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"/>
<title>
<%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %>
- LuCI</title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#09c">
@ -184,82 +67,219 @@
<meta name="msapplication-TileColor" content="#09c">
<meta name="application-name" content="<%=striptags( (boardinfo.hostname or "?") ) %> - LuCI">
<meta name="apple-mobile-web-app-title" content="<%=striptags( (boardinfo.hostname or "?") ) %> - LuCI">
<meta name="msapplication-TileImage" content="<%=media%>/logo.png"/>
<link rel="icon" href="<%=media%>/logo.png" sizes="144x144">
<link rel="apple-touch-icon-precomposed" href="<%=media%>/logo.png" sizes="144x144">
<link rel="stylesheet" href="<%=media%>/cascade.css?v=<%=math.random(1,100000)%>">
<meta name="msapplication-TileImage" content="<%=media%>/logo.png" />
<link rel="icon" href="<%=media%>/logo.png" sizes="144x144">
<link rel="apple-touch-icon-precomposed" href="<%=media%>/logo.png" sizes="144x144">
<link rel="stylesheet" href="<%=media%>/cascade.css">
<link rel="shortcut icon" href="<%=media%>/favicon.ico">
<% if node and node.css then %>
<link rel="stylesheet" href="<%=resource%>/<%=node.css%>">
<link rel="stylesheet" href="<%=resource%>/<%=node.css%>">
<% end -%>
<% if css then %>
<style title="text/css"><%= css %></style>
<style title="text/css">
<%=css %>
</style>
<% end -%>
<script src="<%=url('admin/translations', luci.i18n.context.lang)%>?v=git-20.029.45734-adbbd5c"></script>
<script src="<%=resource%>/cbi.js?v=git-20.029.45734-adbbd5c"></script>
<script src="<%=resource%>/xhr.js?v=git-20.029.45734-adbbd5c"></script>
</head>
<body class="lang_<%=luci.i18n.context.lang%> <% if node then %><%= striptags( node.title ) %><% end %> <% if luci.dispatcher.context.authsession then %>logged-in<% end %>" data-page="<%= table.concat(disp.context.requestpath, "-") %>">
<script src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
<script src="<%=resource%>/cbi.js"></script>
<script src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
(function () {
function get_children(node) {
var children = [];
<div class="main">
<div style="" class="loading">
<div class="sk-folding-cube">
<div class="sk-cube1 sk-cube"></div>
<div class="sk-cube2 sk-cube"></div>
<div class="sk-cube4 sk-cube"></div>
<div class="sk-cube3 sk-cube"></div>
</div>
</div>
<div class="main-left">
<div class="sidenav-header d-flex align-items-center">
<a class="brand" href="#"><%=boardinfo.hostname or "?"%> ™</a>
<div class="ml-auto">
<!-- Sidenav toggler -->
<div class="sidenav-toggler d-none d-xl-block active" data-action="sidenav-unpin" data-target="#sidenav-main">
<div class="sidenav-toggler-inner">
<i class="sidenav-toggler-line"></i>
<i class="sidenav-toggler-line"></i>
<i class="sidenav-toggler-line"></i>
</div>
</div>
</div>
</div>
<% render_topmenu() %>
</div>
<div class="main-right">
<header class="bg-primary">
<div class="fill">
<div class="container">
<a class="showSide"></a>
<a class="brand" href="#"><%=boardinfo.hostname or "?"%> ™</a>
<div class="pull-right">
<span id="xhr_poll_status" style="display:none" onclick="XHR.running() ? XHR.halt() : XHR.run()">
<span class="label success" id="xhr_poll_status_on"><span class="mobile-hide"><%:Auto Refresh%></span> <%:on%></span>
<span class="label" id="xhr_poll_status_off" style="display:none"><span class="mobile-hide"><%:Auto Refresh%></span> <%:off%></span>
</span>
</div>
</div>
</div>
</header>
<div class="darkMask"></div>
<div class="login-bg" style="background-image:url(<%=media%>/img/bg<%=math.random(1,bgcount)%>.jpg)"></div>
<div id="maincontent">
<div class="container">
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%>
<div class="alert-message warning">
for (var k in node.children) {
if (!node.children.hasOwnProperty(k))
continue;
if (!node.children[k].satisfied)
continue;
if (!node.children[k].hasOwnProperty('title'))
continue;
children.push(Object.assign(node.children[k], { name: k }));
}
return children.sort(function (a, b) {
return ((a.order || 1000) - (b.order || 1000));
});
}
function render_mainmenu(tree, url, level) {
var l = (level || 0) + 1,
ul = E('ul', { 'class': level ? 'slide-menu' : 'nav' }),
children = get_children(tree);
if (children.length == 0 || l > 2)
return E([]);
for (var i = 0; i < children.length; i++) {
var submenu = render_mainmenu(children[i], url + '/' + children[i].name, l),
hasChildren = submenu.children.length;
isLogout = (children[i].name == 'logout');
ul.appendChild(E('li', { 'class': hasChildren ? 'slide' : isLogout ? 'lg' : null }, [
E('a', {
'href': hasChildren ? '#' : L.url(url, children[i].name),
'class': hasChildren ? 'menu' : isLogout?"logout":null,
'data-title': children[i].title,
}, [_(children[i].title)]),
submenu
]));
}
if (l == 1) {
var container = document.querySelector('#mainmenu');
container.appendChild(ul);
container.style.display = '';
}
return ul;
}
function render_modemenu(tree) {
var ul = document.querySelector('#modemenu'),
children = get_children(tree);
for (var i = 0; i < children.length; i++) {
var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[0] : i == 0);
ul.appendChild(E('li', {}, [
E('a', {
'href': L.url(children[i].name),
'class': isActive ? 'active' : null
}, [_(children[i].title)])
]));
if (isActive)
render_mainmenu(children[i], children[i].name);
}
if (ul.children.length > 1)
ul.style.display = '';
}
function render_tabmenu(tree, url, level) {
var container = document.querySelector('#tabmenu'),
l = (level || 0) + 1,
ul = E('ul', { 'class': 'tabs' }),
children = get_children(tree),
activeNode = null;
if (children.length == 0)
return E([]);
for (var i = 0; i < children.length; i++) {
var isActive = (L.env.dispatchpath[l + 2] == children[i].name),
activeClass = isActive ? ' active' : '',
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
ul.appendChild(E('li', { 'class': className }, [
E('a', { 'href': L.url(url, children[i].name) }, [_(children[i].title)])
]));
if (isActive)
activeNode = children[i];
}
container.appendChild(ul);
container.style.display = '';
if (activeNode)
container.appendChild(render_tabmenu(activeNode, url + '/' + activeNode.name, l));
return ul;
}
document.addEventListener('luci-loaded', function (ev) {
var tree = <%= luci.http.write_json(luci.dispatcher.menu_json() or { }) %>,
node = tree,
url = '';
render_modemenu(tree);
if (L.env.dispatchpath.length >= 3) {
for (var i = 0; i < 3 && node; i++) {
node = node.children[L.env.dispatchpath[i]];
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
}
if (node)
render_tabmenu(node, url);
}
});
}) ();
//]]></script>
</head>
<body
class="lang_<%=luci.i18n.context.lang%> <% if node then %><%= striptags( node.title ) %><% end %> <% if luci.dispatcher.context.authsession then %>logged-in<% end %>"
data-page="<%= table.concat(disp.context.requestpath, "-") %>">
<div class="main">
<div style="" class="loading">
<div class="sk-folding-cube">
<div class="sk-cube1 sk-cube"></div>
<div class="sk-cube2 sk-cube"></div>
<div class="sk-cube4 sk-cube"></div>
<div class="sk-cube3 sk-cube"></div>
</div>
</div>
<div class="main-left" id="mainmenu" style="display:none">
<div class="sidenav-header d-flex align-items-center">
<a class="brand" href="#"><%=boardinfo.hostname or "?"%> ™</a>
<div class="ml-auto">
<!-- Sidenav toggler -->
<div class="sidenav-toggler d-none d-xl-block active" data-action="sidenav-unpin"
data-target="#sidenav-main">
<div class="sidenav-toggler-inner">
<i class="sidenav-toggler-line"></i>
<i class="sidenav-toggler-line"></i>
<i class="sidenav-toggler-line"></i>
</div>
</div>
</div>
</div>
</div>
<div class="main-right">
<header class="bg-primary">
<div class="fill">
<div class="container">
<a class="showSide"></a>
<a class="brand" href="#"><%=boardinfo.hostname or "?"%> ™</a>
<div class="pull-right">
<span id="xhr_poll_status" style="display:none"
onclick="XHR.running() ? XHR.halt() : XHR.run()">
<span class="label success" id="xhr_poll_status_on"><span
class="mobile-hide"><%:Auto Refresh%></span> <%:on%></span>
<span class="label" id="xhr_poll_status_off" style="display:none"><span
class="mobile-hide"><%:Auto Refresh%></span> <%:off%></span>
</span>
</div>
</div>
</div>
</header>
<div class="darkMask"></div>
<div class="login-bg" style="background-image:url(<%=media%>/img/bg<%=math.random(1,bgcount)%>.jpg)"></div>
<div id="maincontent">
<div class="container">
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") then -%>
<div class="alert-message error">
<h4><%:No password set!%></h4>
<p><%:There is no password set on this router. Please configure a root password to protect the web interface and enable SSH.%></p>
<p><%:There is no password set on this router. Please configure a root password to protect the web interface and enable SSH.%>
</p>
<% if disp.lookup("admin/system/admin") then %>
<div class="right"><a class="btn" href="<%=url("admin/system/admin")%>"><%:Go to password configuration...%></a></div>
<div class="right"><a class="btn"
href="<%=url("admin/system/admin")%>"><%:Go to password configuration...%></a></div>
<% end %>
</div>
<%- end -%>
<%- end -%>
<noscript>
<div class="alert-message warning">
<h4><%:JavaScript required!%></h4>
<p><%:You must enable JavaScript in your browser or LuCI will not work properly.%></p>
</div>
</noscript>
<noscript>
<div class="alert-message error">
<h4><%:JavaScript required!%></h4>
<p><%:You must enable JavaScript in your browser or LuCI will not work properly.%></p>
</div>
</noscript>
<% if category then render_tabmenu(category, cattree) end %>
<div id="tabmenu" style="display:none"></div>

View File

@ -52,6 +52,7 @@ endef
define Package/speederv2-tunnel/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/speederv2_cross $(1)/usr/bin/speederv2
( cd $(1)/usr/bin; $(LN) speederv2 udpspeeder; )
endef
$(eval $(call BuildPackage,speederv2-tunnel))