use std::path; use std::collections::BTreeMap; #[derive(clap::Parser)] pub(crate) struct Args { /// Path to the configuration file listing podcast RSS feeds. #[arg(default_value = "./podcasts.toml")] pub(crate) config: path::PathBuf, #[command(subcommand)] pub(crate) command: Command, } #[derive(clap::ValueEnum, Copy, Clone, Debug,PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum ListenStatus { Listened, Unlistened, } #[derive(clap::Subcommand)] pub(crate) enum Command { /// Updates feed and downloads latest episodes. Download { /// The podcast to update. Updates all in configuration file if unspecified. #[arg(long, short)] podcast: Option, }, /// Lists the episodes for a given podcast, filtered based on if it has been listened or not. List { /// Filter for if episodes have been listened to or not. #[arg(long, short)] status: Option, /// The podcast to list episodes for. #[arg(long, short)] podcast: String, }, /// Marks an entire podcast's history of episodes as played or unplayed. Mark { /// The new listen status for the episodes. #[arg(long, short)] status: ListenStatus, /// The podcast to change the listen status of. #[arg(long, short)] podcast: String, }, /// Generates playlist for use with an iPod. Playlist { /// The podcast to generate the playlist for. #[arg(long, short)] podcast: Option, }, /// Syncs local copy of podcasts to Rockbox iPod. Sync { /// Directory to the root of the iPod running Rockbox. ipod_dir: path::PathBuf, /// Download any new episodes before syncing. #[clap(short, long)] download: bool, }, } /// Struct modelling configuration file format. #[derive(serde::Deserialize)] pub(crate) struct Config { /// Map from podcast alias to RSS feed either as a url (prefix: http) or file path. pub(crate) podcasts: BTreeMap, } #[derive(serde::Deserialize)] #[serde(untagged)] pub(crate) enum Source { String(String), Object { source: String, #[serde(rename = "skip-download")] skip_download: bool, }, } impl Source { pub(crate) fn source_raw(&self) -> &str { match self { Self::String(source) | Self::Object { source, .. } => source, } } pub(crate) fn skip_download(&self) -> bool { match self { Self::String(_) => false, Self::Object { skip_download, .. } => *skip_download, } } fn is_url(&self) -> bool { self.source_raw().starts_with("http") } pub(crate) fn source(&self) -> SourceKind<'_> { if self.is_url() { SourceKind::Url(self.source_raw()) } else { SourceKind::Path(self.source_raw()) } } } pub(crate) enum SourceKind<'a> { Url(&'a str), Path(&'a str), }