App-DrivePlayer
view release on metacpan or search on metacpan
lib/App/DrivePlayer/Scanner.pm view on Meta::CPAN
$self->_seen_folder_ids->{$drive_id} = 1;
my $folder = $self->db->upsert_folder(
drive_id => $drive_id,
name => $folder_name,
parent_drive_id => $args{parent_drive_id},
path => $path,
scan_folder_id => $scan_folder_id,
);
my @items = eval {
$self->drive->list(
filter => "'$drive_id' in parents and trashed=false",
params => { fields => $DRIVE_FIELDS, pageSize => 1000 },
);
};
if ($@) {
$self->_progress("Error scanning $path: $@");
return;
}
# Normalize Drive response bytes to decoded Unicode so SQLite doesn't
# re-encode them as Latin-1 â UTF-8 (double-encoding).
$_->{name} = _u8($_->{name}) for @items;
my (@subfolders, @audio_files);
for my $item (@items) {
if ($item->{mimeType} eq $FOLDER_MIME) {
push @subfolders, $item;
} elsif ($item->{mimeType} =~ m{^audio/}i) {
push @audio_files, $item;
}
}
for my $file (@audio_files) {
return if $self->_stop;
$self->_store_track($file, $folder, $path);
}
for my $subfolder (@subfolders) {
return if $self->_stop;
$self->_scan_dir(
folder_drive_id => $subfolder->{id},
folder_name => $subfolder->{name},
parent_drive_id => $drive_id,
path => "$path/$subfolder->{name}",
scan_folder_id => $scan_folder_id,
);
}
}
sub _store_track {
my ($self, $file, $folder, $folder_path) = @_;
$self->_seen_track_ids->{$file->{id}} = 1;
my ($title, $artist, $album, $track_num, $year) = _parse_filename($file->{name});
# Infer artist/album from folder path depth: Root/Artist/Album/track
my @parts = split m{/}, $folder_path;
if (!$artist && @parts >= 3) {
$artist = $parts[-2];
$album = $parts[-1];
} elsif (!$album && @parts >= 2) {
$album = $parts[-1];
}
# "YYYY-AlbumName" folder convention: strip the year prefix and use the
# captured year as the track's year when one wasn't parsed from the file.
if ($album && $album =~ s{
^
( (?: 19 | 20) \d{2} ) # 4-digit year, 19xx or 20xx
-
}{}x) {
$year //= $1;
}
my $duration_ms;
if (my $meta = $file->{videoMediaMetadata}) {
$duration_ms = $meta->{durationMillis};
}
my %track = (
drive_id => $file->{id},
title => $title,
artist => $artist,
album => $album,
track_number => $track_num,
year => $year,
duration_ms => $duration_ms,
size => $file->{size},
mime_type => $file->{mimeType},
modified_time => $file->{modifiedTime},
folder_id => $folder->{id},
folder_path => $folder_path,
);
$self->db->upsert_track(%track);
$self->on_track_found->(\%track) if $self->has_on_track_found;
}
# Parse filename into (title, artist, album, track_number, year).
# Handles: "NN - Artist - Title", "Artist - Title", "NN - Title", "Title"
sub _parse_filename {
my ($filename) = @_;
(my $base = $filename) =~ s/\.[^.]+$//;
my ($title, $artist, $album, $track_num, $year);
# "YYYY-..." prefix: capture the year and strip it before running the
# track-number patterns below (otherwise 2001 would match \d+ as track#).
if ($base =~ s{
^
( (?: 19 | 20) \d{2} ) # 4-digit year, 19xx or 20xx
-
}{}x) {
$year = $1;
}
if ($base =~ /^(\d+)[\s.\-]+(.+?)\s+[-â]\s+(.+)$/) {
( run in 1.487 second using v1.01-cache-2.11-cpan-71847e10f99 )