diff --git a/crates/archivr-core/src/capture.rs b/crates/archivr-core/src/capture.rs index 7edbb1f..8d006c0 100644 --- a/crates/archivr-core/src/capture.rs +++ b/crates/archivr-core/src/capture.rs @@ -23,6 +23,7 @@ pub enum Source { Snapchat, Local, Url, + WebPage, Other, } @@ -88,6 +89,7 @@ fn generate_entry_title(source: Source, meta: &PlatformMetadata) -> String { Source::Snapchat => format!("Snap by {}", meta.author.as_deref().unwrap_or("unknown")), Source::Local => meta.title.clone().unwrap_or_else(|| "Local File".to_string()), Source::Url => meta.title.clone().unwrap_or_else(|| "Downloaded File".to_string()), + Source::WebPage => meta.title.clone().unwrap_or_else(|| "Archived Web Page".to_string()), Source::Other => "Archived Content".to_string(), } } @@ -416,6 +418,7 @@ fn source_metadata(source: Source) -> (&'static str, &'static str, &'static str) Source::Snapchat => ("snapchat", "story", "video"), Source::Local => ("local", "file", "file"), Source::Url => ("web", "file", "file"), + Source::WebPage => ("web", "page", "webpage"), Source::Other => ("other", "unknown", "unknown"), } } @@ -679,7 +682,23 @@ pub fn perform_capture(archive_paths: &ArchivePaths, locator: &str) -> Result source = Source::WebPage, + Ok(downloader::http::UrlKind::File) => {} + Err(e) => return Err(anyhow::anyhow!("Failed to probe URL: {e}")), + } + } + let (source_kind, entity_kind, _) = source_metadata(source); let run = database::create_archive_run(&conn, user_id, 1)?; @@ -762,6 +781,65 @@ pub fn perform_capture(archive_paths: &ArchivePaths, locator: &str) -> Result { + let file_extension = ".html".to_string(); + let temp_file = store_path + .join("temp") + .join(×tamp) + .join(format!("{timestamp}{file_extension}")); + let byte_size = fs::metadata(&temp_file) + .with_context(|| format!("failed to stat staged file {}", temp_file.display()))? + .len() as i64; + + let hash_exists = hash_exists(&hash, &file_extension, store_path)?; + if hash_exists { + let _ = fs::remove_dir_all(store_path.join("temp").join(×tamp)); + } else { + move_temp_to_raw( + &store_path + .join("temp") + .join(×tamp) + .join(format!("{timestamp}{file_extension}")), + &hash, + store_path, + )?; + let _ = fs::remove_dir_all(store_path.join("temp").join(×tamp)); + } + + record_media_entry( + &conn, + store_path, + user_id, + &run, + &item, + locator, + locator, + source, + &hash, + &file_extension, + byte_size, + title_hint, + )?; + database::finish_archive_run(&conn, run.id)?; + return Ok(CaptureResult { + run_uid: run.run_uid.clone(), + status: "completed".to_string(), + }); + } + Err(e) => { + return Err(fail_run( + &conn, + &run, + &item, + &format!("Failed to archive web page: {e}"), + )); + } + } + } + // Sources: Tweets or Twitter Threads if matches!(source, Source::Tweet | Source::TweetThread) { let tweet_id = match tweet_id_from_archive_path(locator) { @@ -1542,4 +1620,31 @@ mod tests { assert_eq!(meta.caption, Some("Hello Rust world, this is a test tweet".to_string())); } } + + #[test] + fn source_metadata_webpage() { + let (kind, entity, _) = source_metadata(Source::WebPage); + assert_eq!(kind, "web"); + assert_eq!(entity, "page"); + } + + #[test] + fn generate_entry_title_webpage_with_title() { + let mut meta = PlatformMetadata::default(); + meta.title = Some("Paul Graham \u{2014} Great Work".to_string()); + assert_eq!( + generate_entry_title(Source::WebPage, &meta), + "Paul Graham \u{2014} Great Work" + ); + } + + #[test] + fn generate_entry_title_webpage_fallback() { + let meta = PlatformMetadata::default(); + assert_eq!( + generate_entry_title(Source::WebPage, &meta), + "Archived Web Page" + ); + } + }