fix: 修复本地测试发现的若干问题 (#392)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -482,6 +482,7 @@ dependencies = [
|
||||
"assert_matches",
|
||||
"async-stream",
|
||||
"axum",
|
||||
"base64",
|
||||
"bili_sync_entity",
|
||||
"bili_sync_migration",
|
||||
"built",
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<Re
|
||||
let token = config.auth_token.as_str();
|
||||
if headers
|
||||
.get("Authorization")
|
||||
.is_some_and(|v| v.to_str().is_ok_and(|s| s == token))
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.is_some_and(|s| s == token)
|
||||
|| headers
|
||||
.get("Sec-WebSocket-Protocol")
|
||||
.is_some_and(|v| v.to_str().is_ok_and(|s| s == token))
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.and_then(|s| BASE64_URL_SAFE_NO_PAD.decode(s).ok())
|
||||
.is_some_and(|s| s == token.as_bytes())
|
||||
{
|
||||
return Ok(next.run(request).await);
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@ pub async fn update_video_source(
|
||||
} else {
|
||||
// 如果没有记录且 id 为 1,插入一个新的稍后再看记录
|
||||
Some(_ActiveModel::WatchLater(watch_later::ActiveModel {
|
||||
id: Set(1),
|
||||
path: Set(request.path),
|
||||
enabled: Set(request.enabled),
|
||||
..Default::default()
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Result, ensure};
|
||||
use reqwest::Method;
|
||||
|
||||
use crate::bilibili::{BiliClient, Validate};
|
||||
@@ -19,6 +17,7 @@ impl<'a> Me<'a> {
|
||||
}
|
||||
|
||||
pub async fn get_created_favorites(&self) -> Result<Option<Vec<FavoriteItem>>> {
|
||||
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<Collections> {
|
||||
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<FollowedUppers> {
|
||||
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,
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ async fn migrate_database() -> Result<()> {
|
||||
|
||||
/// 进行数据库迁移并获取数据库连接,供外部使用
|
||||
pub async fn setup_database() -> Result<DatabaseConnection> {
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -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<DatabaseConnection>, 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!("本轮任务执行完毕,等待下一轮执行");
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user