package YTMusicAPI::Parsers::Utils; use strict; use warnings; use Exporter 'import'; use YTMusicAPI::Navigation; sub parse_menu_playlists { my ( $data, $result ) = @_; my $watch_menu = find_objects_by_key( nav( $data, \@$MENU_ITEMS ), $MNIR ); foreach my $item ( map { $_->{$MNIR} } @$watch_menu ) { my $icon = nav( $item, \@$ICON_TYPE, 1 ); my $watch_key; if ( $icon eq "MUSIC_SHUFFLE" ) { $watch_key = "shuffleId"; } elsif ( $icon eq "MIX" ) { $watch_key = "radioId"; } else { next; } my $watch_id = nav( $item, [ "navigationEndpoint", "watchPlaylistEndpoint", "playlistId" ], 1 ); unless ($watch_id) { $watch_id = nav( $item, [ "navigationEndpoint", "watchEndpoint", "playlistId" ], 1 ); } if ($watch_id) { $result->{$watch_key} = $watch_id; } } } sub get_item_text { my ( $item, $index, $run_index, $none_if_absent ) = @_; $run_index //= 0; $none_if_absent //= 0; my $column = get_flex_column_item( $item, $index ); return unless $column; if ( $none_if_absent && scalar( @{ $column->{text}->{runs} } ) < $run_index + 1 ) { return; } return $column->{text}->{runs}->[$run_index]->{text}; } sub get_flex_column_item { my ( $item, $index ) = @_; if ( scalar( @{ $item->{'flexColumns'} } ) <= $index || ! exists $item->{'flexColumns'}->[$index] ->{'musicResponsiveListItemFlexColumnRenderer'}->{'text'} || ! exists $item->{'flexColumns'}->[$index] ->{'musicResponsiveListItemFlexColumnRenderer'}->{'text'}->{'runs'} ) { return undef; } return $item->{'flexColumns'}->[$index] ->{'musicResponsiveListItemFlexColumnRenderer'}; } sub get_fixed_column_item { my ( $item, $index ) = @_; if ( !exists $item->{'fixedColumns'}->[$index] ->{'musicResponsiveListItemFixedColumnRenderer'}->{'text'} || ! exists $item->{'fixedColumns'}->[$index] ->{'musicResponsiveListItemFixedColumnRenderer'}->{'text'}->{'runs'} ) { return undef; } return $item->{'fixedColumns'}->[$index] ->{'musicResponsiveListItemFixedColumnRenderer'}; } sub get_dot_separator_index { my ($runs) = @_; my $index = 0; foreach my $run (@$runs) { last if ( $run->{"text"} eq " • " ); $index++; } return $index == scalar @$runs ? $index : $index; } sub parse_duration { my ($duration) = @_; return $duration unless defined $duration; my @mapped_increments = ( [ 1, 60, 3600 ], reverse split /:/, $duration ); my $seconds = 0; while ( my ( $multiplier, $time ) = splice( @mapped_increments, 0, 2 ) ) { $seconds += $multiplier * $time; } return $seconds; } sub parse_id_name { my ($sub_run) = @_; return { "id" => nav( $sub_run, [ "navigationEndpoint", "browseEndpoint", "browseId" ], 1 ), "name" => nav( $sub_run, ["text"], 1 ), }; } our @EXPORT = qw( parse_menu_playlists get_item_text get_flex_column_item get_fixed_column_item get_dot_separator_index parse_duration parse_id_name ); 1;