Skip downloading files with no plugins
Can determine if file contains plugin by recursively walking the file metadata listing until a .esp/.esm/.esl is found.
This commit is contained in:
parent
fd8015024f
commit
93d4bfeca2
11
src/main.rs
11
src/main.rs
@ -189,7 +189,16 @@ pub async fn main() -> Result<()> {
|
||||
)
|
||||
.await?;
|
||||
|
||||
// TODO: check the file metadata to see if there are any plugin files in the archive before bothering to download the file (checking metadata does not count against rate-limit)
|
||||
if let Some(contains_plugin) =
|
||||
nexus_api::metadata::contains_plugin(&client, &api_file).await?
|
||||
{
|
||||
if !contains_plugin {
|
||||
info!("file metadata does not contain a plugin, skip downloading");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
warn!("file has no metadata link");
|
||||
}
|
||||
|
||||
let download_link_resp =
|
||||
nexus_api::download_link::get(&client, db_mod.nexus_mod_id, api_file.file_id)
|
||||
|
@ -20,6 +20,7 @@ pub struct ApiFile<'a> {
|
||||
pub version: Option<&'a str>,
|
||||
pub mod_version: Option<&'a str>,
|
||||
pub size: i64,
|
||||
pub content_preview_link: Option<&'a str>,
|
||||
pub uploaded_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
@ -89,6 +90,10 @@ impl FilesResponse {
|
||||
.get("size_in_bytes")
|
||||
.ok_or_else(|| anyhow!("Missing size_in_bytes key in file in API response"))?
|
||||
.as_i64();
|
||||
let content_preview_link = file
|
||||
.get("content_preview_link")
|
||||
.ok_or_else(|| anyhow!("Missing content_preview_link key in file in API response"))?
|
||||
.as_str();
|
||||
let size = if let Some(size) = size {
|
||||
size
|
||||
} else {
|
||||
@ -120,6 +125,7 @@ impl FilesResponse {
|
||||
version,
|
||||
mod_version,
|
||||
size,
|
||||
content_preview_link,
|
||||
uploaded_at,
|
||||
})
|
||||
})
|
||||
|
64
src/nexus_api/metadata.rs
Normal file
64
src/nexus_api/metadata.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use reqwest::Client;
|
||||
use serde_json::Value;
|
||||
use std::env;
|
||||
use tracing::{info, instrument};
|
||||
|
||||
use super::files::ApiFile;
|
||||
use super::USER_AGENT;
|
||||
|
||||
fn has_plugin(json: &Value) -> Result<bool> {
|
||||
let node_type = json
|
||||
.get("type")
|
||||
.ok_or_else(|| anyhow!("Missing type key in metadata API response"))?
|
||||
.as_str()
|
||||
.ok_or_else(|| anyhow!("type value in metadata is not a string"))?;
|
||||
|
||||
if node_type == "file" {
|
||||
let name = json
|
||||
.get("name")
|
||||
.ok_or_else(|| anyhow!("Missing name key in metadata API response"))?
|
||||
.as_str()
|
||||
.ok_or_else(|| anyhow!("name value in metadata is not a string"))?;
|
||||
|
||||
if name.ends_with(".esp") || name.ends_with(".esm") || name.ends_with(".esl") {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
match json.get("children") {
|
||||
None => Ok(false),
|
||||
Some(children) => {
|
||||
let children = children
|
||||
.as_array()
|
||||
.ok_or_else(|| anyhow!("children value in metadata is not an array"))?;
|
||||
for child in children {
|
||||
if has_plugin(child)? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(client, api_file), fields(metadata_link = api_file.content_preview_link.unwrap_or("null")))]
|
||||
pub async fn contains_plugin(client: &Client, api_file: &ApiFile<'_>) -> Result<Option<bool>> {
|
||||
if let Some(metadata_link) = api_file.content_preview_link {
|
||||
let res = client
|
||||
.get(metadata_link)
|
||||
.header("accept", "application/json")
|
||||
.header("apikey", env::var("NEXUS_API_KEY")?)
|
||||
.header("user-agent", USER_AGENT)
|
||||
.send()
|
||||
.await?
|
||||
.error_for_status()?;
|
||||
|
||||
info!(status = %res.status(), "fetched file metadata from API");
|
||||
let json = res.json::<Value>().await?;
|
||||
|
||||
Ok(Some(has_plugin(&json)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use tracing::info;
|
||||
|
||||
pub mod download_link;
|
||||
pub mod files;
|
||||
pub mod metadata;
|
||||
|
||||
pub static GAME_NAME: &str = "skyrimspecialedition";
|
||||
pub const GAME_ID: u32 = 1704;
|
||||
|
Loading…
Reference in New Issue
Block a user