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;