diff --git a/daed/Makefile b/daed/Makefile index ca69e610..86f45863 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed -PKG_VERSION:=1.26.0 -PKG_RELEASE:=3 +PKG_VERSION:=dae-lang-core-v0.2.0 +PKG_RELEASE:=4 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/daeuniverse/daed.git -PKG_SOURCE_VERSION:=4982c709ef937fd19eced01b2ed07aad23bb56e8 +PKG_SOURCE_VERSION:=06857f52c33cc3264aea9eb90431afbe8909073c PKG_MIRROR_HASH:=skip PKG_LICENSE:=AGPL-3.0-only MIT diff --git a/luci-app-easytier/Makefile b/luci-app-easytier/Makefile index f80881fd..900f72df 100644 --- a/luci-app-easytier/Makefile +++ b/luci-app-easytier/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk -include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.0) -PKG_RELEASE:=2 +PKG_RELEASE:=3 LUCI_TITLE:=LuCI support for EasyTier LUCI_DEPENDS:=+kmod-tun +easytier +luci-compat diff --git a/luci-app-easytier/luasrc/controller/easytier.lua b/luci-app-easytier/luasrc/controller/easytier.lua index 8d12aa55..28c8f00c 100644 --- a/luci-app-easytier/luasrc/controller/easytier.lua +++ b/luci-app-easytier/luasrc/controller/easytier.lua @@ -74,6 +74,9 @@ function index() entry({"admin", "vpn", "easytier", "restart_service"}, call("restart_service")).leaf = true entry({"admin", "vpn", "easytier", "toggle_core"}, call("toggle_core")).leaf = true entry({"admin", "vpn", "easytier", "toggle_web"}, call("toggle_web")).leaf = true + entry({"admin", "vpn", "easytier", "download_easytier"}, call("download_easytier")).leaf = true + entry({"admin", "vpn", "easytier", "download_progress"}, call("download_progress")).leaf = true + entry({"admin", "vpn", "easytier", "cancel_download"}, call("cancel_download")).leaf = true end function act_status() @@ -749,3 +752,389 @@ function toggle_web() luci.http.prepare_content("application/json") luci.http.write_json({success = true}) end +-- 检测CPU架构 +local function detect_arch() + local cputype = safe_exec("uname -ms | tr ' ' '_' | tr '[A-Z]' '[a-z]'") + local cpucore = "" + + if cputype:match("linux.*armv.*") then + cpucore = "arm" + end + if cputype:match("linux.*armv7.*") and safe_exec("cat /proc/cpuinfo | grep vfp") ~= "" then + cpucore = "armv7" + end + if cputype:match("linux.*aarch64.*") or cputype:match("linux.*armv8.*") then + cpucore = "aarch64" + end + if cputype:match("linux.*86.*") then + cpucore = "i386" + end + if cputype:match("linux.*86_64.*") then + cpucore = "x86_64" + end + if cputype:match("linux.*mips.*") then + local mipstype = safe_exec("echo -n I | hexdump -o 2>/dev/null | awk '{ print substr($2,6,1); exit}'") + if mipstype == "0" then + cpucore = "mips" + else + cpucore = "mipsel" + end + end + + return cpucore +end + +-- 检查依赖 +local function check_dependencies() + local arch = detect_arch() + if arch == "" then + return false, i18n.translate("Unable to detect CPU architecture") + end + if arch == "i386" then + return false, i18n.translate("No x86-32bit program available") + end + if safe_exec("which unzip") == "" then + return false, i18n.translate("System lacks unzip, cannot download and extract") + end + return true, arch +end + +-- 获取GitHub镜像列表 +local function get_github_proxies() + local uci = require "luci.model.uci".cursor() + local proxies = {} + + -- 从UCI配置读取代理列表 + local proxy_list = uci:get("easytier", "@easytier[0]", "github_proxys") + + if proxy_list then + if type(proxy_list) == "table" then + -- 多个代理 + for _, proxy in ipairs(proxy_list) do + if proxy and proxy ~= "" then + table.insert(proxies, proxy) + end + end + else + -- 单个代理 + if proxy_list ~= "" then + table.insert(proxies, proxy_list) + end + end + end + + -- 如果没有配置代理,使用默认值 + if #proxies == 0 then + proxies = { + "https://ghproxy.net/", + "https://gh-proxy.com/", + "https://cdn.gh-proxy.com/", + "https://ghfast.top/" + } + end + + -- 添加不使用代理的选项(空字符串表示直连) + table.insert(proxies, "") + + return proxies +end + +-- 下载文件 +local function download_file(url, output_path, progress_callback) + local download_tools = {"curl", "wget"} + + for _, tool in ipairs(download_tools) do + if safe_exec("which " .. tool) ~= "" then + local cmd = "" + if tool == "curl" then + cmd = string.format("curl -L -k --connect-timeout 30 --max-time 300 -o '%s' '%s'", output_path, url) + elseif tool == "wget" then + cmd = string.format("wget --no-check-certificate --timeout=30 --tries=3 -O '%s' '%s'", output_path, url) + end + + if progress_callback then + progress_callback(50, i18n.translate("Downloading with") .. " " .. tool .. "...") + end + + local result = os.execute(cmd) + if result == 0 and nixio.fs.access(output_path) then + -- 检查文件大小,确保下载完整 + local stat = nixio.fs.stat(output_path) + if stat and stat.size > 3 * 1024 * 1024 then -- 至少3MB + return true + end + end + end + end + + return false +end + +function download_easytier() + luci.http.prepare_content("application/json") + + local json = require "luci.jsonc" + local progress_file = "/tmp/easytier_download_progress" + + -- 检查是否已有下载任务 + local existing_progress = safe_read_file(progress_file) + if existing_progress then + local progress_data = json.parse(existing_progress) + if progress_data and progress_data.progress > 0 and progress_data.progress < 100 and not progress_data.error then + luci.http.write_json({ + success = true, + progress = progress_data.progress, + message = i18n.translate("Download task already exists"), + url = progress_data.url or "" + }) + return + end + end + + local req_data = json.parse(luci.http.content()) + if not req_data or not req_data.version then + luci.http.write_json({success = false, message = i18n.translate("Missing version parameter")}) + return + end + + local version = req_data.version + + -- 1. 检查依赖和架构 + local ok, arch_or_error = check_dependencies() + if not ok then + luci.http.write_json({success = false, message = arch_or_error}) + return + end + + local arch = arch_or_error + local proxies = get_github_proxies() + local download_dir = "/tmp/easytier_download" + local zip_file = download_dir .. "/easytier-linux-" .. arch .. "-" .. version .. ".zip" + + -- 创建下载目录 + os.execute("mkdir -p " .. download_dir) + + -- 创建取消标志文件 + local cancel_file = "/tmp/easytier_download_cancel" + os.execute("rm -f " .. cancel_file) + + -- 创建进度文件标记任务开始 + local f = io.open(progress_file, "w") + if f then + f:write(json.stringify({ + progress = 1, + message = "Downloading...", + url = "", + error = false + })) + f:close() + end + + -- 检查是否被取消 + local function check_cancelled() + return nixio.fs.access(cancel_file) + end + + -- 2. 循环尝试不同的镜像地址下载、解压、验证 + local download_success = false + local download_url = "" + local core_file, cli_file, web_file + + for _, proxy in ipairs(proxies) do + -- 检查是否被取消 + if check_cancelled() then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Download cancelled")}) + return + end + + download_url = proxy .. "https://github.com/EasyTier/EasyTier/releases/download/" .. version .. "/easytier-linux-" .. arch .. "-" .. version .. ".zip" + + -- 删除之前的失败文件 + os.execute("rm -f " .. zip_file) + os.execute("rm -rf " .. download_dir .. "/extracted") + + -- 下载 + if download_file(download_url, zip_file) then + local stat = nixio.fs.stat(zip_file) + if stat and stat.size > 10240 then + -- 检查是否被取消 + if check_cancelled() then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Download cancelled")}) + return + end + + -- 解压 + local extract_dir = download_dir .. "/extracted" + os.execute("mkdir -p " .. extract_dir) + local unzip_result = os.execute("cd " .. extract_dir .. " && unzip -o " .. zip_file .. " >/dev/null 2>&1") + + if unzip_result == 0 then + -- 检查是否被取消 + if check_cancelled() then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Download cancelled")}) + return + end + + -- 查找解压后的目录(使用通配符) + local find_cmd = "find " .. extract_dir .. " -maxdepth 1 -type d -name 'easytier-linux-*' 2>/dev/null | head -1" + local handle = io.popen(find_cmd) + local subdir = handle:read("*a"):match("^%s*(.-)%s*$") + handle:close() + + if subdir and subdir ~= "" then + core_file = subdir .. "/easytier-core" + cli_file = subdir .. "/easytier-cli" + web_file = subdir .. "/easytier-web-embed" + + local files_ok = nixio.fs.access(core_file) and nixio.fs.access(cli_file) + if arch ~= "mips" and arch ~= "mipsel" then + files_ok = files_ok and nixio.fs.access(web_file) + end + + if files_ok then + -- 检查是否被取消 + if check_cancelled() then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Download cancelled")}) + return + end + + -- 先赋予执行权限,再测试程序 + local test_files = {core_file, cli_file} + if arch ~= "mips" and arch ~= "mipsel" then + table.insert(test_files, web_file) + end + + local test_ok = true + for _, file in ipairs(test_files) do + os.execute("chmod +x " .. file) + if not test_binary(file) then + test_ok = false + break + end + end + + if test_ok then + download_success = true + break + end + end + end + end + end + end + + -- 删除失败的文件,继续下一个地址 + os.execute("rm -f " .. zip_file) + end + + if not download_success then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("All download attempts failed")}) + return + end + + -- 检查是否被取消(替换前) + if check_cancelled() then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Download cancelled")}) + return + end + + -- 3. 从UCI获取路径并安装 + local uci = require "luci.model.uci".cursor() + local easytierbin = uci:get_first("easytier", "easytier", "easytierbin") or "/usr/bin/easytier-core" + local easytierwebbin = uci:get_first("easytier", "easytier", "easytierwebbin") or "/usr/bin/easytier-web" + + local core_dir = easytierbin:match("^(.*/)[^/]+$") or "/usr/bin/" + + local programs = { + {src = core_file, dest = easytierbin}, + {src = cli_file, dest = core_dir .. "easytier-cli"} + } + + if arch ~= "mips" and arch ~= "mipsel" then + table.insert(programs, {src = web_file, dest = easytierwebbin}) + end + + -- 安装并验证 + for _, prog in ipairs(programs) do + local result = os.execute("cp " .. prog.src .. " " .. prog.dest .. " 2>/dev/null") + if result ~= 0 then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Failed to install program") .. ": " .. prog.dest}) + return + end + + os.execute("chmod +x " .. prog.dest) + + -- 再次验证安装后的程序 + if not test_binary(prog.dest) then + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. progress_file) + luci.http.write_json({success = false, message = i18n.translate("Program is incomplete or architecture mismatch")}) + return + end + end + + -- 7. 清理临时文件和版本缓存 + os.execute("rm -rf " .. download_dir) + os.execute("rm -f " .. cancel_file) + os.execute("rm -f " .. progress_file) + nixio.fs.remove("/tmp/easytier.tag") + nixio.fs.remove("/tmp/easytierweb.tag") + + luci.http.write_json({ + success = true, + progress = 100, + message = i18n.translate("Download and installation completed") + }) +end + +function download_progress() + luci.http.prepare_content("application/json") + + local progress_file = "/tmp/easytier_download_progress" + local content = safe_read_file(progress_file) + + if content then + local json = require "luci.jsonc" + local progress_data = json.parse(content) + if progress_data then + luci.http.write_json({ + success = true, + progress = progress_data.progress or 0, + message = progress_data.message or "", + url = progress_data.url or "", + error = progress_data.error or false + }) + return + end + end + + luci.http.write_json({ + success = true, + progress = 0, + message = i18n.translate("Preparing..."), + url = "", + error = false + }) +end +function cancel_download() + luci.http.prepare_content("application/json") + + -- 创建取消标志文件 + os.execute("touch /tmp/easytier_download_cancel") + + luci.http.write_json({success = true}) +end diff --git a/luci-app-easytier/luasrc/model/cbi/easytier_status.lua b/luci-app-easytier/luasrc/model/cbi/easytier_status.lua index 31f22579..abf20e48 100644 --- a/luci-app-easytier/luasrc/model/cbi/easytier_status.lua +++ b/luci-app-easytier/luasrc/model/cbi/easytier_status.lua @@ -5,6 +5,9 @@ m.description = translate("A simple, secure, decentralized VPN solution for intr .. "Project URL: github.com/EasyTier/EasyTier  " .. "Official Documentation  " .. "QQ Group  ") + .. "\"\" " + .. "\"\" " + .. "\"\"" m.pageaction = false -- 状态卡片 diff --git a/luci-app-easytier/luasrc/view/easytier/easytier_cli.htm b/luci-app-easytier/luasrc/view/easytier/easytier_cli.htm index 2436db1a..0dc2dca5 100644 --- a/luci-app-easytier/luasrc/view/easytier/easytier_cli.htm +++ b/luci-app-easytier/luasrc/view/easytier/easytier_cli.htm @@ -35,7 +35,7 @@ local uci = require 'luci.model.uci'.cursor() border-radius: 16px; box-shadow: 0 8px 32px var(--card-shadow); border: 1px solid var(--border-color); - margin: 20px 0; + margin: 20px 0 20px 0; overflow: hidden; backdrop-filter: blur(10px); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); @@ -403,17 +403,72 @@ local uci = require 'luci.model.uci'.cursor() /* Contributors Section */ .et-contributors-section { - margin-top: 24px; + margin: 20px 0 20px 0; padding: 20px; background: var(--card-bg); - border-top: 1px solid var(--border-color); + border-radius: 16px; + box-shadow: 0 8px 32px var(--card-shadow); + border: 1px solid var(--border-color); + backdrop-filter: blur(10px); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; +} + +.et-contributors-section:hover { + transform: translateY(-2px); + box-shadow: 0 12px 40px var(--card-shadow); +} + +.et-contributors-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; } .et-contributors-title { font-size: 16px; font-weight: 600; color: var(--text-primary); - margin-bottom: 16px; +} + +.et-contributors-pagination { + display: flex; + align-items: center; + gap: 12px; + font-size: 13px; + color: var(--text-secondary); +} + +.et-contributors-dots { + display: flex; + gap: 6px; +} + +.et-contributors-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--border-color); + cursor: pointer; + transition: all 0.3s ease; +} + +.et-contributors-dot.active { + background: var(--tab-active); + width: 24px; + border-radius: 4px; +} + +.et-contributors-dot:hover { + background: var(--tab-active); + opacity: 0.7; +} + +.et-contributors-wrapper { + position: relative; + overflow: hidden; + min-height: 60px; } .et-contributors-container { @@ -422,6 +477,19 @@ local uci = require 'luci.model.uci'.cursor() gap: 8px; justify-content: flex-start; align-items: center; + opacity: 0; + transform: translateX(20px); + transition: opacity 0.8s ease, transform 0.8s ease; +} + +.et-contributors-container.active { + opacity: 1; + transform: translateX(0); +} + +.et-contributors-container.exit { + opacity: 0; + transform: translateX(-20px); } .et-contributors-container a { @@ -442,12 +510,32 @@ local uci = require 'luci.model.uci'.cursor() } .et-contributors-container img:hover { - border-color: var(--info); + border-color: var(--tab-active); } @media (max-width: 768px) { .et-contributors-section { padding: 16px; + margin: 16px 0 16px 0; + } + + .et-contributors-section:hover { + transform: none; + } + + .et-contributors-header { + flex-direction: column; + gap: 12px; + align-items: flex-start; + } + + .et-contributors-pagination { + width: 100%; + justify-content: space-between; + } + + .et-contributors-container { + justify-content: center; } .et-contributors-container img { @@ -557,10 +645,18 @@ local uci = require 'luci.model.uci'.cursor() <%:Collecting data...%> - - - + + + @@ -700,6 +796,9 @@ var translations = { // VPN Portal特殊处理 "ERROR: Wireguard VPN Portal Not Started": "<%:ERROR: Wireguard VPN Portal Not Started%>", + // 错误信息翻译 + "no running instances found": "<%:no running instances found%>", + // 统计指标翻译 "compression_bytes_rx_before": "<%:Compression RX Before%>", "compression_bytes_rx_after": "<%:Compression RX After%>", @@ -808,6 +907,11 @@ function parseTable(content, tabName) { return '
' + escapeHtml(tr('ERROR: Wireguard VPN Portal Not Started')) + '
'; } + // 未找到运行实例错误处理 + if (content.indexOf('no running instances found') !== -1) { + return '
' + escapeHtml(tr('no running instances found')) + '
'; + } + // Peer Center错误处理 if (content.indexOf('Error: Invalid service name: "PeerCenterRpc"') !== -1) { return '
<%:Peer Center service not available. This feature requires multiple nodes in the network.%>
'; @@ -1104,56 +1208,215 @@ document.addEventListener('DOMContentLoaded', function() { refreshConnInfo(); }); -// 加载贡献者头像 (ES5) -function loadContributors() { - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'https://api.github.com/repos/EasyTier/EasyTier/contributors', true); - xhr.timeout = 5000; // 5秒超时 +// 贡献者轮播管理 (ES5) +var contributorsCarousel = { + allContributors: [], + currentPage: 0, + pageSize: 30, + totalPages: 0, + autoPlayTimer: null, + autoPlayInterval: 3000, + container: null, + section: null, + pageInfo: null, + dotsContainer: null, - xhr.onload = function() { - if (xhr.status === 200) { - try { - var data = JSON.parse(xhr.responseText); - var container = document.getElementById('contributors'); - var section = document.getElementById('contributors-section'); - - if (!container || !section || !data.length) return; - - container.innerHTML = ''; - - for (var i = 0; i < data.length; i++) { - var user = data[i]; - var a = document.createElement('a'); - a.href = user.html_url; - a.target = '_blank'; - a.rel = 'noopener noreferrer'; - - var img = document.createElement('img'); - img.src = user.avatar_url; - img.alt = user.login; - img.title = user.login + ' (' + user.contributions + ' contributions)'; - - a.appendChild(img); - container.appendChild(a); + init: function() { + this.container = document.getElementById('contributors'); + this.section = document.getElementById('contributors-section'); + this.pageInfo = document.getElementById('contributors-page-info'); + this.dotsContainer = document.getElementById('contributors-dots'); + this.setupHoverPause(); + this.loadData(); + }, + + setupHoverPause: function() { + var self = this; + if (!this.section) return; + + this.section.addEventListener('mouseenter', function() { + self.stopAutoPlay(); + }); + + this.section.addEventListener('mouseleave', function() { + self.startAutoPlay(); + }); + + // 移动端滑动支持 + this.setupTouchSwipe(); + }, + + setupTouchSwipe: function() { + var self = this; + if (!this.container) return; + + var startX = 0; + var startY = 0; + var threshold = 50; // 滑动阈值 + + this.container.addEventListener('touchstart', function(e) { + self.stopAutoPlay(); + startX = e.touches[0].clientX; + startY = e.touches[0].clientY; + }); + + this.container.addEventListener('touchend', function(e) { + var endX = e.changedTouches[0].clientX; + var endY = e.changedTouches[0].clientY; + var deltaX = endX - startX; + var deltaY = endY - startY; + + // 确保是水平滑动 + if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > threshold) { + if (deltaX > 0) { + // 右滑 - 上一页 + var prevPage = (self.currentPage - 1 + self.totalPages) % self.totalPages; + self.showPage(prevPage); + } else { + // 左滑 - 下一页 + self.nextPage(); } - - // 成功加载后显示卡片 - section.style.display = 'block'; - } catch (e) { - // 失败时保持隐藏 } + + self.startAutoPlay(); + }); + }, + + loadData: function() { + var self = this; + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'https://api.github.com/repos/EasyTier/EasyTier/contributors?per_page=100', true); + xhr.timeout = 10000; + + xhr.onload = function() { + if (xhr.status === 200) { + try { + var data = JSON.parse(xhr.responseText); + if (!data || data.length === 0) return; + + self.allContributors = data; + self.totalPages = Math.ceil(data.length / self.pageSize); + self.renderDots(); + self.showPage(0); + self.section.style.display = 'block'; + self.startAutoPlay(); + } catch (e) { + console.error('Failed to parse contributors:', e); + } + } + }; + + xhr.onerror = function() { + console.error('Failed to load contributors'); + }; + + xhr.ontimeout = function() { + console.error('Contributors request timeout'); + }; + + xhr.send(); + }, + + renderDots: function() { + if (!this.dotsContainer) return; + this.dotsContainer.innerHTML = ''; + + for (var i = 0; i < this.totalPages; i++) { + var dot = document.createElement('div'); + dot.className = 'et-contributors-dot'; + dot.setAttribute('data-page', i); + + var self = this; + (function(page) { + dot.onclick = function() { + self.stopAutoPlay(); + self.showPage(page); + self.startAutoPlay(); + }; + })(i); + + this.dotsContainer.appendChild(dot); } - }; + }, - xhr.onerror = function() { - // 失败时保持隐藏 - }; + showPage: function(pageIndex) { + var self = this; + if (pageIndex < 0 || pageIndex >= this.totalPages) return; + + // 退出动画 + this.container.classList.remove('active'); + this.container.classList.add('exit'); + + setTimeout(function() { + self.currentPage = pageIndex; + var start = pageIndex * self.pageSize; + var end = Math.min(start + self.pageSize, self.allContributors.length); + var pageData = self.allContributors.slice(start, end); + + // 更新内容 + self.container.innerHTML = ''; + for (var i = 0; i < pageData.length; i++) { + var user = pageData[i]; + var a = document.createElement('a'); + a.href = user.html_url; + a.target = '_blank'; + a.rel = 'noopener noreferrer'; + + var img = document.createElement('img'); + img.src = user.avatar_url; + img.alt = user.login; + img.title = user.login + ' (' + user.contributions + ' contributions)'; + + a.appendChild(img); + self.container.appendChild(a); + } + + // 更新分页信息 + if (self.pageInfo) { + self.pageInfo.textContent = (pageIndex + 1) + ' / ' + self.totalPages; + } + + // 更新指示器 + var dots = self.dotsContainer.querySelectorAll('.et-contributors-dot'); + for (var j = 0; j < dots.length; j++) { + dots[j].classList.remove('active'); + } + if (dots[pageIndex]) { + dots[pageIndex].classList.add('active'); + } + + // 进入动画 + self.container.classList.remove('exit'); + setTimeout(function() { + self.container.classList.add('active'); + }, 50); + }, 600); + }, - xhr.ontimeout = function() { - // 超时时保持隐藏 - }; + nextPage: function() { + var next = (this.currentPage + 1) % this.totalPages; + this.showPage(next); + }, - xhr.send(); + startAutoPlay: function() { + var self = this; + this.stopAutoPlay(); + this.autoPlayTimer = setInterval(function() { + self.nextPage(); + }, this.autoPlayInterval); + }, + + stopAutoPlay: function() { + if (this.autoPlayTimer) { + clearInterval(this.autoPlayTimer); + this.autoPlayTimer = null; + } + } +}; + +// 加载贡献者 +function loadContributors() { + contributorsCarousel.init(); } // 自动刷新 diff --git a/luci-app-easytier/luasrc/view/easytier/easytier_log.htm b/luci-app-easytier/luasrc/view/easytier/easytier_log.htm index 0751b67b..5e6761ad 100644 --- a/luci-app-easytier/luasrc/view/easytier/easytier_log.htm +++ b/luci-app-easytier/luasrc/view/easytier/easytier_log.htm @@ -293,6 +293,9 @@ local translate = i18n.translate
+ + Ask DeepWiki + +
+
+ + +
+ +
<%=translate("Used when unable to fetch the latest version during online download")%>
@@ -408,6 +424,39 @@ local translate = i18n.translate
+ + +
<%=translate("Supported Files")%>
diff --git a/luci-app-easytier/po/zh_Hans/easytier.po b/luci-app-easytier/po/zh_Hans/easytier.po index df8bae63..0d2301f0 100644 --- a/luci-app-easytier/po/zh_Hans/easytier.po +++ b/luci-app-easytier/po/zh_Hans/easytier.po @@ -1851,3 +1851,131 @@ msgstr "目标实例ID" msgid "Logs" msgstr "日志" +msgid "Online Download" +msgstr "在线下载" + +msgid "Online Download EasyTier" +msgstr "在线下载EasyTier程序" + +msgid "Download Version" +msgstr "下载版本" + +msgid "Download specified version from GitHub and install to specified path" +msgstr "从GitHub下载指定版本的程序安装到指定路径" + +msgid "Downloading..." +msgstr "正在下载..." + +msgid "Preparing download..." +msgstr "准备下载..." + +msgid "Download completed successfully" +msgstr "下载完成" + +msgid "Download failed" +msgstr "下载失败" + +msgid "Download and installation completed" +msgstr "下载安装完成" + +msgid "Download completed. Restart service now?" +msgstr "下载完成,是否立即重启服务?" + +msgid "Please enter download version" +msgstr "请输入下载版本" + +msgid "Network error" +msgstr "网络错误" + +msgid "Pre-release" +msgstr "预发布版" + +msgid "Stable" +msgstr "稳定版" + +msgid "Custom Input" +msgstr "自定义输入" + +msgid "Loading versions..." +msgstr "正在加载版本..." + +msgid "Program not found" +msgstr "程序不存在" + +msgid "no running instances found" +msgstr "未找到正在运行的实例" + +msgid "Unable to detect CPU architecture" +msgstr "无法检测CPU架构" + +msgid "No x86-32bit program available" +msgstr "没有当前x86-32位的程序" + +msgid "System lacks unzip, cannot download and extract" +msgstr "系统缺少 unzip 下载后无法解压" + +msgid "Missing version parameter" +msgstr "缺少版本号参数" + +msgid "Starting download..." +msgstr "开始下载..." + +msgid "Trying download URL..." +msgstr "尝试下载地址..." + +msgid "Downloading with" +msgstr "使用" + +msgid "Download completed, extracting..." +msgstr "下载完成,正在解压..." + +msgid "Extraction failed" +msgstr "解压失败" + +msgid "Installing programs..." +msgstr "正在安装程序..." + +msgid "Installation completed" +msgstr "安装完成" + +msgid "Preparing..." +msgstr "准备中..." + +msgid "Downloaded package is incomplete, missing required files" +msgstr "下载的压缩包不完整,缺少EasyTier相关程序文件" + +msgid "Program installation failed, verification failed" +msgstr "程序安装失败,验证未通过" + +msgid "Download task already exists" +msgstr "已有下载任务正在进行" + +msgid "Verifying programs..." +msgstr "正在验证程序..." + +msgid "Program is incomplete or architecture mismatch" +msgstr "程序不完整或架构不匹配" + +msgid "Failed to install program" +msgstr "程序安装失败" + +msgid "Cancel Download" +msgstr "取消下载" + +msgid "Download cancelled" +msgstr "已取消下载" + +msgid "All download attempts failed" +msgstr "所有下载地址均下载失败,请确认github加速镜像地址有效或使用手动上传" + +msgid "Download task already exists, continuing..." +msgstr "下载任务已存在,继续中..." + +msgid "Download Successful" +msgstr "下载成功" + +msgid "Retry" +msgstr "重试" + +msgid "Close" +msgstr "关闭" diff --git a/luci-app-easytier/root/etc/init.d/easytier b/luci-app-easytier/root/etc/init.d/easytier index a9df6c35..da293ff1 100755 --- a/luci-app-easytier/root/etc/init.d/easytier +++ b/luci-app-easytier/root/etc/init.d/easytier @@ -103,7 +103,7 @@ check_bin() { # 如果获取失败,从 UCI 配置或使用默认版本 if [ -z "$tag" ]; then tag=$(uci -q get easytier.@easytier[0].fallback_version) - [ -z "$tag" ] && tag="v2.5.0" + [ -z "$tag" ] && tag="v2.6.0" fi echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 开始在线下载${tag}版本,${proxy}https://github.com/EasyTier/EasyTier/releases/download/${tag}/easytier-linux-${cpucore}-${tag}.zip下载较慢耐心等候" >>/tmp/easytier.log echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 开始在线下载${tag}版本,${proxy}https://github.com/EasyTier/EasyTier/releases/download/${tag}/easytier-linux-${cpucore}-${tag}.zip下载较慢耐心等候" >>/tmp/easytierweb.log diff --git a/luci-app-easytier/root/usr/share/easytier/download.sh b/luci-app-easytier/root/usr/share/easytier/download.sh index 083253d8..7c97e28e 100755 --- a/luci-app-easytier/root/usr/share/easytier/download.sh +++ b/luci-app-easytier/root/usr/share/easytier/download.sh @@ -42,7 +42,7 @@ get_latest_version() { # 如果获取失败,从 UCI 配置或使用默认版本 if [ -z "$tag" ]; then tag=$(uci -q get easytier.@easytier[0].fallback_version) - [ -z "$tag" ] && tag="v2.5.0" + [ -z "$tag" ] && tag="v2.6.0" fi echo "$tag" diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index f9adccb3..4526db95 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.4.15 -PKG_RELEASE:=76 +PKG_RELEASE:=77 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 226098e9..28a3684f 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.4.10 -PKG_RELEASE:=32 +PKG_RELEASE:=33 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \