Skip to content

Commit

Permalink
Support custom video players
Browse files Browse the repository at this point in the history
  • Loading branch information
d-k-bo committed Oct 29, 2023
1 parent 8d27fbf commit f1e27eb
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 142 deletions.
2 changes: 2 additions & 0 deletions data/resources/icons/scalable/actions/error-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions data/resources/icons/scalable/actions/test-pass-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 30 additions & 15 deletions po/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Televido main\n"
"Report-Msgid-Bugs-To: https://github.com/d-k-bo/televido/issues\n"
"POT-Creation-Date: 2023-10-26 21:32+0200\n"
"POT-Creation-Date: 2023-10-29 18:20+0100\n"
"PO-Revision-Date: 2023-10-20 20:55+0200\n"
"Last-Translator: David Cabot <[email protected]>\n"
"Language-Team: \n"
Expand Down Expand Up @@ -72,7 +72,7 @@ msgstr ""
msgid "Initital release"
msgstr "Erstveröffentlichung"

#: src/application.rs:116
#: src/application.rs:129
msgid "Failed to play video stream"
msgstr "Videostream konnte nicht abgespielt werden"

Expand Down Expand Up @@ -104,38 +104,53 @@ msgstr "Abbrechen"
msgid "Confirm"
msgstr "Bestätigen"

#: src/launcher/selector.rs:76
#: src/launcher/selector.blp:38
msgid "Custom program"
msgstr "Benutzerdefiniertes Programm"

#. translators: `{}` is replaced by the application ID, e.g. `org.example.Application`
#: src/launcher/selector.rs:115
msgid "Could not find application “{}”"
msgstr "Anwendung „{}“ konnte nicht gefunden werden"

#: src/launcher/selector.rs:169
msgid "Failed to load external applications"
msgstr "Externe Anwendungen konnten nicht geladen werden."

#: src/launcher/selector.rs:80 src/utils.rs:183
#: src/launcher/selector.rs:173 src/utils.rs:183
msgid "See the terminal output for details."
msgstr "In den Programm-Logs finden Sie weitere Details."

#. translators: `{}` is replaced by given ID, a valid one would be e.g. `org.gnome.Totem`
#: src/launcher/selector.rs:146
msgid "Invalid program ID: “{}”"
msgstr "Ungültige Programm-ID: „{}“"

#: src/launcher/selector.rs:196
#: src/launcher/selector.rs:280
msgid "Select video player"
msgstr "Videoplayer auswählen"

#: src/launcher/selector.rs:198
msgid "Select one of the following external programs to stream content"
#: src/launcher/selector.rs:281
msgid "Select one of the following external programs to stream content."
msgstr ""
"Wählen Sie eines der folgenden externen Programme zum Streamen von Inhalten"

#: src/launcher/selector.rs:202
#: src/launcher/selector.rs:284
msgid "Select video downloader"
msgstr "Video-Downloader auswählen"

#: src/launcher/selector.rs:204
msgid "Select one of the following external programs to download content"
#: src/launcher/selector.rs:285
msgid "Select one of the following external programs to download content."
msgstr ""
"Wählen Sie eines der folgenden externen Programme zum Herunterladen von "
"Inhalten"

#: src/launcher/selector.rs:292
msgid ""
"You can also specify a custom application ID (e.g. org.example.Application) "
"of a different program that supports DBus activation, is able to open a "
"https:// URI and is accessible from the context of this application."
msgstr ""
"Sie können auch eine benutzerdefinierte Anwendungs-ID (z.B. org.example."
"Application) angeben, um ein anderes Programm zu nutzen, das DBus-"
"Aktivierung unterstützt, https://-URIs öffnen kann und aus dem Kontext "
"dieser Anwendung erreicht werden kann."

#: src/live/card.blp:46 src/mediathek/card.blp:86
msgid "Play"
msgstr "Abspielen"
Expand Down
41 changes: 26 additions & 15 deletions po/televido.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: televido\n"
"Report-Msgid-Bugs-To: https://github.com/d-k-bo/televido/issues\n"
"POT-Creation-Date: 2023-10-26 21:32+0200\n"
"POT-Creation-Date: 2023-10-29 18:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -57,7 +57,7 @@ msgstr ""
msgid "Initital release"
msgstr ""

#: src/application.rs:116
#: src/application.rs:129
msgid "Failed to play video stream"
msgstr ""

Expand Down Expand Up @@ -89,33 +89,44 @@ msgstr ""
msgid "Confirm"
msgstr ""

#: src/launcher/selector.rs:76
msgid "Failed to load external applications"
#: src/launcher/selector.blp:38
msgid "Custom program"
msgstr ""

#: src/launcher/selector.rs:80 src/utils.rs:183
msgid "See the terminal output for details."
#. translators: `{}` is replaced by the application ID, e.g. `org.example.Application`
#: src/launcher/selector.rs:115
msgid "Could not find application “{}”"
msgstr ""

#. translators: `{}` is replaced by given ID, a valid one would be e.g. `org.gnome.Totem`
#: src/launcher/selector.rs:146
msgid "Invalid program ID: “{}”"
#: src/launcher/selector.rs:169
msgid "Failed to load external applications"
msgstr ""

#: src/launcher/selector.rs:196
#: src/launcher/selector.rs:173 src/utils.rs:183
msgid "See the terminal output for details."
msgstr ""

#: src/launcher/selector.rs:280
msgid "Select video player"
msgstr ""

#: src/launcher/selector.rs:198
msgid "Select one of the following external programs to stream content"
#: src/launcher/selector.rs:281
msgid "Select one of the following external programs to stream content."
msgstr ""

#: src/launcher/selector.rs:202
#: src/launcher/selector.rs:284
msgid "Select video downloader"
msgstr ""

#: src/launcher/selector.rs:204
msgid "Select one of the following external programs to download content"
#: src/launcher/selector.rs:285
msgid "Select one of the following external programs to download content."
msgstr ""

#: src/launcher/selector.rs:292
msgid ""
"You can also specify a custom application ID (e.g. org.example.Application) "
"of a different program that supports DBus activation, is able to open a "
"https:// URI and is accessible from the context of this application."
msgstr ""

#: src/live/card.blp:46 src/mediathek/card.blp:86
Expand Down
41 changes: 27 additions & 14 deletions src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use gettextrs::gettext;

use crate::{
config::{APP_ID, APP_NAME, AUTHOR, ISSUE_URL, PROJECT_URL, VERSION},
launcher::{ExternalProgramType, ProgramSelector},
launcher::{ExternalProgram, ExternalProgramType, ProgramSelector},
preferences::TvPreferencesWindow,
settings::TvSettings,
utils::{show_error, spawn_clone, tokio},
Expand Down Expand Up @@ -93,22 +93,35 @@ impl TvApplication {

pub async fn play(&self, uri: String) {
let settings = TvSettings::get();
let player_name = settings.video_player_name();
let player_id = settings.video_player_id();
let player = if player_id.is_empty() {
let Some(program) = ProgramSelector::select_program(ExternalProgramType::Player).await
else {
return;
};

settings.set_video_player_name(program.name);
settings.set_video_player_id(program.id);

program
let player = if player_id.is_empty() {
None
} else {
let Some(program) = ExternalProgramType::Player.find(&player_id) else {
return;
};
program
match ExternalProgram::find(player_name, player_id.clone()).await {
Ok(player) => player,
Err(e) => {
show_error(e);
None
}
}
};

let player = match player {
Some(player) => player,
None => {
match ProgramSelector::select_program(ExternalProgramType::Player, player_id).await
{
Some(player) => {
settings.set_video_player_name(&player.name);
settings.set_video_player_id(&player.id);

player
}
None => return,
}
}
};

match player.play(uri).await {
Expand Down
113 changes: 68 additions & 45 deletions src/launcher/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2023 David Cabot
// SPDX-License-Identifier: GPL-3.0-or-later

use std::borrow::Cow;

use crate::{application::TvApplication, utils::tokio};

use self::application_proxy::ApplicationProxy;
Expand All @@ -10,47 +12,48 @@ mod application_proxy;
mod selector;

pub static PLAYERS: &[ExternalProgram] = &[
ExternalProgram {
name: "Videos",
id: "org.gnome.Totem",
},
ExternalProgram {
name: "Celluloid",
id: "io.github.celluloid_player.Celluloid",
},
ExternalProgram {
name: "Clapper",
id: "com.github.rafostar.Clapper",
},
ExternalProgram::new("Videos", "org.gnome.Totem"),
ExternalProgram::new("Celluloid", "io.github.celluloid_player.Celluloid"),
ExternalProgram::new("Clapper", "com.github.rafostar.Clapper"),
ExternalProgram::new("Daikhan", "io.gitlab.daikhan.stable"),
// not dbus-activatable
// ExternalProgram { name: "µPlayer", id: "org.sigxcpu.Livi"},
// ExternalProgram { name: "Glide", id: "net.baseart.Glide"},
// ExternalProgram { name: "Daikhan", id: "io.gitlab.daikhan.stable"},
// ExternalProgram::new("µPlayer", "org.sigxcpu.Livi"),
// ExternalProgram::new("Glide", "net.baseart.Glide"),
// doesn't implement org.freedesktop.Application
// ExternalProgram { name: "VLC", id: "org.videolan.VLC"},
// ExternalProgram { name: "mpv", id: "io.mpv.Mpv"},
// ExternalProgram { name: "Haruna Media µPlayer", id: "org.kde.haruna"},
// ExternalProgram::new("VLC", "org.videolan.VLC"),
// ExternalProgram::new("mpv", "io.mpv.Mpv"),
// ExternalProgram::new("Haruna Media µPlayer", "org.kde.haruna"),
];

pub static DOWNLOADERS: &[ExternalProgram] = &[ExternalProgram {
name: "Parabolic",
id: "org.nickvision.tubeconverter",
}];
pub static DOWNLOADERS: &[ExternalProgram] = &[ExternalProgram::new(
"Parabolic",
"org.nickvision.tubeconverter",
)];

#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct ExternalProgram {
pub name: &'static str,
pub id: &'static str,
pub name: Cow<'static, str>,
pub id: Cow<'static, str>,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ExternalProgramType {
Player,
Downloader,
}

impl ExternalProgram {
pub async fn play(self, uri: impl Into<String>) -> eyre::Result<()> {
let conn = TvApplication::dbus().await;
let uri = uri.into();

tokio(async move {
let proxy =
ApplicationProxy::new(&conn, self.id, format!("/{}", self.id.replace('.', "/")))
.await?;
let proxy = ApplicationProxy::new(
&conn,
self.id.clone(),
format!("/{}", self.id.replace('.', "/")),
)
.await?;

proxy.open(&[&uri], Default::default()).await?;

Expand All @@ -60,37 +63,57 @@ impl ExternalProgram {
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ExternalProgramType {
Player,
Downloader,
}

impl ExternalProgramType {
pub fn all(self) -> &'static [ExternalProgram] {
match self {
ExternalProgramType::Player => PLAYERS,
ExternalProgramType::Downloader => DOWNLOADERS,
impl ExternalProgram {
const fn new(name: &'static str, id: &'static str) -> Self {
ExternalProgram {
name: Cow::Borrowed(name),
id: Cow::Borrowed(id),
}
}
pub fn find(self, id: &str) -> Option<ExternalProgram> {
self.all().iter().find(|program| program.id == id).copied()
pub async fn find(
name: impl Into<Cow<'static, str>>,
id: impl Into<Cow<'static, str>>,
) -> eyre::Result<Option<Self>> {
let conn = TvApplication::dbus().await;
let name = name.into();
let id = id.into();

tokio(async move {
let dbus_proxy = zbus::fdo::DBusProxy::new(&conn).await?;

if dbus_proxy
.list_activatable_names()
.await?
.into_iter()
.any(|bus_name| bus_name == &*id)
{
Ok(Some(ExternalProgram { name, id }))
} else {
Ok(None)
}
})
.await
}
pub async fn list(self) -> eyre::Result<Vec<ExternalProgram>> {

pub async fn find_known(program_type: ExternalProgramType) -> eyre::Result<Vec<Self>> {
let conn = TvApplication::dbus().await;

tokio(async move {
let all = self.all();
let known_programs = match program_type {
ExternalProgramType::Player => PLAYERS,
ExternalProgramType::Downloader => DOWNLOADERS,
};
let dbus_proxy = zbus::fdo::DBusProxy::new(&conn).await?;

let programs = dbus_proxy
.list_activatable_names()
.await?
.into_iter()
.filter_map(|bus_name| {
all.iter()
known_programs
.iter()
.find(|program| program.id == bus_name.as_str())
.copied()
.cloned()
})
.collect();

Expand Down
Loading

0 comments on commit f1e27eb

Please sign in to comment.