tonhowtf/omniget · error

cole o link de um VOD ou de um clipe da Twitch

Error message

cole o link de um VOD ou de um clipe da Twitch: {}

What it means

resolve_chat_target parses a user-pasted string into a Twitch VOD or clip target. When parse_video cannot extract a video id or clip slug from the input, it throws this anyhow error embedding the original input. It is a user-input validation error, not an internal fault.

Solutions

  1. Check that the input matches a supported Twitch VOD URL pattern (twitch.tv/videos/<id>) or clip URL (twitch.tv/<ch>/clip/<slug> or clips.twitch.tv/<slug>) before calling
  2. Trim whitespace and strip query parameters (?t=...) from the pasted link
  3. Ask the user to re-copy the link directly from the VOD/clip share button
  4. If supporting more formats is desired, extend parse_video in gql.rs to handle them

Example fix

// before
let info = tool.resolve_chat_target("twitch.tv/somechannel").await?;
// after
let input = "twitch.tv/somechannel";
if !input.contains("/videos/") && !input.contains("/clip/") && !input.contains("clips.twitch.tv") {
    anyhow::bail!("{} não é um link de VOD ou clipe da Twitch", input);
}
let info = tool.resolve_chat_target(input).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_twitch_vod_or_clip(input: &str) -> bool {
    let u = input.trim();
    u.contains("twitch.tv/videos/") || u.contains("/clip/") || u.contains("clips.twitch.tv/")
}

Type guard

fn looks_like_twitch_url(s: &str) -> bool {
    s.starts_with("https://") && (s.contains("twitch.tv/videos/") || s.contains("clips.twitch.tv"))
}

Try / catch

match tool.resolve_chat_target(input).await {
    Ok(info) => info,
    Err(e) => { show_user("link inválido, use um VOD ou clipe da Twitch"); return; }
}

Prevention

When it happens

Trigger: Calling resolve_chat_target with a string that is not a Twitch VOD/clip URL (e.g. a channel URL, a plain video id without context, a YouTube link, or arbitrary text).

Common situations: Users paste a channel page (twitch.tv/name) instead of a VOD link; paste a video ID alone like '123456789'; clipboard contains a timestamped or shortened link variant the parser does not handle.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/twitch/gql.rs:265

            escape(slug)
        );
        let data = self.query(&q).await?;
        let c = data.get("clip").filter(|v| !v.is_null());
        let c = c.ok_or_else(|| anyhow!("clipe não encontrado: {}", slug))?;
        let vid = c
            .pointer("/video/id")
            .and_then(|x| x.as_str())
            .ok_or_else(|| anyhow!("esse clipe não tem VOD de origem, então não há chat"))?;
        let mut info = self.video(vid).await?;
        info.clip_offset = c.get("videoOffsetSeconds").and_then(num);
        info.clip_duration = c.get("durationSeconds").and_then(num);
        Ok(info)
    }

    /// Resolve o que o usuário colou até chegar num VOD.
    pub async fn resolve_chat_target(&self, input: &str) -> anyhow::Result<VideoInfo> {
        let target = parse_video(input)
            .ok_or_else(|| anyhow!("cole o link de um VOD ou de um clipe da Twitch: {}", input))?;
        match target {
            ChatTarget::Video(id) => self.video(&id).await,
            ChatTarget::Clip(slug) => self.clip_video(&slug).await,
        }
    }
}

fn num(v: &Value) -> Option<f64> {
    v.as_f64()
        .or_else(|| v.as_str().and_then(|s| s.parse().ok()))
}

pub(super) fn str_at(v: &Value, key: &str) -> String {
    v.get(key)
        .and_then(|x| x.as_str())
        .unwrap_or_default()
        .to_string()
}

View on GitHub (pinned to 8600b91f42)