pfp and disc modules
This commit is contained in:
		
							parent
							
								
									a22b2c5e4d
								
							
						
					
					
						commit
						4ce3af150c
					
				
					 4 changed files with 155 additions and 57 deletions
				
			
		
							
								
								
									
										21
									
								
								README.org
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								README.org
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -12,7 +12,18 @@ On the first run, if it does not exist, PluralSync will create a configuration d
 | 
			
		|||
#+begin_src js
 | 
			
		||||
{
 | 
			
		||||
  "pk_key": "// Pluralkit token",
 | 
			
		||||
  "sp_key": "// Simplplural token"
 | 
			
		||||
  "sp_key": "// Simplplural token",
 | 
			
		||||
  "pfp_module": {
 | 
			
		||||
    "enabled": false,
 | 
			
		||||
    "pfp_folder": "// Folder to grab profile pictures, they follow they member1member2...memberX.png format",
 | 
			
		||||
    "pfp_output_path": "// Path for the copied selected pfp"
 | 
			
		||||
  },
 | 
			
		||||
  "disc_module": {
 | 
			
		||||
    "enabled": false,
 | 
			
		||||
    "token": "// Discord user token",
 | 
			
		||||
    "python_path": "// Path of the python executable",
 | 
			
		||||
    "script_path": "// Path of the pfp changer python script"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#+end_src
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +47,14 @@ Displays the current front. The result is displayed in console but also stored i
 | 
			
		|||
*** Memberlist
 | 
			
		||||
Writes the known list of members based on the =system.json= file.
 | 
			
		||||
 | 
			
		||||
** Modules
 | 
			
		||||
*** PFP module
 | 
			
		||||
requires docs
 | 
			
		||||
*** Discord module
 | 
			
		||||
goes against ToS be gentle
 | 
			
		||||
 | 
			
		||||
* Future
 | 
			
		||||
Given the nature of the project as a learning exercise, there are currently a set of features and improvements I'd like to add eventually.
 | 
			
		||||
- [ ] Proper error handling (What I have currently is simply a mess)
 | 
			
		||||
- [X] Proper error handling (What I have currently is simply a mess)
 | 
			
		||||
- [ ] Rofi and zenity support
 | 
			
		||||
- [ ] Proper way to handle front conflicts between PluralKit and SimplyPlural
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,15 @@
 | 
			
		|||
{
 | 
			
		||||
  "pk_key": "// Pluralkit token",
 | 
			
		||||
  "sp_key": "// Simplplural token"
 | 
			
		||||
  "sp_key": "// Simplplural token",
 | 
			
		||||
  "pfp_module": {
 | 
			
		||||
    "enabled": false,
 | 
			
		||||
    "pfp_folder": "// Folder to grab profile pictures, they follow they member1member2.png format",
 | 
			
		||||
    "pfp_output_path": "// Path for the copied selected pfp"
 | 
			
		||||
  },
 | 
			
		||||
  "disc_module": {
 | 
			
		||||
    "enabled": false,
 | 
			
		||||
    "token": "// Discord user token",
 | 
			
		||||
    "python_path": "// Path of the python executable",
 | 
			
		||||
    "script_path": "// Path of the pfp changer python script"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										155
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										155
									
								
								src/main.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,7 +1,8 @@
 | 
			
		|||
use std::fs;
 | 
			
		||||
use std::fs::{self, remove_file};
 | 
			
		||||
use std::fs::create_dir;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::process::Command;
 | 
			
		||||
 | 
			
		||||
use reqwest::header::{USER_AGENT, AUTHORIZATION};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +14,45 @@ use dirs;
 | 
			
		|||
const PK_URL: &str = "https://api.pluralkit.me/v2";
 | 
			
		||||
const SP_URL: &str = "https://api.apparyllis.com/v1";
 | 
			
		||||
 | 
			
		||||
const EXAMPLE_JSON: &str = r#"{
 | 
			
		||||
    "pk_key": "// Pluralkit token",
 | 
			
		||||
    "sp_key": "// Simplplural token",
 | 
			
		||||
    "pfp_module": {
 | 
			
		||||
        "enabled": false,
 | 
			
		||||
        "pfp_folder": "// Folder to grab profile pictures, they follow they member1member2.png format",
 | 
			
		||||
        "pfp_output_path": "// Path for the copied selected pfp"
 | 
			
		||||
    },
 | 
			
		||||
    "disc_module": {
 | 
			
		||||
        "enabled": false,
 | 
			
		||||
        "token": "// Discord user token",
 | 
			
		||||
        "python_path": "// Path of the python executable",
 | 
			
		||||
        "script_path": "// Path of the pfp changer python script"
 | 
			
		||||
    }
 | 
			
		||||
}"#;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
struct Config {
 | 
			
		||||
    pk_key: String,
 | 
			
		||||
    sp_key: String,
 | 
			
		||||
    pfp_module: PfpModule,
 | 
			
		||||
    disc_module: DiscModule
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
struct PfpModule {
 | 
			
		||||
    enabled: bool,
 | 
			
		||||
    pfp_folder: String,
 | 
			
		||||
    pfp_output_path: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize)]
 | 
			
		||||
struct DiscModule {
 | 
			
		||||
    enabled: bool,
 | 
			
		||||
    token: String,
 | 
			
		||||
    python_path: String,
 | 
			
		||||
    script_path: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Clone)]
 | 
			
		||||
struct System {
 | 
			
		||||
    pk_userid: String,
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +121,9 @@ memberlist - Shows loaded member list"#;
 | 
			
		|||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    "get" => get(config_path),
 | 
			
		||||
                    "get" => {
 | 
			
		||||
                        let _ = get(config_path);
 | 
			
		||||
                    },
 | 
			
		||||
                    "memberlist" => memberlist(config_path),
 | 
			
		||||
                    &_ => println!("{}", helpstring),
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -93,29 +135,25 @@ memberlist - Shows loaded member list"#;
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn sync(config_path: String) -> Result<(), String>{
 | 
			
		||||
fn sync(config_path: String) -> Result<(), &'static str> {
 | 
			
		||||
    // Get config
 | 
			
		||||
    let config = get_config(&config_path);
 | 
			
		||||
    if config == Value::Null {
 | 
			
		||||
        println!("Stopping.");
 | 
			
		||||
        return Ok(());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let pk_key = &config["pk_key"].as_str().unwrap();
 | 
			
		||||
    let sp_key = &config["sp_key"].as_str().unwrap();
 | 
			
		||||
    let config: Config = match get_config(&config_path) {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => return Err(e)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Get Pluralkit system id
 | 
			
		||||
    let pk_sys = pk_get_system(pk_key);
 | 
			
		||||
    let pk_sys = pk_get_system(&config.pk_key);
 | 
			
		||||
    let pk_sysid = pk_sys["id"].as_str().unwrap();
 | 
			
		||||
 | 
			
		||||
    // Get Simplyplural user id
 | 
			
		||||
    let sp_user_id = sp_get_userid(sp_key);
 | 
			
		||||
    let sp_user_id = sp_get_userid(&config.sp_key);
 | 
			
		||||
 | 
			
		||||
    // Get Simplyplural member ids
 | 
			
		||||
    let sp_member_ids = sp_get_memberids(sp_key, &sp_user_id);
 | 
			
		||||
    let sp_member_ids = sp_get_memberids(&config.sp_key, &sp_user_id);
 | 
			
		||||
 | 
			
		||||
    // get members
 | 
			
		||||
    let pk_members = pk_get_members(pk_key, pk_sysid);
 | 
			
		||||
    let pk_members = pk_get_members(&config.pk_key, pk_sysid);
 | 
			
		||||
    let mut members: Vec<Member> = Vec::new();
 | 
			
		||||
    for member in pk_members {
 | 
			
		||||
        let mut m = Member {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,10 +194,10 @@ TODO }
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
fn set_member(config_path: String, tf_members: &[String]) -> Result<(), &'static str> {
 | 
			
		||||
    let config = get_config(&config_path);
 | 
			
		||||
    if config == Value::Null {
 | 
			
		||||
        return Err("Config not found. Stopping");
 | 
			
		||||
    }
 | 
			
		||||
    let config: Config = match get_config(&config_path) {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => return Err(e)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let system: System = get_system(&config_path);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -175,12 +213,12 @@ fn set_member(config_path: String, tf_members: &[String]) -> Result<(), &'static
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if to_front.len() != 0 {
 | 
			
		||||
        let fronters = get_fronters(&config["pk_key"].as_str().unwrap(), &config["sp_key"].as_str().unwrap(), &system);
 | 
			
		||||
        let fronters = get_fronters(&config.pk_key, &config.sp_key, &system);
 | 
			
		||||
 | 
			
		||||
        pk_set_fronters(&config["pk_key"].as_str().unwrap(), &system, &to_front, &fronters);
 | 
			
		||||
        sp_set_fronters(&config["sp_key"].as_str().unwrap(), &to_front, &fronters);
 | 
			
		||||
        pk_set_fronters(&config.pk_key, &system, &to_front, &fronters);
 | 
			
		||||
        sp_set_fronters(&config.sp_key, &to_front, &fronters);
 | 
			
		||||
 | 
			
		||||
        get(config_path);
 | 
			
		||||
        let _ = get(config_path);
 | 
			
		||||
    } else {
 | 
			
		||||
        println!("No members found. Known members:\n--------------------------");
 | 
			
		||||
        memberlist(config_path);
 | 
			
		||||
| 
						 | 
				
			
			@ -190,10 +228,10 @@ fn set_member(config_path: String, tf_members: &[String]) -> Result<(), &'static
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn add_member(config_path: String, tf_members: &[String]) -> Result<(), &'static str> {
 | 
			
		||||
    let config = get_config(&config_path);
 | 
			
		||||
    if config == Value::Null {
 | 
			
		||||
        return Err("Config not found. Stopping");
 | 
			
		||||
    }
 | 
			
		||||
    let config: Config = match get_config(&config_path) {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => return Err(e)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let system: System = get_system(&config_path);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -207,17 +245,17 @@ fn add_member(config_path: String, tf_members: &[String]) -> Result<(), &'static
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if to_front.len() != 0 {
 | 
			
		||||
        let fronters = get_fronters(&config["pk_key"].as_str().unwrap(), &config["sp_key"].as_str().unwrap(), &system);
 | 
			
		||||
        let fronters = get_fronters(&config.pk_key, &config.sp_key, &system);
 | 
			
		||||
 | 
			
		||||
        let mut aux: Vec<Member> = Vec::new();
 | 
			
		||||
        aux.append(&mut fronters.pk.clone());
 | 
			
		||||
        aux.append(&mut to_front);
 | 
			
		||||
        to_front = aux;
 | 
			
		||||
 | 
			
		||||
        pk_set_fronters(&config["pk_key"].as_str().unwrap(), &system, &to_front, &fronters);
 | 
			
		||||
        sp_set_fronters(&config["sp_key"].as_str().unwrap(), &to_front, &fronters);
 | 
			
		||||
        pk_set_fronters(&config.pk_key, &system, &to_front, &fronters);
 | 
			
		||||
        sp_set_fronters(&config.sp_key, &to_front, &fronters);
 | 
			
		||||
 | 
			
		||||
        get(config_path);
 | 
			
		||||
        let _ = get(config_path);
 | 
			
		||||
    } else {
 | 
			
		||||
        println!("No members found. Known members:\n--------------------------");
 | 
			
		||||
        memberlist(config_path);
 | 
			
		||||
| 
						 | 
				
			
			@ -239,18 +277,37 @@ fn memberlist(config_path: String) {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get(config_path: String) {
 | 
			
		||||
    let config = get_config(&config_path);
 | 
			
		||||
fn get(config_path: String) -> Result<(), &'static str> {
 | 
			
		||||
    let config: Config = match get_config(&config_path) {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => return Err(e)
 | 
			
		||||
    };
 | 
			
		||||
    let sys = get_system(&config_path);
 | 
			
		||||
 | 
			
		||||
    let f = get_fronters(&config["pk_key"].as_str().unwrap(), &config["sp_key"].as_str().unwrap(), &sys);
 | 
			
		||||
    let f = get_fronters(&config.pk_key, &config.sp_key, &sys);
 | 
			
		||||
    let mut names = Vec::new();
 | 
			
		||||
    for m in &f.pk {
 | 
			
		||||
    for m in &f.sp {
 | 
			
		||||
        names.push(String::from(&m.name));
 | 
			
		||||
    }
 | 
			
		||||
    let fronters = names.join(" || ");
 | 
			
		||||
    println!("Currently fronting: {}", fronters);
 | 
			
		||||
    let _ = fs::write(format!("{}/.front", config_path), fronters);
 | 
			
		||||
 | 
			
		||||
    if config.pfp_module.enabled {
 | 
			
		||||
        let pfpnames = names.join("").to_lowercase() + ".png";
 | 
			
		||||
 | 
			
		||||
        if Path::new(&config.pfp_module.pfp_output_path).exists() {
 | 
			
		||||
            let _ = remove_file(&config.pfp_module.pfp_output_path);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Command::new("sh").arg("-c").arg(format!("cp {}/{} {}", &config.pfp_module.pfp_folder, pfpnames, &config.pfp_module.pfp_output_path)).output().expect("pfp module error");
 | 
			
		||||
 | 
			
		||||
        if config.disc_module.enabled {
 | 
			
		||||
            Command::new("sh").arg("-c").arg(format!("{} {}", &config.disc_module.python_path, &config.disc_module.script_path)).output().expect("discord module error");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn pk_get_system(key: &str) -> Value {
 | 
			
		||||
| 
						 | 
				
			
			@ -446,33 +503,23 @@ fn load_json(path: String) -> Value {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_config(config_path: &str) -> Value {
 | 
			
		||||
fn get_config(config_path: &str) -> Result<Config, &'static str> {
 | 
			
		||||
    let path = format!("{}/config.json", config_path);
 | 
			
		||||
    if Path::new(config_path).exists() {
 | 
			
		||||
 | 
			
		||||
        let result = load_json(String::from(&path));
 | 
			
		||||
 | 
			
		||||
        if result == Value::Null {
 | 
			
		||||
            println!("Config file missing, creating template in {path}");
 | 
			
		||||
            let _ = fs::write(path, r#"
 | 
			
		||||
{
 | 
			
		||||
    "pk_key": "// Pluralkit token",
 | 
			
		||||
    "sp_key": "// Simplplural token"
 | 
			
		||||
}
 | 
			
		||||
                                    "#);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
            let _ = fs::write(path, EXAMPLE_JSON);
 | 
			
		||||
            return Err("Config file missing, creating template in {path}");
 | 
			
		||||
        } else {
 | 
			
		||||
            let config: Config = serde_json::from_value(result).expect("Error unwrapping");
 | 
			
		||||
            return Ok(config);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        println!("Directory {config_path} does not exist. Creating with template config");
 | 
			
		||||
        let _ = create_dir(config_path);
 | 
			
		||||
        let _ = fs::write(path, r#"
 | 
			
		||||
{
 | 
			
		||||
    "pk_key": "// Pluralkit token",
 | 
			
		||||
    "sp_key": "// Simplplural token"
 | 
			
		||||
}
 | 
			
		||||
                                "#);
 | 
			
		||||
        return Value::Null;
 | 
			
		||||
        let _ = fs::write(path, EXAMPLE_JSON);
 | 
			
		||||
        return Err("Directory {config_path} does not exist. Creating with template config");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										23
									
								
								updatepfp.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								updatepfp.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import json
 | 
			
		||||
import discord
 | 
			
		||||
 | 
			
		||||
config_dir = os.getenv('APPDATA') if os.name == "nt" else os.path.expanduser('~') + "/.config"
 | 
			
		||||
config_dir += "/pluralsync/config.json"
 | 
			
		||||
 | 
			
		||||
f = open(config_dir)
 | 
			
		||||
json = json.load(f)
 | 
			
		||||
 | 
			
		||||
class MyClient(discord.Client):
 | 
			
		||||
    async def on_ready(self):
 | 
			
		||||
        print('Logged on as', self.user)
 | 
			
		||||
        pfp_path = json["pfp_module"]["pfp_output_path"]
 | 
			
		||||
        fp = open(pfp_path, 'rb')
 | 
			
		||||
        pfp = fp.read()
 | 
			
		||||
        await self.user.edit(avatar=pfp)
 | 
			
		||||
        await self.close()
 | 
			
		||||
 | 
			
		||||
client = MyClient()
 | 
			
		||||
client.run(json["disc_module"]["token"])
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue