mirror of
https://github.com/Xevion/byte-me.git
synced 2025-12-18 06:11:29 -06:00
171 lines
7.3 KiB
Rust
171 lines
7.3 KiB
Rust
use crate::models::MediaType;
|
|
use std::{fs::File, io::Read, path::Path};
|
|
use tracing::{debug, instrument, trace, warn};
|
|
|
|
#[instrument(skip(path), fields(path = %path.display()))]
|
|
pub fn detect_media_type(path: &Path) -> MediaType {
|
|
debug!("Starting media type detection");
|
|
|
|
// First try to detect using infer crate (magic number detection)
|
|
if let Ok(mut file) = File::open(path) {
|
|
let mut buffer = [0; 512];
|
|
if let Ok(bytes_read) = file.read(&mut buffer) {
|
|
trace!(bytes_read = bytes_read, "Read file header for magic number detection");
|
|
|
|
if let Some(kind) = infer::get(&buffer[..bytes_read]) {
|
|
let mime_type = kind.mime_type();
|
|
debug!(mime_type = %mime_type, "Detected MIME type from magic numbers");
|
|
|
|
let media_type = match mime_type {
|
|
// Audio types
|
|
"audio/mpeg" | "audio/mp3" | "audio/m4a" | "audio/ogg" | "audio/x-flac"
|
|
| "audio/x-wav" | "audio/amr" | "audio/aac" | "audio/x-aiff"
|
|
| "audio/x-dsf" | "audio/x-ape" | "audio/midi" => MediaType::Audio,
|
|
|
|
// Video types
|
|
"video/mp4" | "video/x-m4v" | "video/x-matroska" | "video/webm"
|
|
| "video/quicktime" | "video/x-msvideo" | "video/x-ms-wmv" | "video/mpeg"
|
|
| "video/x-flv" => MediaType::Video,
|
|
|
|
// Image types
|
|
"image/jpeg"
|
|
| "image/png"
|
|
| "image/gif"
|
|
| "image/webp"
|
|
| "image/x-canon-cr2"
|
|
| "image/tiff"
|
|
| "image/bmp"
|
|
| "image/heif"
|
|
| "image/avif"
|
|
| "image/vnd.ms-photo"
|
|
| "image/vnd.adobe.photoshop"
|
|
| "image/vnd.microsoft.icon"
|
|
| "image/openraster"
|
|
| "image/vnd.djvu" => MediaType::Image,
|
|
|
|
// Document types
|
|
"application/pdf"
|
|
| "application/rtf"
|
|
| "application/msword"
|
|
| "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
| "application/vnd.ms-excel"
|
|
| "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
| "application/vnd.ms-powerpoint"
|
|
| "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
| "application/vnd.oasis.opendocument.text"
|
|
| "application/vnd.oasis.opendocument.spreadsheet"
|
|
| "application/vnd.oasis.opendocument.presentation" => MediaType::Document,
|
|
|
|
// Archive types
|
|
"application/zip"
|
|
| "application/x-tar"
|
|
| "application/vnd.rar"
|
|
| "application/gzip"
|
|
| "application/x-bzip2"
|
|
| "application/vnd.bzip3"
|
|
| "application/x-7z-compressed"
|
|
| "application/x-xz"
|
|
| "application/x-shockwave-flash"
|
|
| "application/octet-stream"
|
|
| "application/postscript"
|
|
| "application/vnd.sqlite3"
|
|
| "application/x-nintendo-nes-rom"
|
|
| "application/x-google-chrome-extension"
|
|
| "application/vnd.ms-cab-compressed"
|
|
| "application/vnd.debian.binary-package"
|
|
| "application/x-unix-archive"
|
|
| "application/x-compress"
|
|
| "application/x-lzip"
|
|
| "application/x-rpm"
|
|
| "application/dicom"
|
|
| "application/zstd"
|
|
| "application/x-lz4"
|
|
| "application/x-ole-storage"
|
|
| "application/x-cpio"
|
|
| "application/x-par2"
|
|
| "application/epub+zip"
|
|
| "application/x-mobipocket-ebook" => MediaType::Archive,
|
|
|
|
// Executable types
|
|
"application/vnd.microsoft.portable-executable"
|
|
| "application/x-executable"
|
|
| "application/llvm"
|
|
| "application/x-mach-binary"
|
|
| "application/java"
|
|
| "application/vnd.android.dex"
|
|
| "application/vnd.android.dey"
|
|
| "application/x-x509-ca-cert" => MediaType::Executable,
|
|
|
|
// Library types (covered by executable types above, but keeping for clarity)
|
|
_ => MediaType::Unknown,
|
|
};
|
|
|
|
debug!(media_type = ?media_type, "Detected media type from magic numbers");
|
|
return media_type;
|
|
} else {
|
|
debug!("Magic number detection failed, falling back to extension-based detection");
|
|
}
|
|
} else {
|
|
warn!("Failed to read file for magic number detection");
|
|
}
|
|
} else {
|
|
warn!("Failed to open file for magic number detection");
|
|
}
|
|
|
|
// Fallback to extension-based detection
|
|
if let Some(extension) = path.extension() {
|
|
let ext_str = extension.to_str().unwrap_or("").to_lowercase();
|
|
debug!(extension = %ext_str, "Detecting media type from file extension");
|
|
|
|
let media_type = match ext_str.as_str() {
|
|
// Audio extensions
|
|
"mp3" | "wav" | "flac" | "ogg" | "m4a" | "aac" | "wma" | "mid" | "amr" | "aiff"
|
|
| "dsf" | "ape" => MediaType::Audio,
|
|
|
|
// Video extensions
|
|
"mp4" | "mkv" | "webm" | "mov" | "avi" | "wmv" | "mpg" | "flv" | "m4v" => {
|
|
MediaType::Video
|
|
}
|
|
|
|
// Image extensions
|
|
"gif" | "png" | "jpg" | "jpeg" | "bmp" | "tiff" | "webp" | "cr2" | "heif" | "avif"
|
|
| "jxr" | "psd" | "ico" | "ora" | "djvu" => MediaType::Image,
|
|
|
|
// Document extensions
|
|
"txt" | "md" | "pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx" | "odt"
|
|
| "ods" | "odp" | "rtf" => MediaType::Document,
|
|
|
|
// Archive extensions
|
|
"zip" | "rar" | "7z" | "tar" | "gz" | "bz2" | "bz3" | "xz" | "swf" | "sqlite"
|
|
| "nes" | "crx" | "cab" | "deb" | "ar" | "Z" | "lz" | "rpm" | "dcm" | "zst" | "lz4"
|
|
| "cpio" | "par2" | "epub" | "mobi" => MediaType::Archive,
|
|
|
|
// Executable extensions
|
|
"exe" | "dll" | "msi" | "dmg" | "pkg" | "app" | "elf" | "bc" | "mach" | "class"
|
|
| "dex" | "dey" | "der" | "obj" => MediaType::Executable,
|
|
|
|
// Library extensions
|
|
"so" | "dylib" => MediaType::Library,
|
|
|
|
_ => MediaType::Unknown,
|
|
};
|
|
|
|
debug!(media_type = ?media_type, "Detected media type from extension");
|
|
media_type
|
|
} else {
|
|
debug!("No file extension found, returning Unknown");
|
|
MediaType::Unknown
|
|
}
|
|
}
|
|
|
|
#[instrument(skip(media_type))]
|
|
pub fn is_media_file(media_type: &MediaType) -> bool {
|
|
let is_media = matches!(
|
|
media_type,
|
|
MediaType::Audio | MediaType::Video | MediaType::Image
|
|
);
|
|
|
|
debug!(media_type = ?media_type, is_media = is_media, "Checking if file is media type");
|
|
is_media
|
|
}
|