From 2449ef1c163a2c640a2fe4c4a7459df3b15567e5 Mon Sep 17 00:00:00 2001 From: Aaron Manning Date: Thu, 2 Jul 2026 14:44:14 +0100 Subject: [PATCH] bookmark cleaning up --- src/download.rs | 4 ++-- src/folders.rs | 13 +++++++++--- src/playlist.rs | 6 ++---- src/sync.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/download.rs b/src/download.rs index cd5a18b..482d9dd 100644 --- a/src/download.rs +++ b/src/download.rs @@ -38,7 +38,7 @@ pub(crate) fn update_podcast( ) -> anyhow::Result<()> { if source.skip_download() { - println!(r#"[info] skipping download for "{}""#, alias); + println!(r#"[info] skipping "{}""#, alias); return Ok(()) } @@ -49,7 +49,7 @@ pub(crate) fn update_podcast( .context(format!("failed to create output directory for podcast {}", alias))?; } - println!(r#"[info] scanning feed for "{}""#, alias); + println!(r#"[info] scanning "{}""#, alias); match source.source() { input::SourceKind::Url(feed_url) => { diff --git a/src/folders.rs b/src/folders.rs index 743df75..a38ca9a 100644 --- a/src/folders.rs +++ b/src/folders.rs @@ -6,10 +6,17 @@ pub(crate) const SPEC_FILE: &str = "spec.toml"; pub(crate) const LOCAL_PODCASTS_DIR: &str = "podcasts"; pub(crate) const LOCAL_PLAYLISTS_DIR: &str = "playlists"; -pub(crate) const IPOD_PODCASTS_DIR: &str = "Podcasts"; +pub(crate) const IPOD_PODCASTS_DIR: &str = "/Podcasts"; -pub(crate) const LISTENED_PLAYLIST_PATH: &str = "[PC] (Listened).m3u"; -pub(crate) const MASTER_PLAYLIST_PATH: &str = "[PC] (Master Feed).m3u"; + +macro_rules! playlist_ext { () => {"m3u8"}; } +pub(crate) const PLAYLIST_EXT: &str = playlist_ext!(); +macro_rules! bookmark_ext { () => {"bmark"}; } +pub(crate) const BOOKMARK_EXT: &str = bookmark_ext!(); +pub(crate) const PLAYLIST_BOOKMARK_EXT: &str = concat!(playlist_ext!(), ".", bookmark_ext!()); + +pub(crate) const LISTENED_PLAYLIST_PATH: &str = concat!("[PC] (Listened).", playlist_ext!()); +pub(crate) const MASTER_PLAYLIST_PATH: &str = concat!("[PC] (Master Feed).", playlist_ext!()); pub(crate) const MASTER_PLAYLIST_NAME: &str = "[PC] (Master Feed)"; pub(crate) const PLAYLIST_PREFIX: &str = "[PC]"; diff --git a/src/playlist.rs b/src/playlist.rs index f74572a..4c1c9b6 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -51,7 +51,7 @@ impl<'a> Playlist<'a> { .context("failed to create output directory for playlists")?; } let mut path = playlists_folder.join(sanitise(name)); - path.set_extension("m3u"); + path.set_extension(folders::PLAYLIST_EXT); // If the playlist is empty, then don't write it, // and delete the existing one if it exists. @@ -106,9 +106,7 @@ impl<'a> Playlist<'a> { }); match self.files.get_mut(&published) { - Some(existing) => { - existing.push(entry) - }, + Some(existing) => existing.push(entry), None => { self.files.insert( published, diff --git a/src/sync.rs b/src/sync.rs index d9eba68..01d8a78 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -212,7 +212,6 @@ pub(crate) fn sync( // || fs::read(&target)? != fs::read(&source)? { println!("[info] copying playlist {:?}.", source.file_name().unwrap()); fs::copy(source, target)?; - } } @@ -229,11 +228,63 @@ pub(crate) fn sync( // - have not been copied on checked to be up to date, // - is not the listened folder (which is special). if file_stem.starts_with(folders::PLAYLIST_PREFIX) - && extension == "m3u" + && extension == folders::PLAYLIST_EXT && !acknowledged.contains(&target) && file_name != folders::LISTENED_PLAYLIST_PATH { println!("[info] unsyncing playlist file {:?}", file_name); + // Delete the playlist file fs::remove_file(&target)?; + + // Delete the bookmark file as well + let mut bookmark = target.clone(); + bookmark.set_extension(folders::PLAYLIST_BOOKMARK_EXT); + fs::remove_file(&bookmark)?; + } + } + + // We remove any entries from bookmarks which no longer exist in the playlist + for target in fs::read_dir(target_dir.join(folders::LOCAL_PLAYLISTS_DIR))? { + let target = target?.path(); + let file_stem = target.file_stem().unwrap().to_str().unwrap(); + let extension = target.extension().unwrap().to_str().unwrap(); + + if file_stem.starts_with(folders::PLAYLIST_PREFIX) + && extension == folders::BOOKMARK_EXT { + let mut playlist_path = target.clone(); + playlist_path.set_extension(""); + + if playlist_path.is_file() { + // Create a btreeset of all files in the playlist + let mut playlist = BTreeSet::new(); + let playlist_file = fs::read_to_string(playlist_path)?; + for line in playlist_file.lines() { + playlist.insert(line); + } + + let bookmark_path = target; + + let bookmark = fs::read_to_string(&bookmark_path)?; + // Filter out entries from the bookmark which do not + // exist in the playlist + let mut new_bookmark = bookmark.lines().filter(|line| { + line.split(';').last().is_some_and(|file| playlist.contains(file)) + }).fold(String::new(), |mut string, line| { + string.push_str(line); + string.push('\n'); + string + }); + + if new_bookmark.ends_with('\n') { + new_bookmark.pop(); + } + + // Update the bookmark file if it has changed + if new_bookmark.trim() != bookmark.trim() { + let file_name = bookmark_path.file_name().unwrap().to_str().unwrap(); + println!("[info] trimming bookmark file {:?}", file_name); + fs::write(bookmark_path, new_bookmark)?; + } + } } }