Initial commit
This commit is contained in:
177
YTMusicAPI/Mixins/SearchMixin.pm
Normal file
177
YTMusicAPI/Mixins/SearchMixin.pm
Normal file
@@ -0,0 +1,177 @@
|
||||
package YTMusicAPI::Mixins::SearchMixin;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Moose::Role;
|
||||
use Data::Dumper;
|
||||
|
||||
use YTMusicAPI::Helpers;
|
||||
use YTMusicAPI::Navigation;
|
||||
use YTMusicAPI::Parsers::Search;
|
||||
|
||||
sub search {
|
||||
my ( $self, $query, $filter, $scope, $limit, $ignore_spelling ) = @_;
|
||||
$filter //= undef;
|
||||
$scope //= undef;
|
||||
$limit //= 20;
|
||||
$ignore_spelling //= 0;
|
||||
|
||||
my $body = { 'query' => $query };
|
||||
my $endpoint = "search";
|
||||
my $search_results = [];
|
||||
my $filters = [
|
||||
"albums", "artists",
|
||||
"playlists", "community_playlists",
|
||||
"featured_playlists", "songs",
|
||||
"videos", "profiles",
|
||||
"podcasts", "episodes",
|
||||
];
|
||||
|
||||
if ( $filter and !grep { $_ eq $filter } @$filters ) {
|
||||
die "Invalid filter provided. "
|
||||
. "Please use one of the following filters or leave out the parameter: "
|
||||
. join( ", ", @$filters );
|
||||
}
|
||||
|
||||
my $scopes = [ "library", "uploads" ];
|
||||
if ( $scope and !grep { $_ eq $scope } @$scopes ) {
|
||||
die "Invalid scope provided. "
|
||||
. "Please use one of the following scopes or leave out the parameter: "
|
||||
. join( ", ", @$scopes );
|
||||
}
|
||||
|
||||
if ( $scope and $scope eq @$scopes[1] and $filter ) {
|
||||
die "No filter can be set when searching uploads. "
|
||||
. "Please unset the filter parameter when scope is set to uploads.";
|
||||
}
|
||||
|
||||
if ( $scope
|
||||
and $scope eq @$scopes[0]
|
||||
and grep { $_ eq $filter } @$filters[ 3 .. 4 ] )
|
||||
{
|
||||
die "$filter cannot be set when searching library. "
|
||||
. "Please use one of the following filters or leave out the parameter: "
|
||||
. join( ", ", ( @$filters[ 0 .. 2 ], @$filters[ 5 .. $#$filters ] ) );
|
||||
}
|
||||
|
||||
my $params = get_search_params( $filter, $scope, $ignore_spelling );
|
||||
if ($params) {
|
||||
$body->{"params"} = $params;
|
||||
}
|
||||
|
||||
my $response = $self->_send_request( $endpoint, $body );
|
||||
|
||||
if ( !exists $response->{"contents"} ) {
|
||||
return $search_results;
|
||||
}
|
||||
|
||||
my $results;
|
||||
|
||||
if ( exists $response->{"contents"}{"tabbedSearchResultsRenderer"} ) {
|
||||
my $tab_index =
|
||||
!( $scope or $filter ) ? 0 : array_index( $scopes, $scope ) + 1;
|
||||
$results =
|
||||
$response->{"contents"}{"tabbedSearchResultsRenderer"}{"tabs"}
|
||||
[$tab_index]{"tabRenderer"}{"content"};
|
||||
}
|
||||
else {
|
||||
$results = $response->{"contents"};
|
||||
}
|
||||
|
||||
$results = nav( $results, $SECTION_LIST );
|
||||
|
||||
if ( scalar @{$results} == 1
|
||||
and exists $results->[0]->{"itemSectionRenderer"} )
|
||||
{
|
||||
return $search_results;
|
||||
}
|
||||
|
||||
if ( $filter and index( $filter, "playlists" ) != -1 ) {
|
||||
$filter = "playlists";
|
||||
}
|
||||
elsif ( $scope and $scope == $scopes->[1] ) {
|
||||
$filter = $scopes->[1];
|
||||
}
|
||||
|
||||
foreach my $res ( @{$results} ) {
|
||||
my $category = undef;
|
||||
my $type = undef;
|
||||
if ( exists $res->{"musicCardShelfRenderer"} ) {
|
||||
my $top_result = parse_top_result( $res->{"musicCardShelfRenderer"},
|
||||
$self->{parser}->get_search_result_types() );
|
||||
push( @$search_results, $top_result );
|
||||
if ( $results =
|
||||
nav( $res, [ "musicCardShelfRenderer", "contents" ], 1 ) )
|
||||
{
|
||||
# category "more from youtube" is missing sometimes
|
||||
if ( exists $results->[0]->{"messageRenderer"} ) {
|
||||
$category = nav( shift(@$results),
|
||||
[ "messageRenderer", @$TEXT_RUN_TEXT ] );
|
||||
}
|
||||
}
|
||||
else {
|
||||
next;
|
||||
}
|
||||
}
|
||||
elsif ( exists $res->{"musicShelfRenderer"} ) {
|
||||
$results = $res->{"musicShelfRenderer"}{"contents"};
|
||||
my $type_filter = $filter;
|
||||
$category = nav( $res, [ @$MUSIC_SHELF, @$TITLE_TEXT ], 1 );
|
||||
if ( !$type_filter and $scope and $scope eq $scopes->[0] ) {
|
||||
$type_filter = $category;
|
||||
}
|
||||
$type = substr( $type_filter, 0, -1 ) if $type_filter;
|
||||
$type = lc($type) if $type;
|
||||
}
|
||||
else {
|
||||
next;
|
||||
}
|
||||
my $search_result_types = $self->{parser}->get_search_result_types();
|
||||
push(
|
||||
@$search_results,
|
||||
parse_search_results(
|
||||
$results, $search_result_types, $type, $category
|
||||
)
|
||||
);
|
||||
if ($filter) { # if filter is set, there are continuations
|
||||
my $request_func = sub {
|
||||
my ($additionalParams) = @_;
|
||||
return $self->_send_request( $endpoint, $body,
|
||||
$additionalParams );
|
||||
};
|
||||
my $parse_func = sub {
|
||||
my ($contents) = @_;
|
||||
return parse_search_results( $contents, $search_result_types,
|
||||
$type, $category );
|
||||
};
|
||||
push(
|
||||
@$search_results,
|
||||
get_continuations(
|
||||
$res->{"musicShelfRenderer"},
|
||||
"musicShelfContinuation",
|
||||
$limit - scalar(@$search_results),
|
||||
$request_func,
|
||||
$parse_func
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $search_results;
|
||||
}
|
||||
|
||||
sub get_search_suggestions {
|
||||
my ( $self, $query, $detailed_runs ) = @_;
|
||||
|
||||
$detailed_runs //= 0;
|
||||
|
||||
my %body = ( "input" => $query );
|
||||
my $endpoint = "music/get_search_suggestions";
|
||||
my $response = $self->_send_request( $endpoint, %body );
|
||||
my $search_suggestions =
|
||||
parse_search_suggestions( $response, $detailed_runs );
|
||||
return $search_suggestions;
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user