Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
bd015a83f6 | |||
037ab2d409 | |||
![]() |
d43af93c99 | ||
![]() |
d2d00497e1 | ||
e362382cae | |||
bb8c4a9cda | |||
70c20c9e3c | |||
f910b29a6b | |||
9e83feb07e | |||
bc8fc48033 | |||
23d282ff12 | |||
87ac6a29da | |||
a1b30b5f0f | |||
fa4d44488e | |||
2a33ef627a | |||
8cd3f6bbef | |||
971fdadbbf | |||
11fcca4a78 | |||
3d1bee87b6 | |||
969abe34b4 | |||
c37abef665 |
18 changed files with 1458 additions and 249 deletions
11
.drp_config
11
.drp_config
|
@ -1,11 +0,0 @@
|
|||
SHOULD_EXCLUDE_BE_ANONYMOUS:{
|
||||
n
|
||||
}
|
||||
|
||||
PORTFOLIO_LINK:{
|
||||
djkato.net
|
||||
}
|
||||
|
||||
EXCLUDE_CHARACTERS_LIST:{
|
||||
no_drp
|
||||
}
|
1189
Cargo.lock
generated
1189
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
19
Cargo.toml
19
Cargo.toml
|
@ -1,16 +1,18 @@
|
|||
[package]
|
||||
name = "DRP_Creative"
|
||||
version = "0.1.1"
|
||||
name = "drp_creative"
|
||||
version = "1.0.4"
|
||||
edition = "2021"
|
||||
author = "https://djkato.net"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
authors = ["djkatovfx@gmail.com"]
|
||||
|
||||
[dependencies]
|
||||
discord-rich-presence = "0.2.2"
|
||||
regex = "1.6.0"
|
||||
tray-item = "0.7.0"
|
||||
lazy_static = "1.4.0"
|
||||
self_update = { version = "0.36.0", features = ["archive-zip"] }
|
||||
win-msgbox = "0.1.2"
|
||||
serde = { version = "1.0.170", features = ["derive"] }
|
||||
toml = "0.7.6"
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.39.0"
|
||||
|
@ -23,4 +25,9 @@ features = [
|
|||
]
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
windres = "0.2.2"
|
||||
windres = "0.2.2"
|
||||
|
||||
# prefix binary with x86_64-pc-windows-msvc for self_updater
|
||||
[[bin]]
|
||||
name = "DRP_Creative--x86_64-pc-windows-msvc"
|
||||
path = "src/main.rs"
|
||||
|
|
1
FUNDING.yml
Normal file
1
FUNDING.yml
Normal file
|
@ -0,0 +1 @@
|
|||
ko_fi: djkato
|
42
README.md
42
README.md
|
@ -1,21 +1,39 @@
|
|||
<a href='https://ko-fi.com/A0A8Q3SVZ' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|
||||
# Discord Rich Presence for Creative Apps
|
||||
### Show your friends what you're working on, be it in Adobe Suite, Autodesk Suite, Cinema 4D or many more!
|
||||
This app runs in the background and looks for processes, then parses the windows title and turns it into a project name to display with Discords Rich Presence.
|
||||
|
||||
|
||||
Examples:
|
||||

|
||||

|
||||

|
||||

|
||||
## how to install:
|
||||
1. Grab the latest version from the [Releases](https://github.com/djkato/DRP_Creative/releases) page, then make a folder in `C:/Program Files/` and call it whatever, for example `DRP Creative`.
|
||||
3. Do `[WindowsButton] + R`, type `Shell:StartUp`, hit enter. A folder will open.
|
||||
4. Put the exe file inside this folder(Now the app will start on pc start)
|
||||
5. If you want to run it now, double click it
|
||||
6. Enjoy!
|
||||
1. Grab the latest version from the [Releases](https://github.com/djkato/DRP_Creative/releases) page, then make a folder in `C:/Program Files/` and call it whatever, for example `DRP Creative`.
|
||||
3. Put the exe inside the folder you created and create a link to it.
|
||||
4. Do `[WindowsButton] + R`, type `Shell:StartUp`, hit enter. A folder will open.
|
||||
5. Take the link file and put it inside the startup folder (Now the app will start on pc start)
|
||||
6. If you want to run it now, double click it
|
||||
7. Enjoy!
|
||||
|
||||
## How to use:
|
||||
- App updates will be notified and suggested on startup via popup window.
|
||||
- When it's running, you'll notice a new icon appear on your Taskbar. If you want to include/exclude the **currently open project** from showing up, click on the icon and click on `Remove project from include/exclude list`.
|
||||
- There are two modes for the keywords list:
|
||||
1. Exclude(default): If the currently open project files name contains the keyword anywhere, it will show the default project name instead.
|
||||
2. Include: All projects will show default names, unless the the currently open project files name contains a keyword, then it will display the real name. This is a good alternative if you find yourself hiding more than showing what you're working on.
|
||||
- If you don't want to see the default project names, and instead just not display anything, you can change that behavior by setting `show_default_when_excluded` to `false` in the config file.
|
||||
- If you don't like the *"Portfolio: [your link]"* line on your status, you can disable it by setting `hide_portfolio_link` to `true`
|
||||
|
||||
When it's running, you'll notice a new icon appear on your Taskbar. If you want to exclude the **currently open project** from showing up, click on the icon and click on `Don't show current project`.
|
||||

|
||||
If you want to revert these settings, you can go to the folder you put the exe in (example was `C:/Program Files/DRP Creative`)
|
||||
Example `drp_config.toml`:
|
||||
```toml
|
||||
keywords_list = ["WORK", "Untitled 681*"]
|
||||
show_default_when_excluded = true # or false
|
||||
portfolio_link = "djkato.net"
|
||||
hide_portfolio_row = false
|
||||
should_list_include_or_exclude = "Include" # Or "Exclude", capital sensitive
|
||||
|
||||
```
|
||||
### Currently supported programs:
|
||||
**Full support:**
|
||||
- Cinema 4D
|
||||
|
@ -27,7 +45,7 @@ If you want to revert these settings, you can go to the folder you put the exe i
|
|||
- Autodesk 3Ds Max
|
||||
- Davinci Resolve
|
||||
- Isotropix Clarisse
|
||||
- Calvary
|
||||
- Cavalry
|
||||
- Ableton
|
||||
- FL Studio
|
||||
- Blender
|
||||
|
@ -37,5 +55,7 @@ If you want to revert these settings, you can go to the folder you put the exe i
|
|||
- Substance Designer ¹*
|
||||
- Substance Painter ¹*
|
||||
- Adobe Audition ¹*
|
||||
- ZBrush ¹*
|
||||
- Darktable ¹*
|
||||
|
||||
¹*sadly not doable, project name not in proces window title. They will show up though, just with default project name*
|
||||
¹*sadly not doable, project name not in proces window title. They will show up though, just with default project name*
|
||||
|
|
5
drp_config.toml
Normal file
5
drp_config.toml
Normal file
|
@ -0,0 +1,5 @@
|
|||
keywords_list = []
|
||||
show_default_when_excluded = true
|
||||
portfolio_link = "djkato.net"
|
||||
hide_portfolio_row = false
|
||||
should_list_include_or_exclude = "Exclude"
|
2
log.txt
Normal file
2
log.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
'Process_list_dump.exe' is not recognized as an internal or external command,
|
||||
operable program or batch file.
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 256.4 256.4" style="enable-background:new 0 0 256.4 256.4;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#00005B;}
|
||||
.st1{fill:#9999FF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M65.9,34.1h124.7c18.9,0,34.2,15.3,34.2,34.2v119.9c0,18.9-15.3,34.2-34.2,34.2H65.9
|
||||
c-18.9,0-34.2-15.3-34.2-34.2V68.3C31.7,49.4,47,34.1,65.9,34.1z"/>
|
||||
<g>
|
||||
<path class="st1" d="M107.5,146.7H77.6l-6.1,19c-0.2,0.8-0.8,1.2-1.5,1.1H54.9c-0.9,0-1.1-0.5-0.9-1.4L79.9,91
|
||||
c0.2-0.8,0.5-1.7,0.8-2.6c0.4-1.7,0.7-3.4,0.7-5.1c-0.1-0.4,0.2-0.8,0.7-0.9c0.1,0,0.2,0,0.2,0h20.6c0.5,0,1,0.2,1.1,0.7
|
||||
l29.2,82.5c0.2,0.9,0,1.3-0.8,1.3h-16.8c-0.5,0.1-1.1-0.3-1.3-0.9L107.5,146.7z M82.3,130.7h20.4c-0.5-1.7-1.1-3.7-1.9-5.8
|
||||
c-0.8-2.2-1.4-4.5-2.2-6.9c-0.8-2.5-1.5-4.9-2.3-7.4s-1.5-4.8-2.2-7.2c-0.7-2.3-1.2-4.4-1.8-6.2h-0.2c-0.8,3.5-1.6,6.9-2.7,10.4
|
||||
c-1.2,3.8-2.4,7.9-3.7,11.9C84.8,123.5,83.5,127.3,82.3,130.7L82.3,130.7z"/>
|
||||
<path class="st1" d="M194.8,103.4v49.3c0,2.2,0,4.1,0.1,5.8c0.1,1.7,0.2,3.2,0.2,4.4c0.2,1.3,0.2,2,0.3,2.9
|
||||
c0.1,0.8-0.2,1.1-0.9,1.1h-13.8c-0.7,0.1-1.3-0.3-1.5-0.9c-0.2-0.7-0.3-1.4-0.5-2c-0.2-0.5-0.2-1.1-0.2-1.7c-2.6,2.3-5.7,4-9.1,5
|
||||
c-2.9,0.8-5.9,1.2-9,1.2s-5.9-0.4-8.7-1.4c-2.6-0.9-5-2.4-6.9-4.4c-2.1-2.3-3.6-4.9-4.5-7.8c-1.1-3.7-1.7-7.5-1.6-11.4v-39.9
|
||||
c-0.1-0.5,0.2-1,0.8-1.1c0.1,0,0.2,0,0.2,0h15.4c0.5-0.1,1,0.2,1.1,0.8c0,0.1,0,0.2,0,0.2v37.8c0,3.5,0.8,6.3,2.3,8.4
|
||||
c1.5,2,4.7,3.1,8.3,3.1c1.9,0,3.7-0.3,5.5-1c1.9-0.7,3.5-1.5,5-2.6v-45.7c0-0.5,0.4-0.9,1.1-0.9H194c0.4-0.1,0.9,0.2,0.9,0.7
|
||||
C194.8,103.3,194.8,103.4,194.8,103.4z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 35 KiB |
BIN
program icons/after-effects.png
Normal file
BIN
program icons/after-effects.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
program icons/darktable.png
Normal file
BIN
program icons/darktable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 145 KiB |
BIN
program icons/zmanorig.png
Normal file
BIN
program icons/zmanorig.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
50
src/app.rs
50
src/app.rs
|
@ -30,6 +30,8 @@ pub enum AppKind {
|
|||
SubstancePainter,
|
||||
SubstanceDesigner,
|
||||
Vegas,
|
||||
ZBrush,
|
||||
Darktable,
|
||||
}
|
||||
|
||||
pub struct Apps {
|
||||
|
@ -52,10 +54,12 @@ pub struct Apps {
|
|||
SubstancePainter: App,
|
||||
SubstanceDesigner: App,
|
||||
Vegas: App,
|
||||
ZBrush: App,
|
||||
Darktable: App,
|
||||
}
|
||||
impl Apps {
|
||||
pub fn as_iter(&self) -> [&App; 19] {
|
||||
let APPS: [&App; 19] = [
|
||||
pub fn as_iter(&self) -> [&App; 21] {
|
||||
let APPS: [&App; 21] = [
|
||||
&self.C4d,
|
||||
&self.Maya,
|
||||
&self.ThreeDsMax,
|
||||
|
@ -75,13 +79,15 @@ impl Apps {
|
|||
&self.SubstancePainter,
|
||||
&self.SubstanceDesigner,
|
||||
&self.Vegas,
|
||||
&self.ZBrush,
|
||||
&self.Darktable,
|
||||
];
|
||||
APPS
|
||||
}
|
||||
}
|
||||
impl AppKind {
|
||||
pub fn as_iter() -> [AppKind; 19] {
|
||||
let APPKINDS: [AppKind; 19] = [
|
||||
pub fn as_iter() -> [AppKind; 21] {
|
||||
let APPKINDS: [AppKind; 21] = [
|
||||
AppKind::C4d,
|
||||
AppKind::Maya,
|
||||
AppKind::ThreeDsMax,
|
||||
|
@ -101,6 +107,8 @@ impl AppKind {
|
|||
AppKind::SubstancePainter,
|
||||
AppKind::SubstanceDesigner,
|
||||
AppKind::Vegas,
|
||||
AppKind::ZBrush,
|
||||
AppKind::Darktable,
|
||||
];
|
||||
APPKINDS
|
||||
}
|
||||
|
@ -222,6 +230,18 @@ impl Apps {
|
|||
drp_client_id: "1017882355723153448".to_string(),
|
||||
process_search_string: "VEGAS Pro".to_string(),
|
||||
},
|
||||
ZBrush: App {
|
||||
kind: AppKind::Vegas,
|
||||
default_project_name: "ZBrush Project".to_string(),
|
||||
drp_client_id: "1112734356855865425".to_string(),
|
||||
process_search_string: "ZBrush".to_string(),
|
||||
},
|
||||
Darktable: App {
|
||||
kind: AppKind::Darktable,
|
||||
default_project_name: "Darktable Project".to_string(),
|
||||
drp_client_id: "1116027286110609459".to_string(),
|
||||
process_search_string: "darktable.exe".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +249,10 @@ impl Apps {
|
|||
impl Apps {
|
||||
pub fn find_app(&self, str: &String) -> Option<&App> {
|
||||
for app in self.as_iter() {
|
||||
if str.contains(&app.process_search_string) {
|
||||
if str
|
||||
.to_lowercase()
|
||||
.contains(&app.process_search_string.to_lowercase())
|
||||
{
|
||||
return Some(&app);
|
||||
}
|
||||
}
|
||||
|
@ -241,19 +264,12 @@ impl App {
|
|||
pub fn parse(&self, window_title: &String) -> String {
|
||||
match self.kind {
|
||||
AppKind::C4d => {
|
||||
let mut end_i: usize = window_title.len();
|
||||
let mut start_i: usize = 0;
|
||||
for (i, char) in window_title.chars().enumerate() {
|
||||
if char == '[' {
|
||||
start_i = i;
|
||||
if let Some(curr_end_i) = window_title.rfind("] - ") {
|
||||
end_i = curr_end_i;
|
||||
} else {
|
||||
return self.default_project_name.clone();
|
||||
}
|
||||
if let Some(split1) = window_title.rsplit_once("]") {
|
||||
if let Some(split2) = split1.0.rsplit_once("[") {
|
||||
return split2.1.to_string();
|
||||
}
|
||||
}
|
||||
return window_title[start_i + 1..end_i].to_string();
|
||||
return self.default_project_name.clone();
|
||||
}
|
||||
AppKind::Maya => {
|
||||
let match_index = match window_title.as_str().find(".mb* - Autodesk Maya") {
|
||||
|
@ -456,6 +472,8 @@ impl App {
|
|||
};
|
||||
return window_title[..match_index as usize].to_string();
|
||||
}
|
||||
AppKind::ZBrush => self.default_project_name.clone(),
|
||||
AppKind::Darktable => self.default_project_name.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
176
src/config.rs
176
src/config.rs
|
@ -1,117 +1,91 @@
|
|||
use std::fs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs,
|
||||
io::{Read, Write},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub exclude_keywords_list: Vec<String>,
|
||||
pub should_exclude_be_invisible: bool,
|
||||
pub keywords_list: Vec<String>,
|
||||
pub show_default_when_excluded: bool,
|
||||
pub portfolio_link: String,
|
||||
pub hide_portfolio_row: bool,
|
||||
pub should_list_include_or_exclude: IncludeExclude,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> Config {
|
||||
let default_config = use_default_config();
|
||||
|
||||
//if no config file, parse default config file and try save it, then use it
|
||||
let config_file: Config = match fs::read_to_string(".drp_config") {
|
||||
Result::Err(_err) => {
|
||||
let def_config = parse_config_file(&default_config);
|
||||
make_config_file(&def_config);
|
||||
def_config
|
||||
}
|
||||
Result::Ok(val) => parse_config_file(&val),
|
||||
};
|
||||
config_file
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Config {
|
||||
keywords_list: Vec::new(),
|
||||
should_list_include_or_exclude: IncludeExclude::Exclude,
|
||||
portfolio_link: "djkato.net".to_owned(),
|
||||
hide_portfolio_row: false,
|
||||
show_default_when_excluded: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum IncludeExclude {
|
||||
Include,
|
||||
Exclude,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn exclude_project(&mut self, project_name: &String) {
|
||||
if self.exclude_keywords_list.contains(&project_name) {
|
||||
pub fn add_project(&mut self, project_name: &String) {
|
||||
if self.keywords_list.contains(&project_name) {
|
||||
return;
|
||||
}
|
||||
self.exclude_keywords_list.push(project_name.clone());
|
||||
make_config_file(&self);
|
||||
self.keywords_list.push(project_name.clone());
|
||||
self.write();
|
||||
}
|
||||
}
|
||||
fn parse_config_file(config_file: &String) -> Config {
|
||||
let mut exclude_keywords_list: Vec<String> = Vec::new();
|
||||
let mut should_exclude_be_invisible = false;
|
||||
let mut portfolio_link = String::new();
|
||||
|
||||
for (i, line) in config_file.lines().enumerate() {
|
||||
if line.contains("SHOULD_EXCLUDE_BE_ANONYMOUS:") {
|
||||
match config_file
|
||||
.lines()
|
||||
.nth(i + 1)
|
||||
.expect("index out of bounds")
|
||||
.to_lowercase()
|
||||
.as_str()
|
||||
{
|
||||
"n" => should_exclude_be_invisible = false,
|
||||
"no" => should_exclude_be_invisible = false,
|
||||
"y" => should_exclude_be_invisible = true,
|
||||
"yes" => should_exclude_be_invisible = true,
|
||||
_ => should_exclude_be_invisible = false,
|
||||
}
|
||||
}
|
||||
if line.contains("EXCLUDE_CHARACTERS_LIST:") {
|
||||
for arg_line in config_file.lines().skip(i + 1) {
|
||||
if arg_line.trim().contains("}") {
|
||||
break;
|
||||
}
|
||||
exclude_keywords_list.push(arg_line.to_string())
|
||||
}
|
||||
}
|
||||
if line.contains("PORTFOLIO_LINK:") {
|
||||
for arg_line in config_file.lines().skip(i) {
|
||||
if arg_line.trim().contains("}") {
|
||||
break;
|
||||
}
|
||||
portfolio_link = arg_line.to_string();
|
||||
}
|
||||
pub fn remove_project(&mut self, project_name: &String) {
|
||||
if self.keywords_list.contains(&project_name) {
|
||||
self.keywords_list.remove(
|
||||
self.keywords_list
|
||||
.iter()
|
||||
.position(|proj| proj == project_name)
|
||||
.unwrap(),
|
||||
);
|
||||
self.write();
|
||||
}
|
||||
}
|
||||
Config {
|
||||
exclude_keywords_list,
|
||||
should_exclude_be_invisible,
|
||||
portfolio_link,
|
||||
pub fn load_from_file(&mut self) {
|
||||
if !std::path::Path::new("drp_config.toml").exists() {
|
||||
self.write();
|
||||
} else {
|
||||
let mut file = fs::File::options()
|
||||
.read(true)
|
||||
.open("drp_config.toml")
|
||||
.expect(
|
||||
"Config file exists but can't be acccessed. Check permissions for the file.",
|
||||
);
|
||||
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content)
|
||||
.expect("config file not valid");
|
||||
|
||||
if content.is_empty() {
|
||||
self.write();
|
||||
}
|
||||
|
||||
*self = toml::from_str::<Config>(content.as_str())
|
||||
.expect("Config file exists, but the format of it is wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
let mut file = fs::File::options()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open("drp_config.toml")
|
||||
.expect("Couldn't write to file");
|
||||
let buff =
|
||||
toml::ser::to_string_pretty(self).expect("Something is wrong with the default config");
|
||||
|
||||
file.write_all(buff.as_bytes())
|
||||
.expect("Failed to write files");
|
||||
}
|
||||
}
|
||||
|
||||
fn make_config_file(config: &Config) {
|
||||
let mut config_file = String::from("SHOULD_EXCLUDE_BE_ANONYMOUS:{");
|
||||
config_file = config_file
|
||||
+ match config.should_exclude_be_invisible {
|
||||
true => "\ny\n}\n",
|
||||
false => "\nn\n}\n",
|
||||
};
|
||||
|
||||
config_file = config_file + "\nPORTFOLIO_LINK:{\ndjkato.net\n}\n";
|
||||
|
||||
config_file = config_file + "\nEXCLUDE_CHARACTERS_LIST:{";
|
||||
for exclusive_word in &config.exclude_keywords_list {
|
||||
config_file = config_file + format!("\n{}", exclusive_word).as_str();
|
||||
}
|
||||
config_file = config_file + "\n}\n";
|
||||
|
||||
match fs::write(".drp_config", config_file) {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn use_default_config() -> String {
|
||||
let str = String::from(
|
||||
"SHOULD_EXCLUDE_BE_ANONYMOUS:{
|
||||
n
|
||||
}
|
||||
|
||||
PORTFOLIO_LINK:{
|
||||
djkato.net
|
||||
}
|
||||
|
||||
EXCLUDE_CHARACTERS_LIST:{
|
||||
no_drp
|
||||
}
|
||||
",
|
||||
);
|
||||
str
|
||||
}
|
||||
|
|
100
src/main.rs
100
src/main.rs
|
@ -1,17 +1,29 @@
|
|||
#![windows_subsystem = "windows"] //UNCOMMENT ONLY WHEN BUILDING FOR RELEASE TO NOT SHOW TERMINAL WINDOW!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
#[macro_use]
|
||||
extern crate self_update;
|
||||
|
||||
pub mod app;
|
||||
pub mod config;
|
||||
pub mod program_status;
|
||||
pub mod self_updater;
|
||||
pub mod tray_icon;
|
||||
use crate::config::Config;
|
||||
use crate::config::{Config, IncludeExclude};
|
||||
use crate::program_status::*;
|
||||
use crate::self_updater::try_update;
|
||||
use app::{App, Apps};
|
||||
use discord_rich_presence::{activity, DiscordIpc, DiscordIpcClient};
|
||||
use std::process::exit;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::{thread, time};
|
||||
fn main() {
|
||||
match try_update() {
|
||||
Ok(_) => {}
|
||||
Err(e) => println!("Failed to update! {e}"),
|
||||
}
|
||||
let apps = Apps::construct_apps();
|
||||
let mut config = Config::load();
|
||||
let mut config = Config::default();
|
||||
|
||||
config.load_from_file();
|
||||
|
||||
let timeout = time::Duration::from_millis(5000);
|
||||
|
||||
|
@ -26,12 +38,32 @@ fn main() {
|
|||
'main: loop {
|
||||
if let Some(current_app) = current_app_option {
|
||||
if let Some(real_project_name) = is_program_still_running(¤t_app) {
|
||||
//if project name includes filtered words, use default project name
|
||||
for excluded_word in &config.exclude_keywords_list {
|
||||
if real_project_name.contains(excluded_word.as_str()) {
|
||||
project_name = current_app.default_project_name.clone();
|
||||
} else {
|
||||
project_name = real_project_name.clone();
|
||||
project_name = match config.should_list_include_or_exclude {
|
||||
IncludeExclude::Exclude => real_project_name.clone(),
|
||||
IncludeExclude::Include => current_app.default_project_name.clone(),
|
||||
};
|
||||
for listed_word in &config.keywords_list {
|
||||
match &config.should_list_include_or_exclude {
|
||||
&IncludeExclude::Exclude => {
|
||||
if real_project_name.contains(listed_word.as_str()) {
|
||||
if !&config.show_default_when_excluded {
|
||||
continue 'main;
|
||||
}
|
||||
project_name = current_app.default_project_name.clone();
|
||||
} else {
|
||||
project_name = real_project_name.clone();
|
||||
}
|
||||
}
|
||||
&IncludeExclude::Include => {
|
||||
if real_project_name.contains(listed_word.as_str()) {
|
||||
project_name = real_project_name.clone();
|
||||
} else {
|
||||
if !&config.show_default_when_excluded {
|
||||
continue 'main;
|
||||
}
|
||||
project_name = current_app.default_project_name.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//If discord client isn't connected create and conenct it
|
||||
|
@ -61,18 +93,25 @@ fn main() {
|
|||
prev_project_name = project_name.clone();
|
||||
let details = format!("Working on {}", &project_name.clone());
|
||||
//update activity
|
||||
let state = format!("Portfolio: {}", &config.portfolio_link);
|
||||
let activity = activity::Activity::new()
|
||||
.state(state.as_str())
|
||||
|
||||
let mut activity = activity::Activity::new()
|
||||
.details(&details.as_str())
|
||||
.assets(
|
||||
activity::Assets::new().large_image(current_app.drp_client_id.as_str()),
|
||||
)
|
||||
.timestamps(activity::Timestamps::new().start(start_time as i64));
|
||||
let state;
|
||||
if !config.hide_portfolio_row {
|
||||
state = format!("Portfolio: {}", &config.portfolio_link);
|
||||
activity = activity.state(state.as_str());
|
||||
}
|
||||
//if discord client exists, update status
|
||||
if let Some(dc) = discord_client.as_mut() {
|
||||
match dc.set_activity(activity) {
|
||||
_ => (),
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
dbg!(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,21 +124,38 @@ fn main() {
|
|||
//respond to tray icon messages
|
||||
match tray_receiver.try_recv() {
|
||||
Ok(msg) => match msg {
|
||||
tray_icon::Message::AnonymiseProject => {
|
||||
//only exclude project name if it's not the default one
|
||||
for app in apps.as_iter() {
|
||||
if app.kind == current_app.kind {
|
||||
if app.default_project_name != project_name {
|
||||
config.exclude_project(&project_name);
|
||||
}
|
||||
}
|
||||
tray_icon::Message::AddProjectToList => {
|
||||
if let Some(real_project_name) = is_program_still_running(¤t_app) {
|
||||
config.add_project(&real_project_name);
|
||||
}
|
||||
}
|
||||
tray_icon::Message::Quit => break 'main,
|
||||
tray_icon::Message::RemoveProjectFromList => {
|
||||
if let Some(real_project_name) = is_program_still_running(¤t_app) {
|
||||
config.remove_project(&real_project_name);
|
||||
}
|
||||
}
|
||||
tray_icon::Message::Quit => {
|
||||
println!("qiuitting!");
|
||||
exit(0)
|
||||
}
|
||||
tray_icon::Message::OpenOptionsFile => {
|
||||
let _ = std::process::Command::new("notepad")
|
||||
.arg("drp_config.toml")
|
||||
.current_dir("./")
|
||||
.spawn();
|
||||
}
|
||||
},
|
||||
Err(_err) => (),
|
||||
}
|
||||
} else {
|
||||
//respond to tray icon messages
|
||||
match tray_receiver.try_recv() {
|
||||
Ok(msg) => match msg {
|
||||
tray_icon::Message::Quit => exit(0),
|
||||
_ => (),
|
||||
},
|
||||
Err(_err) => (),
|
||||
}
|
||||
//If nothing is running try to find it
|
||||
if let Some(proj_name) = get_running_program(&apps) {
|
||||
let temp_curr_app: &App;
|
||||
|
|
|
@ -8,7 +8,10 @@ pub fn get_running_program(apps: &Apps) -> Option<(&App, String)> {
|
|||
for window_name in running_window_names {
|
||||
//println!("{}", &window_name);
|
||||
if let Some(app) = apps.find_app(&window_name) {
|
||||
if !window_name.contains("- Google Chrome") {
|
||||
if !window_name.contains("- Google Chrome")
|
||||
|| !window_name.contains(" Mozilla Firefox")
|
||||
|| !window_name.contains("- Brave")
|
||||
{
|
||||
//So googling it won't affect the DRP lol
|
||||
return Some((&app, app.parse(&window_name)));
|
||||
}
|
||||
|
@ -20,8 +23,14 @@ pub fn is_program_still_running(app: &App) -> Option<String> {
|
|||
let running_window_names = unsafe { get_running_windows_titles() };
|
||||
|
||||
for window_name in running_window_names {
|
||||
if window_name.contains(&app.process_search_string) {
|
||||
if !window_name.contains("- Google Chrome") {
|
||||
if window_name
|
||||
.to_lowercase()
|
||||
.contains(&app.process_search_string.to_lowercase())
|
||||
{
|
||||
if !window_name.contains("- Google Chrome")
|
||||
|| !window_name.contains(" Mozilla Firefox")
|
||||
|| !window_name.contains("- Brave")
|
||||
{
|
||||
//So googling it won't affect the DRP lol
|
||||
return Some(app.parse(&window_name));
|
||||
}
|
||||
|
|
46
src/self_updater.rs
Normal file
46
src/self_updater.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use windows::w;
|
||||
|
||||
pub fn try_update() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let build = self_update::backends::github::Update::configure()
|
||||
.repo_owner("djkato")
|
||||
.repo_name("DRP_Creative")
|
||||
.bin_name("DRP_Creative")
|
||||
.no_confirm(true)
|
||||
.current_version(cargo_crate_version!())
|
||||
.build()?;
|
||||
|
||||
let latest_release = build.get_latest_release()?;
|
||||
if self_update::version::bump_is_greater(
|
||||
build.current_version().as_str(),
|
||||
latest_release.version.as_str(),
|
||||
)? {
|
||||
let body: windows::core::HSTRING = format!(
|
||||
"Found update! \nCurrent version: {}\nFound Version: {}\nUpdate?",
|
||||
build.current_version(),
|
||||
latest_release.version
|
||||
)
|
||||
.into();
|
||||
if let Ok(response) = win_msgbox::MessageBox::<win_msgbox::OkayCancel>::new(body.as_ptr())
|
||||
.title(w!("DRP Creative Updater").as_ptr())
|
||||
.show()
|
||||
{
|
||||
match response {
|
||||
win_msgbox::OkayCancel::Cancel => {}
|
||||
win_msgbox::OkayCancel::Okay => {
|
||||
build.update()?;
|
||||
win_msgbox::MessageBox::<win_msgbox::Okay>::new(
|
||||
w!("Update successful, restart app to apply").as_ptr(),
|
||||
)
|
||||
.title(w!("DRP Creative").as_ptr())
|
||||
.icon(win_msgbox::Icon::Information)
|
||||
.show()
|
||||
.expect("Failed to show update successful window");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return Err("No updates found".into());
|
||||
}
|
||||
Err("Something got skipped".into())
|
||||
}
|
|
@ -4,23 +4,38 @@ use {std::sync::mpsc, tray_item::TrayItem};
|
|||
|
||||
pub enum Message {
|
||||
Quit,
|
||||
AnonymiseProject,
|
||||
AddProjectToList,
|
||||
RemoveProjectFromList,
|
||||
OpenOptionsFile,
|
||||
}
|
||||
|
||||
pub fn create_tray() -> (Receiver<Message>, TrayItem) {
|
||||
let mut tray = TrayItem::new("DRP Creative", "drp-icon").unwrap();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let tx1 = tx.clone();
|
||||
tray.add_label("DRP Creative Options").unwrap();
|
||||
let tx2 = tx.clone();
|
||||
let tx3 = tx.clone();
|
||||
let tx4 = tx.clone();
|
||||
tray.add_menu_item("Open options file", move || {
|
||||
tx4.send(Message::OpenOptionsFile).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
tray.add_menu_item("Don't show current project", move || {
|
||||
tx.send(Message::AnonymiseProject).unwrap();
|
||||
tray.add_menu_item("Add project to include/exclude list", move || {
|
||||
tx1.send(Message::AddProjectToList).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
tray.add_menu_item("Remove project from include/exclude list", move || {
|
||||
println!("REMOVE");
|
||||
tx3.send(Message::RemoveProjectFromList).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
tray.add_menu_item("Quit", move || {
|
||||
tx1.send(Message::Quit).unwrap();
|
||||
tx2.send(Message::Quit).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
return (rx, tray);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue