App-DrivePlayer
view release on metacpan or search on metacpan
lib/App/DrivePlayer/DB.pm view on Meta::CPAN
my %cond = ( metadata_fetched => 0 );
my %attr = ( order_by => \@TRACK_ORDER );
if (defined $scan_folder_id) {
$cond{'folder.scan_folder_id'} = $scan_folder_id;
$attr{join} = 'folder';
}
return map { _row_to_hash($_) }
$self->_rs('Track')->search(\%cond, \%attr)->all;
}
sub mark_metadata_fetched {
my ($self, $id) = @_;
my $row = $self->_rs('Track')->find($id) or return;
$row->update({ metadata_fetched => 1 });
}
sub reset_metadata_fetched {
my ($self) = @_;
$self->_rs('Track')->update_all({ metadata_fetched => 0 });
}
sub reset_metadata_fetched_incomplete {
my ($self) = @_;
$self->_rs('Track')->search({
metadata_fetched => 1,
-or => [
genre => undef,
genre => '',
artist => undef,
artist => '',
album => undef,
album => '',
year => undef,
],
})->update_all({ metadata_fetched => 0 });
}
sub clear_scan_folder_tracks {
my ($self, $scan_folder_id) = @_;
# Collect folder IDs, then bulk-delete tracks and folders.
# (Relies on foreign_keys=ON cascade for correctness; explicit here for speed.)
my @folder_ids = $self->_rs('Folder')
->search({ scan_folder_id => $scan_folder_id })
->get_column('id')->all;
if (@folder_ids) {
$self->_rs('Track')->search({ folder_id => \@folder_ids })->delete;
}
$self->_rs('Folder')->search({ scan_folder_id => $scan_folder_id })->delete;
}
sub count_unseen_tracks {
my ($self, $scan_folder_id, $seen) = @_;
my @keep = keys %$seen;
my @folder_ids = $self->_rs('Folder')
->search({ scan_folder_id => $scan_folder_id })
->get_column('id')->all;
return 0 unless @folder_ids;
return $self->_rs('Track')->search({
folder_id => { -in => \@folder_ids },
(@keep ? (drive_id => { -not_in => \@keep }) : ()),
})->count;
}
sub remove_unseen_tracks {
my ($self, $scan_folder_id, $seen) = @_;
my @keep = keys %$seen;
my @folder_ids = $self->_rs('Folder')
->search({ scan_folder_id => $scan_folder_id })
->get_column('id')->all;
return 0 unless @folder_ids;
return $self->_rs('Track')->search({
folder_id => { -in => \@folder_ids },
(@keep ? (drive_id => { -not_in => \@keep }) : ()),
})->delete;
}
sub remove_unseen_folders {
my ($self, $scan_folder_id, $seen) = @_;
my @keep = keys %$seen;
return $self->_rs('Folder')->search({
scan_folder_id => $scan_folder_id,
(@keep ? (drive_id => { -not_in => \@keep }) : ()),
})->delete;
}
1;
__END__
=head1 NAME
App::DrivePlayer::DB - SQLite database facade for the DrivePlayer library
=head1 SYNOPSIS
use App::DrivePlayer::DB;
my $db = App::DrivePlayer::DB->new(path => '/path/to/music.db');
# Scan-folder management
my $sf = $db->upsert_scan_folder($drive_id, 'My Music');
my @sfs = $db->all_scan_folders;
$db->delete_scan_folder($drive_id); # cascades to folders + tracks
# Track queries
my @tracks = $db->all_tracks;
my @tracks = $db->search_tracks('zeppelin');
my @tracks = $db->tracks_by_artist('Queen');
my @tracks = $db->tracks_by_album('Led Zeppelin IV');
my $track = $db->get_track_by_drive_id($drive_id);
my $track = $db->get_track($id);
my @artists = $db->all_artists;
my @albums = $db->all_albums;
my $count = $db->track_count;
=head1 DESCRIPTION
A thin L<Moo> facade over a L<App::DrivePlayer::Schema> (L<DBIx::Class>) schema.
Handles database creation on first use and exposes a simple hashref-based
API so the rest of the application never touches DBIx::Class directly.
All query methods return plain hashrefs (or lists of hashrefs), never
DBIx::Class row objects.
=head1 ATTRIBUTES
=head2 path
is: ro, isa: Str, required: 1
Filesystem path to the SQLite database file. The parent directory is
created automatically if it does not exist.
=head2 schema
is: lazy, isa: App::DrivePlayer::Schema
The underlying DBIx::Class schema object. Built automatically on first
access; the database file and tables are created at that point if needed.
=head1 METHODS
( run in 0.916 second using v1.01-cache-2.11-cpan-39bf76dae61 )