Merge branch 'synchronize-feed-updates' into 'master'
Synchronize feed updates Closes #166 See merge request World/podcasts!133
This commit is contained in:
commit
7d212174a6
@ -34,7 +34,7 @@ use gettextrs::{bindtextdomain, setlocale, textdomain, LocaleCategory};
|
|||||||
|
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
use fragile::Fragile;
|
use fragile::Fragile;
|
||||||
use podcasts_data::Show;
|
use podcasts_data::{Show, Source};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
use crate::stacks::PopulatedState;
|
use crate::stacks::PopulatedState;
|
||||||
@ -138,7 +138,9 @@ pub(crate) enum Action {
|
|||||||
HeaderBarShowTile(String),
|
HeaderBarShowTile(String),
|
||||||
HeaderBarNormal,
|
HeaderBarNormal,
|
||||||
MarkAllPlayerNotification(Arc<Show>),
|
MarkAllPlayerNotification(Arc<Show>),
|
||||||
|
UpdateFeed(Option<Vec<Source>>),
|
||||||
ShowUpdateNotif(Receiver<bool>),
|
ShowUpdateNotif(Receiver<bool>),
|
||||||
|
StopUpdating,
|
||||||
RemoveShow(Arc<Show>),
|
RemoveShow(Arc<Show>),
|
||||||
ErrorNotification(String),
|
ErrorNotification(String),
|
||||||
InitEpisode(i32),
|
InitEpisode(i32),
|
||||||
@ -248,6 +250,17 @@ impl PdApplication {
|
|||||||
let notif = InAppNotification::new(&err, 6000, callback, undo_cb);
|
let notif = InAppNotification::new(&err, 6000, callback, undo_cb);
|
||||||
notif.show(&window.overlay);
|
notif.show(&window.overlay);
|
||||||
}
|
}
|
||||||
|
Action::UpdateFeed(source) => {
|
||||||
|
if window.updating.get() {
|
||||||
|
info!("Ignoring feed update request (another one is already running)")
|
||||||
|
} else {
|
||||||
|
window.updating.set(true);
|
||||||
|
utils::refresh_feed(source, window.sender.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Action::StopUpdating => {
|
||||||
|
window.updating.set(false);
|
||||||
|
}
|
||||||
Action::ShowUpdateNotif(receiver) => {
|
Action::ShowUpdateNotif(receiver) => {
|
||||||
let sender = window.sender.clone();
|
let sender = window.sender.clone();
|
||||||
let callback = move |revealer: gtk::Revealer| match receiver.try_recv() {
|
let callback = move |revealer: gtk::Revealer| match receiver.try_recv() {
|
||||||
@ -255,9 +268,15 @@ impl PdApplication {
|
|||||||
Err(TryRecvError::Disconnected) => glib::Continue(false),
|
Err(TryRecvError::Disconnected) => glib::Continue(false),
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
revealer.set_reveal_child(false);
|
revealer.set_reveal_child(false);
|
||||||
|
|
||||||
|
sender
|
||||||
|
.send(Action::StopUpdating)
|
||||||
|
.expect("Action channel blew up somehow");
|
||||||
|
|
||||||
sender
|
sender
|
||||||
.send(Action::RefreshAllViews)
|
.send(Action::RefreshAllViews)
|
||||||
.expect("Action channel blew up somehow");
|
.expect("Action channel blew up somehow");
|
||||||
|
|
||||||
glib::Continue(false)
|
glib::Continue(false)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -269,6 +288,7 @@ impl PdApplication {
|
|||||||
|
|
||||||
let old = window.updater.replace(Some(updater));
|
let old = window.updater.replace(Some(updater));
|
||||||
old.map(|i| i.destroy());
|
old.map(|i| i.destroy());
|
||||||
|
|
||||||
window
|
window
|
||||||
.updater
|
.updater
|
||||||
.borrow()
|
.borrow()
|
||||||
|
|||||||
@ -32,7 +32,7 @@ use podcasts_data::{dbqueries, Source};
|
|||||||
|
|
||||||
use crate::app::Action;
|
use crate::app::Action;
|
||||||
use crate::stacks::Content;
|
use crate::stacks::Content;
|
||||||
use crate::utils::{itunes_to_rss, refresh};
|
use crate::utils::{itunes_to_rss, schedule_refresh};
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ impl AddPopover {
|
|||||||
|
|
||||||
rayon::spawn(clone!(sender => move || {
|
rayon::spawn(clone!(sender => move || {
|
||||||
if let Ok(source) = Source::from_url(&url) {
|
if let Ok(source) = Source::from_url(&url) {
|
||||||
refresh(Some(vec![source]), sender.clone());
|
schedule_refresh(Some(vec![source]), sender.clone());
|
||||||
} else {
|
} else {
|
||||||
error!("Failed to convert, url: {}, to a source entry", url);
|
error!("Failed to convert, url: {}, to a source entry", url);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -203,10 +203,10 @@ pub(crate) fn cleanup(cleanup_date: DateTime<Utc>) {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn refresh<S>(source: Option<S>, sender: Sender<Action>)
|
/// Schedule feed refresh
|
||||||
where
|
/// If `source` is None, Refreshes all sources in the database.
|
||||||
S: IntoIterator<Item = Source> + Send + 'static,
|
/// Current implementation ignores update request if another update is already running
|
||||||
{
|
pub(crate) fn schedule_refresh(source: Option<Vec<Source>>, sender: Sender<Action>) {
|
||||||
// If we try to update the whole db,
|
// If we try to update the whole db,
|
||||||
// Exit early if `source` table is empty
|
// Exit early if `source` table is empty
|
||||||
if source.is_none() {
|
if source.is_none() {
|
||||||
@ -220,15 +220,16 @@ where
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh_feed(source, sender)
|
sender
|
||||||
|
.send(Action::UpdateFeed(source))
|
||||||
|
.expect("Action channel blew up somehow")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the rss feed(s) originating from `source`.
|
/// Update the rss feed(s) originating from `source`.
|
||||||
/// If `source` is None, Fetches all the `Source` entries in the database and updates them.
|
/// If `source` is None, Fetches all the `Source` entries in the database and updates them.
|
||||||
fn refresh_feed<S>(source: Option<S>, sender: Sender<Action>)
|
/// Do not call this function directly unless you are sure no other updates are running.
|
||||||
where
|
/// Use `schedule_refresh()` instead
|
||||||
S: IntoIterator<Item = Source> + Send + 'static,
|
pub(crate) fn refresh_feed(source: Option<Vec<Source>>, sender: Sender<Action>) {
|
||||||
{
|
|
||||||
rayon::spawn(move || {
|
rayon::spawn(move || {
|
||||||
let (up_sender, up_receiver) = bounded(1);
|
let (up_sender, up_receiver) = bounded(1);
|
||||||
sender
|
sender
|
||||||
@ -420,7 +421,7 @@ pub(crate) fn on_import_clicked(window: >k::ApplicationWindow, sender: &Sender
|
|||||||
// Parse the file and import the feeds
|
// Parse the file and import the feeds
|
||||||
if let Ok(sources) = opml::import_from_file(filename) {
|
if let Ok(sources) = opml::import_from_file(filename) {
|
||||||
// Refresh the successfully parsed feeds to index them
|
// Refresh the successfully parsed feeds to index them
|
||||||
refresh(Some(sources), sender)
|
schedule_refresh(Some(sources), sender)
|
||||||
} else {
|
} else {
|
||||||
let text = i18n("Failed to parse the imported file");
|
let text = i18n("Failed to parse the imported file");
|
||||||
sender.send(Action::ErrorNotification(text)).expect("Action channel blew up somehow");
|
sender.send(Action::ErrorNotification(text)).expect("Action channel blew up somehow");
|
||||||
|
|||||||
@ -36,7 +36,7 @@ use crate::widgets::about_dialog;
|
|||||||
use crate::widgets::appnotif::InAppNotification;
|
use crate::widgets::appnotif::InAppNotification;
|
||||||
use crate::widgets::player;
|
use crate::widgets::player;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::{Cell, RefCell};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ pub struct MainWindow {
|
|||||||
pub(crate) content: Rc<Content>,
|
pub(crate) content: Rc<Content>,
|
||||||
pub(crate) headerbar: Rc<Header>,
|
pub(crate) headerbar: Rc<Header>,
|
||||||
pub(crate) player: player::PlayerWrapper,
|
pub(crate) player: player::PlayerWrapper,
|
||||||
|
pub(crate) updating: Cell<bool>,
|
||||||
pub(crate) updater: RefCell<Option<InAppNotification>>,
|
pub(crate) updater: RefCell<Option<InAppNotification>>,
|
||||||
pub(crate) sender: Sender<Action>,
|
pub(crate) sender: Sender<Action>,
|
||||||
pub(crate) receiver: Receiver<Action>,
|
pub(crate) receiver: Receiver<Action>,
|
||||||
@ -137,7 +138,7 @@ impl MainWindow {
|
|||||||
if settings.get_boolean("refresh-on-startup") {
|
if settings.get_boolean("refresh-on-startup") {
|
||||||
info!("Refresh on startup.");
|
info!("Refresh on startup.");
|
||||||
let s: Option<Vec<_>> = None;
|
let s: Option<Vec<_>> = None;
|
||||||
utils::refresh(s, sender.clone());
|
utils::schedule_refresh(s, sender.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let refresh_interval = settings::get_refresh_interval(&settings).num_seconds() as u32;
|
let refresh_interval = settings::get_refresh_interval(&settings).num_seconds() as u32;
|
||||||
@ -146,7 +147,7 @@ impl MainWindow {
|
|||||||
let r_sender = sender.clone();
|
let r_sender = sender.clone();
|
||||||
gtk::timeout_add_seconds(refresh_interval, move || {
|
gtk::timeout_add_seconds(refresh_interval, move || {
|
||||||
let s: Option<Vec<_>> = None;
|
let s: Option<Vec<_>> = None;
|
||||||
utils::refresh(s, r_sender.clone());
|
utils::schedule_refresh(s, r_sender.clone());
|
||||||
|
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
});
|
});
|
||||||
@ -158,6 +159,7 @@ impl MainWindow {
|
|||||||
headerbar: header,
|
headerbar: header,
|
||||||
content,
|
content,
|
||||||
player,
|
player,
|
||||||
|
updating: Cell::new(false),
|
||||||
updater,
|
updater,
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
@ -178,7 +180,7 @@ impl MainWindow {
|
|||||||
action(&self.window, "refresh", clone!(sender => move |_, _| {
|
action(&self.window, "refresh", clone!(sender => move |_, _| {
|
||||||
gtk::idle_add(clone!(sender => move || {
|
gtk::idle_add(clone!(sender => move || {
|
||||||
let s: Option<Vec<_>> = None;
|
let s: Option<Vec<_>> = None;
|
||||||
utils::refresh(s, sender.clone());
|
utils::schedule_refresh(s, sender.clone());
|
||||||
glib::Continue(false)
|
glib::Continue(false)
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user