fix: A/B test 22: commandExecutorCommand for playlist continuations

This commit is contained in:
ThetaDev 2025-03-16 19:45:14 +01:00
parent fcf27aa3b2
commit e8acbfbbcf
No known key found for this signature in database
GPG key ID: E319D3C5148D65B6
12 changed files with 33753 additions and 36 deletions

View file

@ -249,11 +249,9 @@ impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::Continuation {
&mut map_res,
);
}
response::YouTubeListItem::ContinuationItemRenderer {
continuation_endpoint,
} => {
response::YouTubeListItem::ContinuationItemRenderer(ep) => {
if ctoken.is_none() {
ctoken = Some(continuation_endpoint.continuation_command.token);
ctoken = ep.continuation_endpoint.into_token();
}
}
_ => {}

View file

@ -257,6 +257,7 @@ mod tests {
#[case::nomusic("nomusic", "PL1J-6JOckZtE_P9Xx8D3b2O6w0idhuKBe")]
#[case::live("live", "UULVvqRdlKsE5Q8mf8YXbdIJLw")]
#[case::pageheader("20241011_pageheader", "PLT2w2oBf1TZKyvY_M6JsASs73m-wjLzH5")]
#[case::cmdexecutor("20250316_cmdexecutor", "PLbZIPy20-1pN7mqjckepWF78ndb6ci_qi")]
fn map_playlist_data(#[case] name: &str, #[case] id: &str) {
let json_path = path!(*TESTFILES / "playlist" / format!("playlist_{name}.json"));
let json_file = File::open(json_path).unwrap();

View file

@ -152,9 +152,16 @@ pub(crate) struct ContinuationItemRenderer {
pub continuation_endpoint: ContinuationEndpoint,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub(crate) enum ContinuationEndpoint {
ContinuationCommand(ContinuationCommandWrap),
CommandExecutorCommand(CommandExecutorCommandWrap),
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ContinuationEndpoint {
pub(crate) struct ContinuationCommandWrap {
pub continuation_command: ContinuationCommand,
}
@ -164,7 +171,34 @@ pub(crate) struct ContinuationCommand {
pub token: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CommandExecutorCommandWrap {
pub command_executor_command: CommandExecutorCommand,
}
#[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CommandExecutorCommand {
#[serde_as(as = "VecSkipError<_>")]
commands: Vec<ContinuationCommandWrap>,
}
impl ContinuationEndpoint {
pub fn into_token(self) -> Option<String> {
match self {
Self::ContinuationCommand(cmd) => Some(cmd.continuation_command.token),
Self::CommandExecutorCommand(cmd) => cmd
.command_executor_command
.commands
.into_iter()
.next()
.map(|c| c.continuation_command.token),
}
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Icon {

View file

@ -530,7 +530,9 @@ impl MusicListMapper {
MusicResponseItem::ContinuationItemRenderer {
continuation_endpoint,
} => {
self.ctoken = Some(continuation_endpoint.continuation_command.token);
if self.ctoken.is_none() {
self.ctoken = continuation_endpoint.into_token();
}
Ok(None)
}
}

View file

@ -530,15 +530,14 @@ pub(crate) enum ContinuationItemVariants {
}
impl ContinuationItemVariants {
pub fn token(self) -> String {
pub fn into_token(self) -> Option<String> {
match self {
ContinuationItemVariants::Ep {
continuation_endpoint,
} => continuation_endpoint,
ContinuationItemVariants::Btn { button } => button.button_renderer.command,
}
.continuation_command
.token
.into_token()
}
}

View file

@ -4,7 +4,7 @@ use serde_with::{
};
use time::OffsetDateTime;
use super::{ChannelBadge, ContentImage, ContinuationEndpoint, PhMetadataView, Thumbnails};
use super::{ChannelBadge, ContentImage, ContinuationItemRenderer, PhMetadataView, Thumbnails};
use crate::{
model::{Channel, ChannelItem, ChannelTag, PlaylistItem, VideoItem, YouTubeItem},
param::Language,
@ -37,12 +37,9 @@ pub(crate) enum YouTubeListItem {
LockupViewModel(LockupViewModel),
/// Continauation items are located at the end of a list
/// Continuation items are located at the end of a list
/// and contain the continuation token for progressive loading
#[serde(rename_all = "camelCase")]
ContinuationItemRenderer {
continuation_endpoint: ContinuationEndpoint,
},
ContinuationItemRenderer(ContinuationItemRenderer),
/// Corrected search query
#[serde(rename_all = "camelCase")]
@ -838,9 +835,11 @@ impl YouTubeListMapper<YouTubeItem> {
self.items.push(mapped);
}
}
YouTubeListItem::ContinuationItemRenderer {
continuation_endpoint,
} => self.ctoken = Some(continuation_endpoint.continuation_command.token),
YouTubeListItem::ContinuationItemRenderer(r) => {
if self.ctoken.is_none() {
self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query);
}
@ -886,9 +885,11 @@ impl YouTubeListMapper<VideoItem> {
self.items.push(mapped);
}
}
YouTubeListItem::ContinuationItemRenderer {
continuation_endpoint,
} => self.ctoken = Some(continuation_endpoint.continuation_command.token),
YouTubeListItem::ContinuationItemRenderer(r) => {
if self.ctoken.is_none() {
self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query);
}
@ -938,9 +939,11 @@ impl YouTubeListMapper<PlaylistItem> {
self.items.push(mapped);
}
}
YouTubeListItem::ContinuationItemRenderer {
continuation_endpoint,
} => self.ctoken = Some(continuation_endpoint.continuation_command.token),
YouTubeListItem::ContinuationItemRenderer(r) => {
if self.ctoken.is_none() {
self.ctoken = r.continuation_endpoint.into_token();
}
}
YouTubeListItem::ShowingResultsForRenderer { corrected_query } => {
self.corrected_query = Some(corrected_query);
}

View file

@ -207,11 +207,9 @@ impl MapResponse<Paginator<HistoryItem<VideoItem>>> for response::History {
&mut map_res,
);
}
response::YouTubeListItem::ContinuationItemRenderer {
continuation_endpoint,
} => {
response::YouTubeListItem::ContinuationItemRenderer(ep) => {
if ctoken.is_none() {
ctoken = Some(continuation_endpoint.continuation_command.token);
ctoken = ep.continuation_endpoint.into_token();
}
}
_ => {}

View file

@ -208,11 +208,10 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
)
});
let comment_ctoken = comment_ctoken_section.map(|s| {
let comment_ctoken = comment_ctoken_section.and_then(|s| {
s.continuation_item_renderer
.continuation_endpoint
.continuation_command
.token
.into_token()
});
let (owner, description, is_ccommons) = match secondary_info {
@ -333,7 +332,7 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
.sub_menu_items;
items
.try_swap_remove(1)
.map(|c| c.service_endpoint.continuation_command.token)
.and_then(|c| c.service_endpoint.into_token())
});
Ok(MapResult {
@ -453,7 +452,9 @@ impl MapResponse<Paginator<Comment>> for response::VideoComments {
}
}
response::video_details::CommentListItem::ContinuationItemRenderer(cont) => {
ctoken = Some(cont.token());
if ctoken.is_none() {
ctoken = cont.into_token();
}
}
response::video_details::CommentListItem::CommentsHeaderRenderer { count_text } => {
comment_count = count_text
@ -520,7 +521,9 @@ fn map_replies(
))
}
response::video_details::CommentListItem::ContinuationItemRenderer(cont) => {
reply_ctoken = Some(cont.token());
if reply_ctoken.is_none() {
reply_ctoken = cont.into_token();
}
None
}
_ => None,