use std::{fs::DirEntry, io::{Cursor, Write}, sync::Arc}; use directories::ProjectDirs; use file_format::FileFormat; use iced_video_player::Video; use ::image::{DynamicImage, ImageReader}; use iced::{gradient, widget::container, Color}; use tempfile::NamedTempFile; use crate::{LauncherBackground, PossibleGames}; use super::img_utils::round_image; pub fn get_game_background(game: &PossibleGames) -> LauncherBackground { let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap(); let background_bytes = get_background_file(&proj_dirs, game).unwrap(); let data = Arc::new(background_bytes); let file_format = FileFormat::from_bytes(&*data); if file_format.extension() == "mp4" { let mut temp_file = NamedTempFile::new().unwrap(); temp_file.write_all(&data).unwrap(); let temp_path = temp_file.path().to_str().unwrap().to_string(); match Video::new(url::Url::from_file_path(temp_path).unwrap()) { Ok(mut video) => { video.set_looping(true); LauncherBackground::Video(video) }, Err(err) => { panic!("{:#?}", err) }, } } else { let img = ImageReader::new(Cursor::new(&*data)) .with_guessed_format() .unwrap() .decode() .unwrap(); LauncherBackground::Image(img) } } fn get_background_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Result, std::io::Error> { let game_dir = match game { PossibleGames::WutheringWaves => proj_dirs.data_dir().join("kuro/wuwa"), PossibleGames::ZenlessZoneZero => proj_dirs.data_dir().join("hoyoverse/zzz"), PossibleGames::HonkaiStarRail => proj_dirs.data_dir().join("hoyoverse/hsr"), PossibleGames::GenshinImpact => proj_dirs.data_dir().join("hoyoverse/gi"), }; if !game_dir.exists() { return Err(std::io::Error::new( std::io::ErrorKind::NotFound, format!("Game directory does not exist: {:?}", game_dir) )); } let entries = std::fs::read_dir(&game_dir)?; for entry in entries { let entry = entry?; let file_name = entry.file_name().into_string().unwrap_or_default(); if file_name.starts_with("background_") { return std::fs::read(entry.path()); } } Err(std::io::Error::new( std::io::ErrorKind::NotFound, format!("No background file found in {:?}", game_dir) )) } pub fn get_game_splash_dynamic_image(game: &PossibleGames) -> Option { let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap(); let file_data = get_splash_file(&proj_dirs, game); if let Some(data) = file_data { let data_cursor = Cursor::new(data); Some(ImageReader::new(data_cursor) .with_guessed_format() .unwrap() .decode() .unwrap()) } else {None} } pub fn get_game_icon_dynamic_image(game: &PossibleGames) -> DynamicImage { let proj_dirs = ProjectDirs::from("com", "RabbyDevs", "rr-launcher").unwrap(); let file_data: &[u8] = match game { PossibleGames::WutheringWaves => include_bytes!("../../resources/wutheringwaves-icon.png"), PossibleGames::ZenlessZoneZero => &get_hoyo_game_icon_file(&proj_dirs, game), PossibleGames::HonkaiStarRail => &get_hoyo_game_icon_file(&proj_dirs, game), PossibleGames::GenshinImpact => &get_hoyo_game_icon_file(&proj_dirs, game), }; let data_cursor = Cursor::new(file_data); let img = ImageReader::new(data_cursor) .with_guessed_format() .unwrap() .decode() .unwrap() .resize(128, 128, ::image::imageops::FilterType::Lanczos3); round_image(img) .unwrap() } fn get_hoyo_game_icon_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Vec { let game_abbrevation = match game { PossibleGames::ZenlessZoneZero => "zzz", PossibleGames::HonkaiStarRail => "hsr", PossibleGames::GenshinImpact => "gi", _ => panic!("Wuwa inputted in hoyo only func") }; let data_dir = proj_dirs.data_dir().join(format!("hoyoverse/{}", game_abbrevation)); let icon: Option = { let mut icon = None; for path in data_dir.read_dir().unwrap() { let path = path.unwrap(); if path.file_name().into_string().unwrap().starts_with("icon_") { icon = Some(path); } } icon }; std::fs::read(icon.expect("installation went wrong.").path()).unwrap() } fn get_splash_file(proj_dirs: &ProjectDirs, game: &PossibleGames) -> Option> { let game_path = match game { PossibleGames::ZenlessZoneZero => "hoyoverse/zzz", PossibleGames::HonkaiStarRail => "hoyoverse/hsr", PossibleGames::GenshinImpact => "hoyoverse/gi", PossibleGames::WutheringWaves => "kuro/wuwa" }; let data_dir = proj_dirs.data_dir().join(game_path); let icon: Option = { let mut icon = None; for path in data_dir.read_dir().unwrap() { let path = path.unwrap(); if path.file_name().into_string().unwrap().starts_with("splash_") { icon = Some(path); } } icon }; icon.map(|icon| std::fs::read(icon.path()).unwrap()) } fn rad(deg: f32) -> f32 { deg * std::f32::consts::PI / 180.0 } pub fn style_container(direction: f32, use_gradient: bool) -> container::Style { let angle = rad(direction); let gradient: Option = if use_gradient { Some(gradient::Linear::new(angle) .add_stop(0.0, Color::from_rgba8(0, 0, 0, 0.0)) .add_stop(0.75, Color::from_rgba8(0, 0, 0, 0.75)).into()) } else {None}; container::Style { text_color: Color::from_rgba8(255, 255, 255, 1.0).into(), background: gradient, ..container::Style::default() } }