feat: 支持忽略常见错误的通知 (#719)

This commit is contained in:
ᴀᴍᴛᴏᴀᴇʀ
2026-06-08 18:36:31 +08:00
committed by GitHub
parent 6d8bf14880
commit 116ae79578
8 changed files with 61 additions and 7 deletions
+18 -3
View File
@@ -2,10 +2,14 @@ use thiserror::Error;
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
pub enum BiliError { pub enum BiliError {
#[error("response missing 'code' or 'message' field, full response: {0}")] #[error("response missing 'code' field, full response: {0}")]
InvalidResponse(String), InvalidResponse(String),
#[error("API returned error code {0}, full response: {1}")] #[error("API returned error code {code}, full response: {response}")]
ErrorResponse(i64, String), ErrorResponse {
code: i64,
message: Option<String>,
response: String,
},
#[error("risk control triggered by server, full response: {0}")] #[error("risk control triggered by server, full response: {0}")]
RiskControlOccurred(String), RiskControlOccurred(String),
#[error("invalid HTTP response code {0}, reason: {1}")] #[error("invalid HTTP response code {0}, reason: {1}")]
@@ -21,4 +25,15 @@ impl BiliError {
BiliError::RiskControlOccurred(_) | BiliError::VideoStreamsEmpty | BiliError::InvalidStatusCode(_, _) BiliError::RiskControlOccurred(_) | BiliError::VideoStreamsEmpty | BiliError::InvalidStatusCode(_, _)
) )
} }
pub fn is_common_error(&self) -> bool {
matches!(
self,
BiliError::ErrorResponse {
code: -503,
message,
..
} if message.as_ref().is_some_and(|m| m == "服务暂不可用")
)
}
} }
+9 -1
View File
@@ -60,10 +60,18 @@ impl Validate for serde_json::Value {
let code = self["code"] let code = self["code"]
.as_i64() .as_i64()
.with_context(|| BiliError::InvalidResponse(self.to_string()))?; .with_context(|| BiliError::InvalidResponse(self.to_string()))?;
let message = self["message"].as_str().map(ToOwned::to_owned);
if code == -352 || !self["data"]["v_voucher"].is_null() { if code == -352 || !self["data"]["v_voucher"].is_null() {
bail!(BiliError::RiskControlOccurred(self.to_string())); bail!(BiliError::RiskControlOccurred(self.to_string()));
} }
ensure!(code == 0, BiliError::ErrorResponse(code, self.to_string())); ensure!(
code == 0,
BiliError::ErrorResponse {
code,
message,
response: self.to_string(),
}
);
Ok(self) Ok(self)
} }
} }
+3
View File
@@ -38,6 +38,8 @@ pub struct Config {
pub page_name: String, pub page_name: String,
#[serde(default)] #[serde(default)]
pub notifiers: Option<Arc<Vec<Notifier>>>, pub notifiers: Option<Arc<Vec<Notifier>>>,
#[serde(default)]
pub ignore_common_errors: bool,
#[serde(default = "default_favorite_path")] #[serde(default = "default_favorite_path")]
pub favorite_default_path: String, pub favorite_default_path: String,
#[serde(default = "default_collection_path")] #[serde(default = "default_collection_path")]
@@ -124,6 +126,7 @@ impl Default for Config {
video_name: "{{title}}".to_owned(), video_name: "{{title}}".to_owned(),
page_name: "{{bvid}}".to_owned(), page_name: "{{bvid}}".to_owned(),
notifiers: None, notifiers: None,
ignore_common_errors: false,
favorite_default_path: default_favorite_path(), favorite_default_path: default_favorite_path(),
collection_default_path: default_collection_path(), collection_default_path: default_collection_path(),
submission_default_path: default_submission_path(), submission_default_path: default_submission_path(),
@@ -140,6 +140,7 @@ impl DownloadTaskManager {
&initial_config, &initial_config,
&cx.bili_client, &cx.bili_client,
format!("初始化视频下载任务失败:{:#}", err), format!("初始化视频下载任务失败:{:#}", err),
&err,
); );
None None
} }
@@ -193,6 +194,7 @@ impl DownloadTaskManager {
&initial_config, &initial_config,
&cx.bili_client, &cx.bili_client,
format!("重载视频下载任务失败:{:#}", err), format!("重载视频下载任务失败:{:#}", err),
&err,
); );
None None
} }
@@ -234,6 +236,7 @@ impl DownloadTaskManager {
&config, &config,
&cx.bili_client, &cx.bili_client,
format!("本轮凭据检查与刷新任务执行遇到错误:{:#}", e), format!("本轮凭据检查与刷新任务执行遇到错误:{:#}", e),
&e,
); );
} }
} }
@@ -285,6 +288,7 @@ impl DownloadTaskManager {
&config, &config,
&cx.bili_client, &cx.bili_client,
format!("本轮视频下载任务执行遇到错误:{:#}", e), format!("本轮视频下载任务执行遇到错误:{:#}", e),
&e,
); );
} }
} }
@@ -360,6 +364,7 @@ async fn download_video(
config, config,
&bili_client, &bili_client,
format!("处理 {} 时遇到错误:{:#},跳过该视频源", display_name, e), format!("处理 {} 时遇到错误:{:#},跳过该视频源", display_name, e),
&e,
); );
if let Ok(e) = e.downcast::<BiliError>() if let Ok(e) = e.downcast::<BiliError>()
&& e.is_risk_control_related() && e.is_risk_control_related()
+13 -2
View File
@@ -1,4 +1,6 @@
use crate::bilibili::BiliClient; use anyhow::Error;
use crate::bilibili::{BiliClient, BiliError};
use crate::config::Config; use crate::config::Config;
use crate::notifier::{Message, NotifierAllExt}; use crate::notifier::{Message, NotifierAllExt};
@@ -12,8 +14,17 @@ pub fn notify(config: &Config, bili_client: &BiliClient, msg: impl Into<Message<
} }
} }
pub fn error_and_notify(config: &Config, bili_client: &BiliClient, msg: String) { pub fn error_and_notify(config: &Config, bili_client: &BiliClient, msg: String, error: &Error) {
error!("{msg}"); error!("{msg}");
if config.ignore_common_errors
&& error.chain().any(|cause| {
cause
.downcast_ref::<BiliError>()
.is_some_and(BiliError::is_common_error)
})
{
return;
}
if let Some(notifiers) = &config.notifiers if let Some(notifiers) = &config.notifiers
&& !notifiers.is_empty() && !notifiers.is_empty()
{ {
+1 -1
View File
@@ -140,7 +140,7 @@ pub async fn fetch_video_details(
"获取视频 {} - {} 的详细信息失败,错误为:{:#}", "获取视频 {} - {} 的详细信息失败,错误为:{:#}",
&video_model.bvid, &video_model.name, e &video_model.bvid, &video_model.name, e
); );
if let Some(BiliError::ErrorResponse(-404, _)) = e.downcast_ref::<BiliError>() { if let Some(BiliError::ErrorResponse { code: -404, .. }) = e.downcast_ref::<BiliError>() {
let mut video_active_model: bili_sync_entity::video::ActiveModel = video_model.into(); let mut video_active_model: bili_sync_entity::video::ActiveModel = video_model.into();
video_active_model.valid = Set(false); video_active_model.valid = Set(false);
video_active_model.save(connection).await?; video_active_model.save(connection).await?;
+1
View File
@@ -330,6 +330,7 @@ export interface Config {
video_name: string; video_name: string;
page_name: string; page_name: string;
notifiers: Notifier[] | null; notifiers: Notifier[] | null;
ignore_common_errors: boolean;
favorite_default_path: string; favorite_default_path: string;
collection_default_path: string; collection_default_path: string;
submission_default_path: string; submission_default_path: string;
+11
View File
@@ -792,6 +792,17 @@
<!-- 通知设置 --> <!-- 通知设置 -->
<Tabs.Content value="notifiers" class="mt-6 space-y-6"> <Tabs.Content value="notifiers" class="mt-6 space-y-6">
<div class="space-y-4"> <div class="space-y-4">
<div class="flex items-center justify-between rounded-lg border p-4">
<div class="space-y-1">
<Label for="ignore-common-errors">忽略常见错误</Label>
<p class="text-muted-foreground text-sm">
b 站接口频繁出现 -503
服务暂不可用,在通知器内通知容易刷屏,开启该选项以忽略此错误通知
</p>
</div>
<Switch id="ignore-common-errors" bind:checked={formData.ignore_common_errors} />
</div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<h3 class="text-lg font-semibold">通知器管理</h3> <h3 class="text-lg font-semibold">通知器管理</h3>