########################################################################### # # jSongMinerExtractor - helper plugin that identifies audio through # external web services based on either an audio # computed fingerprint or ID3 title and album # # A component of the Greenstone digital library software # from the New Zealand Digital Library Project at the # University of Waikato, New Zealand. # # Copyright (C) 2010 New Zealand Digital Library Project # # This program 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. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ########################################################################### package jSongMinerExtractor; use BaseMediaConverter; use Cwd; use URI::Escape; use strict; no strict 'refs'; # allow filehandles to be variables and viceversa BEGIN { @jSongMinerExtractor::ISA = ('BaseMediaConverter'); } my $arguments = [ { 'name' => "track_identification", 'desc' => "{jSongMinerExtractor.track_identification}", 'type' => "enum", 'list' => [{'name' => "Fingerprint then ID3 tags", 'desc' => "{jSongMinerExtractor.fingerprint_first}"}, {'name' => "ID3 tags only", 'desc' => "{jSongMinerExtractor.only_ids}"}, {'name' => "Disabled", 'desc' => "{jSongMinerExtractor.off}"} ], 'deft' => 'Fingerprint then ID3 tags', 'reqd' => "no" } ]; my $options = { 'name' => "jSongMinerExtractor", 'desc' => "{jSongMinerExtractor.desc}", 'abstract' => "yes", 'inherits' => "yes", 'args' => $arguments }; sub new { my ($class) = shift (@_); my ($pluginlist,$inputargs,$hashArgOptLists) = @_; push(@$pluginlist, $class); push(@{$hashArgOptLists->{"ArgList"}},@{$arguments}); push(@{$hashArgOptLists->{"OptList"}},$options); my $self = new BaseMediaConverter($pluginlist, $inputargs, $hashArgOptLists, 1); # Set controlling variables my $gsdl_home = $ENV{'GSDLHOME'}; my $music_ir_home = $ENV{'GEXT_MUSICIR'}; $self->{'jmir_directory'} = &util::filename_cat($music_ir_home,"lib","java"); # Set the directory holding the jMIR .jar files return bless $self, $class; } sub urlEncode{ # ARG 1: $to_encode is the string to URL encode my ($to_encode) = @_; return uri_escape($to_encode); } # URL Decode the given string sub urlDecode{ # ARG 1: $to_decode is the string to URL decode my ($to_decode) = @_; my $decoded= uri_unescape($to_decode); return $decoded; } sub parse_txt_metadata { my $self = shift @_; my ($doc_obj,$target_txt_file_path) = @_; if (open(MIN,"<$target_txt_file_path")) { my ($md_name, $md_value); while (defined($md_name=) && defined($md_value=)) { chomp $md_name; chomp $md_value; my $top_section=$doc_obj->get_top_section(); $md_name =~ s/\+//g; $md_value =~ s/\+/ /g; $md_name = urlDecode($md_name); $md_value = urlDecode($md_value); # $md_name =~ s/\s+/ /sg; $md_name =~ s/\(.*?\)$//s; # can stretch over multiple lines $md_name =~ s/Last\.FM/LastFM/g; $md_name =~ s/:/^/g; $md_name =~ s/(API)?\^/./; $doc_obj->add_utf8_metadata($top_section,$md_name,$md_value); } close(MIN); } else { print STDERR "Error: Failed to open $target_txt_file_path\n"; print STDERR " !$\n"; } } sub retrieve_metadata { my $self = shift(@_); my ($source_file_path,$id3_title,$id3_artist,$convert_options) = @_; $convert_options = "" if (!defined $convert_options); my $outhandle = $self->{'outhandle'}; my $verbosity = $self->{'verbosity'}; my $source_file_no_path = &File::Basename::basename($source_file_path); $self->init_cache_for_file($source_file_path); my $target_txt_file_path; my $target_acexml_file_path; if ($self->{'enable_cache'}) { my $cached_dir = $self->{'cached_dir'}; my $file_root = $self->{'cached_file_root'}; my $target_txt_file = "${file_root}_metadata.txt"; my $target_acexml_file = "${file_root}.xml"; $target_txt_file_path = &util::filename_cat($cached_dir,$target_txt_file); $target_acexml_file_path = &util::filename_cat($cached_dir,$target_acexml_file); } else { $target_txt_file_path = &util::get_tmp_filename("_metadata.txt"); $target_acexml_file_path = &util::get_tmp_filename(".xml"); } my $jmir_directory = $self->{'jmir_directory'}; my $store_cwd = cwd(); if (!-d $jmir_directory) { print STDERR "Error: Unable able to find directory '$jmir_directory'\n"; print STDERR " Cannot run jAudio\n"; } elsif (chdir($jmir_directory)) { my $source_file_path_os = $source_file_path; if ($^O eq "cygwin") { $source_file_path_os = `cygpath -w "$source_file_path"`; $source_file_path_os =~ s/\s+$//; } my $target_txt_file_path_os = $target_txt_file_path; if ($^O eq "cygwin") { $target_txt_file_path_os = `cygpath -w "$target_txt_file_path"`; $target_txt_file_path_os =~ s/\s+$//; } my $target_acexml_file_path_os = $target_acexml_file_path; if ($^O eq "cygwin") { $target_acexml_file_path_os = `cygpath -w "$target_acexml_file_path"`; $target_acexml_file_path_os =~ s/\s+$//; } my $jsongminer_cmd = "java -Xmx1024M -jar jSongMiner.jar $convert_options"; $jsongminer_cmd .= " -title \"$id3_title\"" if defined $id3_title; $jsongminer_cmd .= " -artist \"$id3_artist\"" if defined $id3_artist; $jsongminer_cmd .= " -audio \"$source_file_path_os\""; $jsongminer_cmd .= " -savetxtfile \"$target_txt_file_path_os\""; $jsongminer_cmd .= " -saveacexmlfile \"$target_acexml_file_path_os\""; if ($verbosity>2) { print $outhandle "jSongMinerExtractor: Running ...\n"; print $outhandle "jSongMinerExtractor: $jsongminer_cmd\n"; } my $print_info = { 'message_prefix' => "jSongMiner", 'message' => "jSongMinerExtractor: Retrieving audio metadata for $source_file_no_path" }; my ($regenerated,$result,$had_error) = $self->autorun_general_cmd($jsongminer_cmd,$source_file_path,$target_txt_file_path,$print_info); if ($verbosity>2) { print $outhandle "jSongMinerExtractor: ...done\n"; } } else { print STDERR "Error: failed to change directory to '$jmir_directory'\n"; print STDERR " Cannot run jAudio\n"; } chdir($store_cwd); return ($target_acexml_file_path,$target_txt_file_path); } 1;