<stdin> |

My Thoughts, Trials and Adventures

Overview of WPC: Writing a wallpaper changer in Rust

Posted at — Mar 13, 2020

Build Status

WPC stands for Wall Paper Changer

Github


Changelog

(09-07-2020)

  • WPC v0.5 is a major release. main.rs is mostly rewritten.

(14-01-2021)

WPC gained partial async support from 0.7 and almost full async (except for wallhaven_api) from 1.0 on wards. some parts of this article may not be relevant anymore, but may still be useful. I’ve written a short “What changed in 1.0? a lot!" to provide a general change log and overview of the project.

  • this tag might be the last tree where this article is 100% relevant.


Why?

I have a dual boot setup (Arch Linux/Windows 10) and I use Gnome DE in my arch Linux which lacks automatic wallpaper changing functionality.

Even in the case of windows 10, While there is a Slideshow of wallpapers, it does not have an option like interval or web source.

both of these reasons led me to develop my own application. I want it to be simple, fast and reliable so I chose Rust.

How?

WPC is written in rust with a modular design in mind.

APIs are divided into modules and used in main.rs as required based on the platform.

.
├── Cargo.lock
├── Cargo.toml
├── LICENSE.md
├── README.md
└── src
    ├── changer
    │   ├── linux
    │   │   └── DE
    │   │       ├── gnome.rs
    │   │       └── startup.rs
    │   └── windows
    │       └── windows.rs
    ├── cli.yml
    ├── main.rs
    ├── misc.rs
    └── web
        ├── bing_wpod.rs
        └── wallheaven_api.rs

6 directories, 12 files


Dependencies

config.toml

[package]
name = "wpc"
version = "0.1.1"
authors = ["Jagadeesh Kotra <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = "1.0.104"
serde_json = "1.0.48"
reqwest = { version = "0.10", features = ["blocking", "json"] }
clap = {version = "2.33", features = ["yaml"]}
rand = "0.7"
chrono = "0.4.10"
enquote = "1.0.3"
dirs = "2.0.2"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }

Some notes,

serde and serde_json is used to deal with JSON data.

reqwest is the used to parse information from web sources.

winapi provides access to Windows API


Wallheaven API

One of the main features of WPC is its ability to parse wallpapers from the web. Namely, Wallheaven and Bing WPOD are implemented.

wallheaven API is implemented in Rust It uses reqwest::blocking to make GET requests and convert them to JSON.

pub fn wallheaven_wallpaperinfo(apikey: &str, id: &str) -> Result<serde_json::value::Value, Box<dyn std::error::Error>> 

pub fn wallheaven_search(apikey: &str, query: HashMap<&str, &str>) -> Result<Value, Box<dyn std::error::Error>>

pub fn wallheaven_taginfo(id: &str) -> Result<Value, Box<dyn std::error::Error>>

pub fn wallheaven_usersettings(apikey: &str) -> Result<Value, Box<dyn std::error::Error>>

pub fn wallheaven_getid(apikey: &str) -> Result<serde_json::value::Value, Box<dyn std::error::Error>>

pub fn wallheaven_getcoll(username: &str, collid: i64) -> Result<serde_json::value::Value, Box<dyn std::error::Error>>

wallhaven.rs


Bing API

pub fn get_wallpaper_of_the_day() -> Result<serde_json::value::Value, Box<dyn std::error::Error>> {
    let resp = reqwest::blocking::get("https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US").expect("Unable to make GET request!")
        .text()?;
    let v: Value = serde_json::from_str(&resp)
        .expect("Cannot Decode JSON Data!");
    Ok(v)
}

Output: JSON


Tests

Network Connectivity is required for the following tests:
fn bing_test_is_jpg()
fn bing_test_is_downloadable()
fn wallheaven_get_wallpapers()


fn it_works() {
        assert_eq!(2 + 2, 4);
}
fn bing_test_is_jpg() 
fn bing_test_is_downloadable() 
fn wallheaven_get_wallpapers()


Conclusion

Creating this application has been a great journey. PR/Issues are welcome.

Github