diff --git a/hammond-data/src/dbqueries.rs b/hammond-data/src/dbqueries.rs index 391ec6e..f1bb8dd 100644 --- a/hammond-data/src/dbqueries.rs +++ b/hammond-data/src/dbqueries.rs @@ -2,7 +2,7 @@ use diesel::prelude::*; use diesel; -use models::queryables::{Episode, Podcast, Source}; +use models::queryables::{Episode, EpisodeWidgetQuery, Podcast, Source}; use chrono::prelude::*; use errors::*; @@ -103,6 +103,21 @@ pub fn get_pd_episodes(parent: &Podcast) -> Result> { .load::(&*con)?) } +pub fn get_pd_episodeswidgets(parent: &Podcast) -> Result> { + use schema::episode::dsl::*; + + let db = connection(); + let con = db.get()?; + + Ok( + episode.select((rowid, title, uri, local_uri, epoch, length, played, podcast_id)) + .filter(podcast_id.eq(parent.id())) + // .group_by(epoch) + .order(epoch.desc()) + .load::(&*con)?, + ) +} + pub fn get_pd_unplayed_episodes(parent: &Podcast) -> Result> { use schema::episode::dsl::*; diff --git a/hammond-data/src/lib.rs b/hammond-data/src/lib.rs index c562fbd..97aec76 100644 --- a/hammond-data/src/lib.rs +++ b/hammond-data/src/lib.rs @@ -61,7 +61,7 @@ pub(crate) mod models; mod parser; mod schema; -pub use models::queryables::{Episode, Podcast, Source}; +pub use models::queryables::{Episode, EpisodeWidgetQuery, Podcast, Source}; /// [XDG Base Direcotory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) Paths. #[allow(missing_debug_implementations)] diff --git a/hammond-data/src/models/queryables.rs b/hammond-data/src/models/queryables.rs index f0cab54..e8ae722 100644 --- a/hammond-data/src/models/queryables.rs +++ b/hammond-data/src/models/queryables.rs @@ -1,4 +1,6 @@ use chrono::prelude::*; +use diesel::prelude::*; +use diesel; use reqwest; use diesel::SaveChangesDsl; @@ -189,6 +191,133 @@ impl Episode { } } +#[derive(Queryable, AsChangeset, PartialEq)] +#[table_name = "episode"] +#[changeset_options(treat_none_as_null = "true")] +#[primary_key(title, podcast_id)] +#[derive(Debug, Clone)] +/// Diesel Model to be used for constructing `EpisodeWidgets`. +pub struct EpisodeWidgetQuery { + rowid: i32, + title: String, + uri: Option, + local_uri: Option, + epoch: i32, + length: Option, + played: Option, + // favorite: bool, + // archive: bool, + podcast_id: i32, +} + +impl EpisodeWidgetQuery { + /// Get the value of the sqlite's `ROW_ID` + pub fn rowid(&self) -> i32 { + self.rowid + } + + /// Get the value of the `title` field. + pub fn title(&self) -> &str { + &self.title + } + + /// Get the value of the `uri`. + /// + /// Represents the url(usually) that the media file will be located at. + pub fn uri(&self) -> Option<&str> { + self.uri.as_ref().map(|s| s.as_str()) + } + + /// Get the value of the `local_uri`. + /// + /// Represents the local uri,usually filesystem path, + /// that the media file will be located at. + pub fn local_uri(&self) -> Option<&str> { + self.local_uri.as_ref().map(|s| s.as_str()) + } + + /// Set the `local_uri`. + pub fn set_local_uri(&mut self, value: Option<&str>) { + self.local_uri = value.map(|x| x.to_string()); + } + + /// Get the `epoch` value. + /// + /// Retrieved from the rss Item publish date. + /// Value is set to Utc whenever possible. + pub fn epoch(&self) -> i32 { + self.epoch + } + + /// Get the `length`. + pub fn length(&self) -> Option { + self.length + } + + /// Set the `length`. + pub fn set_length(&mut self, value: Option) { + self.length = value; + } + + /// Epoch representation of the last time the episode was played. + /// + /// None/Null for unplayed. + pub fn played(&self) -> Option { + self.played + } + + /// Set the `played` value. + pub fn set_played(&mut self, value: Option) { + self.played = value; + } + + // /// Represents the archiving policy for the episode. + // pub fn archive(&self) -> bool { + // self.archive + // } + + // /// Set the `archive` policy. + // /// + // /// If true, the download cleanr will ignore the episode + // /// and the corresponding media value will never be automaticly deleted. + // pub fn set_archive(&mut self, b: bool) { + // self.archive = b + // } + + // /// Get the `favorite` status of the `Episode`. + // pub fn favorite(&self) -> bool { + // self.favorite + // } + + // /// Set `favorite` status. + // pub fn set_favorite(&mut self, b: bool) { + // self.favorite = b + // } + + /// `Podcast` table foreign key. + pub fn podcast_id(&self) -> i32 { + self.podcast_id + } + + /// Sets the `played` value with the current `epoch` timestap and save it. + pub fn set_played_now(&mut self) -> Result<()> { + let epoch = Utc::now().timestamp() as i32; + self.set_played(Some(epoch)); + self.save()?; + Ok(()) + } + + /// Helper method to easily save/"sync" current state of self to the Database. + pub fn save(&self) -> Result { + use schema::episode::dsl::*; + + let db = connection(); + let tempdb = db.get()?; + + Ok(diesel::update(episode).set(self).execute(&*tempdb)?) + } +} + #[derive(Queryable, Identifiable, AsChangeset, Associations, PartialEq)] #[belongs_to(Source, foreign_key = "source_id")] #[changeset_options(treat_none_as_null = "true")] diff --git a/hammond-downloader/src/downloader.rs b/hammond-downloader/src/downloader.rs index fafd726..4343e91 100644 --- a/hammond-downloader/src/downloader.rs +++ b/hammond-downloader/src/downloader.rs @@ -8,7 +8,7 @@ use std::io::{BufWriter, Read, Write}; use std::path::Path; use errors::*; -use hammond_data::{Episode, Podcast}; +use hammond_data::{Episode, EpisodeWidgetQuery, Podcast}; use hammond_data::xdg_dirs::{DL_DIR, HAMMOND_CACHE}; // TODO: Replace path that are of type &str with std::path. @@ -106,7 +106,7 @@ pub fn get_download_folder(pd_title: &str) -> Result { } // TODO: Refactor -pub fn get_episode(ep: &mut Episode, download_folder: &str) -> Result<()> { +pub fn get_episode(ep: &mut EpisodeWidgetQuery, download_folder: &str) -> Result<()> { // Check if its alrdy downloaded if ep.local_uri().is_some() { if Path::new(ep.local_uri().unwrap()).exists() { diff --git a/hammond-gtk/src/widgets/episode.rs b/hammond-gtk/src/widgets/episode.rs index 020341c..89dbf1e 100644 --- a/hammond-gtk/src/widgets/episode.rs +++ b/hammond-gtk/src/widgets/episode.rs @@ -5,10 +5,10 @@ use gtk::prelude::*; use open; use hammond_data::dbqueries; -use hammond_data::{Episode, Podcast}; -use hammond_downloader::downloader; +use hammond_data::{EpisodeWidgetQuery, Podcast}; use hammond_data::utils::*; use hammond_data::errors::*; +use hammond_downloader::downloader; use std::thread; use std::cell::RefCell; @@ -73,13 +73,16 @@ impl EpisodeWidget { } } - pub fn new_initialized(episode: &mut Episode, pd: &Podcast) -> EpisodeWidget { + pub fn new_initialized(episode: &mut EpisodeWidgetQuery, pd: &Podcast) -> EpisodeWidget { let widget = EpisodeWidget::new(); widget.init(episode, pd); widget } - fn init(&self, episode: &mut Episode, pd: &Podcast) { + // TODO: calculate lenght. + // TODO: wire the progress_bar to the downloader. + // TODO: wire the cancel button. + fn init(&self, episode: &mut EpisodeWidgetQuery, pd: &Podcast) { self.title.set_xalign(0.0); self.title.set_text(episode.title()); @@ -131,7 +134,7 @@ impl EpisodeWidget { // TODO: show notification when dl is finished. fn on_download_clicked( pd_title: &str, - ep: &mut Episode, + ep: &mut EpisodeWidgetQuery, download_bttn: >k::Button, play_bttn: >k::Button, del_bttn: >k::Button, @@ -225,7 +228,7 @@ fn receive() -> glib::Continue { } pub fn episodes_listbox(pd: &Podcast) -> Result { - let episodes = dbqueries::get_pd_episodes(pd)?; + let episodes = dbqueries::get_pd_episodeswidgets(pd)?; let list = gtk::ListBox::new(); episodes.into_iter().for_each(|mut ep| {