cktool/downloader/
get_posts_from_page.rs1use std::{
2 thread::{self},
3 time::Duration,
4};
5
6use anyhow::{Context, Result};
7use json::JsonValue;
8
9use crate::{declare, request};
10
11use super::Downloader;
12
13impl Downloader {
14 pub async fn get_posts_from_page(&mut self, url: &str) -> Result<Vec<String>> {
22 let mut posts = Vec::new();
23 let mut json_parse_retry = self.retry;
24 let mut http_retry = self.retry;
25 loop {
26 let client = request::new()?;
27 let res = match client.get(url).send().await {
28 Ok(v) => v,
29 Err(_) => {
30 if !http_retry == 0 {
31 http_retry -= 1;
32 thread::sleep(Duration::from_secs(declare::ERROR_REQUEST_DELAY_SEC));
33 continue;
34 }
35 return Err(anyhow::anyhow!(
36 "Failed http request in `get_posts_from_page`"
37 ));
38 }
39 };
40
41 let text = res
42 .text()
43 .await
44 .context("Cannot convert response body to text [res.text()]")?;
45 let obj = match json::parse(&text).context("Cannot parse JSON from response body") {
46 Ok(v) => v,
47 Err(_) => {
48 if json_parse_retry > 0 {
49 json_parse_retry -= 1;
50 thread::sleep(Duration::from_secs(declare::TOO_MANY_REQUESTS_DELAY_SEC));
51 continue;
52 } else {
53 break;
54 }
55 }
56 };
57
58 if self.creator_name.lock().await.is_none()
60 && let Some(creator_name) = obj["user"]["name"].as_str()
61 {
62 *self.creator_name.lock().await = Some(creator_name.to_string());
63 }
64 let mut is_skip = false;
65 if let JsonValue::Array(attachments) = &obj["attachments"] {
67 for atta in attachments {
68 if atta["server"].is_null() || atta["path"].is_null() {
69 is_skip = true;
70 } else {
71 posts.push(format!("{}/data{}", atta["server"], atta["path"]));
72 }
73 }
74 }
75 if let JsonValue::Array(previews) = &obj["previews"] {
77 for preview in previews {
78 if preview["server"].is_null() || preview["path"].is_null() {
80 if is_skip {
81 self.info.lock().await.add_skip_file(url.to_string());
82 }
83 } else {
84 posts.push(format!("{}/data{}", preview["server"], preview["path"]));
85 }
86 }
87 }
88 break;
89 }
90 Ok(posts)
91 }
92}