mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-05-09 22:15:58 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4db12b154 | ||
|
|
2ef99a20c9 | ||
|
|
67de151234 | ||
|
|
73f97f937f | ||
|
|
8fee6fb97a | ||
|
|
e5e5b07978 | ||
|
|
cd2bd9cbb3 | ||
|
|
f044b18337 | ||
|
|
d3bfca42f6 | ||
|
|
10ccb47790 |
2
.github/workflows/check.yaml
vendored
2
.github/workflows/check.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- run: rustup toolchain install nightly && rustup default nightly && rustup component add rustfmt clippy
|
||||
- run: rustup default nightly-2024-04-30 && rustup component add rustfmt clippy
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: swatinem/rust-cache@v2
|
||||
|
||||
70
Cargo.lock
generated
70
Cargo.lock
generated
@@ -427,7 +427,6 @@ dependencies = [
|
||||
"cookie 0.18.1",
|
||||
"dirs",
|
||||
"entity",
|
||||
"env_logger",
|
||||
"filenamify",
|
||||
"float-ord",
|
||||
"futures",
|
||||
@@ -450,6 +449,8 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -862,29 +863,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@@ -1366,12 +1344,6 @@ version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.2.0"
|
||||
@@ -1700,6 +1672,16 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.4"
|
||||
@@ -1828,6 +1810,12 @@ dependencies = [
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.0"
|
||||
@@ -3446,6 +3434,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3454,13 +3454,17 @@ version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3552,6 +3556,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.8.1"
|
||||
|
||||
@@ -14,7 +14,6 @@ chrono = { version = "0.4.35", features = ["serde"] }
|
||||
cookie = "0.18.0"
|
||||
dirs = "5.0.1"
|
||||
entity = { path = "entity" }
|
||||
env_logger = "0.11.3"
|
||||
filenamify = "0.1.0"
|
||||
float-ord = "0.3.2"
|
||||
futures = "0.3.30"
|
||||
@@ -49,6 +48,8 @@ strum = { version = "0.26", features = ["derive"] }
|
||||
thiserror = "1.0.58"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
toml = "0.8.12"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["chrono"] }
|
||||
|
||||
[workspace]
|
||||
members = [".", "entity", "migration"]
|
||||
|
||||
@@ -4,15 +4,12 @@ ARG TARGETPLATFORM
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./*-bili-sync-rs ./targets/
|
||||
|
||||
RUN apk update && apk add --no-cache \
|
||||
ca-certificates \
|
||||
tzdata \
|
||||
ffmpeg \
|
||||
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
&& apk del tzdata
|
||||
ffmpeg
|
||||
|
||||
COPY ./*-bili-sync-rs ./targets/
|
||||
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
|
||||
mv ./targets/Linux-x86_64-bili-sync-rs ./bili-sync-rs; \
|
||||
|
||||
@@ -144,6 +144,7 @@ services:
|
||||
restart: unless-stopped
|
||||
network_mode: bridge
|
||||
tty: true # 该选项请仅在日志终端支持彩色输出时启用,否则日志中可能会出现乱码
|
||||
# user: 1000:1000 # 非必需设置项,说明见下
|
||||
hostname: bili-sync-rs
|
||||
container_name: bili-sync-rs
|
||||
volumes:
|
||||
@@ -153,6 +154,9 @@ services:
|
||||
logging:
|
||||
driver: "local"
|
||||
```
|
||||
### user 的设置
|
||||
- 可设置为宿主机适当用户的 uid 及 gid (`$uid:$gid`),使项目下载的文件的所有者与该处设置的用户保持一致,不设置默认为 root
|
||||
- 执行 `id ${user}` 以获得 `user` 用户的 uid 及 gid ,了解更多可参阅 [Docker文档](https://docs.docker.com/engine/reference/run/#user)
|
||||
|
||||
## 路线图
|
||||
|
||||
@@ -177,4 +181,4 @@ services:
|
||||
|
||||
+ [bilibili-API-collect](https://github.com/SocialSisterYi/bilibili-API-collect) B 站的第三方接口文档
|
||||
+ [bilibili-api](https://github.com/Nemo2011/bilibili-api) 使用 Python 调用接口的参考实现
|
||||
+ [danmu2ass](https://github.com/gwy15/danmu2ass) 本项目弹幕下载功能的缝合来源
|
||||
+ [danmu2ass](https://github.com/gwy15/danmu2ass) 本项目弹幕下载功能的缝合来源
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub video_id: i32,
|
||||
pub cid: i32,
|
||||
pub cid: i64,
|
||||
pub pid: i32,
|
||||
pub name: String,
|
||||
pub width: Option<u32>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
use reqwest::{header, Method};
|
||||
|
||||
use crate::bilibili::Credential;
|
||||
@@ -29,7 +29,7 @@ impl Client {
|
||||
.default_headers(headers)
|
||||
.gzip(true)
|
||||
.connect_timeout(std::time::Duration::from_secs(10))
|
||||
.read_timeout(std::time::Duration::from_secs(30))
|
||||
.read_timeout(std::time::Duration::from_secs(10))
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
@@ -85,4 +85,13 @@ impl BiliClient {
|
||||
CONFIG.credential.store(Some(Arc::new(new_credential)));
|
||||
CONFIG.save()
|
||||
}
|
||||
|
||||
/// 检查凭据是否已设置且有效
|
||||
pub async fn is_login(&self) -> Result<()> {
|
||||
let credential = CONFIG.credential.load();
|
||||
let Some(credential) = credential.as_deref() else {
|
||||
bail!("no credential found");
|
||||
};
|
||||
credential.is_login(&self.client).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,24 @@ impl Credential {
|
||||
res["data"]["refresh"].as_bool().ok_or(anyhow!("check refresh failed"))
|
||||
}
|
||||
|
||||
/// 需要使用一个需要鉴权的接口来检查是否登录
|
||||
/// 此处使用查看用户状态数的接口,该接口返回内容少,请求成本低
|
||||
pub async fn is_login(&self, client: &Client) -> Result<()> {
|
||||
client
|
||||
.request(
|
||||
Method::GET,
|
||||
"https://api.bilibili.com/x/web-interface/nav/stat",
|
||||
Some(self),
|
||||
)
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?
|
||||
.json::<serde_json::Value>()
|
||||
.await?
|
||||
.validate()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn refresh(&self, client: &Client) -> Result<Self> {
|
||||
let correspond_path = Self::get_correspond_path();
|
||||
let csrf = self.get_refresh_csrf(client, correspond_path).await?;
|
||||
|
||||
@@ -39,7 +39,7 @@ impl serde::Serialize for Tag {
|
||||
}
|
||||
#[derive(Debug, serde::Deserialize, Default)]
|
||||
pub struct PageInfo {
|
||||
pub cid: i32,
|
||||
pub cid: i64,
|
||||
pub page: i32,
|
||||
#[serde(rename = "part")]
|
||||
pub name: String,
|
||||
@@ -92,7 +92,7 @@ impl<'a> Video<'a> {
|
||||
pub async fn get_danmaku_writer(&self, page: &'a PageInfo) -> Result<DanmakuWriter> {
|
||||
let tasks = FuturesUnordered::new();
|
||||
for i in 1..=(page.duration + 359) / 360 {
|
||||
tasks.push(self.get_danmaku_segment(page, i as i32));
|
||||
tasks.push(self.get_danmaku_segment(page, i as i64));
|
||||
}
|
||||
let result: Vec<Vec<DanmakuElem>> = tasks.try_collect().await?;
|
||||
let mut result: Vec<DanmakuElem> = result.into_iter().flatten().collect();
|
||||
@@ -100,7 +100,7 @@ impl<'a> Video<'a> {
|
||||
Ok(DanmakuWriter::new(page, result.into_iter().map(|x| x.into()).collect()))
|
||||
}
|
||||
|
||||
async fn get_danmaku_segment(&self, page: &PageInfo, segment_idx: i32) -> Result<Vec<DanmakuElem>> {
|
||||
async fn get_danmaku_segment(&self, page: &PageInfo, segment_idx: i64) -> Result<Vec<DanmakuElem>> {
|
||||
let mut res = self
|
||||
.client
|
||||
.request(Method::GET, "http://api.bilibili.com/x/v2/dm/web/seg.so")
|
||||
|
||||
@@ -19,7 +19,7 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| {
|
||||
panic!("加载配置文件失败,错误为: {err}");
|
||||
}
|
||||
warn!("配置文件不存在,使用默认配置...");
|
||||
Config::new()
|
||||
Config::default()
|
||||
});
|
||||
// 放到外面,确保新的配置项被保存
|
||||
info!("配置加载完毕,覆盖刷新原有配置");
|
||||
@@ -44,16 +44,20 @@ pub struct Config {
|
||||
pub page_name: Cow<'static, str>,
|
||||
pub interval: u64,
|
||||
pub upper_path: PathBuf,
|
||||
#[serde(default)]
|
||||
pub nfo_time_type: NFOTimeType,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum NFOTimeType {
|
||||
#[default]
|
||||
FavTime,
|
||||
PubTime,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
credential: ArcSwapOption::from(Some(Arc::new(Credential::default()))),
|
||||
filter_option: FilterOption::default(),
|
||||
@@ -63,9 +67,12 @@ impl Config {
|
||||
page_name: Cow::Borrowed("{{bvid}}"),
|
||||
interval: 1200,
|
||||
upper_path: CONFIG_DIR.join("upper_face"),
|
||||
nfo_time_type: NFOTimeType::FavTime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// 简单的预检查
|
||||
pub fn check(&self) {
|
||||
let mut ok = true;
|
||||
|
||||
@@ -157,8 +157,8 @@ pub async fn download_unprocessed_videos(
|
||||
favorite_model.f_id, favorite_model.name
|
||||
);
|
||||
let unhandled_videos_pages = unhandled_videos_pages(&favorite_model, connection).await?;
|
||||
// 对于视频,允许五个同时下载(视频内还有分页、不同分页还有多种下载任务)
|
||||
let semaphore = Semaphore::new(5);
|
||||
// 对于视频,允许三个同时下载(视频内还有分页、不同分页还有多种下载任务)
|
||||
let semaphore = Semaphore::new(3);
|
||||
let downloader = Downloader::new(bili_client.client.clone());
|
||||
let mut uppers_mutex: HashMap<i64, (Mutex<()>, Mutex<()>)> = HashMap::new();
|
||||
for (video_model, _) in &unhandled_videos_pages {
|
||||
@@ -312,8 +312,8 @@ pub async fn dispatch_download_page(
|
||||
if !should_run {
|
||||
return Ok(());
|
||||
}
|
||||
// 对于视频的分页,允许同时下载三个同时下载(绝大部分是单页视频)
|
||||
let child_semaphore = Semaphore::new(5);
|
||||
// 对于视频的分页,允许两个同时下载(绝大部分是单页视频)
|
||||
let child_semaphore = Semaphore::new(2);
|
||||
let mut tasks = pages
|
||||
.into_iter()
|
||||
.map(|page_model| download_page(bili_client, video_model, page_model, &child_semaphore, downloader))
|
||||
@@ -657,7 +657,11 @@ async fn generate_nfo(serializer: NFOSerializer<'_>, nfo_path: PathBuf) -> Resul
|
||||
if let Some(parent) = nfo_path.parent() {
|
||||
fs::create_dir_all(parent).await?;
|
||||
}
|
||||
fs::write(nfo_path, serializer.generate_nfo().await?.as_bytes()).await?;
|
||||
fs::write(
|
||||
nfo_path,
|
||||
serializer.generate_nfo(&CONFIG.nfo_time_type).await?.as_bytes(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ use serde_json::json;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo};
|
||||
use crate::config::CONFIG;
|
||||
use crate::config::{NFOTimeType, CONFIG};
|
||||
use crate::core::status::Status;
|
||||
|
||||
pub static TEMPLATE: Lazy<handlebars::Handlebars> = Lazy::new(|| {
|
||||
@@ -274,7 +274,7 @@ pub async fn update_pages_model(pages: Vec<page::ActiveModel>, connection: &Data
|
||||
/// serde xml 似乎不太好用,先这么裸着写
|
||||
/// (真是又臭又长啊
|
||||
impl<'a> NFOSerializer<'a> {
|
||||
pub async fn generate_nfo(self) -> Result<String> {
|
||||
pub async fn generate_nfo(self, nfo_time_type: &NFOTimeType) -> Result<String> {
|
||||
let mut buffer = r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
"#
|
||||
.as_bytes()
|
||||
@@ -283,6 +283,10 @@ impl<'a> NFOSerializer<'a> {
|
||||
let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
|
||||
match self {
|
||||
NFOSerializer(ModelWrapper::Video(v), NFOMode::MOVIE) => {
|
||||
let nfo_time = match nfo_time_type {
|
||||
NFOTimeType::FavTime => v.favtime,
|
||||
NFOTimeType::PubTime => v.pubtime,
|
||||
};
|
||||
writer
|
||||
.create_element("movie")
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
@@ -316,7 +320,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("year")
|
||||
.write_text_content_async(BytesText::new(&v.favtime.format("%Y").to_string()))
|
||||
.write_text_content_async(BytesText::new(&nfo_time.format("%Y").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
if let Some(tags) = &v.tags {
|
||||
@@ -337,7 +341,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("aired")
|
||||
.write_text_content_async(BytesText::new(&v.favtime.format("%Y-%m-%d").to_string()))
|
||||
.write_text_content_async(BytesText::new(&nfo_time.format("%Y-%m-%d").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(writer)
|
||||
@@ -346,6 +350,10 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
}
|
||||
NFOSerializer(ModelWrapper::Video(v), NFOMode::TVSHOW) => {
|
||||
let nfo_time = match nfo_time_type {
|
||||
NFOTimeType::FavTime => v.favtime,
|
||||
NFOTimeType::PubTime => v.pubtime,
|
||||
};
|
||||
writer
|
||||
.create_element("tvshow")
|
||||
.write_inner_content_async::<_, _, Error>(|writer| async move {
|
||||
@@ -379,7 +387,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("year")
|
||||
.write_text_content_async(BytesText::new(&v.favtime.format("%Y").to_string()))
|
||||
.write_text_content_async(BytesText::new(&nfo_time.format("%Y").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
if let Some(tags) = &v.tags {
|
||||
@@ -400,7 +408,7 @@ impl<'a> NFOSerializer<'a> {
|
||||
.unwrap();
|
||||
writer
|
||||
.create_element("aired")
|
||||
.write_text_content_async(BytesText::new(&v.favtime.format("%Y-%m-%d").to_string()))
|
||||
.write_text_content_async(BytesText::new(&nfo_time.format("%Y-%m-%d").to_string()))
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(writer)
|
||||
@@ -490,8 +498,8 @@ mod tests {
|
||||
chrono::NaiveTime::from_hms_opt(2, 2, 2).unwrap(),
|
||||
),
|
||||
pubtime: chrono::NaiveDateTime::new(
|
||||
chrono::NaiveDate::from_ymd_opt(2022, 2, 2).unwrap(),
|
||||
chrono::NaiveTime::from_hms_opt(2, 2, 2).unwrap(),
|
||||
chrono::NaiveDate::from_ymd_opt(2033, 3, 3).unwrap(),
|
||||
chrono::NaiveTime::from_hms_opt(3, 3, 3).unwrap(),
|
||||
),
|
||||
bvid: "bvid".to_string(),
|
||||
tags: Some(serde_json::json!(["tag1", "tag2"])),
|
||||
@@ -499,7 +507,7 @@ mod tests {
|
||||
};
|
||||
assert_eq!(
|
||||
NFOSerializer(ModelWrapper::Video(&video), NFOMode::MOVIE)
|
||||
.generate_nfo()
|
||||
.generate_nfo(&NFOTimeType::PubTime)
|
||||
.await
|
||||
.unwrap(),
|
||||
r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
@@ -511,16 +519,16 @@ mod tests {
|
||||
<name>1</name>
|
||||
<role>upper_name</role>
|
||||
</actor>
|
||||
<year>2022</year>
|
||||
<year>2033</year>
|
||||
<genre>tag1</genre>
|
||||
<genre>tag2</genre>
|
||||
<uniqueid type="bilibili">bvid</uniqueid>
|
||||
<aired>2022-02-02</aired>
|
||||
<aired>2033-03-03</aired>
|
||||
</movie>"#,
|
||||
);
|
||||
assert_eq!(
|
||||
NFOSerializer(ModelWrapper::Video(&video), NFOMode::TVSHOW)
|
||||
.generate_nfo()
|
||||
.generate_nfo(&NFOTimeType::FavTime)
|
||||
.await
|
||||
.unwrap(),
|
||||
r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
@@ -541,7 +549,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
NFOSerializer(ModelWrapper::Video(&video), NFOMode::UPPER)
|
||||
.generate_nfo()
|
||||
.generate_nfo(&NFOTimeType::FavTime)
|
||||
.await
|
||||
.unwrap(),
|
||||
r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
@@ -549,7 +557,7 @@ mod tests {
|
||||
<plot/>
|
||||
<outline/>
|
||||
<lockdata>false</lockdata>
|
||||
<dateadded>2022-02-02 02:02:02</dateadded>
|
||||
<dateadded>2033-03-03 03:03:03</dateadded>
|
||||
<title>1</title>
|
||||
<sorttitle>1</sorttitle>
|
||||
</person>"#,
|
||||
@@ -561,7 +569,7 @@ mod tests {
|
||||
};
|
||||
assert_eq!(
|
||||
NFOSerializer(ModelWrapper::Page(&page), NFOMode::EPOSODE)
|
||||
.generate_nfo()
|
||||
.generate_nfo(&NFOTimeType::FavTime)
|
||||
.await
|
||||
.unwrap(),
|
||||
r#"<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
|
||||
@@ -40,6 +40,7 @@ impl Downloader {
|
||||
audio_path.to_str().unwrap(),
|
||||
"-c",
|
||||
"copy",
|
||||
"-y",
|
||||
output_path.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
|
||||
26
src/main.rs
26
src/main.rs
@@ -1,5 +1,5 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate tracing;
|
||||
|
||||
mod bilibili;
|
||||
mod config;
|
||||
@@ -8,8 +8,11 @@ mod database;
|
||||
mod downloader;
|
||||
mod error;
|
||||
|
||||
use env_logger::Env;
|
||||
use std::time::Duration;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::time;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
use crate::bilibili::BiliClient;
|
||||
use crate::config::CONFIG;
|
||||
@@ -18,7 +21,15 @@ use crate::database::{database_connection, migrate_database};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> ! {
|
||||
env_logger::init_from_env(Env::default().default_filter_or("None,bili_sync=info"));
|
||||
let default_log_level = std::env::var("RUST_LOG").unwrap_or("None,bili_sync=info".to_owned());
|
||||
tracing_subscriber::fmt::Subscriber::builder()
|
||||
.with_env_filter(tracing_subscriber::EnvFilter::builder().parse_lossy(default_log_level))
|
||||
.with_timer(tracing_subscriber::fmt::time::ChronoLocal::new(
|
||||
"%Y-%m-%d %H:%M:%S%.3f".to_owned(),
|
||||
))
|
||||
.finish()
|
||||
.try_init()
|
||||
.expect("初始化日志失败");
|
||||
Lazy::force(&SCAN_ONLY);
|
||||
Lazy::force(&CONFIG);
|
||||
let mut anchor = chrono::Local::now().date_naive();
|
||||
@@ -26,10 +37,15 @@ async fn main() -> ! {
|
||||
let connection = database_connection().await.unwrap();
|
||||
migrate_database(&connection).await.unwrap();
|
||||
loop {
|
||||
if let Err(e) = bili_client.is_login().await {
|
||||
error!("检查登录状态时遇到错误:{e},等待下一轮执行");
|
||||
time::sleep(Duration::from_secs(CONFIG.interval)).await;
|
||||
continue;
|
||||
}
|
||||
if anchor != chrono::Local::now().date_naive() {
|
||||
if let Err(e) = bili_client.check_refresh().await {
|
||||
error!("检查刷新 Credential 遇到错误:{e},等待下一轮执行");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(CONFIG.interval)).await;
|
||||
time::sleep(Duration::from_secs(CONFIG.interval)).await;
|
||||
continue;
|
||||
}
|
||||
anchor = chrono::Local::now().date_naive();
|
||||
@@ -41,6 +57,6 @@ async fn main() -> ! {
|
||||
}
|
||||
}
|
||||
info!("所有收藏夹处理完毕,等待下一轮执行");
|
||||
tokio::time::sleep(std::time::Duration::from_secs(CONFIG.interval)).await;
|
||||
time::sleep(Duration::from_secs(CONFIG.interval)).await;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user