mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-05-12 02:21:17 +08:00
Compare commits
3 Commits
feat_skip_
...
feat_custo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eadb1565c3 | ||
|
|
c456cea5bc | ||
|
|
2e49d31b15 |
@@ -1,6 +1,8 @@
|
|||||||
mod info;
|
mod info;
|
||||||
mod message;
|
mod message;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
pub use info::DownloadNotifyInfo;
|
pub use info::DownloadNotifyInfo;
|
||||||
@@ -20,6 +22,8 @@ pub enum Notifier {
|
|||||||
Webhook {
|
Webhook {
|
||||||
url: String,
|
url: String,
|
||||||
template: Option<String>,
|
template: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
headers: Option<HashMap<String, String>>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
// 一个内部辅助字段,用于决定是否强制渲染当前模板,在测试时使用
|
// 一个内部辅助字段,用于决定是否强制渲染当前模板,在测试时使用
|
||||||
ignore_cache: Option<()>,
|
ignore_cache: Option<()>,
|
||||||
@@ -74,6 +78,7 @@ impl Notifier {
|
|||||||
Notifier::Webhook {
|
Notifier::Webhook {
|
||||||
url,
|
url,
|
||||||
template,
|
template,
|
||||||
|
headers,
|
||||||
ignore_cache,
|
ignore_cache,
|
||||||
} => {
|
} => {
|
||||||
let key = webhook_template_key(url);
|
let key = webhook_template_key(url);
|
||||||
@@ -82,12 +87,20 @@ impl Notifier {
|
|||||||
Some(_) => handlebar.render_template(webhook_template_content(template), &message)?,
|
Some(_) => handlebar.render_template(webhook_template_content(template), &message)?,
|
||||||
None => handlebar.render(&key, &message)?,
|
None => handlebar.render(&key, &message)?,
|
||||||
};
|
};
|
||||||
client
|
let mut headers_map = header::HeaderMap::new();
|
||||||
.post(url)
|
headers_map.insert(header::CONTENT_TYPE, "application/json".try_into()?);
|
||||||
.header(header::CONTENT_TYPE, "application/json")
|
|
||||||
.body(payload)
|
if let Some(custom_headers) = headers {
|
||||||
.send()
|
for (key, value) in custom_headers {
|
||||||
.await?;
|
if let (Ok(key), Ok(value)) =
|
||||||
|
(header::HeaderName::try_from(key), header::HeaderValue::try_from(value))
|
||||||
|
{
|
||||||
|
headers_map.insert(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.post(url).headers(headers_map).body(payload).send().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ export interface WebhookNotifier {
|
|||||||
type: 'webhook';
|
type: 'webhook';
|
||||||
url: string;
|
url: string;
|
||||||
template?: string | null;
|
template?: string | null;
|
||||||
|
headers?: Record<string, string> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Notifier = TelegramNotifier | WebhookNotifier;
|
export type Notifier = TelegramNotifier | WebhookNotifier;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import type { Notifier } from '$lib/types';
|
import type { Notifier } from '$lib/types';
|
||||||
|
|
||||||
const jsonExample = '{"text": "您的消息内容"}';
|
|
||||||
|
|
||||||
export let notifier: Notifier | null = null;
|
export let notifier: Notifier | null = null;
|
||||||
export let onSave: (notifier: Notifier) => void;
|
export let onSave: (notifier: Notifier) => void;
|
||||||
export let onCancel: () => void;
|
export let onCancel: () => void;
|
||||||
@@ -16,6 +14,7 @@
|
|||||||
let chatId = '';
|
let chatId = '';
|
||||||
let webhookUrl = '';
|
let webhookUrl = '';
|
||||||
let webhookTemplate = '';
|
let webhookTemplate = '';
|
||||||
|
let webhookHeaders: { key: string; value: string }[] = [];
|
||||||
|
|
||||||
// 初始化表单
|
// 初始化表单
|
||||||
$: {
|
$: {
|
||||||
@@ -28,6 +27,11 @@
|
|||||||
type = 'webhook';
|
type = 'webhook';
|
||||||
webhookUrl = notifier.url;
|
webhookUrl = notifier.url;
|
||||||
webhookTemplate = notifier.template || '';
|
webhookTemplate = notifier.template || '';
|
||||||
|
if (notifier.headers) {
|
||||||
|
webhookHeaders = Object.entries(notifier.headers).map(([key, value]) => ({ key, value }));
|
||||||
|
} else {
|
||||||
|
webhookHeaders = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = 'telegram';
|
type = 'telegram';
|
||||||
@@ -35,11 +39,11 @@
|
|||||||
chatId = '';
|
chatId = '';
|
||||||
webhookUrl = '';
|
webhookUrl = '';
|
||||||
webhookTemplate = '';
|
webhookTemplate = '';
|
||||||
|
webhookHeaders = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSave() {
|
function handleSave() {
|
||||||
// 验证表单
|
|
||||||
if (type === 'telegram') {
|
if (type === 'telegram') {
|
||||||
if (!botToken.trim()) {
|
if (!botToken.trim()) {
|
||||||
toast.error('请输入 Bot Token');
|
toast.error('请输入 Bot Token');
|
||||||
@@ -62,7 +66,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简单的 URL 验证
|
|
||||||
try {
|
try {
|
||||||
new URL(webhookUrl.trim());
|
new URL(webhookUrl.trim());
|
||||||
} catch {
|
} catch {
|
||||||
@@ -70,10 +73,20 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {};
|
||||||
|
for (const { key, value } of webhookHeaders) {
|
||||||
|
const trimmedKey = key.trim();
|
||||||
|
const trimmedValue = value.trim();
|
||||||
|
if (trimmedKey && trimmedValue) {
|
||||||
|
headers[trimmedKey] = trimmedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const newNotifier: Notifier = {
|
const newNotifier: Notifier = {
|
||||||
type: 'webhook',
|
type: 'webhook',
|
||||||
url: webhookUrl.trim(),
|
url: webhookUrl.trim(),
|
||||||
template: webhookTemplate.trim() || null
|
template: webhookTemplate.trim() || null,
|
||||||
|
headers: Object.keys(headers).length > 0 ? headers : null
|
||||||
};
|
};
|
||||||
onSave(newNotifier);
|
onSave(newNotifier);
|
||||||
}
|
}
|
||||||
@@ -111,11 +124,7 @@
|
|||||||
{:else if type === 'webhook'}
|
{:else if type === 'webhook'}
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<Label for="webhook-url">Webhook URL</Label>
|
<Label for="webhook-url">Webhook URL</Label>
|
||||||
<Input id="webhook-url" placeholder="https://example.com/webhook" bind:value={webhookUrl} />
|
<Input id="webhook-url" placeholder="请输入 Webhook 地址" bind:value={webhookUrl} />
|
||||||
<p class="text-muted-foreground text-xs">
|
|
||||||
接收通知的 Webhook 地址<br />
|
|
||||||
格式示例:{jsonExample}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<Label for="webhook-template">模板(可选)</Label>
|
<Label for="webhook-template">模板(可选)</Label>
|
||||||
@@ -127,7 +136,48 @@
|
|||||||
></textarea>
|
></textarea>
|
||||||
<p class="text-muted-foreground text-xs">
|
<p class="text-muted-foreground text-xs">
|
||||||
用于渲染 Webhook 的 Handlebars 模板。如果不填写,将使用默认模板。<br />
|
用于渲染 Webhook 的 Handlebars 模板。如果不填写,将使用默认模板。<br />
|
||||||
可用变量:<code class="text-xs">message</code>(通知内容)
|
可用变量:<code class="text-xs">message</code>(通知内容)、<code class="text-xs"
|
||||||
|
>image_url</code
|
||||||
|
>(封面图片地址,无图时为 null)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<Label>自定义请求头(可选)</Label>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onclick={() => (webhookHeaders = [...webhookHeaders, { key: '', value: '' }])}
|
||||||
|
>
|
||||||
|
+ 添加请求头
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{#each webhookHeaders as header, index (index)}
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Input
|
||||||
|
placeholder="Header 名称(例如 Authorization)"
|
||||||
|
bind:value={header.key}
|
||||||
|
class="flex-1"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
placeholder="Header 值"
|
||||||
|
bind:value={header.value}
|
||||||
|
class="flex-1"
|
||||||
|
type={header.key.toLowerCase() === 'authorization' ? 'password' : 'text'}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onclick={() => (webhookHeaders = webhookHeaders.filter((_, i) => i !== index))}
|
||||||
|
class="h-10 px-2"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<p class="text-muted-foreground text-xs">
|
||||||
|
添加自定义请求头,例如:Authorization: Bearer your_token
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user