Compare commits

..

5 Commits

Author SHA1 Message Date
50ae536650 Merge branch 'master' into wallhaven
Some checks failed
/ release x86_64-unknown-linux-musl (push) Failing after 3s
2025-01-02 16:15:18 +11:00
812d3f9d0c Merge branch 'master' into wallhaven 2024-12-05 16:27:17 +11:00
edb02fd8ec Added wallhaven downloading 2024-12-05 16:09:26 +11:00
c1a3083fab More wallhaven features
Updated ABI slightly
2024-11-22 14:08:07 +11:00
edb48a32a0 Added wallhaven initial support 2024-11-20 21:34:59 +11:00
8 changed files with 1764 additions and 53 deletions

View File

@ -4,40 +4,23 @@ on:
push: push:
tags: tags:
- '*' - '*'
env:
CRATE_NAME: mycelium
RUST_BACKTRACE: 1
jobs: jobs:
release: release:
name: release name: release ${{ matrix.target }}
runs-on: ubuntu-24.04 runs-on: alma9
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: target: [x86_64-unknown-linux-musl]
- os-name: Linux-x86_64
runs-on: ubuntu-20.04
target: x86_64-unknown-linux-gnu
toolchain:
- stable
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@master
- name: Install deps - name: Install deps
run: | run: apt-get update; apt-get install -y libdbus-1-dev pkg-config
apt-get update; apt-get install -y libdbus-1-3 libdbus-1-dev libdbus-1-3 pkg-config - name: Compile and release
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/inst_rustup.sh uses: rust-build/rust-build.action@v1.4.5
bash /tmp/inst_rustup.sh -y env:
source /root/.cargo/env GITHUB_TOKEN: ${{ secrets.GT_TOKEN }}
rustup toolchain install stable-x86_64-unknown-linux-gnu
- name: Build binary
run: |
/root/.cargo/bin/cargo build --release
tar -zcvf x86_64-linux.tgz target/release/mycelium README.md
- name: Test
run: |
ls -alh target/release/mycelium
- name: Release
uses: softprops/action-gh-release@v2
with: with:
files: x86_64-linux.tgz RUSTTARGET: ${{ matrix.target }}
EXTRA_FILES: README.md

1419
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,3 +9,4 @@ dbus = "0.9.7"
glob = "0.3.1" glob = "0.3.1"
rand = "0.8.5" rand = "0.8.5"
untildify = { git = "https://git.lovelynet.net/benjamyn/untildify.git", branch = "main" } untildify = { git = "https://git.lovelynet.net/benjamyn/untildify.git", branch = "main" }
reqwest = { version = "0.12.9", features = ["json", "blocking"] }

View File

@ -19,5 +19,4 @@ What I want to add
- Wallhaven API support - Wallhaven API support
- Gnome support - Gnome support
- Plugin system for Desktop environments? (Need to think about how I wanna do this) - Plugin system for Desktop environments? (Need to think about how I wanna do this)
- Add Hyprpaper support (IPC STUFF YOLO) - Other things as I think about them
- Other things as I think about them

View File

@ -82,6 +82,8 @@ pub struct Config {
pub wallpaper_engine: WallpaperHandler, pub wallpaper_engine: WallpaperHandler,
pub wallpaper_dir: WallpaperDir, pub wallpaper_dir: WallpaperDir,
pub monitors: Monitors, pub monitors: Monitors,
pub wallhaven_api_key: String,
pub wallhaven_tmp_dir: String,
} }
impl Config { impl Config {
@ -125,13 +127,17 @@ impl Config {
)); ));
} }
} }
//
let wallhaven_api_key = config.get("wallhaven", "api_key").unwrap();
let wallhaven_tmp_dir = config.get("wallhaven", "tmp_dir").unwrap();
Config { Config {
x_server: config.get("general", "x_server").unwrap(), x_server: config.get("general", "x_server").unwrap(),
wallpaper_engine, wallpaper_engine,
wallpaper_dir, wallpaper_dir,
monitors, monitors,
wallhaven_api_key,
wallhaven_tmp_dir,
} }
} }
} }

View File

@ -17,6 +17,12 @@ impl fmt::Display for Wallpaper {
} }
} }
impl Wallpaper {
pub fn new(path: String) -> Wallpaper {
Wallpaper { path: path }
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Wallpapers { pub struct Wallpapers {
ultrawide: Vec<Wallpaper>, ultrawide: Vec<Wallpaper>,

View File

@ -1,14 +1,19 @@
mod config; mod config;
use std::fmt::format;
use config::*; use config::*;
mod enums; mod enums;
mod files; mod files;
use enums::WallpaperHandler; use enums::WallpaperHandler;
use files::*; use files::*;
mod handlers; mod handlers;
mod wallhaven;
use wallhaven::*;
use untildify::untildify; use untildify::untildify;
fn main() { fn main() {
// test_request();
// Load the config file from the default path // Load the config file from the default path
let path = untildify("~/.config/wallpaperctl/wallpaperctl.ini"); let path = untildify("~/.config/wallpaperctl/wallpaperctl.ini");
let config = Config::from_config(path); let config = Config::from_config(path);
@ -16,24 +21,43 @@ fn main() {
// Initialise the `Wallpapers` struct with a clone of the config // Initialise the `Wallpapers` struct with a clone of the config
let mut wallpapers = Wallpapers::new(config.clone()); let mut wallpapers = Wallpapers::new(config.clone());
// Load all wallpapers based on the config file specs let api = WallHavenAPI::new(config.wallhaven_api_key, config.wallhaven_tmp_dir.clone());
wallpapers.load_all();
// Check the configured Wallpaper engine and run the change_wallpapers() method from the respective handlers let search_terms = vec![String::from("tsundere")];
let wallpaper_engine = config.wallpaper_engine; let purities = vec![Purity::Sketchy];
// println!("{:?}", &wallpapers); let categories = vec![Category::Anime];
match wallpaper_engine {
WallpaperHandler::Plasma => { let query = WallHavenQuery::new(
handlers::plasma::change_wallpapers(&wallpapers); api,
} search_terms,
WallpaperHandler::Feh => { purities,
handlers::feh::change_wallpapers(&wallpapers); categories,
} Ratio::Horizontal,
WallpaperHandler::Gnome => { 1,
handlers::gnome::change_wallpapers(&wallpapers); );
}
_ => { let results = query.run();
println!("Error: Unknown wallpaper engine");
} let wall = results.get_random();
}
println!("{}", results);
// // Load all wallpapers based on the config file specs
// wallpapers.load_all();
// // Check the configured Wallpaper engine and run the change_wallpapers() method from the respective handlers
// let wallpaper_engine = config.wallpaper_engine;
// match wallpaper_engine {
// WallpaperHandler::Plasma => {
// handlers::plasma::change_wallpapers(&wallpapers);
// }
// WallpaperHandler::Feh => {
// handlers::feh::change_wallpapers(&wallpapers);
// }
// WallpaperHandler::Gnome => {
// handlers::gnome::change_wallpapers(&wallpapers);
// }
// _ => {
// println!("Error: Unknown wallpaper engine");
// }
// }
} }

275
src/wallhaven.rs Normal file
View File

@ -0,0 +1,275 @@
use core::fmt;
use dbus::arg::RefArg;
use reqwest::*;
use serde::Deserialize;
use serde::Serialize;
use std::fs::File;
use std::io;
use urlencoding::encode;
use crate::{Wallpaper, Wallpapers};
#[derive(Serialize, Deserialize)]
struct Thumbs {
large: String,
original: String,
small: String,
}
impl fmt::Display for Thumbs {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
write!(f, "large: {}\noriginal: {}", &self.large, &self.original)
}
}
#[derive(Serialize, Deserialize)]
struct Meta {
current_page: i32,
last_page: i32,
per_page: String,
total: i32,
query: Option<String>,
seed: Option<String>,
}
impl fmt::Display for Meta {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
write!(f, "current_page: {}", &self.current_page)
}
}
#[derive(Serialize, Deserialize)]
pub struct WallHavenResponse {
pub data: Vec<WallHavenWallpaper>,
pub meta: Meta,
}
impl fmt::Display for WallHavenResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
for entry in &self.data {
write! {f, "{}\n", entry}.unwrap();
}
write!(f, "{}", &self.meta).unwrap();
Ok(())
}
}
impl WallHavenResponse {
pub fn get_random(&self) -> &WallHavenWallpaper {
self.data.get(0).unwrap()
}
}
#[derive(Serialize, Deserialize)]
pub struct WallHavenWallpaper {
id: String,
url: String,
short_url: String,
views: i64,
favorites: i64,
source: String,
purity: String,
category: String,
dimension_x: i32,
dimension_y: i32,
resolution: String,
ratio: String,
file_size: i64,
file_type: String,
created_at: String,
colors: Vec<String>,
path: String,
thumbs: Thumbs,
}
impl fmt::Display for WallHavenWallpaper {
fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
write!(
f,
"ID: {}\tURL: {} ({})",
&self.id, &self.path, &self.purity
)
}
}
impl WallHavenWallpaper {
pub fn download(self, path: String) -> bool {
let image_resp = blocking::get(self.path).unwrap();
let mut outfile = File::create(path).unwrap();
io::copy(&mut image_resp.text().unwrap().as_bytes(), &mut outfile).unwrap();
true
}
pub fn to_wallpaper(&self) -> Wallpaper {
Wallpaper::new(String::new())
}
}
pub struct WallHavenAPI {
pub api_key: String,
pub tmp_dir: String,
}
impl WallHavenAPI {
pub fn new(api_key: String, tmp_dir: String) -> WallHavenAPI {
WallHavenAPI {
api_key: api_key,
tmp_dir: tmp_dir,
}
}
}
pub enum Ratio {
Ultrawide,
Horizontal,
Vertical,
}
pub enum Purity {
Sfw,
Sketchy,
Nsfw,
}
pub enum Category {
General,
People,
Anime,
}
pub struct WallHavenQuery {
api: WallHavenAPI,
search_terms: Vec<String>,
purity: String,
category: String,
ratio: String,
page: i32,
}
impl WallHavenQuery {
pub fn new(
api: WallHavenAPI,
search_terms: Vec<String>,
purity: Vec<Purity>,
category: Vec<Category>,
ratio: Ratio,
page: i32,
) -> WallHavenQuery {
let mut purity_value = String::from("000");
for p in purity {
match p {
Purity::Nsfw => {
purity_value.replace_range(2..3, "1");
}
Purity::Sfw => {
purity_value.replace_range(0..1, "1");
}
Purity::Sketchy => {
purity_value.replace_range(1..2, "1");
}
}
}
let ratio_value: String;
match ratio {
Ratio::Horizontal => ratio_value = String::from("16x9"),
Ratio::Ultrawide => ratio_value = String::from("21x9"),
Ratio::Vertical => ratio_value = String::from("9x16"),
};
let mut category_value = String::from("000");
for c in category {
match c {
Category::Anime => {
category_value.replace_range(1..2, "1");
}
Category::General => {
category_value.replace_range(0..1, "1");
}
Category::People => {
category_value.replace_range(2..3, "1");
}
}
}
WallHavenQuery {
api: api,
search_terms: search_terms,
purity: purity_value,
category: category_value,
ratio: ratio_value,
page: page,
}
}
pub fn run(&self) -> WallHavenResponse {
// Build the query string, URL encode it then send off the request
let mut query_string = String::from("?q=");
let mut url = String::from("https://wallhaven.cc/api/v1/search");
let mut search_terms = String::new();
for term in &self.search_terms {
search_terms.push_str(term.as_str());
search_terms.push_str("+");
}
query_string.push_str(search_terms.as_str());
query_string.push_str("&ratios=");
query_string.push_str(self.ratio.as_str());
query_string.push_str("&purity=");
query_string.push_str(self.purity.as_str());
query_string.push_str("&categories=");
query_string.push_str(self.category.as_str());
query_string.push_str("&apikey=");
query_string.push_str(self.api.api_key.as_str());
url.push_str(query_string.as_str());
// let encoded = encode(url.as_str()).into_owned();
println!("{}", &url);
serde_json::from_str(blocking::get(url).unwrap().text().unwrap().as_str()).unwrap()
// Return the WallHavenResponse object
}
}
// pub fn test_request() {
// // let body = blocking::get("https://wallhaven.cc/api/v1/search?q=anime+skirt&ratios=21x9");
// // // println!("{}", body.unwrap().json::<HashMap<String, String>>());
// // let data: WallHavenResponse =
// // serde_json::from_str(body.unwrap().text().unwrap().as_str()).unwrap();
// // // for entry in data["data"] {
// // // let v: serde_jwson::Value = serde_json::from_str(entry.as_str().unwrap()).unwrap();
// // // println!("{}", v);
// // // }
// // println!("{}", data);
// // wallhaven.add_tag(String::from("Anime"));
// // wallhaven.add_tag(String::from("Anime3"));
// // wallhaven.add_tag(String::from("Anime2"));
// // wallhaven.add_tag(String::from("Anime4"));
// // wallhaven.add_tag(String::from("Anime5"));
// // println!("{}", wallhaven)
// let mut search_terms = Vec::<String>::new();
// // search_terms.push(String::from("sexy"));
// search_terms.push(String::from("crab"));
// let mut purities = Vec::<Purity>::new();
// purities.push(Purity::Nsfw);
// purities.push(Purity::Sketchy);
// let mut categories = Vec::<Category>::new();
// categories.push(Category::Anime);
// let request = WallHavenQuery::new(
// wallhaven,
// search_terms,
// purities,
// categories,
// Ratio::Horizontal,
// 1,
// );
// let response = request.run();
// print!("{}", response);
// }