kodik-utils 0.2.2

Rust utilities library for Kodik
Documentation
use reqwest::cookie::Jar;
use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
};

pub trait JarExt {
    /// Loads cookies from a Netscape-format cookie file.
    ///
    /// # Errors
    ///
    /// Returns a [`crate::Error`] if the file cannot be opened or is malformed.
    fn load_netscape(path: &impl AsRef<Path>) -> crate::Result<Jar>;
}

impl JarExt for Jar {
    fn load_netscape(path: &impl AsRef<Path>) -> crate::Result<Self> {
        let jar = Self::default();
        let file = File::open(path)?;
        let mut reader = BufReader::new(file);
        let mut line = String::new();

        while reader.read_line(&mut line)? > 0 {
            let trimmed = line.trim();

            if trimmed.starts_with('#') || trimmed.is_empty() {
                line.clear();
                continue;
            }

            let mut parts = trimmed.splitn(7, '\t');
            let domain = parts
                .next()
                .ok_or_else(|| crate::Error::NotFound("malformed cookie: missing domain".into()))?;
            let key = parts
                .nth(4)
                .ok_or_else(|| crate::Error::NotFound("malformed cookie: missing name".into()))?;
            let value = parts
                .next()
                .ok_or_else(|| crate::Error::NotFound("malformed cookie: missing value".into()))?;

            let mut cookie = String::with_capacity(key.len() + value.len() + domain.len() + 10);
            cookie.push_str(key);
            cookie.push('=');
            cookie.push_str(value);
            cookie.push_str("; Domain=");
            cookie.push_str(domain);

            let domain = domain.trim_start_matches('.');
            let mut url_str = String::with_capacity(8 + domain.len());
            url_str.push_str("https://");
            url_str.push_str(domain);

            jar.add_cookie_str(
                &cookie,
                &reqwest::Url::parse(&url_str)
                    .map_err(|e| crate::Error::NotFound(format!("invalid cookie domain '{domain}': {e}")))?,
            );

            line.clear();
        }

        Ok(jar)
    }
}