feat: initial commit
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# End of .gitignore
|
||||
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "bing-wallpaper-downloader"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
winapi = { version = "0.3", features = ["winuser", "winnls"] }
|
||||
log = "0.4"
|
||||
flexi_logger = "0.28"
|
||||
regex = "1.10"
|
||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Bing Wallpaper Downloader
|
||||
|
||||
Ce projet est une application Rust permettant de télécharger le wallpaper Bing du jour en Ultra HD :
|
||||
|
||||
- `src/main.rs` : Ce fichier est le point d'entrée de l'application Rust. Il contient le code principal de l'application.
|
||||
|
||||
- `src/data.rs` : Ce fichier contient les structures de données utiles à l'extraction de l'url de téléchargement du wallpaper.
|
||||
|
||||
- `Cargo.toml` : Ce fichier est le fichier de configuration de Cargo, le gestionnaire de paquets et de construction de Rust. Il spécifie les dépendances du projet et les paramètres de construction.
|
||||
|
||||
## Installation
|
||||
|
||||
Pour installer et exécuter cette application, vous devez avoir Rust et Cargo installés sur votre système. Vous pouvez les installer en suivant les instructions sur le site officiel de Rust (https://www.rust-lang.org/).
|
||||
|
||||
Une fois que vous avez installé Rust et Cargo, vous pouvez vous rendre dans le répertoire du projet et exécuter la commande suivante pour construire et exécuter l'application :
|
||||
|
||||
```
|
||||
cargo run
|
||||
```
|
||||
12
src/data.rs
Normal file
12
src/data.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use serde_derive::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Image {
|
||||
pub startdate: String,
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Data {
|
||||
pub images: Vec<Image>,
|
||||
}
|
||||
132
src/main.rs
Normal file
132
src/main.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
#![windows_subsystem = "windows"]
|
||||
|
||||
use flexi_logger::{Cleanup, Criterion, FileSpec, Logger, Naming, WriteMode};
|
||||
use log::{error, info};
|
||||
use regex::Regex;
|
||||
use reqwest::{self, Url};
|
||||
use serde_json;
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::{
|
||||
env, error::Error, ffi::OsStr, fs::File, io::copy, iter::once, os::windows::ffi::OsStrExt,
|
||||
path::PathBuf,
|
||||
};
|
||||
use winapi::um::winnls::GetUserDefaultLocaleName;
|
||||
use winapi::um::winuser::{SystemParametersInfoW, SPI_SETDESKWALLPAPER};
|
||||
|
||||
mod data;
|
||||
use data::Data;
|
||||
|
||||
/**
|
||||
* Get the locale of the Windows user
|
||||
*/
|
||||
fn get_locale() -> String {
|
||||
let mut buffer = [0u16; 85];
|
||||
unsafe {
|
||||
GetUserDefaultLocaleName(buffer.as_mut_ptr(), buffer.len() as i32);
|
||||
}
|
||||
let os_string = OsString::from_wide(&buffer);
|
||||
let locale: String = os_string.into_string().unwrap();
|
||||
let locale = locale.trim_end_matches('\0');
|
||||
info!("Locale: {}", locale);
|
||||
locale.to_string()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image URL from Bing.com
|
||||
*/
|
||||
async fn get_image_url(locale: &str) -> Result<(Url, String), Box<dyn Error>> {
|
||||
let base_url = "https://www.bing.com";
|
||||
let today_image_url = format!(
|
||||
"{}/HPImageArchive.aspx?format=js&idx=0&n=1&mkt={}",
|
||||
base_url, locale
|
||||
);
|
||||
|
||||
let data: Data = serde_json::from_str(&reqwest::get(&today_image_url).await?.text().await?)?;
|
||||
let url = Url::parse(&format!(
|
||||
"{}{}",
|
||||
base_url,
|
||||
data.images[0].url.replace("_1920x1080", "_UHD")
|
||||
))?;
|
||||
|
||||
info!("Download url: {}", url);
|
||||
|
||||
Ok((url, data.images[0].startdate.clone()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the image from Bing.com
|
||||
*/
|
||||
async fn dowload_image(
|
||||
url: Url,
|
||||
startdate: &str,
|
||||
absolute_path: &PathBuf,
|
||||
) -> Result<PathBuf, Box<dyn Error>> {
|
||||
let file_name = url
|
||||
.query_pairs()
|
||||
.find(|(key, _)| key == "id")
|
||||
.map(|(_, value)| value.into_owned())
|
||||
.unwrap()
|
||||
.replace("OHR.", &format!("{}_", startdate));
|
||||
|
||||
let re = Regex::new(r"_[A-Z]{2}-[A-Z]{2}\d+")?;
|
||||
let image_absolute_path = absolute_path.join(re.replace_all(&file_name, "").to_string());
|
||||
|
||||
info!("Downloading image to: {}", image_absolute_path.display());
|
||||
|
||||
let mut out = File::create(&image_absolute_path)?;
|
||||
let content = reqwest::get(url).await?.bytes().await?;
|
||||
|
||||
copy(&mut content.as_ref(), &mut out)?;
|
||||
|
||||
Ok(image_absolute_path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the image as the wallpaper
|
||||
*/
|
||||
fn set_windows_wallpaper(image_absolute_path: &PathBuf) {
|
||||
let path_wide: Vec<u16> = OsStr::new(&image_absolute_path)
|
||||
.encode_wide()
|
||||
.chain(once(0))
|
||||
.collect();
|
||||
unsafe {
|
||||
SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, path_wide.as_ptr() as *mut _, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the image and set it as the wallpaper
|
||||
*/
|
||||
async fn download_and_set(absolute_path: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
let locale = get_locale();
|
||||
let (url, startdate) = get_image_url(&locale).await?;
|
||||
let image_absolute_path = dowload_image(url, &startdate, &absolute_path).await?;
|
||||
set_windows_wallpaper(&image_absolute_path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let absolute_path: PathBuf = match env::current_exe() {
|
||||
Ok(path) => path.parent().unwrap().to_path_buf(),
|
||||
Err(_) => PathBuf::from("C:\\Users\\Public\\Pictures"),
|
||||
};
|
||||
let _logger = Logger::try_with_str("info")?
|
||||
.log_to_file(FileSpec::default().directory(&absolute_path))
|
||||
.rotate(
|
||||
Criterion::Size(u64::MAX),
|
||||
Naming::Timestamps,
|
||||
Cleanup::KeepLogFiles(3),
|
||||
)
|
||||
.write_mode(WriteMode::BufferAndFlush)
|
||||
.start()?;
|
||||
|
||||
match download_and_set(absolute_path).await {
|
||||
Ok(_) => log::debug!("Program completed successfully"),
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user