diff options
Diffstat (limited to 'lib/gcstar/GCExtract/GCExtractMusics.pm')
-rw-r--r-- | lib/gcstar/GCExtract/GCExtractMusics.pm | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/lib/gcstar/GCExtract/GCExtractMusics.pm b/lib/gcstar/GCExtract/GCExtractMusics.pm new file mode 100644 index 0000000..1a56b68 --- /dev/null +++ b/lib/gcstar/GCExtract/GCExtractMusics.pm @@ -0,0 +1,370 @@ +package GCExtract::GCExtractMusics; + +################################################### +# +# Copyright 2005-2010 Christian Jodar +# +# This file is part of GCstar. +# +# GCstar is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GCstar is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCstar; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +# +################################################### + +use strict; +use GCExtract; + +use GCDialogs; +{ + package GCExtractMusicsResultsDialog; + use base 'GCModalDialog'; + + sub show + { + my $self = shift; + + $self->SUPER::show(); + $self->show_all; + my $response = $self->run; + my $idx = ($self->{results}->get_selected_indices)[0]; + $self->hide; + return -1 if $response ne 'ok'; + return $idx; + } + + sub setData + { + my ($self, @cddbData) = @_; + my @listData; + foreach(@cddbData) + { + push @listData, [$_->{genre}, $_->title, $_->artist, $_->year]; + } + @{$self->{results}->{data}} = @listData; + $self->{results}->select(0); + $self->{results}->columns_autosize; + } + + sub new + { + my ($proto, $parent, $model) = @_; + my $class = ref($proto) || $proto; + + my $self = $class->SUPER::new($parent, + $model->getDisplayedText('ResultsDialog')); + $self->{parent} = $parent; + + my $hbox = new Gtk2::HBox(0,0); + + $self->{results} = new Gtk2::SimpleList( + $model->getDisplayedText('Genre') => 'text', + $model->getDisplayedText('Title') => 'text', + $model->getDisplayedText('Artist') => 'text', + $model->getDisplayedText('Release') => 'text', + ); + + $self->{results}->set_rules_hint(1); + $self->{results}->set_headers_clickable(1); + for my $i (0..3) + { + my $column = $self->{results}->get_column($i); + $column->set_resizable(1); + $column->set_sort_column_id($i); + } + $self->{results}->signal_connect(row_activated => sub { + $self->response('ok'); + }); + + my $scrollPanelList = new Gtk2::ScrolledWindow; + $scrollPanelList->set_policy ('never', 'automatic'); + $scrollPanelList->set_shadow_type('etched-in'); + $scrollPanelList->set_border_width($GCUtils::margin); + $scrollPanelList->add($self->{results}); + + $self->vbox->pack_start($scrollPanelList,1,1,0); + + $self->set_default_size(-1,300); + return $self; + } +} + +{ + package GCExtract::GCmusicsExtracter; + use base 'GCItemExtracter'; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(@_); + bless ($self, $class); + + $self->{hasMP3Info} = $self->checkModule('MP3::Info'); + $self->{hasMP3Tag} = $self->checkModule('MP3::Tag'); + $self->{hasOggVorbisHeader} = $self->checkModule('Ogg::Vorbis::Header::PurePerl'); + $self->{hasNetFreeDB} = $self->checkModule('Net::FreeDB'); + # Even if previous check fails, we want to use it for tracks feature + $self->{errors} = 0; + + $self->{fields} = ['title', 'artist', 'release', 'genre', 'running', 'tracks']; + return $self; + } + + sub resetTracks + { + my $self = shift; + $self->{tracks} = []; + $self->{totalTime} = 0; + $self->{currentTrack} = 0; + $self->{firstTrack} = ''; + } + + sub addTrack + { + my ($self, $title, $time, $number) = @_; + $self->{currentTrack}++; + $self->{totalTime} += $time; + $number = $self->{currentTrack} if !defined $number; + push @{$self->{tracks}}, + [$number, $title, $self->secondsToString($time)]; + } + + sub getTracks + { + my $self = shift; + return $self->{tracks}; + } + + sub secondsToString + { + my ($self, $time) = @_; + return int($time / 60) .':'. sprintf '%02d', ($time %60); + } + + sub getTotalTime + { + my $self = shift; + return $self->secondsToString($self->{totalTime}); + } + + sub getM3UInfo + { + my ($self) = @_; + my $file = $self->{file}; + my $info = {}; + while (<$file>) + { + chomp; + s/\r//; + if (/^#/) + { + next if ! /^#EXTINF:(.*)/; + my @values = split /,/, $1; + $self->addTrack($values[1], $values[0]); + } + else + { + $self->{firstTrack} = $_ + if !$self->{firstTrack}; + } + } + $info->{tracks} = $self->getTracks; + $info->{running} = $self->getTotalTime; + return $info; + } + + sub getPLSInfo + { + my ($self) = @_; + my $file = $self->{file}; + my $info = {}; + my @tracks; + while (<$file>) + { + chomp; + s/\r//; + next if ! /(File|Title|Length)(\d+)=(.*)$/; + $tracks[$2]->{$1} = $3; + $tracks[$2]->{Number} = $2; + } + foreach (@tracks) + { + next if !$_->{Title}; + $self->addTrack($_->{Title}, $_->{Length}, $_->{Number}); + } + + $info->{tracks} = $self->getTracks; + $info->{running} = $self->getTotalTime; + $self->{firstTrack} = $tracks[1]->{File}; + return $info; + } + + sub getFreeDB + { + my @genres = qw(blues classical country data folk jazz newage reggae rock soundtrack misc); + my ($self) = @_; + my $file = $self->{fileName}; + my $info = {}; + return $info if ! -e $file; + return $info if ! $self->{hasNetFreeDB}; + + my $freedb = Net::FreeDB->new; + my $discdata = $freedb->getdiscdata($file); + return if !$discdata; + my $cddb_file_object; + my @results; + + foreach (@genres) + { + my $tmpCddb = $freedb->read($_, $discdata->{ID}); + if ($tmpCddb) + { + $tmpCddb->{genre} = $tmpCddb->genre || $_; + push @results, $tmpCddb; + } + } + + if ($#results == -1) + { + return; + } + elsif ($#results == 0) + { + $cddb_file_object = $results[0]; + } + else + { + my $dialog = new GCExtractMusicsResultsDialog( + $self->{parent}, + $self->{model} + ); + $dialog->setData(@results); + my $selected = $dialog->show; + $dialog->destroy; + return if $selected == -1; + $cddb_file_object = $results[$selected]; + } + + foreach my $track ($cddb_file_object->tracks) + { + $self ->addTrack($track->title,$track->length,$track->number); + } + + $info->{tracks} = $self->getTracks; + $info->{running} = $self->getTotalTime; + $info->{title} = $cddb_file_object->title; + $info->{artist} = $cddb_file_object->artist; + $info->{release} = $cddb_file_object->year; + $info->{genre} = $cddb_file_object->{genre}; + + return $info; + } + + sub addFirstTrackInfo + { + my ($self, $info) = @_; + + if ($^O =~ /win32/i) + { + $self->{firstTrack} =~ s|\\|/|g; + $self->{fileName} =~ /^(.{2})/; + my $drive = $1; + $self->{firstTrack} = $drive.$self->{firstTrack} + if $self->{firstTrack} =~ m|^/|; + } + + if ($self->{firstTrack} =~ /mp3$/i) + { + if ($self->{hasMP3Info}) + { + MP3::Info::use_mp3_utf8(1); + my $song = MP3::Info::get_mp3tag($self->{firstTrack}); + $info->{title} = $song->{ALBUM}; + $info->{artist} = $song->{ARTIST}; + $info->{release} = $song->{YEAR}; + $info->{genre} = $song->{GENRE}; + } + elsif ($self->{hasMP3Tag}) + { + my $song = MP3::Tag->new($self->{firstTrack}); + (undef, undef, $info->{artist}, $info->{title}) = $song->autoinfo; + } + } + elsif ($self->{firstTrack} =~ /ogg$/i) + { + if ($self->{hasOggVorbisHeader}) + { + my $song = Ogg::Vorbis::Header::PurePerl->new($self->{firstTrack}); + $info->{title} = ($song->comment('album'))[0]; + $info->{artist} .= $_.', ' foreach $song->comment('artist'); + $info->{artist} =~ s/, $//; + ($info->{release} = ($song->comment('date'))[0]) =~ s|^(\d{4})-(\d{2})-(\d{2}).*$|$3/$2/$1|; + $info->{genre} .= $_.', ' foreach $song->comment('genre'); + $info->{genre} =~ s/, $//; + } + } + } + + sub getInfo + { + my $self = shift; + my $info = {}; + $self->resetTracks; + + if ((!$self->{fileName}) || ($self->{fileName} =~ /\/dev\//)) + { + if (!$self->{fileName}) + { + $self->{fileName} = $self->{parent}->{options}->cdDevice; + } + $info = $self->getFreeDB; + } + else + { + + open FILE, '<'.$self->{fileName}; + binmode FILE; + + $self->{file} = \*FILE; + my $header = <FILE>; + + $info = $self->getM3UInfo + if ($self->{fileName} =~ /m3u$/) || ($header =~ /^#EXTM3U/); + $info = $self->getPLSInfo + if ($self->{fileName} =~ /pls$/) || ($header =~ /^\[playlist\]/); + close FILE; + } + + $self->addFirstTrackInfo($info); + + return if !defined $info; + my $result; + my $firstTrackName = $info->{tracks}->[0]->[1]; + $result->{tracks} = {displayed => $firstTrackName, value => $info->{tracks}}; + foreach (@{$self->{fields}}) + { + next if /^tracks$/; + $result->{$_} = {displayed => $info->{$_}, value => $info->{$_}}; + } + return $result; + } + + sub getFields + { + my $self = shift; + return $self->{fields}; + } +} + +1; |