chore: update dependencies

This commit is contained in:
Vukašin Vojinović 2026-04-03 00:09:03 +02:00 committed by Michael Murphy
parent a8d9416754
commit 2aa2c841fa
15 changed files with 1061 additions and 1159 deletions

15
.zed/settings.json Normal file
View file

@ -0,0 +1,15 @@
{
"format_on_save": "on",
"lsp": {
"rust-analyzer": {
"initialization_options": {
"check": {
"command": "clippy",
},
"rustfmt": {
"extraArgs": ["+nightly"],
},
},
},
},
}

1812
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,31 +2,32 @@
name = "cosmic-player" name = "cosmic-player"
version = "1.0.11" version = "1.0.11"
edition = "2024" edition = "2024"
rust-version = "1.93"
[build-dependencies] [build-dependencies]
vergen = { version = "8", features = ["git", "gitcl"] } vergen = { version = "8", features = ["git", "gitcl"] }
[dependencies] [dependencies]
ashpd = { version = "0.12", optional = true } ashpd = { version = "0.12", optional = true }
gstreamer-tag = "0.23" gstreamer-tag = "0.25"
image = "0.24.9" image = "0.25"
serde = { version = "1", features = ["serde_derive"] } serde = { version = "1", features = ["serde_derive"] }
tempfile = "3" tempfile = "3"
tokio = { version = "1", features = ["sync"] } tokio = { version = "1", features = ["sync"] }
url = { version = "2", features = ["serde"] } url = { version = "2", features = ["serde"] }
# CLI arguments # CLI arguments
clap_lex = "0.7" clap_lex = "1.1"
# Internationalization # Internationalization
icu_collator = "1.5" icu_collator = "2.2"
icu_provider = { version = "1.5", features = ["sync"] } icu_locale = "2.2"
i18n-embed = { version = "0.14", features = [ i18n-embed = { version = "0.16", features = [
"fluent-system", "fluent-system",
"desktop-requester", "desktop-requester",
] } ] }
i18n-embed-fl = "0.7" i18n-embed-fl = "0.10"
rust-embed = "8" rust-embed = "8"
# Logging # Logging
env_logger = "0.10" env_logger = "0.11"
log = "0.4" log = "0.4"
[dependencies.iced_video_player] [dependencies.iced_video_player]
@ -40,11 +41,12 @@ default-features = false
features = ["advanced-shaping", "tokio", "winit", "multi-window"] features = ["advanced-shaping", "tokio", "winit", "multi-window"]
[dependencies.mpris-server] [dependencies.mpris-server]
version = "0.8.1" version = "0.10"
features = ["tokio"]
optional = true optional = true
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
fork = "0.2" fork = "0.7"
[features] [features]
default = ["mpris-server", "xdg-portal", "wgpu", "wayland"] default = ["mpris-server", "xdg-portal", "wgpu", "wayland"]

View file

@ -1 +1 @@
reorder_imports = false imports_granularity = "Module"

View file

@ -1,7 +1,8 @@
// Copyright 2024 System76 <info@system76.com> // Copyright 2024 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::{fs, io, path::PathBuf}; use std::path::PathBuf;
use std::{fs, io};
use clap_lex::RawArgs; use clap_lex::RawArgs;
use log::warn; use log::warn;

View file

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic::{ use cosmic::cosmic_config::cosmic_config_derive::CosmicConfigEntry;
cosmic_config::{self, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}, use cosmic::cosmic_config::{self, CosmicConfigEntry};
theme, use cosmic::theme;
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::VecDeque, path::PathBuf}; use std::collections::VecDeque;
use std::path::PathBuf;
pub const CONFIG_VERSION: u64 = 1; pub const CONFIG_VERSION: u64 = 1;

View file

@ -1,4 +1,5 @@
use cosmic::{iced::keyboard::Key, iced::core::keyboard::key::Named}; use cosmic::iced::keyboard::Key;
use cosmic::iced::keyboard::key::Named;
use std::collections::HashMap; use std::collections::HashMap;
use crate::Action; use crate::Action;

View file

@ -1,50 +1,64 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::str::FromStr; use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader};
use std::sync::OnceLock; use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer};
use icu_collator::options::CollatorOptions;
use i18n_embed::{ use icu_collator::preferences::CollationNumericOrdering;
DefaultLocalizer, LanguageLoader, Localizer, use icu_collator::{Collator, CollatorBorrowed, CollatorPreferences};
fluent::{FluentLanguageLoader, fluent_language_loader}, use icu_locale::Locale;
};
use icu_collator::{Collator, CollatorOptions, Numeric};
use icu_provider::DataLocale;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::sync::LazyLock;
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "i18n/"] #[folder = "i18n/"]
struct Localizations; struct Localizations;
pub static LANGUAGE_LOADER: OnceLock<FluentLanguageLoader> = OnceLock::new(); pub static LANGUAGE_LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
pub static LANGUAGE_SORTER: OnceLock<Collator> = OnceLock::new(); let loader: FluentLanguageLoader = fluent_language_loader!();
loader
.load_fallback_language(&Localizations)
.expect("Error while loading fallback language");
loader
});
pub static LANGUAGE_SORTER: LazyLock<CollatorBorrowed> = LazyLock::new(|| {
let create_collator = |locale: Locale| {
let mut prefs = CollatorPreferences::from(locale);
prefs.numeric_ordering = Some(CollationNumericOrdering::True);
Collator::try_new(prefs, CollatorOptions::default()).ok()
};
Locale::try_from_str(&LANGUAGE_LOADER.current_language().to_string())
.ok()
.and_then(create_collator)
.or_else(|| {
Locale::try_from_str(&LANGUAGE_LOADER.fallback_language().to_string())
.ok()
.and_then(create_collator)
})
.unwrap_or_else(|| {
let locale = Locale::try_from_str("en-US").expect("en-US is a valid BCP-47 tag");
create_collator(locale)
.expect("Creating a collator from the system's current language, the fallback language, or American English should succeed")
})
});
#[macro_export] #[macro_export]
macro_rules! fl { macro_rules! fl {
($message_id:literal) => {{ ($message_id:literal) => {{
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER.get().unwrap(), $message_id) i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id)
}}; }};
($message_id:literal, $($args:expr),*) => {{ ($message_id:literal, $($args:expr),*) => {{
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER.get().unwrap(), $message_id, $($args), *) i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id, $($args), *)
}}; }};
} }
// Get the `Localizer` to be used for localizing this library. // Get the `Localizer` to be used for localizing this library.
pub fn localizer() -> Box<dyn Localizer> { pub fn localizer() -> Box<dyn Localizer> {
LANGUAGE_LOADER.get_or_init(|| { Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations))
let loader: FluentLanguageLoader = fluent_language_loader!();
loader
.load_fallback_language(&Localizations)
.expect("Error while loading fallback language");
loader
});
Box::from(DefaultLocalizer::new(
LANGUAGE_LOADER.get().unwrap(),
&Localizations,
))
} }
pub fn localize() { pub fn localize() {
@ -52,25 +66,6 @@ pub fn localize() {
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages(); let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
if let Err(error) = localizer.select(&requested_languages) { if let Err(error) = localizer.select(&requested_languages) {
eprintln!("Error while loading language for App List {}", error); eprintln!("Error while loading language for COSMIC Media Player {error}",);
} }
} }
pub fn sorter() -> &'static Collator {
LANGUAGE_SORTER.get_or_init(|| {
let mut options = CollatorOptions::new();
options.numeric = Some(Numeric::On);
let localizer = localizer();
let language_loader = localizer.language_loader();
DataLocale::from_str(&language_loader.current_language().to_string())
.or_else(|_| DataLocale::from_str(&language_loader.fallback_language().to_string()))
.ok()
.and_then(|locale| Collator::try_new(&locale, options).ok())
.or_else(|| {
let locale = DataLocale::from_str("en-US").expect("en-US is a valid BCP-47 tag");
Collator::try_new(&locale, options).ok()
})
.expect("Creating a collator from the system's current language, the fallback language, or American English should succeed")
})
}

View file

@ -1,49 +1,32 @@
// Copyright 2023 System76 <info@system76.com> // Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic::{ use cosmic::app::{Core, Settings, Task};
action, use cosmic::command::set_theme;
app::{Core, Settings, Task}, use cosmic::cosmic_config::{self, CosmicConfigEntry};
command::set_theme, use cosmic::iced::event::{self, Event};
cosmic_config::{self, CosmicConfigEntry}, use cosmic::iced::keyboard::{Event as KeyEvent, Key, Modifiers};
cosmic_theme, executor, font, use cosmic::iced::mouse::{Event as MouseEvent, ScrollDelta};
iced::{ use cosmic::iced::window::{self, set_mode};
event::{self, Event}, use cosmic::iced::{
keyboard::{Event as KeyEvent, Key, Modifiers}, Alignment, Background, Border, Color, ContentFit, Length, Limits, Subscription,
mouse::{Event as MouseEvent, ScrollDelta},
window::{self, set_mode},
Alignment, Background, Border, Color, ContentFit, Length, Limits, Subscription,
},
theme,
widget::{self, menu::action::MenuAction, nav_bar, segmented_button, Slider},
Application, ApplicationExt, Element,
};
use iced_video_player::{
gst::{self, prelude::*},
gst_pbutils, Video, VideoPlayer,
};
use std::{
any::TypeId,
collections::HashMap,
ffi::{CStr, CString},
fs,
path::{Path, PathBuf},
process,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread,
time::{Duration, Instant},
}; };
use cosmic::widget::menu::action::MenuAction;
use cosmic::widget::{self, Slider, nav_bar, segmented_button};
use cosmic::{Application, ApplicationExt, Element, action, cosmic_theme, executor, font, theme};
use iced_video_player::gst::prelude::*;
use iced_video_player::{Video, VideoPlayer, gst, gst_pbutils};
use std::any::TypeId;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::path::{Path, PathBuf};
use std::time::{Duration, Instant};
use std::{fs, process, thread};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::{ use crate::config::{CONFIG_VERSION, Config, ConfigState, RepeatState};
config::{Config, ConfigState, CONFIG_VERSION, RepeatState}, use crate::key_bind::{KeyBind, key_binds};
key_bind::{key_binds, KeyBind}, use crate::project::ProjectNode;
mpris::subscription,
project::ProjectNode,
};
mod argparse; mod argparse;
mod config; mod config;
@ -611,10 +594,10 @@ impl App {
} }
fn save_config_state(&mut self) { fn save_config_state(&mut self) {
if let Some(ref config_state_handler) = self.flags.config_state_handler { if let Some(ref config_state_handler) = self.flags.config_state_handler
if let Err(err) = self.flags.config_state.write_entry(config_state_handler) { && let Err(err) = self.flags.config_state.write_entry(config_state_handler)
log::error!("failed to save config_state: {}", err); {
} log::error!("failed to save config_state: {}", err);
} }
} }
@ -623,9 +606,9 @@ impl App {
|| !self || !self
.video_opt .video_opt
.as_ref() .as_ref()
.map_or(false, |video| video.has_video()) .is_some_and(|video| video.has_video())
{ {
self.core.window.show_headerbar = true && !self.fullscreen; self.core.window.show_headerbar = !self.fullscreen;
self.controls = true; self.controls = true;
self.controls_time = Instant::now(); self.controls_time = Instant::now();
} else if self.controls && self.controls_time.elapsed() > CONTROLS_TIMEOUT { } else if self.controls && self.controls_time.elapsed() > CONTROLS_TIMEOUT {
@ -679,7 +662,7 @@ impl App {
..Default::default() ..Default::default()
}; };
//TODO: use any other stream tags? //TODO: use any other stream tags?
if let Some(tags) = self.audio_tags.get(0) { if let Some(tags) = self.audio_tags.first() {
log::info!("{:#?}", tags); log::info!("{:#?}", tags);
if let Some(tag) = tags.get::<gst::tags::Album>() { if let Some(tag) = tags.get::<gst::tags::Album>() {
new.album = tag.get().into(); new.album = tag.get().into();
@ -752,11 +735,11 @@ impl App {
new.album_art_opt = url::Url::from_file_path(album_art.path()).ok(); new.album_art_opt = url::Url::from_file_path(album_art.path()).ok();
} }
} }
if let Some((old, _, tx)) = &mut self.mpris_opt { if let Some((old, _, tx)) = &mut self.mpris_opt
if new != *old { && new != *old
*old = new.clone(); {
let _ = tx.send(MprisEvent::Meta(new.clone())); *old = new.clone();
} let _ = tx.send(MprisEvent::Meta(new.clone()));
} }
self.mpris_meta = new; self.mpris_meta = new;
} }
@ -951,7 +934,7 @@ impl Application for App {
fn on_escape(&mut self) -> Task<Self::Message> { fn on_escape(&mut self) -> Task<Self::Message> {
if self.fullscreen { if self.fullscreen {
return self.update(Message::Fullscreen); self.update(Message::Fullscreen)
} else { } else {
Task::none() Task::none()
} }
@ -1210,12 +1193,12 @@ impl Application for App {
} }
} }
Message::AudioCode(code) => { Message::AudioCode(code) => {
if let Ok(code) = i32::try_from(code) { if let Ok(code) = i32::try_from(code)
if let Some(video) = &self.video_opt { && let Some(video) = &self.video_opt
let pipeline = video.pipeline(); {
pipeline.set_property("current-audio", code); let pipeline = video.pipeline();
self.current_audio = pipeline.property("current-audio"); pipeline.set_property("current-audio", code);
} self.current_audio = pipeline.property("current-audio");
} }
} }
Message::AudioToggle => { Message::AudioToggle => {
@ -1225,12 +1208,12 @@ impl Application for App {
} }
} }
Message::AudioVolume(volume) => { Message::AudioVolume(volume) => {
if let Some(video) = &mut self.video_opt { if let Some(video) = &mut self.video_opt
if volume >= 0.0 && volume <= 1.0 { && (0.0..=1.0).contains(&volume)
video.set_volume(volume); {
video.set_muted(false); video.set_volume(volume);
self.update_controls(true); video.set_muted(false);
} self.update_controls(true);
} }
} }
Message::TextCode(index) => { Message::TextCode(index) => {
@ -1313,7 +1296,7 @@ impl Application for App {
} }
} }
if (volume >= 0.0 && volume <= 1.0) && !nav_bar_toggled { if (0.0..=1.0).contains(&volume) && !nav_bar_toggled {
video.set_volume(volume); video.set_volume(volume);
video.set_muted(false); video.set_muted(false);
self.update_controls(true); self.update_controls(true);
@ -1537,20 +1520,20 @@ impl Application for App {
self.update_mpris_state(); self.update_mpris_state();
} }
Message::NewFrame => { Message::NewFrame => {
if let Some(video) = &mut self.video_opt { if let Some(video) = &mut self.video_opt
if !self.dragging { && !self.dragging
self.position = video.position().as_secs_f64(); {
self.position = video.position().as_secs_f64();
if let Some((a, b)) = self.ab_repeat { if let Some((a, b)) = self.ab_repeat {
let target_a = a.unwrap_or(0.0); let target_a = a.unwrap_or(0.0);
let target_b = b.unwrap_or(self.duration); let target_b = b.unwrap_or(self.duration);
if self.position >= target_b { if self.position >= target_b {
let _ = video.seek(Duration::from_secs_f64(target_a), true); let _ = video.seek(Duration::from_secs_f64(target_a), true);
}
} }
self.update_controls(self.dropdown_opt.is_some());
} }
self.update_controls(self.dropdown_opt.is_some());
} }
} }
Message::Reload => { Message::Reload => {
@ -1801,7 +1784,7 @@ impl Application for App {
.spacing(space_xxs) .spacing(space_xxs)
.push( .push(
widget::button::icon( widget::button::icon(
if self.video_opt.as_ref().map_or(true, |video| video.paused()) { if self.video_opt.as_ref().is_none_or(|video| video.paused()) {
widget::icon::from_name("media-playback-start-symbolic").size(16) widget::icon::from_name("media-playback-start-symbolic").size(16)
} else { } else {
widget::icon::from_name("media-playback-pause-symbolic").size(16) widget::icon::from_name("media-playback-pause-symbolic").size(16)

View file

@ -1,14 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic::{ use cosmic::widget::RcElementWrapper;
theme, use cosmic::widget::menu::key_bind::KeyBind;
widget::{ use cosmic::widget::menu::{self, ItemHeight, ItemWidth, MenuBar};
menu::{self, key_bind::KeyBind, ItemHeight, ItemWidth, MenuBar}, use cosmic::{Element, theme};
RcElementWrapper, use std::collections::HashMap;
}, use std::path::PathBuf;
Element,
};
use std::{collections::HashMap, path::PathBuf};
use crate::{Action, Config, ConfigState, Message, fl}; use crate::{Action, Config, ConfigState, Message, fl};
@ -22,10 +19,10 @@ pub fn menu_bar<'a>(
) -> Element<'a, Message> { ) -> Element<'a, Message> {
let home_dir_opt = std::env::home_dir(); let home_dir_opt = std::env::home_dir();
let format_path = |path: &PathBuf| -> String { let format_path = |path: &PathBuf| -> String {
if let Some(home_dir) = &home_dir_opt { if let Some(home_dir) = &home_dir_opt
if let Ok(part) = path.strip_prefix(home_dir) { && let Ok(part) = path.strip_prefix(home_dir)
return format!("~/{}", part.display()); {
} return format!("~/{}", part.display());
} }
path.display().to_string() path.display().to_string()
}; };

View file

@ -1,18 +1,16 @@
use cosmic::{ use cosmic::iced::futures::{self, SinkExt, Stream};
iced::{ use cosmic::iced::{Subscription, stream};
futures::{self, SinkExt, Stream}, use mpris_server::zbus::{Result, fdo};
Subscription, stream,
},
};
use mpris_server::{ use mpris_server::{
LoopStatus, Metadata, PlaybackRate, PlaybackStatus, PlayerInterface, Property, RootInterface, LoopStatus, Metadata, PlaybackRate, PlaybackStatus, PlayerInterface, Property, RootInterface,
Server, Signal, Time, TrackId, Volume, Server, Signal, Time, TrackId, Volume,
zbus::{Result, fdo},
}; };
use std::{any::TypeId, future, process}; use std::any::TypeId;
use std::{future, process};
use tokio::sync::{Mutex, mpsc}; use tokio::sync::{Mutex, mpsc};
use crate::{Message, MprisEvent, MprisMeta, MprisState, config::RepeatState}; use crate::config::RepeatState;
use crate::{Message, MprisEvent, MprisMeta, MprisState};
impl MprisMeta { impl MprisMeta {
fn metadata(&self) -> Metadata { fn metadata(&self) -> Metadata {

View file

@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic::widget; use cosmic::widget;
use std::{ use std::cmp::Ordering;
cmp::Ordering, use std::path::{Path, PathBuf};
fs, io, use std::{fs, io};
path::{Path, PathBuf},
};
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum ProjectNode { pub enum ProjectNode {
@ -26,15 +24,15 @@ impl ProjectNode {
let path = fs::canonicalize(path)?; let path = fs::canonicalize(path)?;
let name = path let name = path
.file_name() .file_name()
.ok_or(io::Error::new( .ok_or(io::Error::other(format!(
io::ErrorKind::Other, "path {:?} has no file name",
format!("path {:?} has no file name", path), path
))? )))?
.to_str() .to_str()
.ok_or(io::Error::new( .ok_or(io::Error::other(format!(
io::ErrorKind::Other, "path {:?} is not valid UTF-8",
format!("path {:?} is not valid UTF-8", path), path
))? )))?
.to_string(); .to_string();
Ok(if path.is_dir() { Ok(if path.is_dir() {
Self::Folder { Self::Folder {
@ -94,7 +92,7 @@ impl Ord for ProjectNode {
} }
} }
} }
crate::localize::sorter().compare(self.name(), other.name()) crate::localize::LANGUAGE_SORTER.compare(self.name(), other.name())
} }
} }

View file

@ -1,6 +1,9 @@
use iced_video_player::Position; use iced_video_player::Position;
use image::{DynamicImage, ImageFormat, RgbaImage}; use image::{DynamicImage, ImageFormat, RgbaImage};
use std::{error::Error, num::NonZero, path::Path, time::Duration}; use std::error::Error;
use std::num::NonZero;
use std::path::Path;
use std::time::Duration;
use url::Url; use url::Url;
use super::video; use super::video;
@ -14,7 +17,7 @@ pub fn main(
let thumbnails = { let thumbnails = {
let mut video = match video::new_video(input, video::VideoSettings { mute: true }) { let mut video = match video::new_video(input, video::VideoSettings { mute: true }) {
Ok(ok) => ok, Ok(ok) => ok,
Err(_err) => return Err(Into::into(format!("missing required plugin"))), Err(_err) => return Err(Into::into("missing required plugin".to_string())),
}; };
let duration = video.duration(); let duration = video.duration();
@ -37,7 +40,7 @@ pub fn main(
pixels, pixels,
} => RgbaImage::from_raw(*width, *height, pixels.to_vec()) } => RgbaImage::from_raw(*width, *height, pixels.to_vec())
.map(DynamicImage::ImageRgba8) .map(DynamicImage::ImageRgba8)
.ok_or_else(|| format!("failed to convert thumbnail")), .ok_or_else(|| "failed to convert thumbnail".to_string()),
_ => Err(format!("unsupported thumbnail handle {:?}", thumbnails[0])), _ => Err(format!("unsupported thumbnail handle {:?}", thumbnails[0])),
} }
}?; }?;

View file

@ -1,10 +1,8 @@
use iced_video_player::{ use iced_video_player::gst::prelude::*;
Video, use iced_video_player::{Video, gst, gst_app, gst_pbutils};
gst::{self, prelude::*},
gst_app, gst_pbutils,
};
use cosmic::{action, app::Task}; use cosmic::action;
use cosmic::app::Task;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct VideoSettings { pub struct VideoSettings {
@ -33,13 +31,13 @@ pub fn new_video(
let Ok(elem) = vals[1].get::<gst::Element>() else { let Ok(elem) = vals[1].get::<gst::Element>() else {
return None; return None;
}; };
if let Some(factory) = elem.factory() { if let Some(factory) = elem.factory()
if factory.name() == "souphttpsrc" { && factory.name() == "souphttpsrc"
elem.set_property( {
"user-agent", elem.set_property(
"Mozilla/5.0 (X11; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0", "user-agent",
); "Mozilla/5.0 (X11; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0",
} );
} }
None None
}); });
@ -65,18 +63,15 @@ pub fn new_video(
.unwrap() .unwrap()
.pop_filtered(&[gst::MessageType::Element]) .pop_filtered(&[gst::MessageType::Element])
{ {
match msg.view() { if let gst::MessageView::Element(element) = msg.view()
gst::MessageView::Element(element) => { && gst_pbutils::MissingPluginMessage::is(element)
if gst_pbutils::MissingPluginMessage::is(&element) { {
commands.push(Task::perform( commands.push(Task::perform(
async { action::app(super::Message::MissingPlugin(msg)) }, async { action::app(super::Message::MissingPlugin(msg)) },
|x| x, |x| x,
)); ));
// Do one codec install at a time // Do one codec install at a time
break; break;
}
}
_ => {}
} }
} }
pipeline.set_state(gst::State::Null).unwrap(); pipeline.set_state(gst::State::Null).unwrap();

View file

@ -3,10 +3,8 @@
//! Integrations with XDG portals. //! Integrations with XDG portals.
use ashpd::{ use ashpd::desktop::inhibit::{InhibitFlags, InhibitProxy};
desktop::inhibit::{InhibitFlags, InhibitProxy}, use ashpd::enumflags2::{BitFlags, make_bitflags};
enumflags2::{BitFlags, make_bitflags},
};
use log::{debug, warn}; use log::{debug, warn};
use tokio::sync::watch::Receiver; use tokio::sync::watch::Receiver;