171 lines
4.7 KiB
Perl
171 lines
4.7 KiB
Perl
package YTMusicAPI::Continuations;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Exporter 'import';
|
|
|
|
use YTMusicAPI::Navigation;
|
|
|
|
sub get_continuations {
|
|
my ( $results, $continuation_type, $limit, $request_func, $parse_func,
|
|
$ctoken_path, $reloadable )
|
|
= @_;
|
|
$ctoken_path //= "";
|
|
$reloadable //= 0;
|
|
|
|
my @items = ();
|
|
while ( exists $results->{"continuations"}
|
|
&& ( !defined $limit || scalar(@items) < $limit ) )
|
|
{
|
|
my $additionalParams =
|
|
$reloadable
|
|
? get_reloadable_continuation_params($results)
|
|
: get_continuation_params( $results, $ctoken_path );
|
|
|
|
my $response = $request_func->($additionalParams);
|
|
if ( exists $response->{"continuationContents"} ) {
|
|
$results =
|
|
$response->{"continuationContents"}->{$continuation_type};
|
|
}
|
|
else {
|
|
last;
|
|
}
|
|
|
|
my $contents = get_continuation_contents( $results, $parse_func );
|
|
last if scalar(@$contents) == 0;
|
|
push( @items, @$contents );
|
|
}
|
|
|
|
return \@items;
|
|
}
|
|
|
|
sub get_validated_continuations {
|
|
my ( $results, $continuation_type, $limit, $per_page, $request_func,
|
|
$parse_func, $ctoken_path )
|
|
= @_;
|
|
$ctoken_path //= "";
|
|
|
|
my @items = ();
|
|
while ( exists $results->{"continuations"} && scalar(@items) < $limit ) {
|
|
my $additionalParams =
|
|
get_continuation_params( $results, $ctoken_path );
|
|
|
|
my $wrapped_parse_func = sub {
|
|
my $raw_response = shift;
|
|
return get_parsed_continuation_items( $raw_response, $parse_func,
|
|
$continuation_type );
|
|
};
|
|
|
|
my $validate_func = sub {
|
|
my $parsed = shift;
|
|
return validate_response( $parsed, $per_page, $limit,
|
|
scalar(@items) );
|
|
};
|
|
|
|
my $response =
|
|
resend_request_until_parsed_response_is_valid( $request_func,
|
|
$additionalParams, $wrapped_parse_func, $validate_func, 3 );
|
|
$results = $response->{"results"};
|
|
push( @items, @{ $response->{"parsed"} } );
|
|
}
|
|
|
|
return \@items;
|
|
}
|
|
|
|
sub get_parsed_continuation_items {
|
|
my ( $response, $parse_func, $continuation_type ) = @_;
|
|
my $results = $response->{"continuationContents"}->{$continuation_type};
|
|
return {
|
|
"results" => $results,
|
|
"parsed" => get_continuation_contents( $results, $parse_func )
|
|
};
|
|
}
|
|
|
|
sub get_continuation_params {
|
|
my ( $results, $ctoken_path ) = @_;
|
|
$ctoken_path //= "";
|
|
my $ctoken = nav(
|
|
$results,
|
|
[
|
|
"continuations", 0,
|
|
"next" . $ctoken_path . "ContinuationData", "continuation"
|
|
]
|
|
);
|
|
return get_continuation_string($ctoken);
|
|
}
|
|
|
|
sub get_reloadable_continuation_params {
|
|
my ($results) = @_;
|
|
my $ctoken = nav( $results,
|
|
[ "continuations", 0, "reloadContinuationData", "continuation" ] );
|
|
return get_continuation_string($ctoken);
|
|
}
|
|
|
|
sub get_continuation_string {
|
|
my ($ctoken) = @_;
|
|
return "&ctoken=" . $ctoken . "&continuation=" . $ctoken;
|
|
}
|
|
|
|
sub get_continuation_contents {
|
|
my ( $continuation, $parse_func ) = @_;
|
|
foreach my $term ( "contents", "items" ) {
|
|
if ( exists $continuation->{$term} ) {
|
|
return $parse_func->( $continuation->{$term} );
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
|
|
sub resend_request_until_parsed_response_is_valid {
|
|
my ( $request_func, $request_additional_params, $parse_func,
|
|
$validate_func, $max_retries )
|
|
= @_;
|
|
|
|
my $response = $request_func->($request_additional_params);
|
|
my $parsed_object = $parse_func->($response);
|
|
my $retry_counter = 0;
|
|
|
|
while ( !$validate_func->($parsed_object) && $retry_counter < $max_retries )
|
|
{
|
|
$response = $request_func->($request_additional_params);
|
|
my $attempt = $parse_func->($response);
|
|
|
|
if (
|
|
scalar( @{ $attempt->{"parsed"} } ) >
|
|
scalar( @{ $parsed_object->{"parsed"} } ) )
|
|
{
|
|
$parsed_object = $attempt;
|
|
}
|
|
|
|
$retry_counter++;
|
|
}
|
|
|
|
return $parsed_object;
|
|
}
|
|
|
|
sub validate_response {
|
|
my ( $response, $per_page, $limit, $current_count ) = @_;
|
|
|
|
my $remaining_items_count = $limit - $current_count;
|
|
my $expected_items_count =
|
|
$per_page < $remaining_items_count ? $per_page : $remaining_items_count;
|
|
|
|
# response is invalid, if it has less items than the minimal expected count
|
|
return scalar( @{ $response->{"parsed"} } ) >= $expected_items_count;
|
|
}
|
|
|
|
our @EXPORT = qw(
|
|
get_continuations
|
|
get_validated_continuations
|
|
get_parsed_continuation_items
|
|
get_continuation_params
|
|
get_reloadable_continuation_params
|
|
get_continuation_string
|
|
get_continuation_contents
|
|
resend_request_until_parsed_response_is_valid
|
|
validate_response
|
|
);
|
|
|
|
1;
|