update 2025-01-04 09:25:09

This commit is contained in:
kenzok8 2025-01-04 09:25:09 +08:00
parent 4f2074917c
commit 9c7c0c8eed
28 changed files with 731 additions and 274 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_MAINTAINER:=Thaolga <https://github.com/Thaolga/luci-app-nekobox>
PKG_NAME:=luci-app-nekobox
PKG_VERSION:=1.6.3
PKG_VERSION:=1.6.4
PKG_RELEASE:=cn
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)

View File

@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="186" height="20" role="img" aria-label="Latest Version: v1.6.3">
<title>Latest Version: v1.6.3</title>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="186" height="20" role="img" aria-label="Latest Version: v1.6.4">
<title>Latest Version: v1.6.4</title>
<linearGradient id="s" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
@ -15,7 +15,7 @@
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
<text aria-hidden="true" x="495" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="700" style="letter-spacing: -5;">Latest Version</text>
<text x="495" y="140" transform="scale(.1)" fill="#fff" textLength="700" style="letter-spacing: -5;">Latest Version</text>
<text aria-hidden="true" x="1405" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="600" style="letter-spacing: -3;">v1.6.3</text>
<text x="1405" y="140" transform="scale(.1)" fill="#fff" textLength="600" style="letter-spacing: -3;">v1.6.3</text>
<text aria-hidden="true" x="1405" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="600" style="letter-spacing: -3;">v1.6.4</text>
<text x="1405" y="140" transform="scale(.1)" fill="#fff" textLength="600" style="letter-spacing: -3;">v1.6.4</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="186" height="20" role="img" aria-label="Current Version: v1.6.3">
<title>Current Version: v1.6.3</title>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="186" height="20" role="img" aria-label="Current Version: v1.6.4">
<title>Current Version: v1.6.4</title>
<linearGradient id="s" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
<stop offset="1" stop-opacity=".1"/>
@ -15,7 +15,7 @@
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110">
<text aria-hidden="true" x="495" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="700" style="letter-spacing: -5;">Current Version</text>
<text x="495" y="140" transform="scale(.1)" fill="#fff" textLength="700" style="letter-spacing: -5;">Current Version</text>
<text aria-hidden="true" x="1405" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="600" style="letter-spacing: -3;">v1.6.3</text>
<text x="1405" y="140" transform="scale(.1)" fill="#fff" textLength="600" style="letter-spacing: -3;">v1.6.3</text>
<text aria-hidden="true" x="1405" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="600" style="letter-spacing: -3;">v1.6.4</text>
<text x="1405" y="140" transform="scale(.1)" fill="#fff" textLength="600" style="letter-spacing: -3;">v1.6.4</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -53,6 +53,11 @@ h1, h2, h3, h4, h5, h6 {
margin-bottom: 1rem;
}
.table thead th {
color: #ffffff !important;
background-color: #D2B48C !important;
}
.table {
width: 100%;
margin-bottom: 1rem;

View File

@ -19,11 +19,19 @@
--bs-info: #1890ff;
--bs-warning: #faad14;
--bs-danger: #f5222d;
--bs-heading-1: #ff9a3d;
--bs-heading-2: #f1b88b;
--bs-heading-3: #ffcc00;
--bs-heading-4: #ff4500;
--bs-heading-5: #00ff85;
--bs-heading-6: #00ffff;
--bs-heading-font-family: 'Noto Serif SC', serif;
--bs-heading-font-weight: 700;
--bs-heading-letter-spacing: 0.05em;
--bs-heading-text-transform: uppercase;
--bs-nav-pills-link-color: #004080;
--bs-nav-pills-link-hover-color: #28a745;
}
body {
@ -38,10 +46,83 @@ h1, h2, h3, h4, h5, h6 {
font-weight: var(--bs-heading-font-weight);
letter-spacing: var(--bs-heading-letter-spacing);
text-transform: var(--bs-heading-text-transform);
color: #FFFF00;
color: var(--bs-primary);
margin-bottom: 1rem;
}
h1 {
color: var(--bs-heading-1) !important;
}
h2 {
color: var(--bs-heading-2) !important;
}
h3 {
color: var(--bs-heading-3) !important;
}
h4 {
color: var(--bs-heading-4) !important;
}
h5 {
color: var(--bs-heading-5) !important;
}
h6 {
color: var(--bs-heading-6) !important;
}
.nav-pills .nav-link {
color: var(--bs-nav-pills-link-color);
font-weight: 600;
letter-spacing: 1px;
}
.nav-pills .nav-link.active {
color: var(--bs-nav-pills-link-active-color);
background-color: #ffffff;
}
.nav-pills .nav-link:hover {
color: var(--bs-nav-pills-link-hover-color);
background-color: #e6f2ff;
}
#pluginLogTab {
color: #004080;
font-weight: bold;
font-size: 18px !important;
}
#mihomoLogTab {
color: #800000;
font-weight: bold;
font-size: 18px !important;
}
#singboxLogTab {
color: #006400;
font-weight: bold;
font-size: 18px !important;
}
.nav-pills .nav-link.active {
background-color: #0056b3;
color: #ffffff;
}
.nav-pills .nav-link:hover {
background-color: #007bff;
color: #ffffff;
}
.table thead th {
color: #ffffff !important;
background-color: #ff69b4 !important;
}
.table-3d {
background-color: #C8102E;
color: #FFFF00;
@ -112,7 +193,6 @@ h1, h2, h3, h4, h5, h6 {
text-align: center;
}
.btn {
transition: transform var(--bs-transition-speed), box-shadow var(--bs-transition-speed);
}
@ -132,15 +212,6 @@ h1, h2, h3, h4, h5, h6 {
margin-bottom: 2rem;
}
p, span, div, a, label, input, select, textarea {
color: #FF00FF;
}
a {
color: #FFFF00;
text-decoration: underline;
}
a:hover {
color: #ffffff;
}

View File

@ -18,13 +18,17 @@
--bs-heading-font-weight: 700;
--bs-heading-letter-spacing: 0.05em;
--bs-heading-text-transform: uppercase;
--bs-card-bg: #87ceeb;
--bs-card-border-color: transparent;
--bs-card-border-color: transparent;
--bs-shadow-light: 0 4px 8px rgba(0, 86, 179, 0.1);
--bs-shadow-medium: 0 8px 16px rgba(0, 86, 179, 0.15);
--bs-transition-speed: 0.3s;
--bs-nav-pills-link-color: #004080;
--bs-nav-pills-link-hover-color: #28a745;
--bs-table-heading-bg: #004080;
--bs-table-heading-color: #ffffff;
--bs-table-odd-bg: #004080;
--bs-table-odd-color: #ffffff;
}
body {
@ -50,6 +54,44 @@ h4 { color: #e74c3c !important; }
h5 { color: #4B0082; }
h6 { color: #8B4513; }
.nav-pills .nav-link {
color: var(--bs-nav-pills-link-color);
font-weight: 600;
letter-spacing: 1px;
}
.nav-pills .nav-link.active {
color: var(--bs-nav-pills-link-active-color);
background-color: #ffffff;
}
.nav-pills .nav-link:hover {
color: var(--bs-nav-pills-link-hover-color);
background-color: #e6f2ff;
}
#pluginLogTab {
color: #004080;
}
#mihomoLogTab {
color: #800000;
}
#singboxLogTab {
color: #006400;
}
.nav-pills .nav-link.active {
background-color: #0056b3;
color: #ffffff;
}
.nav-pills .nav-link:hover {
background-color: #007bff;
color: #ffffff;
}
.row .btn-lg {
color: #0056b3 !important;
}
@ -100,18 +142,18 @@ h6 { color: #8B4513; }
}
.table thead th {
background: linear-gradient(45deg, #004080, #0056b3);
color: #ffffff;
border: none;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 600;
padding: 15px;
position: relative;
background-color: var(--bs-table-heading-bg);
color: var(--bs-table-heading-color);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
padding: 15px;
border: none;
}
.table tbody tr:nth-child(even) {
background-color: #87ceeb;
.table thead th {
color: #ffffff !important;
background-color: #004080 !important;
}
.table td {

View File

@ -6,7 +6,7 @@
--bs-body-font-weight: 400;
--bs-body-color: #e0e0e0;
--bs-body-bg: #121212;
--bs-primary: #ff007c;
--bs-primary: #00a2e8;
--bs-secondary: #00ffff;
--bs-success: #00ff85;
--bs-info: #7d5fff;
@ -14,11 +14,11 @@
--bs-danger: #ff4500;
--bs-heading-font-family: 'Montserrat', sans-serif;
--bs-heading-1: #ff007c;
--bs-heading-2: #7d5fff;
--bs-heading-1: #00a2e8;;
--bs-heading-2: #00a2e8;;
--bs-heading-3: #ffcc00;
--bs-heading-4: #ff4500;
--bs-heading-5: #00ff85;
--bs-heading-5: #7d5fff;
--bs-heading-6: #00ffff;
--bs-heading-font-weight: 700;
@ -158,6 +158,11 @@ h1, h2, h3, h4, h5, h6 {
padding: 15px;
}
.table thead th {
color: #ffffff !important;
background-color: #004080 !important;
}
.form-control {
background-color: #333;
border: 2px solid var(--bs-secondary);
@ -280,6 +285,50 @@ h1, h2, h3, h4, h5, h6 {
transform: scaleX(1);
}
.modal-content {
background-color: #f9f9f9;
color: #333;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.modal-header {
background-color: #007bff;
color: #fff;
border-bottom: 1px solid #ccc;
}
.modal-title {
font-size: 1.25rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.modal-body {
background-color: #f9f9f9;
color: #333;
}
button.btn-close {
color: #000 !important;
}
button.btn-close:hover {
color: #333 !important;
}
.form-group button {
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.2);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.form-group button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
}
@media (max-width: 991.98px) {
.container-sm.container-bg.callout {
flex-direction: column;

View File

@ -9,12 +9,12 @@
--bs-body-bg: #ffff;
--bs-heading-font-family: 'Montserrat', sans-serif;
--bs-heading-1: #CD853F;
--bs-heading-2: #A0522D;
--bs-heading-3: #B8860B;
--bs-heading-4: #e74c3c;
--bs-heading-5: #D2691E;
--bs-heading-6: #e74c3c;
--bs-heading-1: #00a2e8;
--bs-heading-2: #00a2e8;
--bs-heading-3: #ffcc00;
--bs-heading-4: #ff4500;
--bs-heading-5: #7d5fff;
--bs-heading-6: #00ffff;
--bs-heading-font-family: 'Montserrat', sans-serif;
--bs-heading-font-weight: 700;
@ -29,6 +29,8 @@
--bs-btn-hover-color: #fff;
--bs-btn-active-color: #fff;
--bs-btn-disabled-color: #fff;
--bs-nav-pills-link-color: #004080;
--bs-nav-pills-link-hover-color: #28a745;
}
body {
@ -47,6 +49,50 @@ h1, h2, h3, h4, h5, h6 {
margin-bottom: 1rem;
}
.nav-pills .nav-link {
color: var(--bs-nav-pills-link-color);
font-weight: 600;
letter-spacing: 1px;
}
.nav-pills .nav-link.active {
color: var(--bs-nav-pills-link-active-color);
background-color: #ffffff;
}
.nav-pills .nav-link:hover {
color: var(--bs-nav-pills-link-hover-color);
background-color: #e6f2ff;
}
#pluginLogTab {
color: #004080;
font-weight: bold;
font-size: 18px !important;
}
#mihomoLogTab {
color: #800000;
font-weight: bold;
font-size: 18px !important;
}
#singboxLogTab {
color: #006400;
font-weight: bold;
font-size: 18px !important;
}
.nav-pills .nav-link.active {
background-color: #0056b3;
color: #ffffff;
}
.nav-pills .nav-link:hover {
background-color: #007bff;
color: #ffffff;
}
.table {
width: 100%;
margin-bottom: 1rem;
@ -98,6 +144,11 @@ h1, h2, h3, h4, h5, h6 {
transform: translate(-3px, -3px);
}
.table thead th {
color: #ffffff !important;
background-color: #1E90FF !important;
}
.table-3d {
background-color: #fff;
color: #333;
@ -415,13 +466,11 @@ h1:hover, h2:hover, h3:hover, h4:hover, h5:hover, h6:hover {
.container-sm.callout .btn:hover {
color: #000 !important;
background-color: #FFDEAD !important;
transition: all 0.3s ease;
}
.container-sm.callout .custom-btn-color:hover {
color: #000 !important;
background-color: #FFDEAD !important;
transition: all 0.3s ease;
}

View File

@ -58,6 +58,11 @@ h1, h2, h3, h4, h5, h6 {
margin-bottom: 1rem;
}
.table thead th {
color: #ffffff !important;
background-color: #ff69b4 !important;
}
.table {
width: 100%;
margin-bottom: 1rem;

View File

@ -141,6 +141,11 @@ h1:hover, h2:hover, h3:hover, h4:hover, h5:hover, h6:hover {
color: #121212;
}
.table thead th {
color: #ffffff !important;
background-color: #004080 !important;
}
.form-control {
background-color: #1a003d;
border: 2px solid var(--bs-border-color);
@ -201,6 +206,50 @@ h1:hover, h2:hover, h3:hover, h4:hover, h5:hover, h6:hover {
transform: scaleX(1);
}
.modal-content {
background-color: #f9f9f9;
color: #333;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.modal-header {
background-color: #007bff;
color: #fff;
border-bottom: 1px solid #ccc;
}
.modal-title {
font-size: 1.25rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.modal-body {
background-color: #f9f9f9;
color: #333;
}
button.btn-close {
color: #000 !important;
}
button.btn-close:hover {
color: #333 !important;
}
.form-group button {
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.2);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.form-group button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
}
.text-neon {
font-family: 'Orbitron', sans-serif;
font-weight: 700;

View File

@ -92,7 +92,7 @@ $dash_link = $neko_cfg['ctrl_host'] . ':' . $neko_cfg['ctrl_port'] . '/ui/dashbo
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="panelModalLabel">选择面板</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div>

View File

@ -11,9 +11,8 @@ $allowed_files = [
];
$file = $_GET['file'] ?? '';
$max_lines = 100;
$max_chars = 1000000;
$max_line_length = 300;
$max_line_length = 160;
function remove_ansi_colors($string) {
$pattern = '/\033\[[0-9;]*m/';
@ -43,21 +42,20 @@ if (array_key_exists($file, $allowed_files)) {
$lines = array_filter($lines, function($line) use ($max_line_length) {
return strlen($line) <= $max_line_length;
});
$content = implode(PHP_EOL, $lines);
$lines_with_numbers = array_map(function($line, $index) {
return sprintf("%d %s", $index + 1, $line);
}, $lines, array_keys($lines));
$content = implode(PHP_EOL, $lines_with_numbers);
if (strlen($content) > $max_chars) {
file_put_contents($file_path, '');
echo "Log file has been cleared, exceeding the character limit.";
return;
}
if (count($lines) > $max_lines) {
$lines = array_slice($lines, -$max_lines);
file_put_contents($file_path, implode(PHP_EOL, $lines));
}
echo htmlspecialchars(implode(PHP_EOL, $lines));
echo htmlspecialchars($content);
} else {
http_response_code(404);
echo "File not found.";

View File

@ -224,6 +224,7 @@ function writeToLog($message) {
function createCronScript() {
$log_file = '/var/log/singbox_log.txt';
$tmp_log_file = '/etc/neko/tmp/neko_log.txt';
$additional_log_file = '/etc/neko/tmp/log.txt';
$max_size = 1048576;
$cron_schedule = "0 */4 * * * /bin/bash /etc/neko/core/set_cron.sh";
$cronScriptContent = <<<EOL
@ -252,6 +253,14 @@ else
echo "Temp log file (\$TMP_LOG_FILE) is within the size limit, no action needed." >> /var/log/cron_debug.log 2>&1
fi
if [ -f "\$ADDITIONAL_LOG_FILE" ] && [ \$(stat -c %s "\$ADDITIONAL_LOG_FILE") -gt \$MAX_SIZE ]; then
echo "Additional log file (\$ADDITIONAL_LOG_FILE) size exceeds \$MAX_SIZE bytes. Clearing logs..." >> /var/log/cron_debug.log 2>&1
> "\$ADDITIONAL_LOG_FILE"
echo "Additional log file (\$ADDITIONAL_LOG_FILE) cleared." >> /var/log/cron_debug.log 2>&1
else
echo "Additional log file (\$ADDITIONAL_LOG_FILE) is within the size limit, no action needed." >> /var/log/cron_debug.log 2>&1
fi
echo "Log rotation completed." >> /var/log/cron_debug.log 2>&1
EOL;
@ -738,8 +747,8 @@ $(document).ready(function() {
}
.section-container {
padding-left: 48px;
padding-right: 48px;
padding-left: 42px;
padding-right: 42px;
}
.btn-group .btn {

View File

@ -144,6 +144,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['editFile'], $_GET['file
exit;
}
}
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['downloadFile'], $_GET['fileType'])) {
$fileType = $_GET['fileType'];
$fileName = basename($_GET['downloadFile']);
$filePath = ($fileType === 'proxy') ? $uploadDir . $fileName : $configDir . $fileName;
if (file_exists($filePath)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
exit;
} else {
echo '文件不存在。';
}
}
?>
<?php
@ -437,6 +457,24 @@ html {
padding-right: 2.4em;
}
#dropZone {
height: 150px;
cursor: pointer;
transition: background-color 0.3s;
}
#dropZone.bg-light {
background-color: #e9ecef;
}
#dropZone:hover {
background-color: #f8f9fa;
border-color: #0d6efd;
}
.upload-icon {
font-size: 1.5rem;
}
</style>
<script>
@ -520,36 +558,46 @@ function showUpdateAlert() {
<?php if ($fileType == '代理文件'): ?>
<form action="" method="post" class="d-inline mb-1">
<input type="hidden" name="deleteFile" value="<?php echo htmlspecialchars($file); ?>">
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('确定要删除这个文件吗?');"><i>🗑️</i> 删除</button>
<button type="submit" class="btn btn-danger btn-sm" title="🗑️ 删除" onclick="return confirm('确定要删除这个文件吗?');"><i class="bi bi-trash"></i></button>
</form>
<form action="" method="post" class="d-inline mb-1">
<input type="hidden" name="oldFileName" value="<?php echo htmlspecialchars($file); ?>">
<input type="hidden" name="fileType" value="proxy">
<button type="button" class="btn btn-success btn-sm btn-rename" data-toggle="modal" data-target="#renameModal" data-filename="<?php echo htmlspecialchars($file); ?>" data-filetype="proxy"><i>✏️</i> 重命名</button>
<button type="button" class="btn btn-success btn-sm btn-rename" title="✏️ 重命名" data-toggle="modal" data-target="#renameModal" data-filename="<?php echo htmlspecialchars($file); ?>" data-filetype="proxy"><i class="bi bi-pencil"></i></button>
</form>
<form action="" method="post" class="d-inline mb-1">
<button type="button" class="btn btn-warning btn-sm" onclick="openEditModal('<?php echo htmlspecialchars($file); ?>', 'proxy')"><i>📝</i> 编辑</button>
<button type="button" class="btn btn-warning btn-sm" title="📝 编辑" onclick="openEditModal('<?php echo htmlspecialchars($file); ?>', 'proxy')"><i class="bi bi-pen"></i></button>
</form>
<form action="" method="post" enctype="multipart/form-data" class="d-inline upload-btn mb-1">
<input type="file" name="fileInput" class="form-control-file" required id="fileInput-<?php echo htmlspecialchars($file); ?>" style="display: none;" onchange="this.form.submit()">
<button type="button" class="btn btn-info btn-sm" onclick="document.getElementById('fileInput-<?php echo htmlspecialchars($file); ?>').click();"><i>📤</i> 上传</button>
<button type="button" class="btn btn-info btn-sm" title="📤 上传" onclick="openUploadModal('proxy')"><i class="bi bi-upload"></i></button>
</form>
<form action="" method="get" class="d-inline mb-1">
<input type="hidden" name="downloadFile" value="<?php echo htmlspecialchars($file); ?>">
<input type="hidden" name="fileType" value="proxy">
<button type="submit" class="btn btn-primary btn-sm" title="📥 下载" ><i class="bi bi-download"></i></button>
</form>
<?php else: ?>
<form action="" method="post" class="d-inline mb-1">
<input type="hidden" name="deleteConfigFile" value="<?php echo htmlspecialchars($file); ?>">
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('确定要删除这个文件吗?');"><i>🗑️</i> 删除</button>
<button type="submit" class="btn btn-danger btn-sm" title="🗑️ 删除" onclick="return confirm('确定要删除这个文件吗?');"><i class="bi bi-trash"></i></button>
</form>
<form action="" method="post" class="d-inline mb-1">
<input type="hidden" name="oldFileName" value="<?php echo htmlspecialchars($file); ?>">
<input type="hidden" name="fileType" value="config">
<button type="button" class="btn btn-success btn-sm btn-rename" data-toggle="modal" data-target="#renameModal" data-filename="<?php echo htmlspecialchars($file); ?>" data-filetype="config"><i>✏️</i> 重命名</button>
<button type="button" class="btn btn-success btn-sm btn-rename" title="✏️ 重命名" data-toggle="modal" data-target="#renameModal" data-filename="<?php echo htmlspecialchars($file); ?>" data-filetype="config"><i class="bi bi-pencil"></i></button>
</form>
<form action="" method="post" class="d-inline mb-1">
<button type="button" class="btn btn-warning btn-sm" onclick="openEditModal('<?php echo htmlspecialchars($file); ?>', 'config')"><i>📝</i> 编辑</button>
<button type="button" class="btn btn-warning btn-sm" title="📝 编辑" onclick="openEditModal('<?php echo htmlspecialchars($file); ?>', 'config')"><i class="bi bi-pen"></i></button>
</form>
<form action="" method="post" enctype="multipart/form-data" class="d-inline upload-btn mb-1">
<input type="file" name="configFileInput" class="form-control-file" required id="fileInput-<?php echo htmlspecialchars($file); ?>" style="display: none;" onchange="this.form.submit()">
<button type="button" class="btn btn-info btn-sm" onclick="document.getElementById('fileInput-<?php echo htmlspecialchars($file); ?>').click();"><i>📤</i> 上传</button>
<button type="button" class="btn btn-info btn-sm" title="📤 上传" onclick="openUploadModal('config')"><i class="bi bi-upload"></i></button>
</form>
<form action="" method="get" class="d-inline mb-1">
<input type="hidden" name="downloadFile" value="<?php echo htmlspecialchars($file); ?>">
<input type="hidden" name="fileType" value="config">
<button type="submit" class="btn btn-primary btn-sm" title="📥 下载" ><i class="bi bi-download"></i></button>
</form>
<?php endif; ?>
</div>
@ -561,12 +609,38 @@ function showUpdateAlert() {
</div>
</div>
<div class="modal fade" id="renameModal" tabindex="-1" aria-labelledby="renameModalLabel" aria-hidden="true">
<div class="modal fade" id="uploadModal" tabindex="-1" aria-labelledby="uploadModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="uploadModalLabel">上传文件</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="关闭">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="dropZone" class="border border-primary rounded text-center py-4 position-relative">
<i class="bi bi-cloud-upload-fill text-primary upload-icon"></i>
<p class="mb-0 mt-3">拖动文件到此区域上传<br>或者点击下方选择文件按钮</p>
</div>
<input type="file" id="fileInputModal" class="form-control mt-3" hidden>
<button id="selectFileBtn" class="btn btn-primary btn-block mt-3 w-100">选择文件</button>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="renameModal" tabindex="-1" aria-labelledby="renameModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="renameModalLabel">重命名文件</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="renameForm" action="" method="post">
@ -597,7 +671,9 @@ function showUpdateAlert() {
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">编辑文件: <span id="editingFileName"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form id="editForm" action="" method="post" onsubmit="syncEditorContent()">
@ -638,6 +714,7 @@ function showUpdateAlert() {
<select id="editorTheme" onchange="changeEditorTheme()" class="form-select mx-1" style="width: auto; font-size: 0.9rem;">
<option value="ace/theme/vibrant_ink">Vibrant Ink</option>
<option value="ace/theme/gob">Gob</option>
<option value="ace/theme/monokai">Monokai</option>
<option value="ace/theme/github">GitHub</option>
<option value="ace/theme/tomorrow">Tomorrow</option>
@ -651,6 +728,7 @@ function showUpdateAlert() {
<option value="ace/theme/dreamweaver">Dreamweaver</option>
<option value="ace/theme/xcode">Xcode</option>
<option value="ace/theme/kuroir">Kuroir</option>
<option value="ace/theme/iplastic">Iplastic</option>
<option value="ace/theme/katzenmilch">KatzenMilch</option>
<option value="ace/theme/sqlserver">SQL Server</option>
<option value="ace/theme/ambiance">Ambiance</option>
@ -917,6 +995,62 @@ function initializeAceEditor() {
.catch((err) => console.error(`Error attempting to exit full-screen mode: ${err.message}`));
}
}
let fileType = '';
function openUploadModal(type) {
fileType = type;
const modal = new bootstrap.Modal(document.getElementById('uploadModal'));
modal.show();
}
const dropZone = document.getElementById('dropZone');
dropZone.addEventListener('dragover', (event) => {
event.preventDefault();
dropZone.classList.add('bg-light');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('bg-light');
});
dropZone.addEventListener('drop', (event) => {
event.preventDefault();
dropZone.classList.remove('bg-light');
const files = event.dataTransfer.files;
if (files.length > 0) {
handleFileUpload(files[0]);
}
});
document.getElementById('selectFileBtn').addEventListener('click', () => {
document.getElementById('fileInputModal').click();
});
document.getElementById('fileInputModal').addEventListener('change', (event) => {
const files = event.target.files;
if (files.length > 0) {
handleFileUpload(files[0]);
}
});
function handleFileUpload(file) {
const formData = new FormData();
formData.append(fileType === 'proxy' ? 'fileInput' : 'configFileInput', file);
fetch('', {
method: 'POST',
body: formData,
})
.then((response) => response.text())
.then((result) => {
alert(result);
location.reload();
})
.catch((error) => {
alert('上传失败:' + error.message);
});
}
</script>
<h2 class="text-center mt-4 mb-4">Mihomo订阅管理</h2>
@ -995,7 +1129,9 @@ function initializeAceEditor() {
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cronModalLabel">设置 Cron 计划任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="mb-3">

View File

@ -254,6 +254,19 @@ $lang = $_GET['lang'] ?? 'en';
justify-content: center;
}
.site-icon[onclick*="openai"] .status-icon {
width: 62px;
height: 64px;
margin-top: -2px;
}
.site-icon[onclick*="openai"] {
width: 62px;
height: 64px;
display: flex;
justify-content: center;
}
.container-sm.container-bg.callout.border {
padding: 12px 15px;
min-height: 70px;
@ -333,15 +346,15 @@ $lang = $_GET['lang'] ?? 'en';
.site-icon[onclick*="baidu"],
.site-icon[onclick*="taobao"],
.site-icon[onclick*="google"],
.site-icon[onclick*="openai"],
.site-icon[onclick*="youtube"],
.site-icon[onclick*="github"] {
display: none !important;
}
}
</style>
<?php if (in_array($lang, ['zh-cn', 'en', 'auto'])): ?>
<div id="status-bar-component" class="container-sm container-bg callout border">
<div id="status-bar-component" class="container-sm container-bg callout border border-3 rounded-4 col-11">
<div class="row align-items-center">
<div class="col-auto">
<div class="img-con">
@ -369,6 +382,10 @@ $lang = $_GET['lang'] ?? 'en';
<img src="./assets/neko/img/site_icon_03.png" id="google-normal" title="测试 Google 延迟" class="status-icon" style="display: none;">
<img src="./assets/neko/img/site_icon1_03.png" id="google-gray" class="status-icon">
</div>
<div class="site-icon mx-1" onclick="pingHost('openai', 'OpenAI')">
<img src="./assets/neko/img/site_icon_06.png" id="openai-normal" title="测试 OpenAI 延迟" class="status-icon" style="display: none;">
<img src="./assets/neko/img/site_icon1_06.png" id="openai-gray" class="status-icon">
</div>
<div class="site-icon mx-1" onclick="pingHost('youtube', 'YouTube')">
<img src="./assets/neko/img/site_icon_04.png" id="youtube-normal" title="测试 YouTube 延迟" class="status-icon" style="display: none;">
<img src="./assets/neko/img/site_icon1_04.png" id="youtube-gray" class="status-icon">
@ -432,7 +449,8 @@ const sitesToPing = {
taobao: { url: 'https://www.taobao.com', name: 'Taobao' },
google: { url: 'https://www.google.com', name: 'Google' },
youtube: { url: 'https://www.youtube.com', name: 'YouTube' },
github: { url: 'https://www.github.com', name: 'GitHub' }
github: { url: 'https://www.github.com', name: 'GitHub' },
openai : { url: 'https://www.openai.com', name: 'OpenAI' }
};
async function checkAllPings() {
@ -458,7 +476,8 @@ const checkSiteStatus = {
taobao: 'https://www.taobao.com',
google: 'https://www.google.com',
youtube: 'https://www.youtube.com',
github: 'https://www.github.com'
github: 'https://www.github.com',
openai: 'https://www.openai.com'
},
check: async function() {
@ -494,9 +513,9 @@ async function pingHost(site, siteName) {
const endTime = performance.now();
const pingTime = Math.round(endTime - startTime);
resultElement.innerHTML = `<span style="font-size: 22px">${siteName} 连接延迟: ${pingTime}ms</span>`;
if(pingTime <= 100) {
if(pingTime <= 300) {
resultElement.style.color = '#09B63F';
} else if(pingTime <= 200) {
} else if(pingTime <= 700) {
resultElement.style.color = '#FFA500';
} else {
resultElement.style.color = '#ff6b6b';
@ -702,19 +721,30 @@ let IP = {
const asnOrganization = await translateText(data.asn_organization || "");
let location = `${region && city && region !== city ? `${region} ${city}` : region || city || ''}`;
let displayISP = isp;
let displayASN = asnOrganization;
if (isp && asnOrganization && asnOrganization.includes(isp)) {
displayISP = '';
} else if (isp && asnOrganization && isp.includes(asnOrganization)) {
displayASN = '';
}
let locationInfo = `<span style="margin-left: 8px;">${location} ${displayISP} ${data.asn || ''} ${displayASN}</span>`;
let simpleDisplay = `
<div class="ip-main" style="cursor: pointer;" onclick="IP.showDetailModal()" title="点击查看 IP 详细信息">
${cachedIP} <span class="badge badge-primary" style="color: #333;">${country}</span>
</div>`;
let locationInfo = `<span style="margin-left: 8px;">${location} ${isp} ${data.asn || ''} ${asnOrganization}</span>`;
document.getElementById('d-ip').innerHTML = simpleDisplay;
document.getElementById('ipip').innerHTML = locationInfo;
const countryCode = data.country_code || 'unknown';
const flagSrc = (countryCode !== 'unknown') ? _IMG + "flags/" + countryCode.toLowerCase() + ".png" : './assets/neko/flags/cn.png';
$("#flag").attr("src", flagSrc);
} catch (error) {
console.error("Error in updateUI:", error);
document.getElementById('d-ip').innerHTML = "更新 IP 信息失败";
@ -761,7 +791,7 @@ let IP = {
const delayInfoHTML = Object.entries(pingResults).map(([key, { name, pingTime }]) => {
let color = '#ff6b6b';
if (typeof pingTime === 'number') {
color = pingTime <= 100 ? '#09B63F' : pingTime <= 200 ? '#FFA500' : '#ff6b6b';
color = pingTime <= 300 ? '#09B63F' : pingTime <= 700 ? '#FFA500' : '#ff6b6b';
}
return `<span style="margin-right: 20px; font-size: 18px; color: ${color};">${name}: ${pingTime === '超时' ? '超时' : `${pingTime}ms`}</span>`;
}).join('');
@ -782,7 +812,7 @@ let IP = {
const modalHTML = `
<div class="modal fade custom-modal" id="ipDetailModal" tabindex="-1" role="dialog" aria-labelledby="ipDetailModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="ipDetailModalLabel">IP详细信息</h5>

View File

@ -318,7 +318,9 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="updateVersionTypeModalLabel">选择更新版本类型</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group text-center">
@ -335,7 +337,9 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="updateLanguageModalLabel">选择语言</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
@ -359,7 +363,7 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="previewLanguageModalLabel">选择预览版语言</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="form-group">
@ -487,7 +491,9 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="singboxVersionModalLabel">选择 Singbox 核心版本(官方通道二)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
@ -511,7 +517,9 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="panelSelectionModalLabel">选择面板</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
@ -537,7 +545,9 @@ $razordVersion = getRazordVersion();
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="versionModalLabel">版本检测结果</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="modalContent">

View File

@ -244,7 +244,9 @@ EOL;
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cronModalLabel">设置定时任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form method="post" action="">
<div class="modal-body">

View File

@ -733,7 +733,9 @@ EOL;
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cronModalLabel">设置 Cron 计划任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form method="POST">

View File

@ -1 +1 @@
V1.6.3-cn
V1.6.4-cn

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -30,8 +30,8 @@
name="theme-color"
content="#FFFFFF"
/>
<script type="module" crossorigin src="./assets/index-Chv6mdat.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CmbT92j7.css">
<script type="module" crossorigin src="./assets/index-BTmREsbq.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-Cq2D8BIO.css">
<link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
<body>
<div id="app"></div>

View File

@ -1 +1 @@
if(!self.define){let e,i={};const s=(s,n)=>(s=new URL(s+".js",n).href,i[s]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()})).then((()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didnt register its module`);return e})));self.define=(n,r)=>{const f=e||("document"in self?document.currentScript.src:"")||location.href;if(i[f])return;let c={};const d=e=>s(e,f),o={module:{uri:f},exports:c,require:d};i[f]=Promise.all(n.map((e=>o[e]||d(e)))).then((e=>(r(...e),c)))}}define(["./workbox-3e8df8c8"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/index-Chv6mdat.js",revision:null},{url:"assets/index-CmbT92j7.css",revision:null},{url:"index.html",revision:"e703c9873b090a7f216d1cbc0c500fe3"},{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"favicon.svg",revision:"7f1c4521acc10694fefef8f72dd2ea5f"},{url:"pwa-192x192.png",revision:"021df52501f4357c03eebd808f40dc6a"},{url:"pwa-512x512.png",revision:"d2f759aaabcb2c44ff52b27fde3de6e0"},{url:"pwa-maskable-192x192.png",revision:"7cd11dc5f0490b349d23eef5591d10e5"},{url:"pwa-maskable-512x512.png",revision:"8c97dc367a85a5a1eba523b24f79d03b"},{url:"manifest.webmanifest",revision:"c452912633990899ffe790f985ad0db9"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))}));
if(!self.define){let e,i={};const s=(s,n)=>(s=new URL(s+".js",n).href,i[s]||new Promise((i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()})).then((()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didnt register its module`);return e})));self.define=(n,r)=>{const f=e||("document"in self?document.currentScript.src:"")||location.href;if(i[f])return;let d={};const o=e=>s(e,f),t={module:{uri:f},exports:d,require:o};i[f]=Promise.all(n.map((e=>t[e]||o(e)))).then((e=>(r(...e),d)))}}define(["./workbox-3e8df8c8"],(function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"assets/index-BTmREsbq.js",revision:null},{url:"assets/index-Cq2D8BIO.css",revision:null},{url:"index.html",revision:"50ead7c708651828a12a51383f662a6d"},{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"favicon.svg",revision:"7f1c4521acc10694fefef8f72dd2ea5f"},{url:"pwa-192x192.png",revision:"021df52501f4357c03eebd808f40dc6a"},{url:"pwa-512x512.png",revision:"d2f759aaabcb2c44ff52b27fde3de6e0"},{url:"pwa-maskable-192x192.png",revision:"7cd11dc5f0490b349d23eef5591d10e5"},{url:"pwa-maskable-512x512.png",revision:"8c97dc367a85a5a1eba523b24f79d03b"},{url:"manifest.webmanifest",revision:"c452912633990899ffe790f985ad0db9"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))}));

View File

@ -1 +1 @@
v1.41.0
v1.44.0