Files
groove/src/covers.rs

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?)
}