feat(ClashRuleProvider): bump version to 2.1.5 and support xhttp protocol

This commit is contained in:
wumode
2026-05-02 17:03:31 +08:00
parent 527327c6cb
commit 1ad19a5b23
7 changed files with 103 additions and 20 deletions

View File

@@ -518,12 +518,14 @@
"name": "Clash Rule Provider",
"description": "随时为Clash添加一些额外的规则。",
"labels": "工具",
"version": "2.1.3",
"version": "2.1.5",
"icon": "Mihomo_Meta_A.png",
"author": "wumode",
"level": 1,
"release": true,
"history": {
"v2.1.5": "优化仪表盘连接鉴权;优化订阅更新提示",
"v2.1.4": "支持 xhttp 协议",
"v2.1.3": "修复代理删除问题",
"v2.1.2": "修复规则集序列化错误",
"v2.1.1": "增强数据管理功能",

View File

@@ -36,7 +36,7 @@ class ClashRuleProvider(_PluginBase):
# 插件图标
plugin_icon = "Mihomo_Meta_A.png"
# 插件版本
plugin_version = "2.1.3"
plugin_version = "2.1.5"
# 插件作者
plugin_author = "wumode"
# 作者主页

View File

@@ -15163,7 +15163,7 @@ const _sfc_main$2 = /* @__PURE__ */ _defineComponent$2({
});
if (props.allowRefresh && componentConfig.clash_available) {
evtSource = new EventSource(
"api/v1/plugin/ClashRuleProvider/clash/ws/traffic?secret=" + componentConfig.secret
"api/v1/plugin/ClashRuleProvider/clash/ws/traffic?secret=" + encodeURIComponent(componentConfig.secret)
);
evtSource.addEventListener("traffic", (event) => {
const data = JSON.parse(event.data);
@@ -15177,7 +15177,7 @@ const _sfc_main$2 = /* @__PURE__ */ _defineComponent$2({
}
});
connectionsEvtSource = new EventSource(
"api/v1/plugin/ClashRuleProvider/clash/ws/connections?secret=" + componentConfig.secret
"api/v1/plugin/ClashRuleProvider/clash/ws/connections?secret=" + encodeURIComponent(componentConfig.secret)
);
connectionsEvtSource.addEventListener("connections", (event) => {
const data = JSON.parse(event.data);

View File

@@ -11,21 +11,21 @@
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
}
.subscription-card[data-v-97c0f367] {
.subscription-card[data-v-b5b6e9bb] {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.subscription-card[data-v-97c0f367]:hover {
.subscription-card[data-v-b5b6e9bb]:hover {
transform: translateY(-4px);
box-shadow: 0 4px 25px 0 rgba(0, 0, 0, 0.1);
border-color: rgb(var(--v-theme-primary));
}
.card-header[data-v-97c0f367] {
.card-header[data-v-b5b6e9bb] {
background: rgba(var(--v-theme-surface-variant), 0.05);
}
.bg-surface-variant-lighten[data-v-97c0f367] {
.bg-surface-variant-lighten[data-v-b5b6e9bb] {
background: rgba(var(--v-theme-surface-variant), 0.02);
}
.stats-grid[data-v-97c0f367] {
.stats-grid[data-v-b5b6e9bb] {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;

View File

@@ -10863,14 +10863,22 @@ const _sfc_main$c = /* @__PURE__ */ _defineComponent$c({
loading.value = true;
emit("start-loading");
try {
await props.api.put("plugin/ClashRuleProvider/refresh", {
const result = await props.api.put("plugin/ClashRuleProvider/refresh", {
url: props.url
});
emit("show-snackbar", {
show: true,
message: "订阅更新成功",
color: "success"
});
if (result.success) {
emit("show-snackbar", {
show: true,
message: "订阅更新成功",
color: "success"
});
} else {
emit("show-snackbar", {
show: true,
message: "订阅更新失败",
color: "error"
});
}
emit("refresh", [
"status",
"clash-outbounds",
@@ -10887,6 +10895,7 @@ const _sfc_main$c = /* @__PURE__ */ _defineComponent$c({
}
}
async function toggleSubscription(val) {
if (val === null) return;
emit("start-loading");
try {
await props.api.post("plugin/ClashRuleProvider/subscription-info", {
@@ -11089,7 +11098,7 @@ const _sfc_main$c = /* @__PURE__ */ _defineComponent$c({
}
});
const SubscriptionCard = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-97c0f367"]]);
const SubscriptionCard = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-b5b6e9bb"]]);
const {defineComponent:_defineComponent$b} = await importShared('vue');

View File

@@ -2,14 +2,14 @@ const currentImports = {};
const exportSet = new Set(['Module', '__esModule', 'default', '_export_sfc']);
let moduleMap = {
"./Page":()=>{
dynamicLoadingCss(["__federation_expose_Page-CJILOVp4.css"], false, './Page');
return __federation_import('./__federation_expose_Page-DU-ODF61.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
dynamicLoadingCss(["__federation_expose_Page-BVPPK5SA.css"], false, './Page');
return __federation_import('./__federation_expose_Page-DfFWx370.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
"./Config":()=>{
dynamicLoadingCss(["__federation_expose_Config-CwbjkOP2.css"], false, './Config');
return __federation_import('./__federation_expose_Config-CY46uj5g.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},
"./Dashboard":()=>{
dynamicLoadingCss(["__federation_expose_Dashboard-CFBdUa27.css"], false, './Dashboard');
return __federation_import('./__federation_expose_Dashboard-CybypqLB.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},};
return __federation_import('./__federation_expose_Dashboard-CABqciWS.js').then(module =>Object.keys(module).every(item => exportSet.has(item)) ? () => module.default : () => module)},};
const seen = {};
const dynamicLoadingCss = (cssFilePaths, dontAppendStylesToHead, exposeItemName) => {
const metaUrl = import.meta.url;

View File

@@ -27,9 +27,81 @@ class WsOpts(BaseModel):
v2ray_http_upgrade_fast_open: Optional[bool] = Field(None, alias='v2ray-http-upgrade-fast-open')
class XhttpReuseSettings(BaseModel):
max_concurrency: Optional[str] = Field(None, alias='max-concurrency')
max_connections: Optional[str] = Field(None, alias='max-connections')
c_max_reuse_times: Optional[str] = Field(None, alias='c-max-reuse-times')
h_max_request_times: Optional[str] = Field(None, alias='h-max-request-times')
h_max_reusable_secs: Optional[str] = Field(None, alias='h-max-reusable-secs')
h_keep_alive_period: Optional[int] = Field(None, alias='h-keep-alive-period')
class XhttpDownloadSettings(BaseModel):
# xhttp part
path: Optional[str] = None
host: Optional[str] = None
headers: Optional[Dict[str, str]] = None
no_grpc_header: Optional[bool] = Field(None, alias='no-grpc-header')
x_padding_bytes: Optional[str] = Field(None, alias='x-padding-bytes')
x_padding_obfs_mode: Optional[bool] = Field(None, alias='x-padding-obfs-mode')
x_padding_key: Optional[str] = Field(None, alias='x-padding-key')
x_padding_header: Optional[str] = Field(None, alias='x-padding-header')
x_padding_placement: Optional[str] = Field(None, alias='x-padding-placement')
x_padding_method: Optional[str] = Field(None, alias='x-padding-method')
uplink_http_method: Optional[str] = Field(None, alias='uplink-http-method')
session_placement: Optional[str] = Field(None, alias='session-placement')
session_key: Optional[str] = Field(None, alias='session-key')
seq_placement: Optional[str] = Field(None, alias='seq-placement')
seq_key: Optional[str] = Field(None, alias='seq-key')
uplink_data_placement: Optional[str] = Field(None, alias='uplink-data-placement')
uplink_data_key: Optional[str] = Field(None, alias='uplink-data-key')
uplink_chunk_size: Optional[str] = Field(None, alias='uplink-chunk-size')
sc_max_each_post_bytes: Optional[str] = Field(None, alias='sc-max-each-post-bytes')
sc_min_posts_interval_ms: Optional[str] = Field(None, alias='sc-min-posts-interval-ms')
reuse_settings: Optional[XhttpReuseSettings] = Field(None, alias='reuse-settings')
# proxy part
server: Optional[str] = None
port: Optional[int] = None
tls: Optional[bool] = None
alpn: Optional[List[str]] = None
skip_cert_verify: Optional[bool] = Field(None, alias='skip-cert-verify')
fingerprint: Optional[str] = None
certificate: Optional[str] = None
private_key: Optional[str] = Field(None, alias='private-key')
servername: Optional[str] = None
client_fingerprint: Optional[str] = Field(None, alias='client-fingerprint')
class XhttpOpts(BaseModel):
host: Optional[str] = None
path: str = '/'
mode: Literal["auto", "stream-one", "stream-up", "packet-up"] | None = None
headers: Optional[Dict[str, str]] = None
no_grpc_header: Optional[bool] = Field(None, alias='no-grpc-header')
x_padding_bytes: Optional[str] = Field(None, alias='x-padding-bytes')
x_padding_obfs_mode: Optional[bool] = Field(None, alias='x-padding-obfs-mode')
x_padding_key: Optional[str] = Field(None, alias='x-padding-key')
x_padding_header: Optional[str] = Field(None, alias='x-padding-header')
x_padding_placement: Optional[str] = Field(None, alias='x-padding-placement')
x_padding_method: Optional[str] = Field(None, alias='x-padding-method')
uplink_http_method: Optional[str] = Field(None, alias='uplink-http-method')
session_placement: Optional[str] = Field(None, alias='session-placement')
session_key: Optional[str] = Field(None, alias='session-key')
seq_placement: Optional[str] = Field(None, alias='seq-placement')
seq_key: Optional[str] = Field(None, alias='seq-key')
uplink_data_placement: Optional[str] = Field(None, alias='uplink-data-placement')
uplink_data_key: Optional[str] = Field(None, alias='uplink-data-key')
uplink_chunk_size: Optional[str] = Field(None, alias='uplink-chunk-size')
sc_max_each_post_bytes: Optional[str] = Field(None, alias='sc-max-each-post-bytes')
sc_min_posts_interval_ms: Optional[str] = Field(None, alias='sc-min-posts-interval-ms')
reuse_settings: Optional[XhttpReuseSettings] = Field(None, alias='reuse-settings')
download_settings: Optional[XhttpDownloadSettings] = Field(None, alias='download-settings')
class NetworkMixin(BaseModel):
# Transport settings
network: Optional[Literal['tcp', 'http', 'h2', 'grpc', 'ws', 'kcp']] = None
network: Optional[Literal['tcp', 'http', 'h2', 'grpc', 'ws', 'kcp', 'xhttp']] = None
http_opts: Optional[HttpOpts] = Field(None, alias='http-opts')
h2_opts: Optional[H2Opts] = Field(None, alias='h2-opts')
grpc_opts: Optional[GrpcOpts] = Field(None, alias='grpc-opts')