From 87fb597ba442693f1c7e9a9879ffa03d7cd254e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=80=E1=B4=8D=E1=B4=9B=E1=B4=8F=E1=B4=80=E1=B4=87?= =?UTF-8?q?=CA=80?= Date: Sat, 12 Jul 2025 15:17:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=8F=91=E7=8E=B0=E7=9A=84=E8=8B=A5=E5=B9=B2?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#392)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + Cargo.toml | 1 + crates/bili_sync/Cargo.toml | 1 + crates/bili_sync/src/adapter/collection.rs | 38 +++------------- crates/bili_sync/src/adapter/favorite.rs | 29 +++--------- crates/bili_sync/src/adapter/mod.rs | 44 +++++++++++++------ crates/bili_sync/src/adapter/submission.rs | 28 ++---------- crates/bili_sync/src/adapter/watch_later.rs | 28 ++---------- crates/bili_sync/src/api/routes/mod.rs | 9 +++- .../src/api/routes/video_sources/mod.rs | 1 - crates/bili_sync/src/bilibili/me.rs | 8 ++-- crates/bili_sync/src/database.rs | 3 ++ crates/bili_sync/src/task/video_downloader.rs | 4 +- web/src/lib/ws.ts | 7 ++- 14 files changed, 73 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c81769b..713688c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,6 +482,7 @@ dependencies = [ "assert_matches", "async-stream", "axum", + "base64", "bili_sync_entity", "bili_sync_migration", "built", diff --git a/Cargo.toml b/Cargo.toml index 99f13dc..a9b6571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ async-std = { version = "1.13.1", features = ["attributes", "tokio1"] } async-stream = "0.3.6" async-trait = "0.1.88" axum = { version = "0.8.4", features = ["macros", "ws"] } +base64 = "0.22.1" built = { version = "0.7.7", features = ["git2", "chrono"] } chrono = { version = "0.4.41", features = ["serde"] } clap = { version = "4.5.41", features = ["env", "string"] } diff --git a/crates/bili_sync/Cargo.toml b/crates/bili_sync/Cargo.toml index 4083784..a6ebe12 100644 --- a/crates/bili_sync/Cargo.toml +++ b/crates/bili_sync/Cargo.toml @@ -14,6 +14,7 @@ anyhow = { workspace = true } arc-swap = { workspace = true } async-stream = { workspace = true } axum = { workspace = true } +base64 = { workspace = true } bili_sync_entity = { workspace = true } bili_sync_migration = { workspace = true } chrono = { workspace = true } diff --git a/crates/bili_sync/src/adapter/collection.rs b/crates/bili_sync/src/adapter/collection.rs index f2269ab..26d232d 100644 --- a/crates/bili_sync/src/adapter/collection.rs +++ b/crates/bili_sync/src/adapter/collection.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::Path; use std::pin::Pin; @@ -14,6 +15,10 @@ use crate::adapter::{_ActiveModel, VideoSource, VideoSourceEnum}; use crate::bilibili::{BiliClient, Collection, CollectionItem, CollectionType, VideoInfo}; impl VideoSource for collection::Model { + fn display_name(&self) -> Cow<'static, str> { + format!("{}「{}」", CollectionType::from(self.r#type), self.name).into() + } + fn filter_expr(&self) -> SimpleExpr { video::Column::CollectionId.eq(self.id) } @@ -58,39 +63,6 @@ impl VideoSource for collection::Model { None } - fn log_refresh_video_start(&self) { - info!("开始扫描{}「{}」..", CollectionType::from(self.r#type), self.name); - } - - fn log_refresh_video_end(&self, count: usize) { - info!( - "扫描{}「{}」完成,获取到 {} 条新视频", - CollectionType::from(self.r#type), - self.name, - count, - ); - } - - fn log_fetch_video_start(&self) { - info!( - "开始填充{}「{}」视频详情..", - CollectionType::from(self.r#type), - self.name - ); - } - - fn log_fetch_video_end(&self) { - info!("填充{}「{}」视频详情完成", CollectionType::from(self.r#type), self.name); - } - - fn log_download_video_start(&self) { - info!("开始下载{}「{}」视频..", CollectionType::from(self.r#type), self.name); - } - - fn log_download_video_end(&self) { - info!("下载{}「{}」视频完成", CollectionType::from(self.r#type), self.name); - } - async fn refresh<'a>( self, bili_client: &'a BiliClient, diff --git a/crates/bili_sync/src/adapter/favorite.rs b/crates/bili_sync/src/adapter/favorite.rs index 866f5fa..3bb8162 100644 --- a/crates/bili_sync/src/adapter/favorite.rs +++ b/crates/bili_sync/src/adapter/favorite.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::path::Path; use std::pin::Pin; @@ -13,6 +14,10 @@ use crate::adapter::{_ActiveModel, VideoSource, VideoSourceEnum}; use crate::bilibili::{BiliClient, FavoriteList, VideoInfo}; impl VideoSource for favorite::Model { + fn display_name(&self) -> Cow<'static, str> { + format!("收藏夹「{}」", self.name).into() + } + fn filter_expr(&self) -> SimpleExpr { video::Column::FavoriteId.eq(self.id) } @@ -37,30 +42,6 @@ impl VideoSource for favorite::Model { }) } - fn log_refresh_video_start(&self) { - info!("开始扫描收藏夹「{}」..", self.name); - } - - fn log_refresh_video_end(&self, count: usize) { - info!("扫描收藏夹「{}」完成,获取到 {} 条新视频", self.name, count); - } - - fn log_fetch_video_start(&self) { - info!("开始填充收藏夹「{}」视频详情..", self.name); - } - - fn log_fetch_video_end(&self) { - info!("填充收藏夹「{}」视频详情完成", self.name); - } - - fn log_download_video_start(&self) { - info!("开始下载收藏夹「{}」视频..", self.name); - } - - fn log_download_video_end(&self) { - info!("下载收藏夹「{}」视频完成", self.name); - } - async fn refresh<'a>( self, bili_client: &'a BiliClient, diff --git a/crates/bili_sync/src/adapter/mod.rs b/crates/bili_sync/src/adapter/mod.rs index 6d32d55..63c9ffb 100644 --- a/crates/bili_sync/src/adapter/mod.rs +++ b/crates/bili_sync/src/adapter/mod.rs @@ -3,6 +3,7 @@ mod favorite; mod submission; mod watch_later; +use std::borrow::Cow; use std::path::Path; use std::pin::Pin; @@ -10,6 +11,7 @@ use anyhow::Result; use chrono::Utc; use enum_dispatch::enum_dispatch; use futures::Stream; +use sea_orm::ActiveValue::Set; use sea_orm::DatabaseConnection; use sea_orm::entity::prelude::*; use sea_orm::sea_query::SimpleExpr; @@ -32,6 +34,9 @@ pub enum VideoSourceEnum { #[enum_dispatch(VideoSourceEnum)] pub trait VideoSource { + /// 获取视频源的名称 + fn display_name(&self) -> Cow<'static, str>; + /// 获取特定视频列表的筛选条件 fn filter_expr(&self) -> SimpleExpr; @@ -63,23 +68,29 @@ pub trait VideoSource { video_info.ok() } - /// 开始刷新视频 - fn log_refresh_video_start(&self); + fn log_refresh_video_start(&self) { + info!("开始扫描{}..", self.display_name()); + } - /// 结束刷新视频 - fn log_refresh_video_end(&self, count: usize); + fn log_refresh_video_end(&self, count: usize) { + info!("扫描{}完成,获取到 {} 条新视频", self.display_name(), count); + } - /// 开始填充视频 - fn log_fetch_video_start(&self); + fn log_fetch_video_start(&self) { + info!("开始填充{}视频详情..", self.display_name()); + } - /// 结束填充视频 - fn log_fetch_video_end(&self); + fn log_fetch_video_end(&self) { + info!("填充{}视频详情完成", self.display_name()); + } - /// 开始下载视频 - fn log_download_video_start(&self); + fn log_download_video_start(&self) { + info!("开始下载{}视频..", self.display_name()); + } - /// 结束下载视频 - fn log_download_video_end(&self); + fn log_download_video_end(&self) { + info!("下载{}视频完成", self.display_name()); + } async fn refresh<'a>( self, @@ -110,8 +121,13 @@ impl _ActiveModel { _ActiveModel::Submission(model) => { model.save(connection).await?; } - _ActiveModel::WatchLater(model) => { - model.save(connection).await?; + _ActiveModel::WatchLater(mut model) => { + if model.id.is_not_set() { + model.id = Set(1); + model.insert(connection).await?; + } else { + model.save(connection).await?; + } } } Ok(()) diff --git a/crates/bili_sync/src/adapter/submission.rs b/crates/bili_sync/src/adapter/submission.rs index c588307..8851691 100644 --- a/crates/bili_sync/src/adapter/submission.rs +++ b/crates/bili_sync/src/adapter/submission.rs @@ -13,6 +13,10 @@ use crate::adapter::{_ActiveModel, VideoSource, VideoSourceEnum}; use crate::bilibili::{BiliClient, Submission, VideoInfo}; impl VideoSource for submission::Model { + fn display_name(&self) -> std::borrow::Cow<'static, str> { + format!("「{}」投稿", self.upper_name).into() + } + fn filter_expr(&self) -> SimpleExpr { video::Column::SubmissionId.eq(self.id) } @@ -37,30 +41,6 @@ impl VideoSource for submission::Model { }) } - fn log_refresh_video_start(&self) { - info!("开始扫描「{}」投稿..", self.upper_name); - } - - fn log_refresh_video_end(&self, count: usize) { - info!("扫描「{}」投稿完成,获取到 {} 条新视频", self.upper_name, count,); - } - - fn log_fetch_video_start(&self) { - info!("开始填充「{}」投稿视频详情..", self.upper_name); - } - - fn log_fetch_video_end(&self) { - info!("填充「{}」投稿视频详情完成", self.upper_name); - } - - fn log_download_video_start(&self) { - info!("开始下载「{}」投稿视频..", self.upper_name); - } - - fn log_download_video_end(&self) { - info!("下载「{}」投稿视频完成", self.upper_name); - } - async fn refresh<'a>( self, bili_client: &'a BiliClient, diff --git a/crates/bili_sync/src/adapter/watch_later.rs b/crates/bili_sync/src/adapter/watch_later.rs index fe1d667..93c8e2d 100644 --- a/crates/bili_sync/src/adapter/watch_later.rs +++ b/crates/bili_sync/src/adapter/watch_later.rs @@ -13,6 +13,10 @@ use crate::adapter::{_ActiveModel, VideoSource, VideoSourceEnum}; use crate::bilibili::{BiliClient, VideoInfo, WatchLater}; impl VideoSource for watch_later::Model { + fn display_name(&self) -> std::borrow::Cow<'static, str> { + "稍后再看".into() + } + fn filter_expr(&self) -> SimpleExpr { video::Column::WatchLaterId.eq(self.id) } @@ -37,30 +41,6 @@ impl VideoSource for watch_later::Model { }) } - fn log_refresh_video_start(&self) { - info!("开始扫描稍后再看.."); - } - - fn log_refresh_video_end(&self, count: usize) { - info!("扫描稍后再看完成,获取到 {} 条新视频", count); - } - - fn log_fetch_video_start(&self) { - info!("开始填充稍后再看视频详情.."); - } - - fn log_fetch_video_end(&self) { - info!("填充稍后再看视频详情完成"); - } - - fn log_download_video_start(&self) { - info!("开始下载稍后再看视频.."); - } - - fn log_download_video_end(&self) { - info!("下载稍后再看视频完成"); - } - async fn refresh<'a>( self, bili_client: &'a BiliClient, diff --git a/crates/bili_sync/src/api/routes/mod.rs b/crates/bili_sync/src/api/routes/mod.rs index 7355a9c..dd555b9 100644 --- a/crates/bili_sync/src/api/routes/mod.rs +++ b/crates/bili_sync/src/api/routes/mod.rs @@ -8,6 +8,8 @@ use axum::middleware::Next; use axum::response::{IntoResponse, Response}; use axum::routing::get; use axum::{Router, middleware}; +use base64::Engine; +use base64::prelude::BASE64_URL_SAFE_NO_PAD; use reqwest::{Method, StatusCode, header}; use super::request::ImageProxyParams; @@ -43,10 +45,13 @@ pub async fn auth(headers: HeaderMap, request: Request, next: Next) -> Result Me<'a> { } pub async fn get_created_favorites(&self) -> Result>> { + ensure!(!self.mid.is_empty(), "未获取到用户 ID,请确保填写设置中的 B 站认证信息"); let mut resp = self .client .request(Method::GET, "https://api.bilibili.com/x/v3/fav/folder/created/list-all") @@ -34,6 +33,7 @@ impl<'a> Me<'a> { } pub async fn get_followed_collections(&self, page_num: i32, page_size: i32) -> Result { + ensure!(!self.mid.is_empty(), "未获取到用户 ID,请确保填写设置中的 B 站认证信息"); let mut resp = self .client .request(Method::GET, "https://api.bilibili.com/x/v3/fav/folder/collected/list") @@ -54,6 +54,7 @@ impl<'a> Me<'a> { } pub async fn get_followed_uppers(&self, page_num: i32, page_size: i32) -> Result { + ensure!(!self.mid.is_empty(), "未获取到用户 ID,请确保填写设置中的 B 站认证信息"); let mut resp = self .client .request(Method::GET, "https://api.bilibili.com/x/relation/followings") @@ -82,7 +83,6 @@ pub struct FavoriteItem { pub title: String, pub media_count: i64, pub id: i64, - pub fid: i64, pub mid: i64, } diff --git a/crates/bili_sync/src/database.rs b/crates/bili_sync/src/database.rs index b525037..f69345b 100644 --- a/crates/bili_sync/src/database.rs +++ b/crates/bili_sync/src/database.rs @@ -26,6 +26,9 @@ async fn migrate_database() -> Result<()> { /// 进行数据库迁移并获取数据库连接,供外部使用 pub async fn setup_database() -> Result { + tokio::fs::create_dir_all(CONFIG_DIR.as_path()) + .await + .context("Failed to create config directory")?; migrate_database().await.context("Failed to migrate database")?; database_connection().await.context("Failed to connect to database") } diff --git a/crates/bili_sync/src/task/video_downloader.rs b/crates/bili_sync/src/task/video_downloader.rs index 9184d60..cd502fc 100644 --- a/crates/bili_sync/src/task/video_downloader.rs +++ b/crates/bili_sync/src/task/video_downloader.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use sea_orm::DatabaseConnection; use tokio::time; +use crate::adapter::VideoSource; use crate::bilibili::{self, BiliClient}; use crate::config::VersionedConfig; use crate::utils::model::get_enabled_video_sources; @@ -48,8 +49,9 @@ pub async fn video_downloader(connection: Arc, bili_client: break 'inner; } for video_source in video_sources { + let display_name = video_source.display_name(); if let Err(e) = process_video_source(video_source, &bili_client, &connection).await { - error!("处理 {} 时遇到错误:{:#},等待下一轮执行", "test", e); + error!("处理 {} 时遇到错误:{:#},等待下一轮执行", display_name, e); } } info!("本轮任务执行完毕,等待下一轮执行"); diff --git a/web/src/lib/ws.ts b/web/src/lib/ws.ts index d0b4d98..500443d 100644 --- a/web/src/lib/ws.ts +++ b/web/src/lib/ws.ts @@ -65,8 +65,11 @@ export class WebSocketManager { try { const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; - this.socket = new WebSocket(`${protocol}${window.location.host}/api/ws`, [token]); - + // 使用 base64URL no padding 编码 token 以避免特殊字符问题 + this.socket = new WebSocket( + `${protocol}${window.location.host}/api/ws`, + btoa(token).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '') + ); this.socket.onopen = () => { this.connected = true; this.connecting = false;