1mod deferred;
19mod encoding;
20mod s3;
21pub mod status;
22mod upload;
23mod url_mapping;
24
25pub use typub_core::AssetStrategy;
31
32pub use deferred::{DeferredAssets, PendingAsset, PendingAssetList, build_pending_asset_list};
34
35pub use encoding::{base64_encode, to_data_uri};
37
38pub use s3::{S3Storage, UploadResult};
40
41pub use url_mapping::{
43 build_image_marker_url_map, build_image_src_url_map, build_preview_file_url_map,
44 key_candidates, resolve_image_reference_url,
45};
46
47pub use upload::{
49 AssetAnalysis, AssetInfo, analyze_assets, build_resolved_url_map, materialize_external_assets,
50 materialize_external_assets_with_status, materialize_with_analysis, upload_pending_assets,
51};
52
53pub use status::{
55 AssetUploadRecord, LifecycleAction, PlatformStatus, PostStatus, PublishResult, StatusDatabase,
56 StatusTracker, determine_lifecycle_action, validate_remote_status,
57};
58
59use std::path::Path;
64
65pub fn replace_asset_placeholders(
80 content: &str,
81 url_map: &std::collections::HashMap<usize, String>,
82) -> String {
83 let mut result = content.to_string();
84
85 for (index, url) in url_map {
86 let placeholder = format!("{{{{ASSET:{}}}}}", index);
87 result = result.replace(&placeholder, url);
88 }
89
90 result
91}
92
93pub fn mime_type_from_path(path: &Path) -> &'static str {
96 mime_guess::from_path(path)
97 .first_raw()
98 .unwrap_or("application/octet-stream")
99}
100
101#[cfg(test)]
106mod tests {
107 #![allow(clippy::expect_used)]
108
109 use super::*;
110
111 #[test]
112 fn test_replace_asset_placeholders_single() {
113 let content = "Here is an image: {{ASSET:0}}";
114 let mut url_map = std::collections::HashMap::new();
115 url_map.insert(0, "https://cdn.example.com/abc123.png".to_string());
116
117 let result = replace_asset_placeholders(content, &url_map);
118 assert_eq!(
119 result,
120 "Here is an image: https://cdn.example.com/abc123.png"
121 );
122 }
123
124 #[test]
125 fn test_replace_asset_placeholders_multiple() {
126 let content = "First: {{ASSET:0}}, Second: {{ASSET:1}}, First again: {{ASSET:0}}";
127 let mut url_map = std::collections::HashMap::new();
128 url_map.insert(0, "https://cdn.example.com/first.png".to_string());
129 url_map.insert(1, "https://cdn.example.com/second.jpg".to_string());
130
131 let result = replace_asset_placeholders(content, &url_map);
132 assert_eq!(
133 result,
134 "First: https://cdn.example.com/first.png, Second: https://cdn.example.com/second.jpg, First again: https://cdn.example.com/first.png"
135 );
136 }
137
138 #[test]
139 fn test_replace_asset_placeholders_missing() {
140 let content = "Here is an image: {{ASSET:99}}";
141 let url_map = std::collections::HashMap::new();
142
143 let result = replace_asset_placeholders(content, &url_map);
144 assert_eq!(result, "Here is an image: {{ASSET:99}}");
145 }
146
147 #[test]
148 fn test_mime_type_from_path() {
149 assert_eq!(mime_type_from_path(Path::new("image.png")), "image/png");
150 assert_eq!(mime_type_from_path(Path::new("photo.JPEG")), "image/jpeg");
151 assert_eq!(mime_type_from_path(Path::new("doc.pdf")), "application/pdf");
152 assert_eq!(
153 mime_type_from_path(Path::new("unknown.unknownext123")),
154 "application/octet-stream"
155 );
156 }
157}