Compare commits
6 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 44edd7aa8b | |||
| e79cac13cc | |||
| d1d03155e3 | |||
| e808886083 | |||
| 20f73be4c1 | |||
| ccc6603f88 |
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
# custom
|
||||
.env
|
||||
app/data.json
|
||||
|
||||
# ---> Rust
|
||||
# Generated by Cargo
|
||||
|
|
|
|||
13
README.md
|
|
@ -1,3 +1,12 @@
|
|||
# hdrezka-discord-rpc
|
||||
# HDRezka Discord RPC | Chrome Extension
|
||||
|
||||
HDRezka Discord RPC | Chrome Extension
|
||||
## How to build app
|
||||
```
|
||||
git clone https://git.amok.dev/AmokDev/HDRezcord.git
|
||||
```
|
||||
```
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
## How to build extension
|
||||
- SOON
|
||||
|
|
@ -1,11 +1,21 @@
|
|||
[package]
|
||||
name = "DiscordRPC-HDRezcord-APP"
|
||||
version = "0.1.0"
|
||||
version = "0.1.3"
|
||||
authors = ["AmokDev <amokdevv@gmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4"
|
||||
rust-discord-activity = { git = "https://github.com/AmokDev/rust-discord-activity", version = "0.3.1" }
|
||||
image = "0.25.5"
|
||||
open = "5.3.2"
|
||||
dioxus = { version = "0.6.3", features = ["desktop"] }
|
||||
dioxus-desktop = "0.6.3"
|
||||
rust-discord-rpc = { git = "https://git.amok.dev/AmokDev/rust-discord-rpc", version = "1.0.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||
tray-icon = "0.20.0"
|
||||
winit = "0.30.9"
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
winresource = "0.1.20"
|
||||
|
|
|
|||
11
app/build.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#[cfg(windows)]
|
||||
fn main() {
|
||||
let mut res = winresource::WindowsResource::new();
|
||||
res.set_icon("resources/icon.ico");
|
||||
res.compile().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn main() {
|
||||
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
{"episode":6,"season":1,"timestamps":[18000,2597000],"name":"Элементарно","image_url":"https://statichdrezka.ac/i/2020/12/17/xe6ea25038d76rc83x59z.jpeg"}
|
||||
{"episode":0,"season":0,"timestamps":[1,1],"name":"Полетта","image_url":"https://statichdrezka.ac/i/2014/1/25/ze3dffce6f572bx77h96o.jpg"}
|
||||
BIN
app/resources/icon.ico
Normal file
|
After Width: | Height: | Size: 264 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
use rust_discord_activity::{
|
||||
use rust_discord_rpc::{
|
||||
DiscordClient,
|
||||
Asset,
|
||||
Timestamp,
|
||||
|
|
@ -17,8 +17,13 @@ pub async fn start_presence() {
|
|||
let _ = client.connect();
|
||||
println!(":: Rich Presence started!");
|
||||
|
||||
|
||||
loop {
|
||||
if client.is_connected == false {
|
||||
println!(":: Reconnecting...");
|
||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||
let _ = client.connect();
|
||||
continue;
|
||||
}
|
||||
let post_data = load_from_json();
|
||||
let mut episode: u8 = 0;
|
||||
let mut season: u8 = 0;
|
||||
|
|
@ -33,29 +38,41 @@ pub async fn start_presence() {
|
|||
image_url = data.image_url;
|
||||
}
|
||||
|
||||
let asset = Asset::new(Some(image_url), Some(String::from("#noWar")), None, None);
|
||||
let mut asset = Asset::new(Some(image_url.clone()), None, None, None);
|
||||
let now_in_millis = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis();
|
||||
let timestamp = Timestamp::new(Some(now_in_millis - timestamps[0]), Some(now_in_millis + (timestamps[1] - timestamps[0])));
|
||||
let mut activity = Activity::new();
|
||||
let mut activity_type = ActivityType::WATCHING;
|
||||
|
||||
let mut subtitle = format!("Сезон {season} Серия {episode}");
|
||||
if season == 0 && episode == 0 {
|
||||
subtitle = format!("Фильм");
|
||||
}
|
||||
if episode == 0 && timestamps[0] == 0 && timestamps[1] == 0 {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
client.is_connected = false;
|
||||
continue;
|
||||
}
|
||||
if timestamps[0] == 1 && timestamps[1] == 1 {
|
||||
activity_type = ActivityType::COMPETING;
|
||||
asset = Asset::new(Some(image_url), Some(String::from("Paused")), None, None);
|
||||
}
|
||||
if timestamps[0] == 2 && timestamps[1] == 2 {
|
||||
activity_type = ActivityType::COMPETING;
|
||||
asset = Asset::new(Some(String::from("hdrezcord-logo")), None, None, None);
|
||||
name = String::from("Ничего не смотрит");
|
||||
subtitle = String::from("...");
|
||||
}
|
||||
// сорян за гкод, потом пофикшу
|
||||
activity
|
||||
.set_state(Some(subtitle).into())
|
||||
.set_activity_type(Some(ActivityType::WATCHING))
|
||||
.set_activity_type(Some(activity_type))
|
||||
.set_details(Some(name))
|
||||
.set_timestamps(Some(timestamp))
|
||||
.set_assets(Some(asset))
|
||||
.set_instance(Some(true));
|
||||
|
||||
let payload = Payload::new(EventName::Activity, EventData::Activity(activity));
|
||||
|
||||
if episode == 0 && timestamps[0] == 0 && timestamps[1] == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let _ = client.send_payload(payload);
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
|
|
|
|||
BIN
app/src/icons/32.ico
Normal file
|
After Width: | Height: | Size: 184 KiB |
|
|
@ -1,12 +1,21 @@
|
|||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
mod network;
|
||||
mod discord;
|
||||
mod utils;
|
||||
|
||||
use network::api::start_api;
|
||||
use discord::rpc::start_presence;
|
||||
use utils::tray::init_tray;
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
std::thread::spawn(|| {
|
||||
init_tray();
|
||||
});
|
||||
let _ = tokio::join!(start_api(), start_presence());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::utils::json_database::{save_to_json, PostData};
|
|||
|
||||
#[post("/set_presence")]
|
||||
async fn set_presence(data: web::Json<PostData>) -> HttpResponse {
|
||||
// println!("{:?}", data);
|
||||
println!("{:?}", data);
|
||||
let _ = save_to_json(&data);
|
||||
HttpResponse::Ok().finish()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
pub mod json_database;
|
||||
pub mod json_database;
|
||||
pub mod tray;
|
||||
113
app/src/utils/tray.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
use tray_icon::{
|
||||
menu::{Menu, MenuEvent, MenuId, MenuItem},
|
||||
TrayIcon, TrayIconBuilder, TrayIconEvent,
|
||||
};
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
event_loop::EventLoop, platform::windows::EventLoopBuilderExtWindows,
|
||||
};
|
||||
use std::process;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum UserEvent {
|
||||
MenuEvent(tray_icon::menu::MenuEvent),
|
||||
}
|
||||
|
||||
struct Application {
|
||||
tray_icon: Option<TrayIcon>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
fn new() -> Application {
|
||||
Application { tray_icon: None }
|
||||
}
|
||||
|
||||
fn new_tray_icon() -> TrayIcon {
|
||||
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/src/icons/32.ico");
|
||||
let icon = load_icon(std::path::Path::new(path));
|
||||
|
||||
TrayIconBuilder::new()
|
||||
.with_menu(Box::new(Self::new_tray_menu()))
|
||||
.with_tooltip("HDRezcord")
|
||||
.with_icon(icon)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn new_tray_menu() -> Menu {
|
||||
let menu = Menu::new();
|
||||
let _ = menu.append(&MenuItem::new("Sources", true, None));
|
||||
// let _ = menu.append(&MenuItem::new("Stop Presence", true, None));
|
||||
let _ = menu.append(&MenuItem::new("Exit", true, None));
|
||||
menu
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler<UserEvent> for Application {
|
||||
fn resumed(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
_event_loop: &winit::event_loop::ActiveEventLoop,
|
||||
_window_id: winit::window::WindowId,
|
||||
_event: winit::event::WindowEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn new_events(
|
||||
&mut self,
|
||||
_event_loop: &winit::event_loop::ActiveEventLoop,
|
||||
cause: winit::event::StartCause,
|
||||
) {
|
||||
if winit::event::StartCause::Init == cause {
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
self.tray_icon = Some(Self::new_tray_icon());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn user_event(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop, event: UserEvent) {
|
||||
// println!("{event:?}");
|
||||
match event {
|
||||
UserEvent::MenuEvent(menu_event) => {
|
||||
// println!("{:?}", menu_event.id);
|
||||
if menu_event.id == MenuId("1001".to_string()) {
|
||||
let _ = open::that("https://git.amok.dev/AmokDev/HDRezcord");
|
||||
} else if menu_event.id == MenuId("1002".to_string()) {
|
||||
process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_tray() {
|
||||
let event_loop = EventLoop::<UserEvent>::with_user_event().with_any_thread(true).build().unwrap();
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
MenuEvent::set_event_handler(Some(move |event| {
|
||||
let _ = proxy.send_event(UserEvent::MenuEvent(event));
|
||||
}));
|
||||
|
||||
let mut app = Application::new();
|
||||
|
||||
let _menu_channel = MenuEvent::receiver();
|
||||
let _tray_channel = TrayIconEvent::receiver();
|
||||
|
||||
if let Err(err) = event_loop.run_app(&mut app) {
|
||||
println!("Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
|
||||
let (icon_rgba, icon_width, icon_height) = {
|
||||
let image = image::open(path)
|
||||
.expect("Failed to open icon path")
|
||||
.into_rgba8();
|
||||
let (width, height) = image.dimensions();
|
||||
let rgba = image.into_raw();
|
||||
(rgba, width, height)
|
||||
};
|
||||
tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
|
||||
}
|
||||
40
content.js
|
|
@ -56,12 +56,32 @@ function get_timestamps() {
|
|||
return [0, 0];
|
||||
}
|
||||
|
||||
if (!get_timestamps.previousTimes) {
|
||||
get_timestamps.previousTimes = [];
|
||||
}
|
||||
|
||||
get_timestamps.previousTimes.push(currentTime);
|
||||
|
||||
if (get_timestamps.previousTimes.length > 3) {
|
||||
get_timestamps.previousTimes.shift();
|
||||
}
|
||||
|
||||
if (get_timestamps.previousTimes.length === 3 &&
|
||||
get_timestamps.previousTimes.every(val => val === currentTime)) {
|
||||
console.warn("currentTime repeated too many times");
|
||||
return [1, 1];
|
||||
}
|
||||
|
||||
return [timeToMilliseconds(currentTime), timeToMilliseconds(totalTime)];
|
||||
}
|
||||
|
||||
function get_name() {
|
||||
let element = document.querySelector('.b-post__title h1[itemprop="name"]');
|
||||
return element.textContent;
|
||||
try {
|
||||
return element.textContent;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_url() {
|
||||
|
|
@ -73,7 +93,7 @@ if (window.location.href.includes("flymaterez.net")) {
|
|||
setInterval(async () => {
|
||||
try {
|
||||
chrome.storage.local.get(['pluginEnabled'], function(result) {
|
||||
if (result.pluginEnabled === true) {
|
||||
if (result.pluginEnabled === true && get_name() !== null) {
|
||||
chrome.runtime.sendMessage({
|
||||
type: "send_rpc_request",
|
||||
title: document.title,
|
||||
|
|
@ -84,12 +104,22 @@ if (window.location.href.includes("flymaterez.net")) {
|
|||
name: get_name(),
|
||||
image_url: get_image_url(),
|
||||
});
|
||||
} else if (result.pluginEnabled === true && get_name() === null) {
|
||||
chrome.runtime.sendMessage({
|
||||
type: "send_rpc_request",
|
||||
title: document.title,
|
||||
url: window.location.href,
|
||||
episode: 0,
|
||||
season: 0,
|
||||
timestamps: [2, 2],
|
||||
name: "name",
|
||||
image_url: "image_url",
|
||||
});
|
||||
}
|
||||
console.log(result.pluginEnabled);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
// console.log(error);
|
||||
;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
|
|
|||
BIN
icons/128.png
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 11 KiB |
BIN
icons/16.png
|
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 545 B |
BIN
icons/32.png
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 971 B |
BIN
icons/48.png
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 1.3 KiB |
14
popup.js
|
|
@ -9,11 +9,21 @@ function edit_status() {
|
|||
if (result.pluginEnabled === true) {
|
||||
chrome.storage.local.set({ pluginEnabled: false });
|
||||
plugin_status.innerHTML = "Plugin is disabled";
|
||||
chrome.runtime.sendMessage({
|
||||
type: "send_rpc_request",
|
||||
title: document.title,
|
||||
url: window.location.href,
|
||||
episode: 0,
|
||||
season: 0,
|
||||
timestamps: [0, 0],
|
||||
name: "name",
|
||||
image_url: "image_url",
|
||||
});
|
||||
} else if (result.pluginEnabled === false) {
|
||||
chrome.storage.local.set({ pluginEnabled: true });
|
||||
plugin_status.innerHTML = "Plugin is enabled";
|
||||
}
|
||||
console.log(result.pluginEnabled);
|
||||
// console.log(result.pluginEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -30,7 +40,7 @@ function get_status() {
|
|||
} else if (result.pluginEnabled === false) {
|
||||
plugin_status.innerHTML = "Plugin is disabled";
|
||||
}
|
||||
console.log(result.pluginEnabled);
|
||||
// console.log(result.pluginEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ async function send_rpc_request(data) {
|
|||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
console.log(response.type)
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
|
|
@ -27,7 +26,6 @@ chrome.runtime.onMessage.addListener(
|
|||
name: request.name,
|
||||
image_url: request.image_url
|
||||
})
|
||||
console.log(request.episode, request.season, request.timestamps)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||