App-DrivePlayer

 view release on metacpan or  search on metacpan

lib/App/DrivePlayer/GUI.pm  view on Meta::CPAN


sub _play_at_path {
    my ($self, $path, %opts) = @_;
    my $track = $self->_track_at_path($path) or return;
    return unless $self->_init_api();

    eval { $self->player->play($track) };
    if ($@) {
        $self->_show_error("Playback error: $@");
        return;
    }

    $self->_playing_track_id($track->{id});
    $self->_playing_row_ref(Gtk3::TreeRowReference->new($self->track_store, $path));
    $self->_update_now_playing($track);
    $self->_highlight_path($path) unless $opts{no_scroll};
}

sub _toggle_play {
    my ($self) = @_;
    if (!$self->player || $self->player->state eq 'stop') {
        my $sel = $self->track_view->get_selection();
        my (undef, @paths) = $sel->get_selected_rows();
        my $path = @paths ? $paths[0] : Gtk3::TreePath->new_from_indices(0);
        $self->_play_at_path($path);
    } else {
        return unless $self->_init_api();
        $self->player->pause_resume();
    }
}

sub _stop {
    my ($self) = @_;
    return unless $self->player;
    $self->player->stop();
    $self->progress->set_value(0);
    $self->time_label->set_text('0:00');
    $self->now_playing_label->set_text('Not playing');
}

sub _next_track {
    my ($self) = @_;
    my $path = $self->_current_path();
    if ($path) {
        my $iter = $self->track_store->get_iter($path);
        return unless $iter && $self->track_store->iter_next($iter);
        $self->_play_at_path($self->track_store->get_path($iter));
    } else {
        $self->_play_at_path(Gtk3::TreePath->new_from_indices(0))
            if @{ $self->_playlist };
    }
}

sub _prev_track {
    my ($self) = @_;
    my $path = $self->_current_path() or return;
    return unless $path->prev();
    $self->_play_at_path($path);
}

# ---- Player callbacks ----

sub _on_track_end {
    my ($self) = @_;
    $self->_next_track();
}

sub _on_position {
    my ($self, $pos, $dur) = @_;
    return if $self->_progress_dragging;
    $self->progress->set_range(0, $dur) if $dur;
    $self->progress->set_value($pos)    if defined $pos;
    $self->time_label->set_text(_sec_str($pos));
    $self->dur_label->set_text(_sec_str($dur));

    # Persist duration when mpv reports it for a track that doesn't have one yet.
    if ($dur && $dur > 0) {
        my $id    = $self->_playing_track_id;
        my $track = $id ? $self->_track_by_id->{$id} : undef;
        if ($track && !$track->{duration_ms}) {
            my $ms = int($dur * 1000);
            $track->{duration_ms} = $ms;   # mutate to prevent firing again
            $self->db->update_track_metadata($track->{id}, duration_ms => $ms);
            $self->_refresh_track_row($track->{id});
        }
    }
}

sub _on_state_change {
    my ($self, $state) = @_;
    my $icon = $state eq 'play' ? 'media-playback-pause' : 'media-playback-start';
    $self->play_btn->set_image(Gtk3::Image->new_from_icon_name($icon, 'button'));
    if ($state eq 'stop') {
        $self->stop_btn->hide();
    } else {
        $self->stop_btn->show();
    }
}

sub _player_poll {
    my ($self) = @_;
    if ($self->player) {
        eval { $self->player->poll() };
        $log->warn("Player poll error: $@") if $@ && $log;
    }
}

# ---- Sidebar activation ----

sub _sidebar_activated {
    my ($self, $view) = @_;
    return if $self->_suppress_sidebar_activated;
    my ($path) = $view->get_cursor();
    return unless $path;
    my $store = $self->sidebar_store;
    my $iter  = $store->get_iter($path);
    my $type  = $store->get($iter, 1);
    my $value = $store->get($iter, 2);
    my $label = $store->get($iter, 0);

    # Resolve the alpha-nav category for the current selection. Leaf rows look



( run in 1.395 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )