Skip to content

Commit

Permalink
feat: add media_control plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
DASPRiD committed Nov 22, 2023
1 parent 08abd84 commit 35bf42f
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 2 deletions.
53 changes: 53 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ file-rotate = "0.7.4"
hyper = { version = "0.14.27", features = ["http1", "server"] }
log = "0.4.17"
reqwest = { version = "0.11.17", features = ["default", "json"], optional = true }
enigo = { version = "0.2.0-rc2", optional = true }
searchlight = "0.3.1"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.105"
Expand All @@ -42,6 +43,7 @@ tray-item = { version = "0.9.0", features = ["ksni"] }
tray-item = { version = "0.9.0" }

[features]
default = ["pishock", "watch"]
default = ["media-control", "pishock", "watch"]
media-control = ["dep:enigo"]
pishock = ["dep:reqwest"]
watch = []
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Please note that on Windows oyu will not see any debug output on the console wit

Log files can be found on Linux under `~/.local/share/vrc-osc-manager\logs`. On Windows they should be located under
`C:\Users\username\Application Data\vrc-osc-manager\logs`. The latest log file is always called `log`, while older
ones are suffixed with a timestamp. Log files are rotated every hour and a maximum of 12 log files is every kept.
ones are suffixed with a timestamp.

## Dark mode

Expand All @@ -64,6 +64,16 @@ Both Linux and Windows are supported, though Linux is the primarily tested platf

## Plugins

### Media Control

This plugin allows you to control your local media player from VRChat without relying on overlays. All you need is to
set up is a menu within your avatar with buttons controlling the following booleans:

- `MC_PrevTrack`
- `MC_NextTrack`
- `MC_PlayPause`
- `MC_Stop`

### Watch

This plugin drives the [OSC Watch VRChat accessory](https://booth.pm/en/items/3687002) component. It implements the
Expand Down
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ async fn run_plugins(
receiver_tx: broadcast::Sender<OscMessage>,
sender_tx: mpsc::Sender<OscMessage>,
) -> Result<()> {
#[cfg(feature = "media-control")]
{
let receiver_rx = receiver_tx.subscribe();
subsys.start("PluginMediaControl", |subsys| {
plugins::media_control::MediaControl::new(receiver_rx).run(subsys)
});
}

#[cfg(feature = "watch")]
{
let sender_tx = sender_tx.clone();
Expand Down
3 changes: 3 additions & 0 deletions src/osc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ impl Query {
"".to_string(),
);

#[cfg(feature = "media-control")]
plugins::media_control::register_osc_query_parameters(&mut osc_query_service);

#[cfg(feature = "pishock")]
plugins::pishock::register_osc_query_parameters(&mut osc_query_service);

Expand Down
103 changes: 103 additions & 0 deletions src/plugins/media_control.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use anyhow::{bail, Result};
use async_osc::{prelude::OscMessageExt, OscMessage, OscType};
use enigo::Direction::Click;
use enigo::{Enigo, Key, Keyboard, Settings};
use log::{debug, warn};
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::RecvError;
use tokio_graceful_shutdown::{errors::CancelledByShutdown, FutureExt, SubsystemHandle};

use crate::osc_query::{OscAccess, OscQueryService};

pub struct MediaControl {
rx: broadcast::Receiver<OscMessage>,
}

impl MediaControl {
pub fn new(rx: broadcast::Receiver<OscMessage>) -> Self {
Self { rx }
}

async fn handle_buttons(&mut self) -> Result<()> {
let mut enigo = Enigo::new(&Settings::default())?;

loop {
match self.rx.recv().await {
Ok(message) => match message.as_tuple() {
("/avatar/parameters/MC_PrevTrack", &[OscType::Bool(value)]) => {
if value {
enigo.key(Key::MediaPrevTrack, Click)?;
}
}
("/avatar/parameters/MC_NextTrack", &[OscType::Bool(value)]) => {
if value {
enigo.key(Key::MediaNextTrack, Click)?;
}
}
("/avatar/parameters/MC_PlayPause", &[OscType::Bool(value)]) => {
if value {
enigo.key(Key::MediaPlayPause, Click)?;
}
}
("/avatar/parameters/MC_Stop", &[OscType::Bool(value)]) => {
if value {
enigo.key(Key::MediaStop, Click)?;
}
}
_ => {}
},
Err(error) => match error {
RecvError::Closed => {
debug!("Channel closed");
break;
}
RecvError::Lagged(skipped) => {
warn!(
"MediaControl lagging behind, {} messages have been dropped",
skipped
);
}
},
}
}

bail!("Message receiver died unexpectedly");
}

pub async fn run(mut self, subsys: SubsystemHandle) -> Result<()> {
match (self.handle_buttons().cancel_on_shutdown(&subsys)).await {
Ok(Ok(())) => subsys.request_shutdown(),
Ok(Err(error)) => return Err(error),
Err(CancelledByShutdown) => {}
}

Ok(())
}
}

pub fn register_osc_query_parameters(service: &mut OscQueryService) {
service.add_endpoint(
"/avatar/parameters/MC_PrevTrack".to_string(),
"b".to_string(),
OscAccess::Read,
"Media Control: Previous Track".to_string(),
);
service.add_endpoint(
"/avatar/parameters/MC_NextTrack".to_string(),
"b".to_string(),
OscAccess::Read,
"Media Control: Next Track".to_string(),
);
service.add_endpoint(
"/avatar/parameters/MC_PlayPause".to_string(),
"b".to_string(),
OscAccess::Read,
"Media Control: Play/Pause".to_string(),
);
service.add_endpoint(
"/avatar/parameters/MC_Stop".to_string(),
"b".to_string(),
OscAccess::Read,
"Media Control: Stop".to_string(),
);
}
2 changes: 2 additions & 0 deletions src/plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#[cfg(feature = "media-control")]
pub mod media_control;
#[cfg(feature = "pishock")]
pub mod pishock;
#[cfg(feature = "watch")]
Expand Down

0 comments on commit 35bf42f

Please sign in to comment.