App-DrivePlayer
view release on metacpan or search on metacpan
lib/App/DrivePlayer/GUI/MetadataFetch.pm view on Meta::CPAN
my $net_meta = eval { $fetcher->fetch(
title => $track->{title},
artist => $track->{artist},
album => $track->{album},
) };
if ($net_meta) {
$meta = $meta ? { %$net_meta, %$meta } : $net_meta;
$source = $source ? "$source + text search" : 'text search';
}
}
# 3. Fingerprint as last resort
if (!$tags_complete && !$meta && $use_fp) {
print {$writer} encode_json({
status => 'fingerprinting', n => $n, total => $total,
title => $track->{title},
}) . "\n";
$meta = eval { $fetcher->fetch_by_fingerprint(drive_id => $track->{drive_id}) };
$source = 'fingerprint' if $meta;
}
$source //= 'none';
# 4. Get duration: prefer embedded tags, then ffprobe
my $duration_ms = $meta ? delete $meta->{duration_ms} : undef;
my $dur_source;
if ($duration_ms) {
$dur_source = 'embedded tags';
} elsif (!$track->{duration_ms}
&& App::DrivePlayer::MetadataFetcher::ffprobe_available()) {
$duration_ms = eval {
App::DrivePlayer::MetadataFetcher::probe_duration_ms(
undef, $track->{drive_id}, $token,
)
};
$dur_source = 'ffprobe' if $duration_ms;
}
print {$writer} encode_json({
result => 1,
track_id => $track->{id},
track => $track,
meta => $meta,
duration_ms => $duration_ms,
source => $source,
dur_source => $dur_source,
}) . "\n";
}
print {$writer} encode_json({ done => 1 }) . "\n";
close $writer;
POSIX::_exit(0);
}
# ---- parent: reads results without blocking ----
close $writer;
$self->_meta_pid($pid);
$self->_meta_reader($reader);
$self->_meta_buf(q{});
my $updated = 0;
my $finish = sub {
if (my $wid = $self->_meta_watch_id) {
$self->_meta_watch_id(undef);
Glib::Source->remove($wid);
}
$self->_meta_pid(undef);
$self->_meta_fetch_item->set_label('Fetch All Metadata');
close $reader;
$self->_meta_reader(undef);
waitpid($pid, 0);
};
my $process_msg = sub {
my ($msg) = @_;
if ($msg->{status}) {
$self->_set_status(
"$msg->{status} $msg->{n}/$msg->{total} ($updated updated): $msg->{title}"
);
}
elsif ($msg->{result}) {
$updated += $self->_apply_meta_result($msg);
}
return;
};
my $watch_id = Glib::IO->add_watch(fileno($reader), ['in', 'hup'], sub {
my (undef, $cond) = @_;
my $chunk = q{};
my $bytes = sysread($reader, $chunk, 65536);
if (!defined $bytes || $bytes == 0) {
$finish->();
$self->_set_status("Metadata fetch done â $updated of $total updated.");
$self->_load_library();
$self->_auto_sync_to_sheet() if $updated;
return FALSE;
}
my $buf = $self->_meta_buf . $chunk;
while ($buf =~ s/\A([^\n]+)\n//) {
my $msg = eval { decode_json($1) } or next;
$process_msg->($msg);
}
$self->_meta_buf($buf);
return TRUE;
});
$self->_meta_watch_id($watch_id);
$self->_meta_fetch_item->set_label('Stop Metadata Fetch');
$self->_set_status("Fetching metadata for $total tracks in backgroundâ¦");
return;
}
sub _stop_metadata_fetch {
my ($self) = @_;
return unless $self->_meta_watch_id;
Glib::Source->remove($self->_meta_watch_id);
$self->_meta_watch_id(undef);
$self->_meta_fetch_item->set_label('Fetch All Metadata');
if (my $pid = $self->_meta_pid) {
kill 'TERM', $pid;
waitpid($pid, 0);
$self->_meta_pid(undef);
}
# Drain any result messages the child had already written before dying
if (my $reader = $self->_meta_reader) {
my $buf = $self->_meta_buf;
my $chunk = q{};
while (sysread($reader, $chunk, 65536)) {
$buf .= $chunk;
}
while ($buf =~ s/\A([^\n]+)\n//) {
my $msg = eval { decode_json($1) } or next;
next unless $msg->{result};
$self->_apply_meta_result($msg);
}
close $reader;
$self->_meta_reader(undef);
$self->_meta_buf(q{});
}
$self->_set_status('Metadata fetch stopped. Progress saved â will resume here next time.');
return;
}
sub _reset_metadata_fetch {
my ($self) = @_;
if ($self->_meta_watch_id) {
$self->_show_error('Cannot reset while a fetch is in progress.');
return;
}
$self->db->reset_metadata_fetched();
$self->_set_status('Metadata fetch progress reset â all tracks will be retried.');
return;
}
( run in 0.522 second using v1.01-cache-2.11-cpan-39bf76dae61 )