1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
2use serde::{ Deserialize, Serialize };
3use serde_json::json;
4#[derive(Debug, Clone, Deserialize, Serialize)]
8pub struct NoteAddResponseData {
9 pub note_id: String,
11}
12
13impl BpiClient {
16 pub async fn note_add(
34 &self,
35 oid: u64,
36 title: &str,
37 summary: &str,
38 content: &str,
39 note_id: Option<&str>,
40 tags: Option<&str>,
41 publish: Option<bool>,
42 auto_comment: Option<bool>
43 ) -> Result<BpiResponse<NoteAddResponseData>, BpiError> {
44 let csrf = self.csrf()?;
45
46 let content = json!([{"insert": content}]);
47
48 let mut form = vec![
49 ("oid", oid.to_string()),
50 ("oid_type", "0".to_string()),
51 ("title", title.to_string()),
52 ("summary", summary.to_string()),
53 ("content", content.to_string()),
54 ("cls", "1".to_string()),
55 ("from", "save".to_string()),
56 ("platform", "web".to_string()),
57 ("csrf", csrf)
58 ];
59
60 if let Some(tags) = tags {
61 form.push(("tags", tags.to_string()));
62 }
63
64 if let Some(note_id) = note_id {
65 form.push(("note_id", note_id.to_string()));
66 }
67
68 if let Some(publish) = publish {
69 form.push(("publish", (if publish { "1" } else { "0" }).to_string()));
70 }
71 if let Some(auto_comment) = auto_comment {
72 form.push(("auto_comment", (if auto_comment { "1" } else { "0" }).to_string()));
73 }
74
75 self.post("https://api.bilibili.com/x/note/add").form(&form).send_bpi("保存视频笔记").await
76 }
77
78 pub async fn note_add_simple(
93 &self,
94 oid: u64,
95 title: &str,
96 summary: &str,
97 content: &str,
98 note_id: Option<&str>
99 ) -> Result<BpiResponse<NoteAddResponseData>, BpiError> {
100 self.note_add(oid, title, summary, content, note_id, None, None, None).await
101 }
102
103 pub async fn note_del(
115 &self,
116 oid: u64,
117 note_id: Option<String>
118 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
119 let csrf = self.csrf()?;
120
121 let mut form = vec![("oid", oid.to_string()), ("csrf", csrf)];
122
123 if let Some(note_id) = note_id {
124 form.push(("note_id", note_id.to_string()));
125 }
126
127 self.post("https://api.bilibili.com/x/note/del").form(&form).send_bpi("删除视频笔记").await
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use tracing::info;
135
136 #[tokio::test]
137 async fn test_note_add_and_del() {
138 let bpi = BpiClient::new();
139 let oid = 464606672;
140 let title = "测试笔记";
141 let summary = "这是个测试摘要";
142 let content =
143 "Lorem Ipsum is simply dummy text \
144 of the printing and typesetting industry. Lorem Ipsum\
145 has been the industry's standard dummy text ever since \
146 the 1500s, when an unknown printer took a galley of type \
147 and scrambled it to make a type specimen book. \
148 It has survived not only five centuries, but also the leap into electronic typesetting, \
149 remaining essentially unchanged. It was popularised \
150 in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, \
151 and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum";
152
153 let add_resp = bpi.note_add(
155 oid,
156 title,
157 summary,
158 content,
159 None,
160 None,
161 Some(false),
162 Some(false)
163 ).await;
164
165 info!("Add note result: {:?}", add_resp);
166 assert!(add_resp.is_ok());
167
168 let note_id = add_resp.unwrap().data.unwrap().note_id;
169 info!("New note ID: {}", note_id);
170
171 tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
172
173 let del_resp = bpi.note_del(oid, Some(note_id)).await;
175 info!("Delete note result: {:?}", del_resp);
176 assert!(del_resp.is_ok());
177 }
178}