89 lines
2.4 KiB
Rust
89 lines
2.4 KiB
Rust
use std::{fs, path::Path};
|
|
use image::EncodableLayout;
|
|
use webp::Encoder;
|
|
use axum::Router;
|
|
use tower_http::services::ServeDir;
|
|
|
|
use crate::music::metadata::CoverData;
|
|
|
|
pub fn get_cover_base_path() -> String {
|
|
dotenvy::dotenv().ok();
|
|
|
|
std::env::var("COVER_URL").expect("Error getting cover directory URL")
|
|
}
|
|
|
|
pub fn get_all_cover_hashes() -> Vec<String> {
|
|
let path = get_cover_base_path();
|
|
|
|
let base_path = Path::new(&path);
|
|
|
|
if !base_path.exists() {
|
|
let _ = fs::create_dir_all(base_path);
|
|
}
|
|
|
|
let walkdir = walkdir::WalkDir::new(path).min_depth(1).max_depth(1);
|
|
|
|
let hashes: Vec<String> = walkdir
|
|
.into_iter()
|
|
.map(|e| {
|
|
let entry = e.unwrap();
|
|
|
|
let file_name = entry.file_name().to_str().unwrap();
|
|
|
|
// len - 5 because the file names end with .webp
|
|
let hash = file_name[0..(file_name.len() - 5)].to_string();
|
|
|
|
return hash;
|
|
})
|
|
.collect();
|
|
|
|
hashes
|
|
}
|
|
|
|
pub fn write_cover(hash: &str, cover: &CoverData, base_path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
if cover.mime_type != "image/jpeg"
|
|
&& cover.mime_type != "image/png"
|
|
&& cover.mime_type != "image/webp"
|
|
{
|
|
return Err(format!("Invalid cover MIME type: {}", cover.mime_type).into());
|
|
}
|
|
|
|
let path = Path::new(&base_path).join(format!("{hash}.webp"));
|
|
|
|
let dynamic_image = image::load_from_memory_with_format(
|
|
&cover.bytes,
|
|
match cover.mime_type.as_str() {
|
|
"image/png" => image::ImageFormat::Png,
|
|
"image/jpeg" => image::ImageFormat::Jpeg,
|
|
"image/webp" => image::ImageFormat::WebP,
|
|
_ => panic!("Invalid cover MIME type (this should never happen)"),
|
|
},
|
|
)?;
|
|
|
|
let resized_image = if dynamic_image.width() > 640 || dynamic_image.height() > 640 {
|
|
let a = dynamic_image.resize_to_fill(640, 640, image::imageops::FilterType::Lanczos3);
|
|
drop(dynamic_image);
|
|
a
|
|
} else {
|
|
dynamic_image
|
|
};
|
|
|
|
let webp = Encoder::from_image(&resized_image)?.encode_lossless();
|
|
|
|
fs::write(path, webp.as_bytes())?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn create_cover_server() -> Result<(), Box<dyn std::error::Error>> {
|
|
let path = get_cover_base_path();
|
|
|
|
let service = ServeDir::new(path);
|
|
|
|
let app = Router::new().nest_service("/", service);
|
|
|
|
let listener = tokio::net::TcpListener::bind("[::1]:39994").await?;
|
|
|
|
Ok(axum::serve(listener, app).await?)
|
|
}
|