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