Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 57 additions & 219 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion config/applications.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ load_app {
'--country-code', 'PL',
'--administrative', 'Masovian',
}
}
}
29 changes: 18 additions & 11 deletions config/scripts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,17 @@ local function volume()
}
end

-- 5s duration on Windows due to an issue mentioned in oled-applications/media/README.md
local SPOTIFY_DURATION = PLATFORM.Os == 'windows' and 5000 or 1000
local function spotify()
local function media(source)
return {
widgets = {
Widget.Bar {
value = SPOTIFY.Progress,
range = { min = 0, max = SPOTIFY.Duration },
value = source.Position,
range = { min = 0, max = source.Duration or 0 },
position = { x = 0, y = 0 },
size = { width = SCREEN.Width, height = 2 },
},
Widget.Text {
text = string.format("%s - %s", SPOTIFY.Artist, SPOTIFY.Title),
text = table.concat({ source.Artist, source.Title }, ' - '),
scrolling = true,
position = { x = 0, y = 2 },
size = { width = SCREEN.Width, height = 20 },
Expand All @@ -71,7 +69,7 @@ local function spotify()
size = { width = SCREEN.Width, height = 2 },
},
},
duration = SPOTIFY_DURATION,
duration = 1000,
}
end

Expand Down Expand Up @@ -154,17 +152,26 @@ local function weather()
}
end

-- Helper function to easily register layout for any media source
function make_media_layout(source)
return {
layout = function() return media(_ENV[source]) end,
run_on = {
string.format('%s.Artist', source),
string.format('%s.Progress', source),
string.format('%s.Title', source)
},
}
end

SCREEN_BUILDER
:new('Emulator')
:with_layout_group({
{
layout = volume,
run_on = { 'AUDIO.Input', 'AUDIO.Output' },
},
{
layout = spotify,
run_on = { 'SPOTIFY.Artist', 'SPOTIFY.Progress', 'SPOTIFY.Title' },
},
make_media_layout('SPOTIFY'),
{
layout = clock,
run_on = { 'CLOCK.Seconds' },
Expand Down
10 changes: 5 additions & 5 deletions omni-led-applications/media/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ omni-led-api = { path = "../../omni-led-api" }
omni-led-derive = { path = "../../omni-led-derive", features = ["into-proto"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

[target.'cfg(target_os = "windows")'.dependencies.windows]
version = "0.62"
features = ["Foundation", "Foundation_Collections", "Media_Control"]
[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.62", features = ["Foundation", "Foundation_Collections", "Media_Control"] }

[target.'cfg(target_os = "linux")'.dependencies.mpris]
version = "2"
[target.'cfg(target_os = "linux")'.dependencies]
futures-util = "0.3"
zbus = { version = "5", features = ["tokio"] }
39 changes: 22 additions & 17 deletions omni-led-applications/media/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Media

Media application provides information about currently playing media, e.g. title, artist, duration etc.
Media application provides information about currently playing media, e.g., title, artist, duration, etc.

## Running

Expand All @@ -14,16 +14,20 @@ Media expects three arguments
- `a`/`address` - server address
- Optional:
- `m`/`mode` - reporting mode - `individual`, `focused` or `both`.
Default: `both`.
Described in [reporting mode](#reporting-mode).
Default: `both`.
Described in [reporting mode](#reporting-mode).
- `map` - map input application name to an event name, e.g. `--map "my_app_name=APP"`. Can be passed multiple
times. Target name must be an uppercase alphanumeric string, that can contain underscores and cannot start with a
number.
Default: `[]`.
Describen in [application name mapping](#application-name-mapping).
times. Target name must be an uppercase alphanumeric string that can contain underscores and cannot start with a
number.
Default: `[]`.
Described in [application name mapping](#application-name-mapping).

## Reporting mode

> On Linux with MPRIS, there is no concept of a “currently focused” media source. As a result, only individual
> updates are sent. Setting the mode to “Both” behaves the same as “Individual”, while setting it to “Focused”
> results in no events being sent.

### Individual

Send separate events for each currently playing application. Each application will have its own event name as
Expand All @@ -36,15 +40,15 @@ All updates will be sent with event name `MEDIA`, regardless of source applicati

### Both

Report events in both ways - individual per application and combined for currently focused application.
Report events in both ways individual per application and combined for currently focused application.

## Application name mapping

When sending events in [individual](#individual) mode, application names will be mapped to event names.
If mapping was provided as a command line parameter, then it will use the target name from that mapping.
If mapping was not provided, source application name will be converted in the following manner:
If mapping was not provided, the source application name will be converted in the following manner:

- If name starts with a digit it will be prefixed with an underscore.
- If the name starts with a digit, it will be prefixed with an underscore.
- All ascii letters will be converted to uppercase.
- All non-alphanumeric characters will be converted to underscores.

Expand All @@ -63,16 +67,17 @@ Examples:

Media sends a single type of event, and its name depends on the selected [mode](#reporting-mode).

> There is a discrepancy in event frequency between current implementations on Windows and Linux operating systems.
> On Windows the interval seems to be around 4 seconds and on Linux it's a fixed update interval of 1 second.
> Apps report the updates with varying frequencies.
> This application tracks the playback rate and duration since the last update to send updates once every ~500ms.

> Availability of event fields depends entirely on the media source. Be sure to check if a field is present when
> The availability of event fields depends entirely on the media source. Be sure to check if a field is present when
> handling media events.

`MEDIA` or `<MAPPED_NAME>`: table

- `Artist`: string,
- `Title`: string,
- `Progress`: integer (value in milliseconds),
- `Duration`: integer (value in milliseconds),
- `Artist`: string | none,
- `Title`: string | none,
- `Position`: integer (value in milliseconds),
- `Duration`: integer (value in milliseconds) | none,
- `Playing`: bool,
- `Rate`: float (Playback speed multiplier - `1.0` for regular speed)
4 changes: 1 addition & 3 deletions omni-led-applications/media/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ async fn main() {
}
let mode = options.mode;

let media = Media::new(tx.clone());

let loop_handle = tokio::task::spawn(async move {
while let Some((current, name, session_data)) = rx.recv().await {
if current && (mode == Focused || mode == Both) {
Expand All @@ -51,7 +49,7 @@ async fn main() {
}
});

media.run().await;
Media::run(tx).await;

loop_handle.await.unwrap();
}
Expand Down
Loading
Loading