Skip to content

Commit

Permalink
feat: add function support to media provider
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-berger committed Nov 21, 2024
1 parent 001c49c commit e641f1a
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 13 deletions.
7 changes: 7 additions & 0 deletions examples/boilerplate-solid-ts/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ function App() {
<div class="chip">
Media: {output.media?.session?.title} -
{output.media?.session?.artist}
<button onClick={() => output.media?.play()}>Play</button>
<button onClick={() => output.media?.pause()}>Pause</button>
<button onClick={() => output.media?.togglePlayPause()}>
Toggle Play Pause
</button>
<button onClick={() => output.media?.next()}>Next</button>
<button onClick={() => output.media?.previous()}>Previous</button>
</div>
<div class="chip">CPU usage: {output.cpu?.usage}</div>
<div class="chip">
Expand Down
15 changes: 15 additions & 0 deletions packages/client-api/src/desktop/desktop-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ export const desktopCommands = {
startPreset,
listenProvider,
unlistenProvider,
callProviderFunction,
setAlwaysOnTop,
setSkipTaskbar,
};

export type ProviderFunction = MediaFunction;

export interface MediaFunction {
type: 'media';
function: 'play' | 'pause' | 'toggle_play_pause' | 'next' | 'previous';
}

function startWidget(
configPath: string,
placement: WidgetPlacement,
Expand All @@ -43,6 +51,13 @@ function unlistenProvider(configHash: string): Promise<void> {
return invoke<void>('unlisten_provider', { configHash });
}

function callProviderFunction(args: {
configHash: string;
function: ProviderFunction;
}): Promise<void> {
return invoke<void>('call_provider_function', args);
}

function setAlwaysOnTop(): Promise<void> {
return invoke<void>('set_always_on_top');
}
Expand Down
51 changes: 43 additions & 8 deletions packages/client-api/src/providers/media/create-media-provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from 'zod';
import { createBaseProvider } from '../create-base-provider';
import { onProviderEmit } from '~/desktop';
import { desktopCommands, onProviderEmit } from '~/desktop';
import type {
MediaOutput,
MediaProvider,
Expand All @@ -17,12 +17,47 @@ export function createMediaProvider(
const mergedConfig = mediaProviderConfigSchema.parse(config);

return createBaseProvider(mergedConfig, async queue => {
return onProviderEmit<MediaOutput>(mergedConfig, ({ result }) => {
if ('error' in result) {
queue.error(result.error);
} else {
queue.output(result.output);
}
});
return onProviderEmit<MediaOutput>(
mergedConfig,
({ result, configHash }) => {
if ('error' in result) {
queue.error(result.error);
} else {
queue.output({
...result.output,
play: () => {
desktopCommands.callProviderFunction({
configHash,
function: { type: 'media', function: 'play' },
});
},
pause: () => {
desktopCommands.callProviderFunction({
configHash,
function: { type: 'media', function: 'pause' },
});
},
togglePlayPause: () => {
desktopCommands.callProviderFunction({
configHash,
function: { type: 'media', function: 'toggle_play_pause' },
});
},
next: () => {
desktopCommands.callProviderFunction({
configHash,
function: { type: 'media', function: 'next' },
});
},
previous: () => {
desktopCommands.callProviderFunction({
configHash,
function: { type: 'media', function: 'previous' },
});
},
});
}
},
);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export interface MediaProviderConfig {

export interface MediaOutput {
session: MediaSession | null;
play(): void;
pause(): void;
togglePlayPause(): void;
next(): void;
previous(): void;
}

export interface MediaSession {
Expand Down
56 changes: 52 additions & 4 deletions packages/desktop/src/providers/media/media_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ use windows::{
},
};

use crate::providers::{CommonProviderState, Provider, RuntimeType};
use crate::providers::{
CommonProviderState, MediaFunction, Provider, ProviderFunction,
ProviderFunctionResponse, ProviderFunctionResult, ProviderInputMsg,
RuntimeType,
};

#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -93,9 +97,53 @@ impl MediaProvider {
self.register_session_changed_handler(&manager)?;
self.create_session()?;

while let Ok(event) = self.event_receiver.recv() {
debug!("Got media session event: {:?}", event);
self.handle_event(event)?;
loop {
crossbeam::select! {
recv(self.event_receiver) -> event => {
if let Ok(event) = event {
debug!("Got media session event: {:?}", event);
self.handle_event(event)?;
}
}
recv(self.common.input.sync_rx) -> input => {
match input {
Ok(ProviderInputMsg::Stop) => {
break;
}
Ok(ProviderInputMsg::Function(
ProviderFunction::Media(media_function),
sender,
)) => {
if let Some(session) = &self.session {
let result = match media_function {
MediaFunction::Play => {
session.TryPlayAsync()?.get()?;
Ok(ProviderFunctionResponse::Null)
}
MediaFunction::Pause => {
session.TryPauseAsync()?.get()?;
Ok(ProviderFunctionResponse::Null)
}
MediaFunction::TogglePlayPause => {
session.TryTogglePlayPauseAsync()?.get()?;
Ok(ProviderFunctionResponse::Null)
}
MediaFunction::Next => {
session.TrySkipNextAsync()?.get()?;
Ok(ProviderFunctionResponse::Null)
}
MediaFunction::Previous => {
session.TrySkipPreviousAsync()?.get()?;
Ok(ProviderFunctionResponse::Null)
}
};
sender.send(result).unwrap();
}
}
_ => {}
}
}
}
}

Ok(())
Expand Down
6 changes: 5 additions & 1 deletion packages/desktop/src/providers/provider_function.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "function", rename_all = "snake_case")]
pub enum ProviderFunction {
Media(MediaFunction),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MediaFunction {
PlayPause,
Play,
Pause,
TogglePlayPause,
Next,
Previous,
}
Expand Down
5 changes: 5 additions & 0 deletions packages/desktop/src/providers/provider_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ impl ProviderManager {
config_hash: String,
function: ProviderFunction,
) -> anyhow::Result<ProviderFunctionResponse> {
info!(
"Calling provider function: {:?} for: {}",
function, config_hash
);

let provider_refs = self.provider_refs.lock().await;
let provider_ref = provider_refs
.get(&config_hash)
Expand Down

0 comments on commit e641f1a

Please sign in to comment.