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:
tags:
- '*'
env:
CRATE_NAME: mycelium
RUST_BACKTRACE: 1
jobs:
release:
name: release
runs-on: ubuntu-24.04
name: release ${{ matrix.target }}
runs-on: alma9
strategy:
fail-fast: false
matrix:
platform:
- os-name: Linux-x86_64
runs-on: ubuntu-20.04
target: x86_64-unknown-linux-gnu
toolchain:
- stable
matrix:
target: [x86_64-unknown-linux-musl]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@master
- name: Install deps
run: |
apt-get update; apt-get install -y libdbus-1-3 libdbus-1-dev libdbus-1-3 pkg-config
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/inst_rustup.sh
bash /tmp/inst_rustup.sh -y
source /root/.cargo/env
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
run: apt-get update; apt-get install -y libdbus-1-dev pkg-config
- name: Compile and release
uses: rust-build/rust-build.action@v1.4.5
env:
GITHUB_TOKEN: ${{ secrets.GT_TOKEN }}
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"
rand = "0.8.5"
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
- Gnome support
- 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_dir: WallpaperDir,
pub monitors: Monitors,
pub wallhaven_api_key: String,
pub wallhaven_tmp_dir: String,
}
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 {
x_server: config.get("general", "x_server").unwrap(),
wallpaper_engine,
wallpaper_dir,
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)]
pub struct Wallpapers {
ultrawide: Vec<Wallpaper>,

View File

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