App-DrivePlayer
view release on metacpan or search on metacpan
lib/App/DrivePlayer/DB.pm view on Meta::CPAN
my $existing = $self->_rs('Track')->find({ drive_id => $t{drive_id} });
if ($existing) {
# Always refresh structural fields from the Drive scan.
# Preserve metadata fields that are already populated; only fill in
# nulls from the scan's filename-derived values. This ensures that
# metadata loaded from the sheet (or set via AcoustID) is never
# silently overwritten by a re-scan.
my %update = map { $_ => _trunc($t{$_}, $_) } @STRUCTURAL_FIELDS;
for my $f (@METADATA_FIELDS) {
my $cur = $existing->get_column($f);
# Treat the drive_id placeholder as absent for the title field.
my $absent = !defined $cur || $cur eq ''
|| ($f eq 'title' && $cur eq $existing->drive_id);
$update{$f} = _trunc($t{$f}, $f) if $absent;
}
$existing->update(\%update);
} else {
$self->_rs('Track')->create({
drive_id => $t{drive_id},
title => _trunc($t{title}, 'title'),
artist => _trunc($t{artist}, 'artist'),
album => _trunc($t{album}, 'album'),
track_number => $t{track_number},
year => $t{year},
duration_ms => $t{duration_ms},
size => $t{size},
mime_type => _trunc($t{mime_type}, 'mime_type'),
modified_time => _trunc($t{modified_time}, 'modified_time'),
folder_id => $t{folder_id},
folder_path => _trunc($t{folder_path}, 'folder_path'),
genre => _trunc($t{genre}, 'genre'),
comment => _trunc($t{comment}, 'comment'),
});
}
}
sub update_track_metadata {
my ($self, $id, %fields) = @_;
my $row = $self->_rs('Track')->find($id) or return;
my %allowed = map { $_ => 1 }
qw( title artist album track_number year duration_ms genre comment );
my %update = map { $_ => $fields{$_} }
grep { $allowed{$_} } keys %fields;
$row->update(\%update) if %update;
}
# Count tracks whose $field exactly equals $value, optionally excluding one
# track id. Used to decide whether an edit should offer to propagate a
# rename to siblings (e.g. cleaning up mojibake artist/album/genre values
# without having to revisit every track).
sub count_tracks_with_field {
my ($self, $field, $value, $exclude_id) = @_;
return 0 unless defined $value && length $value;
my %where = ($field => $value);
$where{id} = { '!=' => $exclude_id } if defined $exclude_id;
return $self->_rs('Track')->search(\%where)->count;
}
# Bulk-rename: set $field = $new for every track where $field = $old.
# Returns the number of rows updated.
sub rename_field {
my ($self, $field, $old, $new) = @_;
return 0 unless defined $old && length $old;
return $self->_rs('Track')->search({ $field => $old })
->update({ $field => $new });
}
# Track ids whose $field exactly equals $value. Used to drive a targeted
# sheet sync after a bulk rename so we don't rewrite the whole spreadsheet.
sub track_ids_with_field {
my ($self, $field, $value) = @_;
return () unless defined $value && length $value;
return $self->_rs('Track')->search({ $field => $value },
{ columns => ['id'] })
->get_column('id')->all;
}
# Insert or update a track using only the metadata fields available from the
# sheet (drive_id + title/artist/album etc.). Structural fields (folder_id,
# mime_type, size, â¦) are left null or at their placeholder values so that a
# subsequent Drive scan can fill them in via upsert_track.
sub upsert_track_from_metadata {
my ($self, %fields) = @_;
$self->_rs('Track')->update_or_create(
{
drive_id => $fields{drive_id},
title => _trunc($fields{title} || $fields{drive_id}, 'title'),
mime_type => _trunc($fields{mime_type} || 'audio/', 'mime_type'),
folder_id => $fields{folder_id} // undef,
artist => _trunc($fields{artist}, 'artist'),
album => _trunc($fields{album}, 'album'),
track_number => $fields{track_number} // undef,
year => $fields{year} // undef,
duration_ms => $fields{duration_ms} // undef,
genre => _trunc($fields{genre}, 'genre'),
comment => _trunc($fields{comment}, 'comment'),
},
{ key => 'unique_drive_id' },
);
}
sub get_track {
my ($self, $id) = @_;
return _row_to_hash( $self->_rs('Track')->find($id) );
}
# Walk Track â Folder â ScanFolder and return the scan folder hashref.
# Used by targeted single-row sheet sync so it knows which tab to update.
sub scan_folder_for_track {
my ($self, $track_id) = @_;
my $track = $self->_rs('Track')->find($track_id) or return;
my $folder = $track->folder or return;
my $sf = $folder->scan_folder or return;
return _row_to_hash($sf);
}
sub get_track_by_drive_id {
my ($self, $drive_id) = @_;
return _row_to_hash(
$self->_rs('Track')->find({ drive_id => $drive_id })
( run in 1.250 second using v1.01-cache-2.11-cpan-bbb979687b5 )