### Client Initialization and Async Setup Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Shows how to initialize the `Client` GObject, which manages application state, including the database, cache, and HTTP client. `setup()` is synchronous, while `setup_async()` must be called in an async context after the GTK main loop starts. ```rust use crate::backend::Client; // Initialization (called once at application startup) let client = Client::new(); client.setup().expect("Failed to set up client"); // In an async context after the GTK main loop starts: gspawn!(clone!(#[weak] client, async move { client.setup_async().await; // Provider registry is now live; searches and feed fetches will work })); ``` -------------------------------- ### Install Fedora/RHEL Dependencies Source: https://gitlab.com/schmiddi-on-mobile/pipeline/-/blob/master/CONTRIBUTING.md Installs necessary system dependencies for building on Fedora or RHEL. ```bash sudo dnf install meson gcc pkgconf-pcre gtk4 clapper-devel rust cargo sqlite glib2 gobject-introspection libadwaita blueprint-compiler ``` -------------------------------- ### Point to a Self-Hosted PeerTube Search API with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Specify the URL of a self-hosted PeerTube instance to be used for search queries. Replace the example URL with your preferred PeerTube instance. ```bash gsettings set de.schmidhuberj.tubefeeder peertube-search-api 'https://my.peertube.instance/' ``` -------------------------------- ### Install Debian/Ubuntu Dependencies Source: https://gitlab.com/schmiddi-on-mobile/pipeline/-/blob/master/CONTRIBUTING.md Installs necessary system dependencies for building on Debian or Ubuntu. ```bash sudo apt install meson gcc pkg-config libgtk-4-dev libclapper-0.0-dev rustc cargo libsqlite3-dev libglib2.0-dev libgirepository1.0-dev libadwaita blueprint-compiler ``` -------------------------------- ### Install Arch Linux Dependencies Source: https://gitlab.com/schmiddi-on-mobile/pipeline/-/blob/master/CONTRIBUTING.md Installs necessary system dependencies for building on Arch Linux. ```bash sudo pacman -S --needed meson gcc pkgconf gtk4 libclapper clapper rust cargo sqlite glib2 gobject-introspection libadwaita blueprint-compiler ``` -------------------------------- ### Build Project with Meson Source: https://gitlab.com/schmiddi-on-mobile/pipeline/-/blob/master/CONTRIBUTING.md Sets up the build environment and compiles the project using Meson. ```bash meson setup build meson compile -C build ``` -------------------------------- ### Build and Run Pipeline from Source Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Instructions for configuring, building, and running the Pipeline application from source on various Linux distributions. Includes commands for both standard and development profiles. ```bash # Arch Linux sudo pacman -S --needed meson gcc pkgconf gtk4 libclapper clapper rust cargo sqlite glib2 gobject-introspection libadwaita blueprint-compiler # Fedora/RHEL sudo dnf install meson gcc pkgconf-pcre gtk4 clapper-devel rust cargo sqlite glib2 gobject-introspection libadwaita blueprint-compiler # Debian/Ubuntu sudo apt install meson gcc pkg-config libgtk-4-dev libclapper-0.0-dev rustc cargo libsqlite3-dev libglib2.0-dev libgirepository1.0-dev libadwaita blueprint-compiler # Configure and build meson setup build meson compile -C build # Run with the local GSettings schema GSETTINGS_SCHEMA_DIR=build/data ./build/target/release/tubefeeder # Development profile (enables Devel app ID and git-hash version suffix) meson setup build -Dprofile=development meson compile -C build GSETTINGS_SCHEMA_DIR=build/data ./build/target/debug/tubefeeder ``` -------------------------------- ### Fetching Videos and Searching with Client Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Illustrates how to use the `Client` to fetch videos for subscribed channels and perform searches across YouTube and PeerTube. These operations are asynchronous and return streams of data. ```rust // Fetch videos for a set of channel IDs (filtered by active Filter rules) let channel_ids = client.subscriptions() .iter() .map(|c| c.id()) .collect::>(); gspawn!(clone!(#[weak] client, async move { let stream = client.videos_for_channels(&channel_ids, true).await; // stream implements Stream — collect or bind to a ListModel })); // Search YouTube + PeerTube simultaneously gspawn!(clone!(#[weak] client, async move { let stream = client.search("Rust programming").await; // stream implements Stream (Video or Channel) })); ``` -------------------------------- ### Initialize and Use SQLite Store Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Opens or creates an SQLite database, automatically applies migrations, and provides methods for subscribing/unsubscribing to channels, managing filters, and trimming unused data. WAL mode and foreign keys are enabled by default. ```rust use crate::store::Store; use pcore::{Channel, ChannelId, Video, VideoId}; use std::borrow::Cow; // Open (creates if missing, migrates automatically) let mut store = Store::new("/home/user/.local/share/tubefeeder/data.sqlite") .expect("Could not open database"); // Subscribe to a channel let channel = Channel { id: ChannelId { id: "UCxxxxxx".into(), platform: Cow::Borrowed("youtube") }, name: "Example Channel".into(), avatar: None, banner: None, description: None, subscribers: None, }; store.subscribe(&channel).expect("subscribe failed"); // List all subscriptions let subs = store.subscriptions().expect("query failed"); assert_eq!(subs[0].name, "Example Channel"); // Unsubscribe store.unsubscribe(&channel).expect("unsubscribe failed"); assert!(store.subscriptions().unwrap().is_empty()); // Add/remove a content filter use crate::backend::Filter; let f = Filter::new("youtube", "shorts", ""); store.add_filter(&f).expect("add filter failed"); let filters = store.filters().expect("query failed"); assert_eq!(filters.len(), 1); store.remove_filter(&f).expect("remove filter failed"); // Trim orphaned rows (videos/channels not in any list) store.trim_unused().expect("trim failed"); ``` -------------------------------- ### Run Application from Build Directory Source: https://gitlab.com/schmiddi-on-mobile/pipeline/-/blob/master/CONTRIBUTING.md Executes the application after building it from source. ```bash GSETTINGS_SCHEMA_DIR=build/data ./build/target/release/tubefeeder ``` -------------------------------- ### Read YouTube Backend Mode with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Use this command to read the current YouTube backend mode. The output indicates the active backend, such as 'rustypipe-then-piped'. ```bash gsettings get de.schmidhuberj.tubefeeder youtube-mode ``` -------------------------------- ### Set Custom yt-dlp Download Format with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Configure a custom download format for yt-dlp by specifying the desired format string. This allows for fine-grained control over video quality and selection. ```bash gsettings set de.schmidhuberj.tubefeeder download-format 'bestvideo[height<=1080]+bestaudio/best' ``` -------------------------------- ### Initialize and Use SubscriptionsStore Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt A `gio::ListModel` and `gtk::SelectionModel` for channels, sorted alphabetically by name and then ID. The `toggle()` method inserts or removes a channel and fires `items-changed` signals. Useful for binding directly to GTK list views. ```rust use crate::backend::{Channel, SubscriptionsStore}; let store = SubscriptionsStore::default(); let ch = Channel::new(pcore::Channel { /* ... */ }); let was_added = store.toggle(ch.clone()); assert!(was_added); // true on first call let was_added_again = store.add_if_not_exists(ch.clone()); assert!(!was_added_again); // already present // Bind to a GTK list view let selection_model: gtk::SingleSelection = gtk::SingleSelection::new(Some(store.clone())); // list_view.set_model(Some(&selection_model)); ``` -------------------------------- ### Backup SQLite Database Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Creates a point-in-time copy of the SQLite database to a specified file. Requires a `gio::File` object for the backup path. ```rust use gdk::gio::File; // Backup let backup_file = File::for_path("/home/user/pipeline_backup.sqlite"); client.backup(backup_file).expect("Backup failed"); ``` -------------------------------- ### Client::backup / Client::restore Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Create a point-in-time copy of the SQLite database, or replace the current database with a previously saved backup. Restoring automatically runs pending migrations. ```APIDOC ## `Client::backup` / `Client::restore` — Database Backup and Restore Create a point-in-time copy of the SQLite database, or replace the current database with a previously saved backup. Restoring automatically runs pending migrations so the restored file is always up-to-date. ### Usage ```rust use gdk::gio::File; // Backup let backup_file = File::for_path("/home/user/pipeline_backup.sqlite"); client.backup(backup_file).expect("Backup failed"); // Restore — all in-memory stores are rebuilt from the restored DB let restore_file = File::for_path("/home/user/pipeline_backup.sqlite"); client.restore(restore_file).expect("Restore failed"); // After restore, subscriptions(), watch-later, history, etc. reflect the backup ``` ``` -------------------------------- ### Switch YouTube Backend to Piped-only Mode with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Set the YouTube backend to use Piped exclusively by running this command. This ensures that only Piped is used for YouTube content. ```bash gsettings set de.schmidhuberj.tubefeeder youtube-mode 'piped' ``` -------------------------------- ### Manually Set a List of Piped API Endpoints with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Manually specify a list of Piped API endpoints to be used by the application. This allows for custom configurations or load balancing across multiple Piped instances. ```bash gsettings set de.schmidhuberj.tubefeeder piped-api-urls \ "['https://pipedapi.kavin.rocks', 'https://pipedapi.adminforge.de']" ``` -------------------------------- ### Asynchronous Spawn Macros for GTK and Tokio Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Demonstrates the usage of `gspawn!`, `gspawn_global!`, and `tspawn!` macros for managing asynchronous tasks between the GTK GLib main loop and a Tokio runtime. Use `gspawn!` for UI updates and `tspawn!` within `gspawn!` for background network requests. ```rust use crate::{gspawn, gspawn_global, tspawn}; // Run a UI update asynchronously on the GTK main loop gspawn!(async move { some_widget.set_label("Loaded"); }); // Run a network request on the Tokio runtime, then update the UI gspawn!(async move { let result = tspawn!(async move { reqwest::get("https://example.com").await }) .await .expect("tokio join"); match result { Ok(resp) => label.set_label(&format!("Status: {}", resp.status())), Err(e) => label.set_label(&format!("Error: {e}")), } }); ``` -------------------------------- ### Periodic Client Cleanup Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Demonstrates the synchronous `cleanup()` method on the `Client`, used for pruning orphaned database rows and stale image cache entries. This should be called periodically. ```rust // Periodic cleanup: prune orphaned DB rows and stale image cache entries client.cleanup().expect("cleanup failed"); ``` -------------------------------- ### Restore SQLite Database Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Replaces the current database with a previously saved backup. Restoring automatically runs pending migrations to ensure the database is up-to-date. Requires a `gio::File` object for the backup path. ```rust use gdk::gio::File; // Restore — all in-memory stores are rebuilt from the restored DB let restore_file = File::for_path("/home/user/pipeline_backup.sqlite"); client.restore(restore_file).expect("Restore failed"); // After restore, subscriptions(), watch-later, history, etc. reflect the backup ``` -------------------------------- ### Store::new, Store::subscribe, Store::subscriptions, Store::unsubscribe, Store::add_filter, Store::filters, Store::remove_filter, Store::trim_unused Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt The `Store` is a low-level SQLite database wrapper that handles opening, creating, and migrating the database. It provides typed methods for subscribing/unsubscribing to channels, managing filters, and trimming unused rows. ```APIDOC ## `Store` — SQLite Persistence Layer `Store` is the low-level database wrapper. It opens (or creates) an SQLite database at a given path, applies all pending migrations automatically using `rusqlite_migration`, and provides typed methods for every persistent operation. WAL mode and foreign keys are enabled by default. ### Usage ```rust use crate::store::Store; use pcore::{Channel, ChannelId, Video, VideoId}; use std::borrow::Cow; // Open (creates if missing, migrates automatically) let mut store = Store::new("/home/user/.local/share/tubefeeder/data.sqlite") .expect("Could not open database"); // Subscribe to a channel let channel = Channel { id: ChannelId { id: "UCxxxxxx".into(), platform: Cow::Borrowed("youtube") }, name: "Example Channel".into(), avatar: None, banner: None, description: None, subscribers: None, }; store.subscribe(&channel).expect("subscribe failed"); // List all subscriptions let subs = store.subscriptions().expect("query failed"); assert_eq!(subs[0].name, "Example Channel"); // Unsubscribe store.unsubscribe(&channel).expect("unsubscribe failed"); assert!(store.subscriptions().unwrap().is_empty()); // Add/remove a content filter use crate::backend::Filter; let f = Filter::new("youtube", "shorts", ""); store.add_filter(&f).expect("add filter failed"); let filters = store.filters().expect("query failed"); assert_eq!(filters.len(), 1); store.remove_filter(&f).expect("remove filter failed"); // Trim orphaned rows (videos/channels not in any list) store.trim_unused().expect("trim failed"); ``` ``` -------------------------------- ### Import Subscriptions from Exported Files Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Imports subscription lists from NewPipe JSON, YouTube CSV, or Invidious JSON exports. This method bulk-subscribes to recognized channels. Requires `gdk::gio::File` objects pointing to the export files. ```rust use gdk::gio::File; // Import from a NewPipe JSON export let file = File::for_path("/home/user/Downloads/newpipe_subscriptions.json"); client.import_newpipe(file).expect("Failed to import NewPipe subscriptions"); // Import from a YouTube CSV export (downloaded from Google Takeout) let csv_file = File::for_path("/home/user/Downloads/subscriptions.csv"); client.import_youtube(csv_file).expect("Failed to import YouTube subscriptions"); // Import from an Invidious JSON export let inv_file = File::for_path("/home/user/Downloads/invidious.json"); client.import_invidious(inv_file).expect("Failed to import Invidious subscriptions"); ``` -------------------------------- ### Create and Test a Filter GObject Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Extends `gtk::Filter` to hide videos based on platform, title substring, and channel criteria. An empty criterion matches everything. This is typically used with `gtk::FilterListModel`. ```rust use crate::backend::Filter; use gtk::prelude::FilterExt; // Hide all YouTube "shorts" videos regardless of channel let filter = Filter::new("youtube", "shorts", ""); // Test a video manually (returns false = hidden when all criteria match) // In practice this is called automatically by GTK's filter infrastructure // when bound to a gtk::FilterListModel. let is_visible = filter.match_(video.upcast_ref::()); // is_visible == false when the video is on YouTube and its title contains "shorts" // is_visible == true for all other videos ``` -------------------------------- ### Client::import_newpipe, Client::import_youtube, Client::import_invidious Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Imports subscription lists from exported files. Supports NewPipe JSON (YouTube/PeerTube), YouTube CSV, and Invidious JSON formats. ```APIDOC ## `Client::import_newpipe` / `Client::import_youtube` / `Client::import_invidious` — Import Subscriptions Import a subscription list from an exported file and bulk-subscribe to all recognized channels. NewPipe JSON exports support both YouTube (service ID 0) and PeerTube (service ID 3) channels. YouTube CSV uses the standard "channel ID, URL, name" format. Invidious exports are also supported as JSON. ### Usage ```rust use gdk::gio::File; // Import from a NewPipe JSON export let file = File::for_path("/home/user/Downloads/newpipe_subscriptions.json"); client.import_newpipe(file).expect("Failed to import NewPipe subscriptions"); // Import from a YouTube CSV export (downloaded from Google Takeout) let csv_file = File::for_path("/home/user/Downloads/subscriptions.csv"); client.import_youtube(csv_file).expect("Failed to import YouTube subscriptions"); // Import from an Invidious JSON export let inv_file = File::for_path("/home/user/Downloads/invidious.json"); client.import_invidious(inv_file).expect("Failed to import Invidious subscriptions"); ``` ``` -------------------------------- ### SubscriptionsStore::default, SubscriptionsStore::toggle, SubscriptionsStore::add_if_not_exists Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt `SubscriptionsStore` implements `gio::ListModel` and `gtk::SelectionModel`, allowing it to be directly bound to GTK list views. It keeps channels sorted alphabetically and provides methods to add, remove, or toggle subscriptions. ```APIDOC ## `SubscriptionsStore` — Alphabetically Sorted Channel List Model `SubscriptionsStore` implements both `gio::ListModel` and `gtk::SelectionModel`, making it directly bindable to `gtk::ListView` / `gtk::GridView`. Channels are kept sorted alphabetically by name (case-insensitive, then by ID as a tiebreaker). `toggle()` inserts or removes a channel and fires the standard `items-changed` signal. ### Usage ```rust use crate::backend::{Channel, SubscriptionsStore}; let store = SubscriptionsStore::default(); let ch = Channel::new(pcore::Channel { /* ... */ }); let was_added = store.toggle(ch.clone()); assert!(was_added); // true on first call let was_added_again = store.add_if_not_exists(ch.clone()); assert!(!was_added_again); // already present // Bind to a GTK list view let selection_model: gtk::SingleSelection = gtk::SingleSelection::new(Some(store.clone())); // list_view.set_model(Some(&selection_model)); ``` ``` -------------------------------- ### Bookmark/Unbookmark a Video Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Adds or removes a video from the 'watch later' list. Video metadata is upserted into the SQLite `videos` table for persistence. Use this to toggle the `watch_later` property. ```rust client.toggle_watch_later(video.clone()); assert!(video.watch_later()); ``` ```rust client.toggle_watch_later(video.clone()); assert!(!video.watch_later()); ``` -------------------------------- ### Force Cairo Software Renderer with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Enable the Cairo software renderer to force software rendering. This is useful on devices that lack GLES 3.0 support, ensuring video playback compatibility. ```bash gsettings set de.schmidhuberj.tubefeeder cairo-software-renderer true ``` -------------------------------- ### Export Subscriptions to YouTube CSV Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Serializes current subscriptions to a CSV file with channel ID, URL, and name columns, compatible with YouTube's subscription import. Requires a `gio::File` object for the output path. ```rust use gdk::gio::File; // Export to YouTube CSV let csv_out = File::for_path("/home/user/Downloads/pipeline_youtube.csv"); client.export_youtube(csv_out).expect("Failed to export to YouTube CSV format"); ``` -------------------------------- ### Pin the Sidebar by Default on Desktop with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Configure the sidebar to be pinned by default on desktop environments. This setting ensures the sidebar remains visible upon application startup. ```bash gsettings set de.schmidhuberj.tubefeeder sidebar-pinned true ``` -------------------------------- ### Disable PeerTube as a Video Source with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Disable PeerTube as a source for video content by setting 'enable-source-peertube' to false. This command prevents Pipeline from fetching content from PeerTube instances. ```bash gsettings set de.schmidhuberj.tubefeeder enable-source-peertube false ``` -------------------------------- ### Track Downloaded Videos Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Registers a local file path for a downloaded video in the SQLite `downloaded` table. Updates the `downloaded-path` and `downloaded` properties. Use `remove_downloaded` to remove the record without deleting the file. ```rust use std::path::PathBuf; let path = PathBuf::from("/home/user/Videos/my_video.mkv"); client.downloaded(video.clone(), path.clone()); assert!(video.downloaded()); assert_eq!(video.downloaded_path(), Some(path.to_string_lossy().into_owned())); ``` ```rust client.remove_downloaded(&video); assert!(!video.downloaded()); ``` -------------------------------- ### Client::toggle_watch_later Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Bookmarks a video to the "watch later" list or removes it. Video metadata is stored locally for persistence. ```APIDOC ## `Client::toggle_watch_later` — Bookmark a Video Adds or removes a `Video` from the "watch later" list. The video's metadata (title, uploader, thumbnail URL, etc.) is upserted into the SQLite `videos` table so the entry is available after a restart without a network round-trip. ### Usage ```rust // Mark a video for later viewing client.toggle_watch_later(video.clone()); assert!(video.watch_later()); // property is now true // Toggle again to remove client.toggle_watch_later(video.clone()); assert!(!video.watch_later()); ``` ``` -------------------------------- ### Export Subscriptions to NewPipe JSON Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Serializes current subscriptions to a JSON file compatible with NewPipe's import feature. Requires a `gio::File` object for the output path. ```rust use gdk::gio::File; // Export to NewPipe JSON let out_file = File::for_path("/home/user/Downloads/pipeline_export.json"); client.export_newpipe(out_file).expect("Failed to export to NewPipe format"); ``` -------------------------------- ### Client::export_newpipe / Client::export_youtube Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Serialize all current subscriptions to a file. Supports NewPipe JSON format and YouTube CSV format. ```APIDOC ## `Client::export_newpipe` / `Client::export_youtube` — Export Subscriptions Serialize all current subscriptions to a file. The NewPipe format is a JSON document compatible with NewPipe's import feature. The YouTube format is a CSV file with channel ID, URL, and name columns (compatible with YouTube's subscription import). ### Usage ```rust use gdk::gio::File; // Export to NewPipe JSON let out_file = File::for_path("/home/user/Downloads/pipeline_export.json"); client.export_newpipe(out_file).expect("Failed to export to NewPipe format"); // Export to YouTube CSV let csv_out = File::for_path("/home/user/Downloads/pipeline_youtube.csv"); client.export_youtube(csv_out).expect("Failed to export to YouTube CSV format"); ``` ``` -------------------------------- ### Client::toggle_subscription Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Subscribes to or unsubscribes from a channel. The changes are persisted immediately to the SQLite store and the channel's subscribed status is updated. ```APIDOC ## `Client::toggle_subscription` — Subscribe / Unsubscribe Adds a `Channel` to the subscriptions list if it is not already present, or removes it if it is. The result is written immediately to the SQLite store so it persists across restarts. The `Channel` object's `subscribed` property is updated to reflect the new state. ### Usage ```rust // Assuming `channel` is a Channel GObject obtained from a search result or the store client.toggle_subscription(channel.clone()); // Read back the subscription list (sorted alphabetically by name) let subs: Vec = client.subscriptions(); for ch in &subs { println!("{} ({})", ch.name(), ch.id().platform); } ``` ### Example Output ``` GNOME (youtube) KDE (youtube) Blender (peertube) ``` ``` -------------------------------- ### Filter::new, Filter::match_ Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt The `Filter` GObject extends `gtk::Filter` and implements the GTK filter protocol. Its `match_()` method determines if a video should be hidden based on platform, title, and channel criteria. ```APIDOC ## `Filter` GObject — Video Matching Rule `Filter` extends `gtk::Filter` and implements the GTK filter protocol. Its `match_()` method returns `false` (i.e., hides the video) when all three criteria — `platform`, `title` (case-insensitive substring), and `channel` — simultaneously match a `Video`. Any empty criterion matches everything. ### Usage ```rust use crate::backend::Filter; use gtk::prelude::FilterExt; // Hide all YouTube "shorts" videos regardless of channel let filter = Filter::new("youtube", "shorts", ""); // Test a video manually (returns false = hidden when all criteria match) // In practice this is called automatically by GTK's filter infrastructure // when bound to a gtk::FilterListModel. let is_visible = filter.match_(video.upcast_ref::()); // is_visible == false when the video is on YouTube and its title contains "shorts" // is_visible == true for all other videos ``` ``` -------------------------------- ### Client::downloaded and Client::remove_downloaded Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Tracks downloaded videos by registering their local file paths in the SQLite `downloaded` table. Updates the video object's properties to reflect the download state and path. Removing a record does not delete the file. ```APIDOC ## `Client::downloaded` / `Client::remove_downloaded` — Track Downloaded Videos Registers a local file path for a downloaded video in the SQLite `downloaded` table. The `Video` object's `downloaded-path` and `downloaded` properties are updated so the UI can reflect the download state and open the local file. ### Usage ```rust use std::path::PathBuf; let path = PathBuf::from("/home/user/Videos/my_video.mkv"); client.downloaded(video.clone(), path.clone()); assert!(video.downloaded()); // true assert_eq!(video.downloaded_path(), Some(path.to_string_lossy().into_owned())); // Remove the record (does not delete the file on disk) client.remove_downloaded(&video); assert!(!video.downloaded()); ``` ``` -------------------------------- ### Add/Remove Content Filtering Rules Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Toggles a `Filter` rule in the active filter set. Filters match on platform, video title, and channel name. Videos matching any active filter are hidden. Use `Filter::new` to create rules and call `toggle_filter` to add or remove them. ```rust use crate::backend::Filter; // Block all videos whose title contains "shorts" on YouTube let filter = Filter::new("youtube", "shorts", ""); client.toggle_filter(filter.clone()); // Block all videos from a specific channel on any platform let channel_filter = Filter::new("", "", "ClickbaitChannel"); client.toggle_filter(channel_filter); // Remove the first filter client.toggle_filter(filter); ``` -------------------------------- ### Subscribe/Unsubscribe to a Channel Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Toggles a channel's subscription status. The change is immediately persisted to the SQLite store and updates the Channel's `subscribed` property. ```rust client.toggle_subscription(channel.clone()); ``` ```rust let subs: Vec = client.subscriptions(); for ch in &subs { println!("{} ({})", ch.name(), ch.id().platform); } ``` -------------------------------- ### Record Watch History Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Records a video as watched at a specific UTC timestamp. This is a no-op if 'watch-history-enabled' is false. The video's `watched` property is updated. Use `delete_watch_history` to clear all history. ```rust use chrono::Utc; let now = Utc::now(); client.watched(video.clone(), now); assert!(video.watched()); ``` ```rust client.delete_watch_history(); assert!(!client.has_watch_history()); ``` -------------------------------- ### Disable Watch History with gsettings Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Turn off the watch history feature by setting 'watch-history-enabled' to false. This enhances privacy by not recording viewed videos. ```bash gsettings set de.schmidhuberj.tubefeeder watch-history-enabled false ``` -------------------------------- ### Client::toggle_filter Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Adds or removes a content filtering rule. Filters can match on platform, video title substring (case-insensitive), or channel name substring. Videos matching active filters are hidden. ```APIDOC ## `Client::toggle_filter` — Content Filtering Rules Adds or removes a `Filter` rule from the active filter set. Each `Filter` matches on a combination of platform name, video title substring (case-insensitive), and channel name substring. Videos matching any active filter are hidden from the feed. ### Usage ```rust use crate::backend::Filter; // Block all videos whose title contains "shorts" on YouTube let filter = Filter::new("youtube", "shorts", ""); client.toggle_filter(filter.clone()); // Block all videos from a specific channel on any platform let channel_filter = Filter::new("", "", "ClickbaitChannel"); client.toggle_filter(channel_filter); // Remove the first filter client.toggle_filter(filter); ``` ``` -------------------------------- ### Client::watched and Client::delete_watch_history Source: https://context7.com/schmiddi-on-mobile/pipeline/llms.txt Records a video as watched with a UTC timestamp. Optionally, the entire watch history can be deleted. This feature is controlled by the `watch-history-enabled` GSettings key. ```APIDOC ## `Client::watched` — Record Watch History Records that a video was watched at a specific UTC timestamp. If the `watch-history-enabled` GSettings key is `false` this is a no-op. The history is used by the "hide watched" feed filter. ### Usage ```rust use chrono::Utc; let now = Utc::now(); client.watched(video.clone(), now); // The video's `watched` property is now true assert!(video.watched()); // Delete the entire watch history client.delete_watch_history(); assert!(!client.has_watch_history()); ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.