Deliver ytdlpCommand for an allowlist of verified channels

decorate_channel ignored every provider-declared ytdlpCommand except
pimpbunny's. Send the declared command for freepornvideosxxx and missav,
where plain yt-dlp is verified to fail; other channels stay unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUYdCh2nCVsQYgJAT7gwSi
This commit is contained in:
Simon
2026-10-10 10:28:57 +00:00
parent 40eab41b2b
commit 2addcc2e7c
2 changed files with 37 additions and 6 deletions

View File

@@ -64,13 +64,16 @@ Status: `[ ]` open, `[~]` in progress, `[x]` fixed and verified, `[-]` not repro
|---|---|---| |---|---|---|
| [x] | `check.py` "url points to hottub server" | contradicted the hottub skill | proxied `video.url` is now verified to resolve (redirect target reachable, CF hosts -> warning) instead of hard-failing. Affected: spankbang, hqporner, pornhd3x, pimpbunny, sxyprn, noodlemagazine | | [x] | `check.py` "url points to hottub server" | contradicted the hottub skill | proxied `video.url` is now verified to resolve (redirect target reachable, CF hosts -> warning) instead of hard-failing. Affected: spankbang, hqporner, pornhd3x, pimpbunny, sxyprn, noodlemagazine |
## Open decision (needs the owner) ## Decision: `ytdlpCommand` delivery (agreed: targeted rollout)
`ytdlpCommand` set on providers (`Channel.ytdlpCommand`, ~90 channels, e.g. `yt-dlp --impersonate chrome-120`) is **never sent to clients**: Providers declare `Channel.ytdlpCommand` (~90 channels), but `/api/status` used to send it only for `pimpbunny`.
`decorate_channel` in `src/providers/mod.rs` builds `ChannelView.ytdlpCommand` from a hardcoded `match` (only `pimpbunny`), and Delivering all of them at once risks breaking working channels if the app's yt-dlp lacks impersonation support, so
`decorates_channel_with_group_and_tags` pins `hsex` to `None`. `/api/status` therefore reports `null` for all of them. Either deliver `decorate_channel` now delivers a provider's declared command **only for channels in `YTDLP_COMMAND_CHANNELS`**
`channel.ytdlpCommand` (clients then need yt-dlp impersonation support) or drop the dead declarations. Channels that only fail (`src/providers/mod.rs`): `freepornvideosxxx`, `missav`. Add a channel there once plain yt-dlp is verified to fail for it.
under plain yt-dlp TLS (freepornvideosxxx, missav, ...) depend on this. `check.py` now applies whatever `/api/status` exposes.
Still to do with the app side: confirm the app applies `ytdlpCommand` for non-pimpbunny channels and that its yt-dlp has an
impersonation target; if a minimum client version is needed, gate on `ClientVersion` (not done, the minimum is unknown).
`check.py` applies whatever `/api/status` exposes, so it verifies each addition.
## Found while fixing (pre-existing, unrelated) ## Found while fixing (pre-existing, unrelated)

View File

@@ -778,11 +778,20 @@ fn sanitize_status_options(options: Vec<ChannelOption>) -> Vec<ChannelOption> {
.collect() .collect()
} }
/// Channels whose own declared `ytdlpCommand` is delivered in `/api/status`.
/// Verified: `freepornvideosxxx` (plain yt-dlp gets 502 on its pages, fine with
/// `--impersonate chrome-120`) and `missav` (Cloudflare 403 without it).
const YTDLP_COMMAND_CHANNELS: &[&str] = &["freepornvideosxxx", "missav"];
pub fn decorate_channel(channel: Channel) -> ChannelView { pub fn decorate_channel(channel: Channel) -> ChannelView {
let metadata = channel_metadata_for(&channel.id); let metadata = channel_metadata_for(&channel.id);
let runtime_status = current_provider_channel_status(&channel.id); let runtime_status = current_provider_channel_status(&channel.id);
let ytdlp_command = match channel.id.as_str() { let ytdlp_command = match channel.id.as_str() {
"pimpbunny" => Some("yt-dlp --compat-options allow-unsafe-ext".to_string()), "pimpbunny" => Some("yt-dlp --compat-options allow-unsafe-ext".to_string()),
// Providers declare a `ytdlpCommand`, but it is only sent to clients
// for channels where plain yt-dlp was verified to fail (TLS-fingerprint
// 403/502 that real clients hit). Widen this list one channel at a time.
id if YTDLP_COMMAND_CHANNELS.contains(&id) => channel.ytdlpCommand.clone(),
_ => None, _ => None,
}; };
ChannelView { ChannelView {
@@ -1372,6 +1381,25 @@ mod tests {
assert_eq!(groups[2].id, "jav"); assert_eq!(groups[2].id, "jav");
} }
#[test]
fn delivers_declared_ytdlp_command_only_for_allowlisted_channels() {
for id in ["freepornvideosxxx", "missav"] {
PROVIDER_RUNTIME_STATUS.remove(id);
assert_eq!(
decorate_channel(base_channel(id)).ytdlpCommand.as_deref(),
Some("yt-dlp --impersonate chrome-120"),
"{id} should deliver its declared command"
);
}
// Declares the same command but is not allowlisted.
PROVIDER_RUNTIME_STATUS.remove("hsex");
assert_eq!(decorate_channel(base_channel("hsex")).ytdlpCommand, None);
// An allowlisted id that declares nothing stays None.
let mut undeclared = base_channel("missav");
undeclared.ytdlpCommand = None;
assert_eq!(decorate_channel(undeclared).ytdlpCommand, None);
}
#[test] #[test]
fn decorates_pimpbunny_with_ytdlp_command() { fn decorates_pimpbunny_with_ytdlp_command() {
PROVIDER_RUNTIME_STATUS.remove("pimpbunny"); PROVIDER_RUNTIME_STATUS.remove("pimpbunny");