1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
mod prelude {
pub use reqwest::{Client, Response, StatusCode};
pub use serde::de::DeserializeOwned;
pub use std::{future::Future, pin::Pin};
pub use crate::{Error, Result};
pub(super) use super::BiliResponseExt;
pub use super::{Request, RequestResponse};
}
use prelude::*;
#[derive(Debug, Deserialize, Serialize, Clone)]
struct BiliResponse<T> {
code: i64,
#[serde(default)]
message: String,
#[serde(bound(deserialize = "T: serde::Deserialize<'de>"))]
#[serde(default = "Option::default")]
data: Option<T>,
}
impl<T: DeserializeOwned> BiliResponse<T> {
#[allow(unused)]
pub fn into_data(self) -> Option<T> {
self.data
}
pub async fn from_response(response: Response) -> Result<T> {
if response.status() != StatusCode::OK {
return Err(Error::StatusCode(response.status()));
}
let response_text = response.text().await?;
let this: Self = serde_json::from_str(&response_text).map_err(|e| {
debug!("response text = {}", response_text);
e
})?;
if this.code != 0 {
return Err(Error::BiliCustom {
code: this.code,
message: this.message,
});
}
match this.data {
Some(data) => Ok(data),
None => Err(Error::DataNotFound),
}
}
}
pub trait BiliResponseExt<T: DeserializeOwned> {
fn bili_data(self) -> Pin<Box<dyn Future<Output = Result<T>> + Send>>;
}
impl<T: DeserializeOwned> BiliResponseExt<T> for Response {
fn bili_data(self) -> Pin<Box<dyn Future<Output = Result<T>> + Send>> {
Box::pin(async move { BiliResponse::<T>::from_response(self).await })
}
}
pub trait Request: DeserializeOwned {
type Args;
fn request(client: &Client, args: Self::Args) -> RequestResponse<Self>;
}
pub type RequestResponse<T> = Pin<Box<dyn Future<Output = Result<T>> + Send>>;
mod room_info;
pub use room_info::{InfoByRoom, RoomInfo};
mod danmu_info;
pub use danmu_info::{DanmuInfo, DanmuServer};
mod video_info;
pub use video_info::{VideoInfo, VideoStat};
mod login;
pub use login::{CheckQrLogin, QrLoginRequest};
mod uploader_stat;
pub use uploader_stat::UploaderStat;
mod user_info;
pub use user_info::UserInfo;
mod vote_info;
pub use vote_info::VoteInfo;
mod my_account_info;
pub use my_account_info::MyAccountInfo;