koishi-plugin-memesluna 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/lib/index.js +188 -373
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{icons as r}from"@koishijs/client";import{h as e}from"vue";const o="M1024 512C1024 229.230208 794.769792 0 512 0 229.230208 0 0 229.230208 0 512 0 794.769792 229.230208 1024 512 1024 629.410831 1024 740.826187 984.331046 830.768465 912.686662 841.557579 904.092491 843.33693 888.379234 834.742758 877.590121 826.148587 866.801009 810.43533 865.021658 799.646219 873.615827 718.470035 938.277495 618.001779 974.048781 512 974.048781 256.817504 974.048781 49.951219 767.182496 49.951219 512 49.951219 256.817504 256.817504 49.951219 512 49.951219 767.182496 49.951219 974.048781 256.817504 974.048781 512 974.048781 599.492834 949.714859 683.336764 904.470807 755.960693 897.177109 767.668243 900.755245 783.071797 912.462793 790.365493 924.170342 797.659191 939.573897 794.081058 946.867595 782.373508 997.013826 701.880796 1024 608.898379 1024 512ZM337.170731 499.512194C371.654852 499.512194 399.609756 471.557291 399.609756 437.073171 399.609756 402.58905 371.654852 374.634146 337.170731 374.634146 302.686611 374.634146 274.731708 402.58905 274.731708 437.073171 274.731708 471.557291 302.686611 499.512194 337.170731 499.512194ZM711.804879 499.512194C746.288998 499.512194 774.243902 471.557291 774.243902 437.073171 774.243902 402.58905 746.288998 374.634146 711.804879 374.634146 677.320757 374.634146 649.365854 402.58905 649.365854 437.073171 649.365854 471.557291 677.320757 499.512194 711.804879 499.512194ZM352.788105 768.770967C396.165222 803.472661 453.151987 824.195121 524.487806 824.195121 595.823622 824.195121 652.810387 803.472661 696.187505 768.770967 722.700531 747.560546 738.882517 725.984565 746.631548 710.486505 752.800254 698.149092 747.799529 683.146916 735.462114 676.978208 723.124702 670.809502 708.122526 675.810227 701.953818 688.147642 701.03616 689.982957 698.492224 694.172969 694.165854 699.941463 686.602473 710.025971 676.927317 720.210345 664.983226 729.765617 630.311565 757.502948 584.273939 774.243902 524.487806 774.243902 464.70167 774.243902 418.664045 757.502948 383.992384 729.765617 372.048292 720.210345 362.373137 710.025971 354.809756 699.941463 350.483386 694.172969 347.93945 689.982957 347.021792 688.147642 340.853084 675.810227 325.850908 670.809502 313.513495 676.978208 301.176081 683.146916 296.175356 698.149092 302.344062 710.486505 310.093092 725.984565 326.275078 747.560546 352.788105 768.770967Z",a={name:"MemesLunaIcon",render(){return e("svg",{class:"k-icon",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg"},[e("path",{fill:"currentColor",d:o})])}},s={name:"MemesLunaDashboard",render(){return e("iframe",{src:"/memesluna/",style:"width: 100%; height: calc(100vh - 120px); border: 0; background: transparent;"})}};r.register("MemesLunaEmoji",a);const
|
|
1
|
+
import{icons as r}from"@koishijs/client";import{h as e}from"vue";const o="M1024 512C1024 229.230208 794.769792 0 512 0 229.230208 0 0 229.230208 0 512 0 794.769792 229.230208 1024 512 1024 629.410831 1024 740.826187 984.331046 830.768465 912.686662 841.557579 904.092491 843.33693 888.379234 834.742758 877.590121 826.148587 866.801009 810.43533 865.021658 799.646219 873.615827 718.470035 938.277495 618.001779 974.048781 512 974.048781 256.817504 974.048781 49.951219 767.182496 49.951219 512 49.951219 256.817504 256.817504 49.951219 512 49.951219 767.182496 49.951219 974.048781 256.817504 974.048781 512 974.048781 599.492834 949.714859 683.336764 904.470807 755.960693 897.177109 767.668243 900.755245 783.071797 912.462793 790.365493 924.170342 797.659191 939.573897 794.081058 946.867595 782.373508 997.013826 701.880796 1024 608.898379 1024 512ZM337.170731 499.512194C371.654852 499.512194 399.609756 471.557291 399.609756 437.073171 399.609756 402.58905 371.654852 374.634146 337.170731 374.634146 302.686611 374.634146 274.731708 402.58905 274.731708 437.073171 274.731708 471.557291 302.686611 499.512194 337.170731 499.512194ZM711.804879 499.512194C746.288998 499.512194 774.243902 471.557291 774.243902 437.073171 774.243902 402.58905 746.288998 374.634146 711.804879 374.634146 677.320757 374.634146 649.365854 402.58905 649.365854 437.073171 649.365854 471.557291 677.320757 499.512194 711.804879 499.512194ZM352.788105 768.770967C396.165222 803.472661 453.151987 824.195121 524.487806 824.195121 595.823622 824.195121 652.810387 803.472661 696.187505 768.770967 722.700531 747.560546 738.882517 725.984565 746.631548 710.486505 752.800254 698.149092 747.799529 683.146916 735.462114 676.978208 723.124702 670.809502 708.122526 675.810227 701.953818 688.147642 701.03616 689.982957 698.492224 694.172969 694.165854 699.941463 686.602473 710.025971 676.927317 720.210345 664.983226 729.765617 630.311565 757.502948 584.273939 774.243902 524.487806 774.243902 464.70167 774.243902 418.664045 757.502948 383.992384 729.765617 372.048292 720.210345 362.373137 710.025971 354.809756 699.941463 350.483386 694.172969 347.93945 689.982957 347.021792 688.147642 340.853084 675.810227 325.850908 670.809502 313.513495 676.978208 301.176081 683.146916 296.175356 698.149092 302.344062 710.486505 310.093092 725.984565 326.275078 747.560546 352.788105 768.770967Z",a={name:"MemesLunaIcon",render(){return e("svg",{class:"k-icon",viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg"},[e("path",{fill:"currentColor",d:o})])}},s={name:"MemesLunaDashboard",render(){return e("iframe",{src:"/memesluna/",style:"width: 100%; height: calc(100vh - 120px); border: 0; background: transparent;"})}};r.register("MemesLunaEmoji",a);const c=n=>{n.page({name:"MemesLuna",path:"/memesluna/",icon:"MemesLunaEmoji",component:s,authority:3,order:500})};export{c as default};
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
8
|
var __export = (target, all) => {
|
|
8
9
|
for (var name2 in all)
|
|
9
10
|
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
@@ -72,6 +73,9 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
72
73
|
this._readyResolve();
|
|
73
74
|
});
|
|
74
75
|
}
|
|
76
|
+
static {
|
|
77
|
+
__name(this, "MemesLunaService");
|
|
78
|
+
}
|
|
75
79
|
_readyPromise;
|
|
76
80
|
_readyResolve;
|
|
77
81
|
static inject = ["database"];
|
|
@@ -426,7 +430,7 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
426
430
|
return {
|
|
427
431
|
id: row.id,
|
|
428
432
|
name: row.name,
|
|
429
|
-
group: row.group || "
|
|
433
|
+
group: row.group || "默认分组",
|
|
430
434
|
description: row.description || "",
|
|
431
435
|
url: row.url,
|
|
432
436
|
method: row.method || "redirect",
|
|
@@ -459,7 +463,7 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
459
463
|
await this.ctx.database.create("memesluna_endpoints", {
|
|
460
464
|
id,
|
|
461
465
|
name: input.name,
|
|
462
|
-
group: input.group || "
|
|
466
|
+
group: input.group || "默认分组",
|
|
463
467
|
description: input.description || "",
|
|
464
468
|
url: input.url,
|
|
465
469
|
method: input.method || "redirect",
|
|
@@ -483,7 +487,7 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
483
487
|
const payload = {
|
|
484
488
|
updated_at: /* @__PURE__ */ new Date()
|
|
485
489
|
};
|
|
486
|
-
if (input.group !== void 0) payload.group = input.group || "
|
|
490
|
+
if (input.group !== void 0) payload.group = input.group || "默认分组";
|
|
487
491
|
if (input.description !== void 0) payload.description = input.description || "";
|
|
488
492
|
if (input.url !== void 0) payload.url = input.url;
|
|
489
493
|
if (input.method !== void 0) payload.method = input.method;
|
|
@@ -526,12 +530,12 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
526
530
|
// src/config.ts
|
|
527
531
|
var import_koishi2 = require("koishi");
|
|
528
532
|
var Config = import_koishi2.Schema.object({
|
|
529
|
-
backendPath: import_koishi2.Schema.string().default("/memesluna").description("
|
|
530
|
-
storagePath: import_koishi2.Schema.string().default("data/memesluna").description("
|
|
531
|
-
selfUrl: import_koishi2.Schema.string().default("").description("
|
|
532
|
-
injectVariables: import_koishi2.Schema.boolean().default(true).description("
|
|
533
|
-
variableRefreshIntervalMs: import_koishi2.Schema.number().min(30 * 1e3).max(60 * 60 * 1e3).default(5 * 60 * 1e3).description("
|
|
534
|
-
injectVariablesPrompt: import_koishi2.Schema.string().role("textarea").default(
|
|
533
|
+
backendPath: import_koishi2.Schema.string().default("/memesluna").description("后端服务路径前缀"),
|
|
534
|
+
storagePath: import_koishi2.Schema.string().default("data/memesluna").description("本地合集存储目录"),
|
|
535
|
+
selfUrl: import_koishi2.Schema.string().default("").description("服务公开地址,不填则优先使用 server.selfUrl"),
|
|
536
|
+
injectVariables: import_koishi2.Schema.boolean().default(true).description("是否向 ChatLuna 注入 {{endpoint}} 和 {{memesluna}} 变量"),
|
|
537
|
+
variableRefreshIntervalMs: import_koishi2.Schema.number().min(30 * 1e3).max(60 * 60 * 1e3).default(5 * 60 * 1e3).description("变量刷新间隔(毫秒)"),
|
|
538
|
+
injectVariablesPrompt: import_koishi2.Schema.string().role("textarea").default(`你可以使用表情包来丰富你的回复。表情包列表是{endpoint},基础URL是{base_url},你要把基础URL拼接到路径前面,不要加文件名,只加路径,用发送图片的方式发送。`).description("注入到 ChatLuna {{memesluna}} 变量的提示词模板,支持 {endpoint} 和 {base_url} 占位符")
|
|
535
539
|
});
|
|
536
540
|
var name = "memesluna";
|
|
537
541
|
|
|
@@ -554,6 +558,7 @@ var IMAGE_URL_REGEXP = /\.(jpeg|jpg|gif|png|webp|bmp|svg)(\?.*)?$/i;
|
|
|
554
558
|
function isReservedPath(name2) {
|
|
555
559
|
return RESERVED_PATHS.has(name2) || name2.includes(".");
|
|
556
560
|
}
|
|
561
|
+
__name(isReservedPath, "isReservedPath");
|
|
557
562
|
function getValueByDotNotation(obj, dotPath) {
|
|
558
563
|
if (!dotPath) return void 0;
|
|
559
564
|
const parts = dotPath.split(".").filter(Boolean);
|
|
@@ -567,10 +572,12 @@ function getValueByDotNotation(obj, dotPath) {
|
|
|
567
572
|
}
|
|
568
573
|
return current;
|
|
569
574
|
}
|
|
575
|
+
__name(getValueByDotNotation, "getValueByDotNotation");
|
|
570
576
|
function normalizeContentType(contentType) {
|
|
571
577
|
if (!contentType) return "";
|
|
572
578
|
return contentType.toLowerCase().split(";")[0].trim();
|
|
573
579
|
}
|
|
580
|
+
__name(normalizeContentType, "normalizeContentType");
|
|
574
581
|
function guessMimeByExt(filePath) {
|
|
575
582
|
const ext = import_path2.default.extname(filePath).toLowerCase();
|
|
576
583
|
switch (ext) {
|
|
@@ -590,6 +597,7 @@ function guessMimeByExt(filePath) {
|
|
|
590
597
|
return "image/jpeg";
|
|
591
598
|
}
|
|
592
599
|
}
|
|
600
|
+
__name(guessMimeByExt, "guessMimeByExt");
|
|
593
601
|
async function handleProxyRequest(targetUrl, proxySettings = {}) {
|
|
594
602
|
try {
|
|
595
603
|
const response = await fetch(targetUrl, {
|
|
@@ -668,9 +676,11 @@ async function handleProxyRequest(targetUrl, proxySettings = {}) {
|
|
|
668
676
|
};
|
|
669
677
|
}
|
|
670
678
|
}
|
|
679
|
+
__name(handleProxyRequest, "handleProxyRequest");
|
|
671
680
|
function toAbsoluteBaseUrl(ctx, config) {
|
|
672
681
|
return config.selfUrl || ctx.server?.selfUrl || "";
|
|
673
682
|
}
|
|
683
|
+
__name(toAbsoluteBaseUrl, "toAbsoluteBaseUrl");
|
|
674
684
|
async function applyDynamicForward(ctx, config, service, routeName, query) {
|
|
675
685
|
const endpoint = await service.getEndpointByName(routeName);
|
|
676
686
|
const isCollection = await service.collectionExists(routeName);
|
|
@@ -784,6 +794,7 @@ async function applyDynamicForward(ctx, config, service, routeName, query) {
|
|
|
784
794
|
contentType: guessMimeByExt(resource.value)
|
|
785
795
|
};
|
|
786
796
|
}
|
|
797
|
+
__name(applyDynamicForward, "applyDynamicForward");
|
|
787
798
|
function setKoaResponse(koa, result) {
|
|
788
799
|
if (result.redirectTo) {
|
|
789
800
|
koa.redirect(result.redirectTo);
|
|
@@ -800,6 +811,7 @@ function setKoaResponse(koa, result) {
|
|
|
800
811
|
}
|
|
801
812
|
koa.body = result.body;
|
|
802
813
|
}
|
|
814
|
+
__name(setKoaResponse, "setKoaResponse");
|
|
803
815
|
function getRequestBody(koa) {
|
|
804
816
|
const body = koa?.request?.body;
|
|
805
817
|
if (!body) return {};
|
|
@@ -815,13 +827,16 @@ function getRequestBody(koa) {
|
|
|
815
827
|
}
|
|
816
828
|
return {};
|
|
817
829
|
}
|
|
830
|
+
__name(getRequestBody, "getRequestBody");
|
|
818
831
|
function toTrimmedString(value) {
|
|
819
832
|
return typeof value === "string" ? value.trim() : "";
|
|
820
833
|
}
|
|
834
|
+
__name(toTrimmedString, "toTrimmedString");
|
|
821
835
|
function toStringArray(value) {
|
|
822
836
|
if (!Array.isArray(value)) return [];
|
|
823
837
|
return value.map((item) => typeof item === "string" ? item.trim() : "").filter((item) => item.length > 0);
|
|
824
838
|
}
|
|
839
|
+
__name(toStringArray, "toStringArray");
|
|
825
840
|
function parseJsonLike(value, fallback) {
|
|
826
841
|
if (value === null || value === void 0) return fallback;
|
|
827
842
|
if (typeof value === "string") {
|
|
@@ -838,9 +853,11 @@ function parseJsonLike(value, fallback) {
|
|
|
838
853
|
}
|
|
839
854
|
return fallback;
|
|
840
855
|
}
|
|
856
|
+
__name(parseJsonLike, "parseJsonLike");
|
|
841
857
|
function normalizeForwardMethod(value) {
|
|
842
858
|
return toTrimmedString(value) === "proxy" ? "proxy" : "redirect";
|
|
843
859
|
}
|
|
860
|
+
__name(normalizeForwardMethod, "normalizeForwardMethod");
|
|
844
861
|
function normalizeUrlConstruction(value) {
|
|
845
862
|
const normalized = toTrimmedString(value);
|
|
846
863
|
if (normalized === "special_forward" || normalized === "special_pollinations" || normalized === "special_draw_redirect") {
|
|
@@ -848,6 +865,7 @@ function normalizeUrlConstruction(value) {
|
|
|
848
865
|
}
|
|
849
866
|
return "normal";
|
|
850
867
|
}
|
|
868
|
+
__name(normalizeUrlConstruction, "normalizeUrlConstruction");
|
|
851
869
|
async function buildAdminState(service) {
|
|
852
870
|
const endpoints = await service.getEndpoints();
|
|
853
871
|
const collectionNames = await service.getCollections();
|
|
@@ -858,13 +876,14 @@ async function buildAdminState(service) {
|
|
|
858
876
|
collections: collections.filter(Boolean)
|
|
859
877
|
};
|
|
860
878
|
}
|
|
879
|
+
__name(buildAdminState, "buildAdminState");
|
|
861
880
|
function buildHomepageHtml(basePath) {
|
|
862
881
|
return `<!doctype html>
|
|
863
882
|
<html lang="zh-CN">
|
|
864
883
|
<head>
|
|
865
884
|
<meta charset="utf-8" />
|
|
866
885
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
867
|
-
<title
|
|
886
|
+
<title>图床转发 - 首页</title>
|
|
868
887
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
869
888
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css">
|
|
870
889
|
<style>
|
|
@@ -1052,8 +1071,8 @@ function buildHomepageHtml(basePath) {
|
|
|
1052
1071
|
animation: spin 1s linear infinite;
|
|
1053
1072
|
}
|
|
1054
1073
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1074
|
+
.error-panel {
|
|
1075
|
+
display: none !important;
|
|
1057
1076
|
}
|
|
1058
1077
|
|
|
1059
1078
|
@keyframes spin {
|
|
@@ -1082,13 +1101,10 @@ function buildHomepageHtml(basePath) {
|
|
|
1082
1101
|
<div class="collapse navbar-collapse" id="navbarNav">
|
|
1083
1102
|
<ul class="navbar-nav me-auto">
|
|
1084
1103
|
<li class="nav-item">
|
|
1085
|
-
<a class="nav-link active" href="${basePath}/"
|
|
1086
|
-
</li>
|
|
1087
|
-
<li class="nav-item">
|
|
1088
|
-
<a class="nav-link" href="${basePath}/admin">\u7BA1\u7406</a>
|
|
1104
|
+
<a class="nav-link active" href="${basePath}/">首页</a>
|
|
1089
1105
|
</li>
|
|
1090
1106
|
<li class="nav-item">
|
|
1091
|
-
<a class="nav-link" href="${basePath}/admin
|
|
1107
|
+
<a class="nav-link" href="${basePath}/admin">管理</a>
|
|
1092
1108
|
</li>
|
|
1093
1109
|
</ul>
|
|
1094
1110
|
</div>
|
|
@@ -1097,17 +1113,17 @@ function buildHomepageHtml(basePath) {
|
|
|
1097
1113
|
|
|
1098
1114
|
<div class="container page-container mt-3 pb-4">
|
|
1099
1115
|
<div class="group-section">
|
|
1100
|
-
<h3 class="group-title-home"
|
|
1116
|
+
<h3 class="group-title-home">🌐 接口端点</h3>
|
|
1101
1117
|
<div class="cards-row" id="endpoint-cards"></div>
|
|
1102
1118
|
</div>
|
|
1103
1119
|
|
|
1104
1120
|
<div class="group-section">
|
|
1105
|
-
<h3 class="group-title-home"
|
|
1121
|
+
<h3 class="group-title-home">📷 本地图片合集</h3>
|
|
1106
1122
|
<div class="cards-row" id="collection-cards"></div>
|
|
1107
1123
|
</div>
|
|
1108
1124
|
|
|
1109
1125
|
<div class="alert alert-danger error-panel" id="error-panel">
|
|
1110
|
-
<strong
|
|
1126
|
+
<strong>加载失败:</strong><span id="error-text"></span>
|
|
1111
1127
|
</div>
|
|
1112
1128
|
</div>
|
|
1113
1129
|
|
|
@@ -1119,13 +1135,14 @@ function buildHomepageHtml(basePath) {
|
|
|
1119
1135
|
const panel = document.getElementById('error-panel')
|
|
1120
1136
|
const text = document.getElementById('error-text')
|
|
1121
1137
|
if (text) text.textContent = message
|
|
1138
|
+
if (panel) panel.classList.remove('error-panel')
|
|
1122
1139
|
if (panel) panel.style.display = 'block'
|
|
1123
1140
|
}
|
|
1124
1141
|
|
|
1125
1142
|
function createLoader() {
|
|
1126
1143
|
const loader = document.createElement('div')
|
|
1127
1144
|
loader.className = 'media-loader'
|
|
1128
|
-
loader.innerHTML = '<div class="loader-spinner"></div><span
|
|
1145
|
+
loader.innerHTML = '<div class="loader-spinner"></div><span>加载中...</span>'
|
|
1129
1146
|
return loader
|
|
1130
1147
|
}
|
|
1131
1148
|
|
|
@@ -1183,9 +1200,9 @@ function buildHomepageHtml(basePath) {
|
|
|
1183
1200
|
const target = String(item.url || '')
|
|
1184
1201
|
|
|
1185
1202
|
info.innerHTML =
|
|
1186
|
-
'<p class="api-hint"
|
|
1203
|
+
'<p class="api-hint">⚙️ ' + method + ' · ' + mode + '</p>' +
|
|
1187
1204
|
'<p class="api-url">' + endpointPath + '</p>' +
|
|
1188
|
-
'<p class="api-url"
|
|
1205
|
+
'<p class="api-url">→ ' + target + '</p>'
|
|
1189
1206
|
|
|
1190
1207
|
card.appendChild(info)
|
|
1191
1208
|
return card
|
|
@@ -1211,7 +1228,7 @@ function buildHomepageHtml(basePath) {
|
|
|
1211
1228
|
const totalCount = Number(item.totalCount || 0)
|
|
1212
1229
|
|
|
1213
1230
|
info.innerHTML =
|
|
1214
|
-
'<p class="api-hint"
|
|
1231
|
+
'<p class="api-hint">📁 本地 ' + localCount + ' · 外链 ' + linkCount + ' · 总计 ' + totalCount + '</p>' +
|
|
1215
1232
|
'<p class="api-url">' + route + '</p>'
|
|
1216
1233
|
|
|
1217
1234
|
card.appendChild(info)
|
|
@@ -1234,7 +1251,7 @@ function buildHomepageHtml(basePath) {
|
|
|
1234
1251
|
if (!endpoints.length) {
|
|
1235
1252
|
const empty = document.createElement('div')
|
|
1236
1253
|
empty.className = 'alert alert-secondary mb-0'
|
|
1237
|
-
empty.textContent = '
|
|
1254
|
+
empty.textContent = '暂无 endpoint'
|
|
1238
1255
|
endpointWrap.appendChild(empty)
|
|
1239
1256
|
} else {
|
|
1240
1257
|
endpoints.forEach((item) => endpointWrap.appendChild(buildEndpointCard(item)))
|
|
@@ -1247,7 +1264,7 @@ function buildHomepageHtml(basePath) {
|
|
|
1247
1264
|
if (!collections.length) {
|
|
1248
1265
|
const empty = document.createElement('div')
|
|
1249
1266
|
empty.className = 'alert alert-secondary mb-0'
|
|
1250
|
-
empty.textContent = '
|
|
1267
|
+
empty.textContent = '暂无 collection'
|
|
1251
1268
|
collectionWrap.appendChild(empty)
|
|
1252
1269
|
} else {
|
|
1253
1270
|
collections.forEach((item) => collectionWrap.appendChild(buildCollectionCard(item)))
|
|
@@ -1264,13 +1281,14 @@ function buildHomepageHtml(basePath) {
|
|
|
1264
1281
|
</body>
|
|
1265
1282
|
</html>`;
|
|
1266
1283
|
}
|
|
1284
|
+
__name(buildHomepageHtml, "buildHomepageHtml");
|
|
1267
1285
|
function buildAdminHtml(basePath) {
|
|
1268
1286
|
return `<!doctype html>
|
|
1269
1287
|
<html lang="zh-CN">
|
|
1270
1288
|
<head>
|
|
1271
1289
|
<meta charset="utf-8" />
|
|
1272
1290
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1273
|
-
<title
|
|
1291
|
+
<title>图床转发 - 管理</title>
|
|
1274
1292
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
1275
1293
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css">
|
|
1276
1294
|
<style>
|
|
@@ -1389,9 +1407,9 @@ function buildAdminHtml(basePath) {
|
|
|
1389
1407
|
</button>
|
|
1390
1408
|
<div class="collapse navbar-collapse" id="navbarNavAdmin">
|
|
1391
1409
|
<ul class="navbar-nav me-auto">
|
|
1392
|
-
<li class="nav-item"><a class="nav-link" href="${basePath}/"
|
|
1393
|
-
<li class="nav-item"><a class="nav-link active" href="${basePath}/admin"
|
|
1394
|
-
<li class="nav-item"><a class="nav-link" href="${basePath}/admin/endpoint"
|
|
1410
|
+
<li class="nav-item"><a class="nav-link" href="${basePath}/">首页</a></li>
|
|
1411
|
+
<li class="nav-item"><a class="nav-link active" href="${basePath}/admin">管理</a></li>
|
|
1412
|
+
<li class="nav-item"><a class="nav-link" href="${basePath}/admin/endpoint">端点</a></li>
|
|
1395
1413
|
</ul>
|
|
1396
1414
|
</div>
|
|
1397
1415
|
</div>
|
|
@@ -1401,26 +1419,26 @@ function buildAdminHtml(basePath) {
|
|
|
1401
1419
|
<div class="row g-3">
|
|
1402
1420
|
<div class="col-lg-3">
|
|
1403
1421
|
<div class="sidebar-panel">
|
|
1404
|
-
<h5 class="mb-3"
|
|
1422
|
+
<h5 class="mb-3">合集管理</h5>
|
|
1405
1423
|
<div class="input-group mb-3">
|
|
1406
|
-
<input id="new-collection-name" class="form-control" placeholder="
|
|
1407
|
-
<button id="create-collection" class="btn btn-primary"
|
|
1424
|
+
<input id="new-collection-name" class="form-control" placeholder="新合集名称" />
|
|
1425
|
+
<button id="create-collection" class="btn btn-primary">创建</button>
|
|
1408
1426
|
</div>
|
|
1409
1427
|
<div id="collection-list" class="list-group mb-3"></div>
|
|
1410
|
-
<button id="delete-collection" class="btn btn-outline-danger w-100" disabled
|
|
1428
|
+
<button id="delete-collection" class="btn btn-outline-danger w-100" disabled>删除当前合集</button>
|
|
1411
1429
|
|
|
1412
1430
|
<hr>
|
|
1413
|
-
<h6 class="mb-2"
|
|
1431
|
+
<h6 class="mb-2">合集描述</h6>
|
|
1414
1432
|
<div class="input-group mb-3">
|
|
1415
|
-
<input id="collection-description" class="form-control" placeholder="
|
|
1416
|
-
<button id="save-description" class="btn btn-primary" disabled
|
|
1433
|
+
<input id="collection-description" class="form-control" placeholder="为当前合集添加描述" disabled />
|
|
1434
|
+
<button id="save-description" class="btn btn-primary" disabled>保存</button>
|
|
1417
1435
|
</div>
|
|
1418
1436
|
|
|
1419
1437
|
<hr>
|
|
1420
|
-
<h6 class="mb-2"
|
|
1438
|
+
<h6 class="mb-2">快捷信息</h6>
|
|
1421
1439
|
<div class="small text-muted">
|
|
1422
|
-
<div
|
|
1423
|
-
<div class="mt-1"
|
|
1440
|
+
<div>管理链接:<code>${basePath}/admin</code></div>
|
|
1441
|
+
<div class="mt-1">随机访问:<code id="collection-random-url">-</code></div>
|
|
1424
1442
|
</div>
|
|
1425
1443
|
</div>
|
|
1426
1444
|
</div>
|
|
@@ -1428,74 +1446,38 @@ function buildAdminHtml(basePath) {
|
|
|
1428
1446
|
<div class="col-lg-9">
|
|
1429
1447
|
<div class="main-panel mb-3">
|
|
1430
1448
|
<div class="d-flex justify-content-between align-items-center">
|
|
1431
|
-
<h5 class="mb-0"
|
|
1432
|
-
<span id="selected-collection-badge" class="badge bg-primary"
|
|
1449
|
+
<h5 class="mb-0">合集内容</h5>
|
|
1450
|
+
<span id="selected-collection-badge" class="badge bg-primary">未选择</span>
|
|
1433
1451
|
</div>
|
|
1434
1452
|
|
|
1435
1453
|
<div class="row g-3 mt-1">
|
|
1436
1454
|
<div class="col-md-6">
|
|
1437
1455
|
<div class="sub-card h-100">
|
|
1438
|
-
<div class="section-title mb-2"
|
|
1456
|
+
<div class="section-title mb-2">上传本地图片</div>
|
|
1439
1457
|
<input id="upload-files" type="file" class="form-control mb-2" multiple accept="image/*" />
|
|
1440
|
-
<button id="upload-images" class="btn btn-primary w-100" disabled
|
|
1441
|
-
<div class="form-text"
|
|
1458
|
+
<button id="upload-images" class="btn btn-primary w-100" disabled>上传到当前合集</button>
|
|
1459
|
+
<div class="form-text">支持多选。上传后自动刷新列表。</div>
|
|
1442
1460
|
</div>
|
|
1443
1461
|
</div>
|
|
1444
1462
|
<div class="col-md-6">
|
|
1445
1463
|
<div class="sub-card h-100">
|
|
1446
|
-
<div class="section-title mb-2"
|
|
1447
|
-
<textarea id="links-input" class="form-control mb-2" rows="4" placeholder="
|
|
1448
|
-
<button id="add-links" class="btn btn-primary w-100" disabled
|
|
1464
|
+
<div class="section-title mb-2">添加外链</div>
|
|
1465
|
+
<textarea id="links-input" class="form-control mb-2" rows="4" placeholder="每行一个 http/https 链接"></textarea>
|
|
1466
|
+
<button id="add-links" class="btn btn-primary w-100" disabled>添加外链到当前合集</button>
|
|
1449
1467
|
</div>
|
|
1450
1468
|
</div>
|
|
1451
1469
|
</div>
|
|
1452
1470
|
|
|
1453
1471
|
<div class="sub-card mt-3">
|
|
1454
|
-
<div class="section-title mb-2"
|
|
1472
|
+
<div class="section-title mb-2">本地图片</div>
|
|
1455
1473
|
<div id="images-grid" class="image-grid"></div>
|
|
1456
|
-
<div id="images-empty" class="empty-tip mt-2"
|
|
1474
|
+
<div id="images-empty" class="empty-tip mt-2">暂无本地图片</div>
|
|
1457
1475
|
</div>
|
|
1458
1476
|
|
|
1459
1477
|
<div class="sub-card mt-3">
|
|
1460
|
-
<div class="section-title mb-2"
|
|
1478
|
+
<div class="section-title mb-2">外链列表</div>
|
|
1461
1479
|
<div id="links-list" class="list-group"></div>
|
|
1462
|
-
<div id="links-empty" class="empty-tip mt-2"
|
|
1463
|
-
</div>
|
|
1464
|
-
</div>
|
|
1465
|
-
|
|
1466
|
-
<div class="main-panel">
|
|
1467
|
-
<h5 class="mb-3">API \u7AEF\u70B9\u7BA1\u7406</h5>
|
|
1468
|
-
|
|
1469
|
-
<div class="row g-2 mb-3">
|
|
1470
|
-
<div class="col-md-3"><input id="endpoint-name" class="form-control" placeholder="name" /></div>
|
|
1471
|
-
<div class="col-md-3"><input id="endpoint-group" class="form-control" placeholder="group" /></div>
|
|
1472
|
-
<div class="col-md-3"><select id="endpoint-method" class="form-select"><option value="redirect">redirect</option><option value="proxy">proxy</option></select></div>
|
|
1473
|
-
<div class="col-md-3"><select id="endpoint-mode" class="form-select"><option value="normal">normal</option><option value="special_forward">special_forward</option><option value="special_pollinations">special_pollinations</option><option value="special_draw_redirect">special_draw_redirect</option></select></div>
|
|
1474
|
-
<div class="col-md-8"><input id="endpoint-url" class="form-control" placeholder="target url" /></div>
|
|
1475
|
-
<div class="col-md-4"><input id="endpoint-model" class="form-control" placeholder="modelName (optional)" /></div>
|
|
1476
|
-
<div class="col-md-6"><textarea id="endpoint-description" class="form-control" rows="2" placeholder="description"></textarea></div>
|
|
1477
|
-
<div class="col-md-3"><textarea id="endpoint-query" class="form-control code-url" rows="2" placeholder='queryParams JSON'></textarea></div>
|
|
1478
|
-
<div class="col-md-3"><textarea id="endpoint-proxy" class="form-control code-url" rows="2" placeholder='proxySettings JSON'></textarea></div>
|
|
1479
|
-
</div>
|
|
1480
|
-
|
|
1481
|
-
<div class="d-flex gap-2 mb-3">
|
|
1482
|
-
<button id="save-endpoint" class="btn btn-primary">\u521B\u5EFA / \u66F4\u65B0\u7AEF\u70B9</button>
|
|
1483
|
-
<button id="reset-endpoint" class="btn btn-outline-secondary">\u6E05\u7A7A\u8868\u5355</button>
|
|
1484
|
-
</div>
|
|
1485
|
-
|
|
1486
|
-
<div class="table-responsive">
|
|
1487
|
-
<table class="table table-sm align-middle">
|
|
1488
|
-
<thead>
|
|
1489
|
-
<tr>
|
|
1490
|
-
<th>name</th>
|
|
1491
|
-
<th>method</th>
|
|
1492
|
-
<th>mode</th>
|
|
1493
|
-
<th>url</th>
|
|
1494
|
-
<th></th>
|
|
1495
|
-
</tr>
|
|
1496
|
-
</thead>
|
|
1497
|
-
<tbody id="endpoint-table"></tbody>
|
|
1498
|
-
</table>
|
|
1480
|
+
<div id="links-empty" class="empty-tip mt-2">暂无外链</div>
|
|
1499
1481
|
</div>
|
|
1500
1482
|
</div>
|
|
1501
1483
|
</div>
|
|
@@ -1526,15 +1508,19 @@ function buildAdminHtml(basePath) {
|
|
|
1526
1508
|
}
|
|
1527
1509
|
|
|
1528
1510
|
async function request(url, options = {}) {
|
|
1511
|
+
console.log('Requesting:', url)
|
|
1529
1512
|
const headers = Object.assign({}, options.headers || {})
|
|
1530
1513
|
if (options.body && !headers['Content-Type']) {
|
|
1531
1514
|
headers['Content-Type'] = 'application/json'
|
|
1532
1515
|
}
|
|
1533
1516
|
const res = await fetch(url, Object.assign({}, options, { headers }))
|
|
1517
|
+
console.log('Response status:', res.status)
|
|
1534
1518
|
let data = null
|
|
1535
1519
|
try {
|
|
1536
1520
|
data = await res.json()
|
|
1537
|
-
|
|
1521
|
+
console.log('Response data:', data)
|
|
1522
|
+
} catch (e) {
|
|
1523
|
+
console.log('JSON parse error:', e)
|
|
1538
1524
|
data = null
|
|
1539
1525
|
}
|
|
1540
1526
|
if (!res.ok) {
|
|
@@ -1554,7 +1540,6 @@ function buildAdminHtml(basePath) {
|
|
|
1554
1540
|
}
|
|
1555
1541
|
|
|
1556
1542
|
renderCollectionList()
|
|
1557
|
-
renderEndpointTable()
|
|
1558
1543
|
await refreshCollectionResources()
|
|
1559
1544
|
syncSelectedCollectionUi()
|
|
1560
1545
|
}
|
|
@@ -1576,7 +1561,7 @@ function buildAdminHtml(basePath) {
|
|
|
1576
1561
|
|
|
1577
1562
|
function syncSelectedCollectionUi() {
|
|
1578
1563
|
const selected = state.selectedCollection
|
|
1579
|
-
byId('selected-collection-badge').textContent = selected || '
|
|
1564
|
+
byId('selected-collection-badge').textContent = selected || '未选择'
|
|
1580
1565
|
byId('delete-collection').disabled = !selected
|
|
1581
1566
|
byId('upload-images').disabled = !selected
|
|
1582
1567
|
byId('add-links').disabled = !selected
|
|
@@ -1594,7 +1579,7 @@ function buildAdminHtml(basePath) {
|
|
|
1594
1579
|
if (!state.collectionNames.length) {
|
|
1595
1580
|
const empty = document.createElement('div')
|
|
1596
1581
|
empty.className = 'text-muted small'
|
|
1597
|
-
empty.textContent = '
|
|
1582
|
+
empty.textContent = '暂无合集'
|
|
1598
1583
|
list.appendChild(empty)
|
|
1599
1584
|
return
|
|
1600
1585
|
}
|
|
@@ -1647,7 +1632,7 @@ function buildAdminHtml(basePath) {
|
|
|
1647
1632
|
const collections = state.collectionNames.filter((item) => item !== state.selectedCollection)
|
|
1648
1633
|
const placeholder = document.createElement('option')
|
|
1649
1634
|
placeholder.value = ''
|
|
1650
|
-
placeholder.textContent = '
|
|
1635
|
+
placeholder.textContent = '移动到...'
|
|
1651
1636
|
moveSelect.appendChild(placeholder)
|
|
1652
1637
|
collections.forEach((target) => {
|
|
1653
1638
|
const opt = document.createElement('option')
|
|
@@ -1658,7 +1643,7 @@ function buildAdminHtml(basePath) {
|
|
|
1658
1643
|
|
|
1659
1644
|
const moveBtn = document.createElement('button')
|
|
1660
1645
|
moveBtn.className = 'btn btn-sm btn-outline-primary'
|
|
1661
|
-
moveBtn.textContent = '
|
|
1646
|
+
moveBtn.textContent = '移动'
|
|
1662
1647
|
moveBtn.disabled = collections.length === 0
|
|
1663
1648
|
moveBtn.addEventListener('click', async () => {
|
|
1664
1649
|
const targetCollection = moveSelect.value
|
|
@@ -1667,19 +1652,19 @@ function buildAdminHtml(basePath) {
|
|
|
1667
1652
|
BASE_PATH + '/api/admin/collections/' + encodeURIComponent(state.selectedCollection) + '/images/' + encodeURIComponent(name) + '/move',
|
|
1668
1653
|
{ method: 'POST', body: JSON.stringify({ targetCollection }) }
|
|
1669
1654
|
)
|
|
1670
|
-
showAlert('
|
|
1655
|
+
showAlert('图片已移动', 'success')
|
|
1671
1656
|
await refreshState()
|
|
1672
1657
|
})
|
|
1673
1658
|
|
|
1674
1659
|
const delBtn = document.createElement('button')
|
|
1675
1660
|
delBtn.className = 'btn btn-sm btn-outline-danger'
|
|
1676
|
-
delBtn.textContent = '
|
|
1661
|
+
delBtn.textContent = '删除'
|
|
1677
1662
|
delBtn.addEventListener('click', async () => {
|
|
1678
1663
|
await request(
|
|
1679
1664
|
BASE_PATH + '/api/admin/collections/' + encodeURIComponent(state.selectedCollection) + '/images/' + encodeURIComponent(name),
|
|
1680
1665
|
{ method: 'DELETE' }
|
|
1681
1666
|
)
|
|
1682
|
-
showAlert('
|
|
1667
|
+
showAlert('图片已删除', 'success')
|
|
1683
1668
|
await refreshCollectionResources()
|
|
1684
1669
|
})
|
|
1685
1670
|
|
|
@@ -1710,19 +1695,19 @@ function buildAdminHtml(basePath) {
|
|
|
1710
1695
|
|
|
1711
1696
|
const open = document.createElement('a')
|
|
1712
1697
|
open.className = 'btn btn-sm btn-outline-primary'
|
|
1713
|
-
open.textContent = '
|
|
1698
|
+
open.textContent = '查看'
|
|
1714
1699
|
open.href = link
|
|
1715
1700
|
open.target = '_blank'
|
|
1716
1701
|
|
|
1717
1702
|
const del = document.createElement('button')
|
|
1718
1703
|
del.className = 'btn btn-sm btn-outline-danger'
|
|
1719
|
-
del.textContent = '
|
|
1704
|
+
del.textContent = '删除'
|
|
1720
1705
|
del.addEventListener('click', async () => {
|
|
1721
1706
|
await request(
|
|
1722
1707
|
BASE_PATH + '/api/admin/collections/' + encodeURIComponent(state.selectedCollection) + '/links',
|
|
1723
1708
|
{ method: 'DELETE', body: JSON.stringify({ link }) }
|
|
1724
1709
|
)
|
|
1725
|
-
showAlert('
|
|
1710
|
+
showAlert('外链已删除', 'success')
|
|
1726
1711
|
await refreshCollectionResources()
|
|
1727
1712
|
})
|
|
1728
1713
|
|
|
@@ -1734,75 +1719,11 @@ function buildAdminHtml(basePath) {
|
|
|
1734
1719
|
})
|
|
1735
1720
|
}
|
|
1736
1721
|
|
|
1737
|
-
function fillEndpointForm(item) {
|
|
1738
|
-
byId('endpoint-name').value = item.name || ''
|
|
1739
|
-
byId('endpoint-group').value = item.group || ''
|
|
1740
|
-
byId('endpoint-method').value = item.method || 'redirect'
|
|
1741
|
-
byId('endpoint-mode').value = item.urlConstruction || 'normal'
|
|
1742
|
-
byId('endpoint-url').value = item.url || ''
|
|
1743
|
-
byId('endpoint-model').value = item.modelName || ''
|
|
1744
|
-
byId('endpoint-description').value = item.description || ''
|
|
1745
|
-
byId('endpoint-query').value = JSON.stringify(item.queryParams || [], null, 2)
|
|
1746
|
-
byId('endpoint-proxy').value = JSON.stringify(item.proxySettings || {}, null, 2)
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
function renderEndpointTable() {
|
|
1750
|
-
const body = byId('endpoint-table')
|
|
1751
|
-
body.textContent = ''
|
|
1752
|
-
if (!state.endpoints.length) {
|
|
1753
|
-
const tr = document.createElement('tr')
|
|
1754
|
-
const td = document.createElement('td')
|
|
1755
|
-
td.colSpan = 5
|
|
1756
|
-
td.className = 'text-muted'
|
|
1757
|
-
td.textContent = '\u6682\u65E0 endpoint'
|
|
1758
|
-
tr.appendChild(td)
|
|
1759
|
-
body.appendChild(tr)
|
|
1760
|
-
return
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
state.endpoints.forEach((item) => {
|
|
1764
|
-
const tr = document.createElement('tr')
|
|
1765
|
-
tr.innerHTML =
|
|
1766
|
-
'<td class="code-url"></td>' +
|
|
1767
|
-
'<td></td>' +
|
|
1768
|
-
'<td class="code-url"></td>' +
|
|
1769
|
-
'<td class="code-url"></td>' +
|
|
1770
|
-
'<td></td>'
|
|
1771
|
-
|
|
1772
|
-
tr.children[0].textContent = item.name || ''
|
|
1773
|
-
tr.children[1].textContent = item.method || 'redirect'
|
|
1774
|
-
tr.children[2].textContent = item.urlConstruction || 'normal'
|
|
1775
|
-
tr.children[3].textContent = item.url || ''
|
|
1776
|
-
|
|
1777
|
-
const actions = document.createElement('div')
|
|
1778
|
-
actions.className = 'd-flex gap-1 justify-content-end'
|
|
1779
|
-
|
|
1780
|
-
const edit = document.createElement('button')
|
|
1781
|
-
edit.className = 'btn btn-sm btn-outline-primary'
|
|
1782
|
-
edit.textContent = '\u7F16\u8F91'
|
|
1783
|
-
edit.addEventListener('click', () => fillEndpointForm(item))
|
|
1784
|
-
|
|
1785
|
-
const del = document.createElement('button')
|
|
1786
|
-
del.className = 'btn btn-sm btn-outline-danger'
|
|
1787
|
-
del.textContent = '\u5220\u9664'
|
|
1788
|
-
del.addEventListener('click', async () => {
|
|
1789
|
-
await request(BASE_PATH + '/api/admin/endpoints/' + encodeURIComponent(item.name || ''), { method: 'DELETE' })
|
|
1790
|
-
showAlert('\u7AEF\u70B9\u5DF2\u5220\u9664', 'success')
|
|
1791
|
-
await refreshState()
|
|
1792
|
-
})
|
|
1793
|
-
|
|
1794
|
-
actions.appendChild(edit)
|
|
1795
|
-
actions.appendChild(del)
|
|
1796
|
-
tr.children[4].appendChild(actions)
|
|
1797
|
-
body.appendChild(tr)
|
|
1798
|
-
})
|
|
1799
|
-
}
|
|
1800
|
-
|
|
1801
1722
|
function readFileAsDataURL(file) {
|
|
1802
1723
|
return new Promise((resolve, reject) => {
|
|
1803
1724
|
const reader = new FileReader()
|
|
1804
1725
|
reader.onload = () => resolve(reader.result)
|
|
1805
|
-
reader.onerror = () => reject(new Error('
|
|
1726
|
+
reader.onerror = () => reject(new Error('读取文件失败'))
|
|
1806
1727
|
reader.readAsDataURL(file)
|
|
1807
1728
|
})
|
|
1808
1729
|
}
|
|
@@ -1815,7 +1736,7 @@ function buildAdminHtml(basePath) {
|
|
|
1815
1736
|
body: JSON.stringify({ name }),
|
|
1816
1737
|
})
|
|
1817
1738
|
byId('new-collection-name').value = ''
|
|
1818
|
-
showAlert('
|
|
1739
|
+
showAlert('合集创建成功', 'success')
|
|
1819
1740
|
await refreshState()
|
|
1820
1741
|
})
|
|
1821
1742
|
|
|
@@ -1824,7 +1745,7 @@ function buildAdminHtml(basePath) {
|
|
|
1824
1745
|
await request(BASE_PATH + '/api/admin/collections/' + encodeURIComponent(state.selectedCollection), {
|
|
1825
1746
|
method: 'DELETE',
|
|
1826
1747
|
})
|
|
1827
|
-
showAlert('
|
|
1748
|
+
showAlert('合集已删除', 'success')
|
|
1828
1749
|
await refreshState()
|
|
1829
1750
|
})
|
|
1830
1751
|
|
|
@@ -1835,7 +1756,7 @@ function buildAdminHtml(basePath) {
|
|
|
1835
1756
|
method: 'PATCH',
|
|
1836
1757
|
body: JSON.stringify({ description }),
|
|
1837
1758
|
})
|
|
1838
|
-
showAlert('
|
|
1759
|
+
showAlert('描述已保存', 'success')
|
|
1839
1760
|
await refreshState()
|
|
1840
1761
|
})
|
|
1841
1762
|
|
|
@@ -1853,7 +1774,7 @@ function buildAdminHtml(basePath) {
|
|
|
1853
1774
|
body: JSON.stringify({ images }),
|
|
1854
1775
|
})
|
|
1855
1776
|
byId('upload-files').value = ''
|
|
1856
|
-
showAlert('
|
|
1777
|
+
showAlert('图片上传成功', 'success')
|
|
1857
1778
|
await refreshCollectionResources()
|
|
1858
1779
|
await refreshState()
|
|
1859
1780
|
})
|
|
@@ -1869,76 +1790,11 @@ function buildAdminHtml(basePath) {
|
|
|
1869
1790
|
body: JSON.stringify({ links }),
|
|
1870
1791
|
})
|
|
1871
1792
|
byId('links-input').value = ''
|
|
1872
|
-
showAlert('
|
|
1793
|
+
showAlert('外链添加成功', 'success')
|
|
1873
1794
|
await refreshCollectionResources()
|
|
1874
1795
|
await refreshState()
|
|
1875
1796
|
})
|
|
1876
1797
|
|
|
1877
|
-
byId('save-endpoint').addEventListener('click', async () => {
|
|
1878
|
-
const name = byId('endpoint-name').value.trim()
|
|
1879
|
-
const url = byId('endpoint-url').value.trim()
|
|
1880
|
-
if (!name || !url) {
|
|
1881
|
-
showAlert('name \u548C url \u5FC5\u586B', 'warning')
|
|
1882
|
-
return
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
let queryParams = []
|
|
1886
|
-
let proxySettings = {}
|
|
1887
|
-
try {
|
|
1888
|
-
queryParams = byId('endpoint-query').value.trim() ? JSON.parse(byId('endpoint-query').value) : []
|
|
1889
|
-
} catch {
|
|
1890
|
-
showAlert('queryParams JSON \u683C\u5F0F\u9519\u8BEF', 'warning')
|
|
1891
|
-
return
|
|
1892
|
-
}
|
|
1893
|
-
try {
|
|
1894
|
-
proxySettings = byId('endpoint-proxy').value.trim() ? JSON.parse(byId('endpoint-proxy').value) : {}
|
|
1895
|
-
} catch {
|
|
1896
|
-
showAlert('proxySettings JSON \u683C\u5F0F\u9519\u8BEF', 'warning')
|
|
1897
|
-
return
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
const payload = {
|
|
1901
|
-
name,
|
|
1902
|
-
group: byId('endpoint-group').value.trim(),
|
|
1903
|
-
description: byId('endpoint-description').value.trim(),
|
|
1904
|
-
url,
|
|
1905
|
-
method: byId('endpoint-method').value,
|
|
1906
|
-
urlConstruction: byId('endpoint-mode').value,
|
|
1907
|
-
modelName: byId('endpoint-model').value.trim(),
|
|
1908
|
-
queryParams,
|
|
1909
|
-
proxySettings,
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
|
-
const exists = state.endpoints.some((item) => item.name === name)
|
|
1913
|
-
if (exists) {
|
|
1914
|
-
await request(BASE_PATH + '/api/admin/endpoints/' + encodeURIComponent(name), {
|
|
1915
|
-
method: 'PATCH',
|
|
1916
|
-
body: JSON.stringify(payload),
|
|
1917
|
-
})
|
|
1918
|
-
showAlert('\u7AEF\u70B9\u5DF2\u66F4\u65B0', 'success')
|
|
1919
|
-
} else {
|
|
1920
|
-
await request(BASE_PATH + '/api/admin/endpoints', {
|
|
1921
|
-
method: 'POST',
|
|
1922
|
-
body: JSON.stringify(payload),
|
|
1923
|
-
})
|
|
1924
|
-
showAlert('\u7AEF\u70B9\u5DF2\u521B\u5EFA', 'success')
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
await refreshState()
|
|
1928
|
-
})
|
|
1929
|
-
|
|
1930
|
-
byId('reset-endpoint').addEventListener('click', () => {
|
|
1931
|
-
byId('endpoint-name').value = ''
|
|
1932
|
-
byId('endpoint-group').value = ''
|
|
1933
|
-
byId('endpoint-method').value = 'redirect'
|
|
1934
|
-
byId('endpoint-mode').value = 'normal'
|
|
1935
|
-
byId('endpoint-url').value = ''
|
|
1936
|
-
byId('endpoint-model').value = ''
|
|
1937
|
-
byId('endpoint-description').value = ''
|
|
1938
|
-
byId('endpoint-query').value = ''
|
|
1939
|
-
byId('endpoint-proxy').value = ''
|
|
1940
|
-
})
|
|
1941
|
-
|
|
1942
1798
|
byId('upload-files').addEventListener('change', () => {
|
|
1943
1799
|
byId('upload-images').disabled = !state.selectedCollection
|
|
1944
1800
|
})
|
|
@@ -1951,13 +1807,14 @@ function buildAdminHtml(basePath) {
|
|
|
1951
1807
|
</body>
|
|
1952
1808
|
</html>`;
|
|
1953
1809
|
}
|
|
1810
|
+
__name(buildAdminHtml, "buildAdminHtml");
|
|
1954
1811
|
function buildAdminEndpointHtml(basePath) {
|
|
1955
1812
|
return `<!doctype html>
|
|
1956
1813
|
<html lang="zh-CN">
|
|
1957
1814
|
<head>
|
|
1958
1815
|
<meta charset="utf-8" />
|
|
1959
1816
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1960
|
-
<title
|
|
1817
|
+
<title>图床转发 - 302 端点管理</title>
|
|
1961
1818
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
1962
1819
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css">
|
|
1963
1820
|
<style>
|
|
@@ -2023,9 +1880,9 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2023
1880
|
</button>
|
|
2024
1881
|
<div class="collapse navbar-collapse" id="navbarNavEndpoint">
|
|
2025
1882
|
<ul class="navbar-nav me-auto">
|
|
2026
|
-
<li class="nav-item"><a class="nav-link" href="${basePath}/"
|
|
2027
|
-
<li class="nav-item"><a class="nav-link" href="${basePath}/admin"
|
|
2028
|
-
<li class="nav-item"><a class="nav-link active" href="${basePath}/admin/endpoint"
|
|
1883
|
+
<li class="nav-item"><a class="nav-link" href="${basePath}/">首页</a></li>
|
|
1884
|
+
<li class="nav-item"><a class="nav-link" href="${basePath}/admin">管理</a></li>
|
|
1885
|
+
<li class="nav-item"><a class="nav-link active" href="${basePath}/admin/endpoint">端点</a></li>
|
|
2029
1886
|
</ul>
|
|
2030
1887
|
</div>
|
|
2031
1888
|
</div>
|
|
@@ -2035,45 +1892,31 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2035
1892
|
<div class="row g-3">
|
|
2036
1893
|
<div class="col-lg-3">
|
|
2037
1894
|
<div class="panel sidebar-panel">
|
|
2038
|
-
<h5 class="mb-3"
|
|
2039
|
-
<input id="endpoint-name" class="form-control mb-2" placeholder="
|
|
2040
|
-
<input id="endpoint-description" class="form-control mb-2" placeholder="
|
|
2041
|
-
<input id="endpoint-url" class="form-control mb-2" placeholder="
|
|
2042
|
-
|
|
2043
|
-
<
|
|
2044
|
-
<
|
|
2045
|
-
<
|
|
2046
|
-
</select>
|
|
2047
|
-
<select id="endpoint-mode" class="form-select mb-2">
|
|
2048
|
-
<option value="normal">normal</option>
|
|
2049
|
-
<option value="special_forward">special_forward</option>
|
|
2050
|
-
<option value="special_pollinations">special_pollinations</option>
|
|
2051
|
-
<option value="special_draw_redirect">special_draw_redirect</option>
|
|
2052
|
-
</select>
|
|
2053
|
-
<input id="endpoint-model" class="form-control mb-2" placeholder="modelName (optional)" />
|
|
2054
|
-
<textarea id="endpoint-query" class="form-control code-text mb-2" rows="3" placeholder='queryParams JSON'></textarea>
|
|
2055
|
-
<textarea id="endpoint-proxy" class="form-control code-text mb-2" rows="3" placeholder='proxySettings JSON'></textarea>
|
|
2056
|
-
|
|
2057
|
-
<div class="d-grid gap-2">
|
|
2058
|
-
<button id="save-endpoint" class="btn btn-primary">\u521B\u5EFA</button>
|
|
2059
|
-
<button id="reset-endpoint" class="btn btn-outline-secondary">\u6E05\u7A7A</button>
|
|
1895
|
+
<h5 class="mb-3">添加 / 编辑端点</h5>
|
|
1896
|
+
<input id="endpoint-name" class="form-control mb-2" placeholder="端点名称" />
|
|
1897
|
+
<input id="endpoint-description" class="form-control mb-2" placeholder="描述" />
|
|
1898
|
+
<input id="endpoint-url" class="form-control mb-2" placeholder="目标 URL" />
|
|
1899
|
+
|
|
1900
|
+
<div class="d-grid gap-2 mt-3">
|
|
1901
|
+
<button id="save-endpoint" class="btn btn-primary">创建</button>
|
|
1902
|
+
<button id="reset-endpoint" class="btn btn-outline-secondary">清空</button>
|
|
2060
1903
|
</div>
|
|
2061
1904
|
</div>
|
|
2062
1905
|
</div>
|
|
2063
1906
|
|
|
2064
1907
|
<div class="col-lg-9">
|
|
2065
1908
|
<div class="panel">
|
|
2066
|
-
<h4 class="mb-3">
|
|
2067
|
-
<p class="text-muted mb-3"
|
|
1909
|
+
<h4 class="mb-3">302 跳转端点管理</h4>
|
|
1910
|
+
<p class="text-muted mb-3">通过 <code>${basePath}/端点名称</code> 访问,自动 302 跳转到目标 URL。</p>
|
|
2068
1911
|
|
|
2069
1912
|
<div class="table-responsive">
|
|
2070
1913
|
<table class="table table-sm align-middle">
|
|
2071
1914
|
<thead>
|
|
2072
1915
|
<tr>
|
|
2073
|
-
<th
|
|
2074
|
-
<th
|
|
2075
|
-
<th
|
|
2076
|
-
<th
|
|
1916
|
+
<th>名称</th>
|
|
1917
|
+
<th>描述</th>
|
|
1918
|
+
<th>目标 URL</th>
|
|
1919
|
+
<th>访问</th>
|
|
2077
1920
|
<th></th>
|
|
2078
1921
|
</tr>
|
|
2079
1922
|
</thead>
|
|
@@ -2088,34 +1931,32 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2088
1931
|
</div>
|
|
2089
1932
|
|
|
2090
1933
|
<script>
|
|
2091
|
-
|
|
2092
|
-
|
|
1934
|
+
var BASE_PATH = '${basePath}'
|
|
1935
|
+
var endpointState = {
|
|
2093
1936
|
endpoints: [],
|
|
2094
1937
|
editingName: '',
|
|
2095
1938
|
}
|
|
2096
1939
|
|
|
2097
|
-
|
|
1940
|
+
var byId = function(id) { return document.getElementById(id) }
|
|
2098
1941
|
|
|
2099
|
-
function showAlert(message, type
|
|
2100
|
-
|
|
1942
|
+
function showAlert(message, type) {
|
|
1943
|
+
type = type || 'info'
|
|
1944
|
+
var el = byId('endpoint-alert')
|
|
2101
1945
|
el.className = 'alert alert-' + type + ' mt-3'
|
|
2102
1946
|
el.textContent = message
|
|
2103
1947
|
el.classList.remove('d-none')
|
|
2104
|
-
setTimeout(()
|
|
1948
|
+
setTimeout(function() { el.classList.add('d-none') }, 2400)
|
|
2105
1949
|
}
|
|
2106
1950
|
|
|
2107
|
-
async function request(url, options
|
|
2108
|
-
|
|
1951
|
+
async function request(url, options) {
|
|
1952
|
+
options = options || {}
|
|
1953
|
+
var headers = Object.assign({}, options.headers || {})
|
|
2109
1954
|
if (options.body && !headers['Content-Type']) {
|
|
2110
1955
|
headers['Content-Type'] = 'application/json'
|
|
2111
1956
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
try {
|
|
2115
|
-
data = await res.json()
|
|
2116
|
-
} catch {
|
|
2117
|
-
data = null
|
|
2118
|
-
}
|
|
1957
|
+
var res = await fetch(url, Object.assign({}, options, { headers: headers }))
|
|
1958
|
+
var data = null
|
|
1959
|
+
try { data = await res.json() } catch(e) { data = null }
|
|
2119
1960
|
if (!res.ok) {
|
|
2120
1961
|
throw new Error(data && data.error ? data.error : String(res.status) + ' ' + String(res.statusText))
|
|
2121
1962
|
}
|
|
@@ -2127,13 +1968,7 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2127
1968
|
byId('endpoint-name').value = ''
|
|
2128
1969
|
byId('endpoint-description').value = ''
|
|
2129
1970
|
byId('endpoint-url').value = ''
|
|
2130
|
-
byId('endpoint
|
|
2131
|
-
byId('endpoint-method').value = 'redirect'
|
|
2132
|
-
byId('endpoint-mode').value = 'normal'
|
|
2133
|
-
byId('endpoint-model').value = ''
|
|
2134
|
-
byId('endpoint-query').value = ''
|
|
2135
|
-
byId('endpoint-proxy').value = ''
|
|
2136
|
-
byId('save-endpoint').textContent = '\u521B\u5EFA'
|
|
1971
|
+
byId('save-endpoint').textContent = '创建'
|
|
2137
1972
|
byId('endpoint-name').disabled = false
|
|
2138
1973
|
}
|
|
2139
1974
|
|
|
@@ -2142,68 +1977,63 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2142
1977
|
byId('endpoint-name').value = item.name || ''
|
|
2143
1978
|
byId('endpoint-description').value = item.description || ''
|
|
2144
1979
|
byId('endpoint-url').value = item.url || ''
|
|
2145
|
-
byId('endpoint
|
|
2146
|
-
byId('endpoint-method').value = item.method || 'redirect'
|
|
2147
|
-
byId('endpoint-mode').value = item.urlConstruction || 'normal'
|
|
2148
|
-
byId('endpoint-model').value = item.modelName || ''
|
|
2149
|
-
byId('endpoint-query').value = JSON.stringify(item.queryParams || [], null, 2)
|
|
2150
|
-
byId('endpoint-proxy').value = JSON.stringify(item.proxySettings || {}, null, 2)
|
|
2151
|
-
byId('save-endpoint').textContent = '\u66F4\u65B0'
|
|
1980
|
+
byId('save-endpoint').textContent = '更新'
|
|
2152
1981
|
byId('endpoint-name').disabled = true
|
|
2153
1982
|
}
|
|
2154
1983
|
|
|
2155
1984
|
function renderTable() {
|
|
2156
|
-
|
|
1985
|
+
var body = byId('endpoint-table')
|
|
2157
1986
|
body.textContent = ''
|
|
2158
1987
|
|
|
2159
1988
|
if (!endpointState.endpoints.length) {
|
|
2160
|
-
|
|
2161
|
-
|
|
1989
|
+
var tr = document.createElement('tr')
|
|
1990
|
+
var td = document.createElement('td')
|
|
2162
1991
|
td.colSpan = 5
|
|
2163
1992
|
td.className = 'text-muted'
|
|
2164
|
-
td.textContent = '
|
|
1993
|
+
td.textContent = '暂无端点'
|
|
2165
1994
|
tr.appendChild(td)
|
|
2166
1995
|
body.appendChild(tr)
|
|
2167
1996
|
return
|
|
2168
1997
|
}
|
|
2169
1998
|
|
|
2170
|
-
endpointState.endpoints.forEach((item)
|
|
2171
|
-
|
|
2172
|
-
|
|
1999
|
+
endpointState.endpoints.forEach(function(item) {
|
|
2000
|
+
var tr = document.createElement('tr')
|
|
2001
|
+
var visitUrl = BASE_PATH + '/' + encodeURIComponent(item.name || '')
|
|
2173
2002
|
|
|
2174
2003
|
tr.innerHTML =
|
|
2175
2004
|
'<td class="code-text"></td>' +
|
|
2176
2005
|
'<td></td>' +
|
|
2177
2006
|
'<td class="code-text"></td>' +
|
|
2178
|
-
'<td
|
|
2007
|
+
'<td></td>' +
|
|
2179
2008
|
'<td></td>'
|
|
2180
2009
|
|
|
2181
|
-
|
|
2182
|
-
link.href = visitUrl
|
|
2183
|
-
link.target = '_blank'
|
|
2184
|
-
link.className = 'text-decoration-none'
|
|
2185
|
-
link.textContent = '/' + (item.name || '')
|
|
2186
|
-
tr.children[0].appendChild(link)
|
|
2010
|
+
tr.children[0].textContent = item.name || ''
|
|
2187
2011
|
tr.children[1].textContent = item.description || '-'
|
|
2188
|
-
tr.children[2].textContent =
|
|
2189
|
-
|
|
2012
|
+
tr.children[2].textContent = item.url || ''
|
|
2013
|
+
|
|
2014
|
+
var visitLink = document.createElement('a')
|
|
2015
|
+
visitLink.href = visitUrl
|
|
2016
|
+
visitLink.target = '_blank'
|
|
2017
|
+
visitLink.className = 'btn btn-sm btn-outline-secondary'
|
|
2018
|
+
visitLink.innerHTML = '<i class="bi bi-box-arrow-up-right"></i>'
|
|
2019
|
+
tr.children[3].appendChild(visitLink)
|
|
2190
2020
|
|
|
2191
|
-
|
|
2021
|
+
var actionWrap = document.createElement('div')
|
|
2192
2022
|
actionWrap.className = 'd-flex gap-1 justify-content-end'
|
|
2193
2023
|
|
|
2194
|
-
|
|
2024
|
+
var editBtn = document.createElement('button')
|
|
2195
2025
|
editBtn.className = 'btn btn-sm btn-outline-primary'
|
|
2196
|
-
editBtn.textContent = '
|
|
2197
|
-
editBtn.addEventListener('click', ()
|
|
2026
|
+
editBtn.textContent = '编辑'
|
|
2027
|
+
editBtn.addEventListener('click', function() { fillForm(item) })
|
|
2198
2028
|
|
|
2199
|
-
|
|
2029
|
+
var delBtn = document.createElement('button')
|
|
2200
2030
|
delBtn.className = 'btn btn-sm btn-outline-danger'
|
|
2201
|
-
delBtn.textContent = '
|
|
2202
|
-
delBtn.addEventListener('click', async ()
|
|
2031
|
+
delBtn.textContent = '删除'
|
|
2032
|
+
delBtn.addEventListener('click', async function() {
|
|
2203
2033
|
await request(BASE_PATH + '/api/admin/endpoints/' + encodeURIComponent(item.name || ''), {
|
|
2204
2034
|
method: 'DELETE',
|
|
2205
2035
|
})
|
|
2206
|
-
showAlert('
|
|
2036
|
+
showAlert('端点已删除', 'success')
|
|
2207
2037
|
await loadEndpoints()
|
|
2208
2038
|
if (endpointState.editingName === item.name) resetForm()
|
|
2209
2039
|
})
|
|
@@ -2216,50 +2046,28 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2216
2046
|
}
|
|
2217
2047
|
|
|
2218
2048
|
async function loadEndpoints() {
|
|
2219
|
-
|
|
2049
|
+
var data = await request(BASE_PATH + '/api/admin/endpoints')
|
|
2220
2050
|
endpointState.endpoints = Array.isArray(data.endpoints) ? data.endpoints : []
|
|
2221
2051
|
renderTable()
|
|
2222
2052
|
}
|
|
2223
2053
|
|
|
2224
|
-
byId('save-endpoint').addEventListener('click', async ()
|
|
2225
|
-
|
|
2226
|
-
|
|
2054
|
+
byId('save-endpoint').addEventListener('click', async function() {
|
|
2055
|
+
var name = byId('endpoint-name').value.trim()
|
|
2056
|
+
var url = byId('endpoint-url').value.trim()
|
|
2227
2057
|
if (!name || !url) {
|
|
2228
|
-
showAlert('
|
|
2229
|
-
return
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
let queryParams = []
|
|
2233
|
-
let proxySettings = {}
|
|
2234
|
-
|
|
2235
|
-
try {
|
|
2236
|
-
queryParams = byId('endpoint-query').value.trim()
|
|
2237
|
-
? JSON.parse(byId('endpoint-query').value)
|
|
2238
|
-
: []
|
|
2239
|
-
} catch {
|
|
2240
|
-
showAlert('queryParams JSON \u683C\u5F0F\u9519\u8BEF', 'warning')
|
|
2058
|
+
showAlert('名称与目标 URL 必填', 'warning')
|
|
2241
2059
|
return
|
|
2242
2060
|
}
|
|
2243
2061
|
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
? JSON.parse(byId('endpoint-proxy').value)
|
|
2247
|
-
: {}
|
|
2248
|
-
} catch {
|
|
2249
|
-
showAlert('proxySettings JSON \u683C\u5F0F\u9519\u8BEF', 'warning')
|
|
2250
|
-
return
|
|
2251
|
-
}
|
|
2252
|
-
|
|
2253
|
-
const payload = {
|
|
2254
|
-
name,
|
|
2062
|
+
var payload = {
|
|
2063
|
+
name: name,
|
|
2255
2064
|
description: byId('endpoint-description').value.trim(),
|
|
2256
|
-
url,
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
proxySettings,
|
|
2065
|
+
url: url,
|
|
2066
|
+
method: 'redirect',
|
|
2067
|
+
urlConstruction: 'normal',
|
|
2068
|
+
modelName: '',
|
|
2069
|
+
queryParams: [],
|
|
2070
|
+
proxySettings: { fallbackAction: 'returnJson' },
|
|
2263
2071
|
}
|
|
2264
2072
|
|
|
2265
2073
|
if (endpointState.editingName) {
|
|
@@ -2267,13 +2075,13 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2267
2075
|
method: 'PATCH',
|
|
2268
2076
|
body: JSON.stringify(payload),
|
|
2269
2077
|
})
|
|
2270
|
-
showAlert('
|
|
2078
|
+
showAlert('端点更新成功', 'success')
|
|
2271
2079
|
} else {
|
|
2272
2080
|
await request(BASE_PATH + '/api/admin/endpoints', {
|
|
2273
2081
|
method: 'POST',
|
|
2274
2082
|
body: JSON.stringify(payload),
|
|
2275
2083
|
})
|
|
2276
|
-
showAlert('
|
|
2084
|
+
showAlert('端点创建成功', 'success')
|
|
2277
2085
|
}
|
|
2278
2086
|
|
|
2279
2087
|
await loadEndpoints()
|
|
@@ -2282,7 +2090,7 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2282
2090
|
|
|
2283
2091
|
byId('reset-endpoint').addEventListener('click', resetForm)
|
|
2284
2092
|
|
|
2285
|
-
loadEndpoints().catch((error)
|
|
2093
|
+
loadEndpoints().catch(function(error) {
|
|
2286
2094
|
showAlert(error instanceof Error ? error.message : String(error), 'danger')
|
|
2287
2095
|
})
|
|
2288
2096
|
</script>
|
|
@@ -2290,23 +2098,25 @@ function buildAdminEndpointHtml(basePath) {
|
|
|
2290
2098
|
</body>
|
|
2291
2099
|
</html>`;
|
|
2292
2100
|
}
|
|
2101
|
+
__name(buildAdminEndpointHtml, "buildAdminEndpointHtml");
|
|
2293
2102
|
async function updateMemesVariable(ctx, config, service) {
|
|
2294
2103
|
const baseUrl = toAbsoluteBaseUrl(ctx, config);
|
|
2295
2104
|
const inventory = await service.buildRouteInventory(config.backendPath);
|
|
2296
|
-
ctx.chatluna.promptRenderer.setVariable("endpoint", inventory || "-
|
|
2297
|
-
const memeslunaText = config.injectVariablesPrompt.replace("{endpoint}", inventory || "-
|
|
2105
|
+
ctx.chatluna.promptRenderer.setVariable("endpoint", inventory || "- 暂无可用路由");
|
|
2106
|
+
const memeslunaText = config.injectVariablesPrompt.replace("{endpoint}", inventory || "- 暂无可用路由").replace("{base_url}", baseUrl);
|
|
2298
2107
|
ctx.chatluna.promptRenderer.setVariable("memesluna", memeslunaText);
|
|
2299
2108
|
}
|
|
2109
|
+
__name(updateMemesVariable, "updateMemesVariable");
|
|
2300
2110
|
function applyConsole(ctx, config, service) {
|
|
2301
2111
|
if (!ctx.console) return;
|
|
2302
2112
|
const consoleService = ctx.console;
|
|
2303
2113
|
const packageBase = import_path2.default.resolve(ctx.baseDir, "node_modules/koishi-plugin-memesluna");
|
|
2304
|
-
const withReady = (handler) => {
|
|
2114
|
+
const withReady = /* @__PURE__ */ __name((handler) => {
|
|
2305
2115
|
return async (...args) => {
|
|
2306
2116
|
await service.ready;
|
|
2307
2117
|
return await handler(...args);
|
|
2308
2118
|
};
|
|
2309
|
-
};
|
|
2119
|
+
}, "withReady");
|
|
2310
2120
|
consoleService.addEntry({
|
|
2311
2121
|
dev: import_path2.default.resolve(packageBase, "client/index.ts"),
|
|
2312
2122
|
prod: import_path2.default.resolve(packageBase, "dist")
|
|
@@ -2397,6 +2207,7 @@ function applyConsole(ctx, config, service) {
|
|
|
2397
2207
|
return `${toAbsoluteBaseUrl(ctx, config)}${config.backendPath}`;
|
|
2398
2208
|
});
|
|
2399
2209
|
}
|
|
2210
|
+
__name(applyConsole, "applyConsole");
|
|
2400
2211
|
function applyServer(ctx, config, service) {
|
|
2401
2212
|
if (!ctx.server) return;
|
|
2402
2213
|
const basePath = config.backendPath;
|
|
@@ -2406,7 +2217,7 @@ function applyServer(ctx, config, service) {
|
|
|
2406
2217
|
const collections = await service.getCollections();
|
|
2407
2218
|
const collectionInfos = await Promise.all(collections.map((name2) => service.getCollectionInfo(name2)));
|
|
2408
2219
|
const inventory = await service.buildRouteInventory(basePath);
|
|
2409
|
-
const llmPrompt = config.injectVariablesPrompt.replace("{endpoint}", inventory || "-
|
|
2220
|
+
const llmPrompt = config.injectVariablesPrompt.replace("{endpoint}", inventory || "- 暂无可用路由").replace("{base_url}", baseUrl);
|
|
2410
2221
|
koa.body = {
|
|
2411
2222
|
llmPrompt,
|
|
2412
2223
|
routeInventory: inventory,
|
|
@@ -2415,7 +2226,9 @@ function applyServer(ctx, config, service) {
|
|
|
2415
2226
|
};
|
|
2416
2227
|
});
|
|
2417
2228
|
ctx.server.get(`${basePath}/api/admin/state`, async (koa) => {
|
|
2418
|
-
|
|
2229
|
+
const state = await buildAdminState(service);
|
|
2230
|
+
console.log("Admin State:", JSON.stringify(state, null, 2));
|
|
2231
|
+
koa.body = state;
|
|
2419
2232
|
});
|
|
2420
2233
|
ctx.server.post(`${basePath}/api/admin/collections`, async (koa) => {
|
|
2421
2234
|
const body = getRequestBody(koa);
|
|
@@ -2577,7 +2390,7 @@ function applyServer(ctx, config, service) {
|
|
|
2577
2390
|
}
|
|
2578
2391
|
const payload = {
|
|
2579
2392
|
name: name2,
|
|
2580
|
-
group: toTrimmedString(body.group) || "
|
|
2393
|
+
group: toTrimmedString(body.group) || "默认分组",
|
|
2581
2394
|
description: toTrimmedString(body.description),
|
|
2582
2395
|
url,
|
|
2583
2396
|
method: normalizeForwardMethod(body.method),
|
|
@@ -2598,7 +2411,7 @@ function applyServer(ctx, config, service) {
|
|
|
2598
2411
|
const currentName = toTrimmedString(koa.params.name);
|
|
2599
2412
|
const body = getRequestBody(koa);
|
|
2600
2413
|
const payload = {};
|
|
2601
|
-
if (body.group !== void 0) payload.group = toTrimmedString(body.group) || "
|
|
2414
|
+
if (body.group !== void 0) payload.group = toTrimmedString(body.group) || "默认分组";
|
|
2602
2415
|
if (body.description !== void 0) payload.description = toTrimmedString(body.description);
|
|
2603
2416
|
if (body.url !== void 0) payload.url = toTrimmedString(body.url);
|
|
2604
2417
|
if (body.method !== void 0) payload.method = normalizeForwardMethod(body.method);
|
|
@@ -2669,6 +2482,7 @@ function applyServer(ctx, config, service) {
|
|
|
2669
2482
|
setKoaResponse(koa, result);
|
|
2670
2483
|
});
|
|
2671
2484
|
}
|
|
2485
|
+
__name(applyServer, "applyServer");
|
|
2672
2486
|
function apply(ctx, config) {
|
|
2673
2487
|
ctx.plugin(MemesLunaService, config);
|
|
2674
2488
|
ctx.inject(["memesluna", "server"], async (ctx2) => {
|
|
@@ -2681,8 +2495,8 @@ function apply(ctx, config) {
|
|
|
2681
2495
|
applyConsole(ctx2, config, service);
|
|
2682
2496
|
});
|
|
2683
2497
|
ctx.inject(["memesluna"], (ctx2) => {
|
|
2684
|
-
const root = ctx2.command("memesluna", "MemesLuna
|
|
2685
|
-
root.subcommand(".list", "
|
|
2498
|
+
const root = ctx2.command("memesluna", "MemesLuna 命令");
|
|
2499
|
+
root.subcommand(".list", "查看当前可用表情路由").action(async () => {
|
|
2686
2500
|
const service = ctx2.memesluna;
|
|
2687
2501
|
await service.ready;
|
|
2688
2502
|
const [collectionNames, endpoints] = await Promise.all([
|
|
@@ -2693,14 +2507,14 @@ function apply(ctx, config) {
|
|
|
2693
2507
|
for (const collectionName of collectionNames) {
|
|
2694
2508
|
const info = await service.getCollectionInfo(collectionName);
|
|
2695
2509
|
if (!info?.hasContent) continue;
|
|
2696
|
-
lines.push(`${collectionName} ${collectionName}
|
|
2510
|
+
lines.push(`${collectionName} ${collectionName}表情包`);
|
|
2697
2511
|
}
|
|
2698
2512
|
for (const endpoint of endpoints) {
|
|
2699
|
-
const endpointLabel = endpoint.description || `${endpoint.name}
|
|
2513
|
+
const endpointLabel = endpoint.description || `${endpoint.name}端点`;
|
|
2700
2514
|
lines.push(`${endpoint.name} ${endpointLabel}`);
|
|
2701
2515
|
}
|
|
2702
2516
|
if (!lines.length) {
|
|
2703
|
-
return "
|
|
2517
|
+
return "暂无可用表情路由";
|
|
2704
2518
|
}
|
|
2705
2519
|
return lines.join("\n");
|
|
2706
2520
|
});
|
|
@@ -2709,9 +2523,9 @@ function apply(ctx, config) {
|
|
|
2709
2523
|
ctx.inject(["memesluna", "chatluna", "server"], async (ctx2) => {
|
|
2710
2524
|
const service = ctx2.memesluna;
|
|
2711
2525
|
await service.ready;
|
|
2712
|
-
const refresh = async () => {
|
|
2526
|
+
const refresh = /* @__PURE__ */ __name(async () => {
|
|
2713
2527
|
await updateMemesVariable(ctx2, config, service);
|
|
2714
|
-
};
|
|
2528
|
+
}, "refresh");
|
|
2715
2529
|
await refresh();
|
|
2716
2530
|
ctx2.setInterval(refresh, config.variableRefreshIntervalMs);
|
|
2717
2531
|
ctx2.effect(() => () => {
|
|
@@ -2722,6 +2536,7 @@ function apply(ctx, config) {
|
|
|
2722
2536
|
});
|
|
2723
2537
|
}
|
|
2724
2538
|
}
|
|
2539
|
+
__name(apply, "apply");
|
|
2725
2540
|
var inject = ["database", "chatluna", "server"];
|
|
2726
2541
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2727
2542
|
0 && (module.exports = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-memesluna",
|
|
3
3
|
"description": "Image Forward service for Koishi with ChatLuna integration",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.6",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -82,4 +82,3 @@
|
|
|
82
82
|
"icon": "mdi:emoticon-outline"
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
|