tonhowtf/omniget · error · anyhow::Error

HLS stream uses SAMPLE-AES (FairPlay DRM), cannot decrypt

Error message

HLS stream uses SAMPLE-AES (FairPlay DRM), cannot decrypt

What it means

Hard stop in fetch_encryption_info: the HLS playlist declares key method SAMPLE-AES, which is Apple FairPlay DRM — only AES-128 with a fetchable key URI is supported, so the stream is undecryptable by design and the download is refused early.

Solutions

  1. Use a non-DRM source or stream variant for the content
  2. Capture via a DRM-aware licensed workflow if you own the content rights
  3. Check for an alternate HLS rendition without SAMPLE-AE encryption
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at src-tauri/omniget-core/src/core/hls_downloader.rs:454 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/9c3772ef61b8783e. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/hls_downloader.rs:454

    async fn fetch_encryption_info(
        &self,
        playlist: &m3u8_rs::MediaPlaylist,
        m3u8_url: &str,
        referer: &str,
    ) -> anyhow::Result<Option<EncryptionInfo>> {
        for segment in &playlist.segments {
            if let Some(key) = &segment.key {
                match key.method {
                    m3u8_rs::KeyMethod::AES128 => {
                        if let Some(uri) = &key.uri {
                            let key_url = resolve_url(m3u8_url, uri);
                            let key_bytes = self.fetch_key_with_retry(&key_url, referer, 3).await?;
                            let iv = key.iv.as_ref().map(|iv_str| parse_hex_iv(iv_str));
                            return Ok(Some(EncryptionInfo { key_bytes, iv }));
                        }
                    }
                    m3u8_rs::KeyMethod::SampleAES => {
                        anyhow::bail!("HLS stream uses SAMPLE-AES (FairPlay DRM), cannot decrypt");
                    }
                    _ => {}
                }
            }
        }
        Ok(None)
    }

    async fn fetch_key_with_retry(
        &self,
        url: &str,
        referer: &str,
        max_retries: u32,
    ) -> anyhow::Result<Vec<u8>> {
        let mut last_err = None;
        for attempt in 0..max_retries {
            let req = apply_referer_headers(self.client.get(url), referer)
                .header("User-Agent", self.effective_user_agent());

View on GitHub (pinned to 8600b91f42)