diff options
Diffstat (limited to 'lib/gcstar/GCImport/GCImportFolder.pm')
-rw-r--r-- | lib/gcstar/GCImport/GCImportFolder.pm | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/lib/gcstar/GCImport/GCImportFolder.pm b/lib/gcstar/GCImport/GCImportFolder.pm new file mode 100644 index 0000000..10d9fd1 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportFolder.pm @@ -0,0 +1,510 @@ +package GCImport::GCImportFolder; + +################################################### +# +# 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 GCImport::GCImportBase; + +{ + package GCImport::GCImporterFolder; + + use File::Find; + use File::Basename; + use base qw(GCImport::GCImportBaseClass); + + use GCPlugins; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + + bless ($self, $class); + return $self; + } + + sub wantsFieldsSelection + { + return 0; + } + + sub wantsFileSelection + { + return 1; + } + + sub wantsDirectorySelection + { + return 1; + } + + sub shouldBeHidden + { + return 1; + } + + sub getFilePatterns + { + return (); + } + + #Return supported models name + sub getModels + { + return ['GCfilms', 'GCMusics']; + } + + sub getOptions + { + my $self = shift; + + my $pluginsList; + foreach (@{$self->{model}->getPluginsNames}) + { + my $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$_}; + push @$pluginsList,$plugin->getName; + } + + + return [ + { + name => 'plugin', + type => 'options', + label => 'Plugin', + valuesList => $pluginsList + }, + { + name => 'multipleResult', + type => 'options', + label => 'MultipleResult', + tooltip => 'MultipleResultTooltip', + valuesList => 'Ask,AskEnd,AddWithoutInfo,DontAdd,TakeFirst', + default => 'Ask', + }, + { + name => 'noResult', + type => 'options', + label => 'NoResult', + tooltip => 'NoResultTooltip', + valuesList => 'AddWithoutInfo,DontAdd', # TODO AskNewName AskNewPlugin at End + default => 'AddEmpty', + }, + { + name => 'recursive', + type => 'yesno', + label => 'Recursive', + default => '1' + }, + + { + name => 'suffixes', + type => 'short text', + label => 'Suffixes', + tooltip => 'SuffixesTooltip', + default => '', + }, + + { + name => 'remove', + type => 'short text', + label => 'Remove', + tooltip => 'RemoveTooltip', + default => '', + }, + { + name => 'removeWholeWord', + type => 'yesno', + label => 'RemoveWholeWord', + tooltip => 'RemoveTooltipWholeWord', + default => '1', + }, + { + name => 'removeRegularExpr', + type => 'yesno', + label => 'RemoveRegularExpr', + tooltip => 'RemoveTooltipRegularExpr', + changedCallback => sub { + my ($self,$widget) =@_; + $widget->[0]->{options}->{removeWholeWord}->lock($self->getValue); + }, + default => '0', + }, + { + name => 'skipFileAlreadyInCollection', + type => 'options', + label => 'SkipFileAlreadyInCollection', + tooltip => 'SkipFileAlreadyInCollectionTooltip', + valuesList => 'SkipFileNo,SkipFileFullPath,SkipFileFileName,SkipFileFileNameAndUpdate', + default => 'SkipFileNo', + }, + { + name => 'infoFromFileNameRegExp', + type => 'history text', + label => 'InfoFromFileNameRegExp', + tooltip => 'InfoFromFileNameRegExpTooltip', + initValues => ['', + '^$A\s*([[\(]part $x( of $y)?[)\]])?\s*([[\(]$Y[)\]])?\s*$', + '^$N\s+[^\w ]\s+S$SE$E\s+[^\w ]\s+$T\s+([[(]part $x( of $y)?[)\]])?\s*$', + ], + default => '', + }, + ]; + + + } + + sub getModelName + { + my $self = shift; + return $self->{model}->getName; + } + + # Required by extracter to make this class acts as a panel + sub AUTOLOAD + { + return []; + } + + sub getItemsArray + { + my ($self, $directory) = @_; + my @result; + my @filesList; + + #First we try to get the correct plugin + my $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$self->{options}->{plugin}}; + $plugin->{bigPics} = $self->{options}->{parent}->{options}->bigPics; + my $titleField = $self->{model}->{commonFields}->{title}; + my $fileField = $self->{model}->{commonFields}->{play}; + + # Required by extracter + $self->{lang} = $self->{options}->{lang}; + + (my $suffixes = $self->{options}->{suffixes}) =~ s/[,; ]/\|/g; + $suffixes =~ s/\*\.//g; + # Create list of files + if ($self->{options}->{recursive}) + { + find(sub { + return if -d $File::Find::name; + return if ! /$suffixes$/; + my $name=Encode::decode_utf8($File::Find::name); + push @filesList, $name; + }, $directory); + } + else + { + foreach (glob "$directory/*") + { + next if -d $_; + next if ! /$suffixes$/; + push @filesList, $_; + } + } + my $resultsDialog; + # initialize choose good result dialog if needed + if (($self->{options}->{multipleResult} ne 'Ask') || ($self->{options}->{multipleResult} ne 'AskEnd')) + { + $resultsDialog = $self->{options}->{parent}->getDialog('Results'); + $resultsDialog->setModel($self->{model}, $self->{model}->{fieldsInfo}); + $resultsDialog->setMultipleSelection(0); + } + #Initialize stuff to retrieve info from name with regexp + my $infoFromName; + if ($self->{options}->{infoFromFileNameRegExp} ne '') + { + my %knownParam=($titleField=>'T',alphabTitle=>'A',year=>'Y',season=>'S',episode=>'E',alphabSeries=>'N',number=>'x',totNumber=>'y'); + my $orderStr= $self->{options}->{infoFromFileNameRegExp}; + $orderStr=~ s/(?<!\$).//g; + # Search the order of $A $T ... in the user regexp + my %places; + foreach my $key (keys %knownParam) { + my $i=1+index $orderStr,$knownParam{$key}; + $places{$i} = $key; + } + my $myRegExp=$self->{options}->{infoFromFileNameRegExp}; + # avoid capturing something else than $T,$A ... make already present () not capturing + $myRegExp =~ s/(?<!\\)\(/(?:/g; + my $articles='(?:'.join('|',@{$self->{model}->{parent}->{articles}}).')\'?\b'; + our $myRegExpArt=qr/^(.*?)(?:, ?($articles))?$/i; + + $myRegExp =~ s/\$A/(.*?(?:, ?$articles)?)/g; + $myRegExp =~ s/\$N/(.*?(?:, ?$articles)?)/g; + $myRegExp =~ s/\$T/(.*?)/; + $myRegExp =~ s/\$Y/(\\d{2}|\\d{4}?)/; + $myRegExp =~ s/\$x/(\\d{1,2})/; + $myRegExp =~ s/\$y/(\\d{1,2})/; + $myRegExp =~ s/\$E/(\\d{1,4}?)/; + $myRegExp =~ s/\$S/(\\d{1,2}?)/; + sub deAlpha{ + my $s; + $_[0] =~ $myRegExpArt; + $s=$1; + my $a=$2.' ' if $2 && (substr($2,-1) ne '\''); + $s=$a.$s if $a; + return $s; + } + # Check if regexp is good + my $pattern = shift; + my $test = eval { $myRegExp=qr/$myRegExp/i }; + #print $myRegExp; + # + if ($@) + { + $myRegExp= qr/./ ;print $@; + } + my $i=2; + $infoFromName=sub { + my $n=$_[0] ; + $n=~ $myRegExp; + my %info; # TODO Can be more readable in Perl 5.10 by using named capturing + $info{$places{1}}=$1 if $1;$info{$places{2}}=$2 if $2;$info{$places{3}}=$3 if $3;$info{$places{4}}=$4 if $4;$info{$places{5}}=$5 if $5; + $info{$places{6}}=$6 if $6;$info{$places{7}}=$7 if $7;$info{$places{8}}=$8 if $8;$info{$places{9}}=$9 if $9;$info{$places{10}}=$10 if $10; + $info{$places{11}}=$11 if $11;$info{$places{12}}=$12 if $12;$info{$places{13}}=$13 if $13;$info{$places{14}}=$14 if $14;$info{$places{15}}=$15 if $15; + $info{$places{16}}=$16 if $16;$info{$places{17}}=$17 if $17;$info{$places{18}}=$18 if $18;$info{$places{19}}=$19 if $19;$info{$places{20}}=$20 if $20; + + $info{$titleField}=deAlpha($info{alphabTitle}) if($info{alphabTitle}); + $info{series}=deAlpha($info{alphabSeries}) if($info{alphabSeries}); + return \%info; + } + } + # initialize regexp word to remove + my $removed =$self->{options}->{remove}; + if(!$self->{options}->{removeRegularExpr}) + { + $removed =~ s/[,; ]/\|/g; + if($self->{options}->{removeWholeWord}) + { + $removed=~s/\|/\\b\|\\b/g ; + $removed='\b'.$removed.'\b'; + } + } + # if we want to ignore files already in the list + # we initialize a hash with filenames to be fast ! + my %fileNameKnown; + if($self->{options}->{skipFileAlreadyInCollection} ne 'SkipFileNo') + { + if($self->{options}->{skipFileAlreadyInCollection} eq 'SkipFileFullPath') + { + foreach my $originalFilm(@{$self->{options}->{originalList}->{itemArray}}) + { + $fileNameKnown{$originalFilm->{$fileField}}=$originalFilm; + } + } + else + { + foreach my $originalFilm(@{$self->{options}->{originalList}->{itemArray}}) + { + $fileNameKnown{basename($originalFilm->{$fileField})}=$originalFilm; + } + } + } + my $hasFileWaiting=0;my $inWaitingQueue=0; + # Main loop on files entries + file: foreach my $file(@filesList) + { + if($file eq 'WaitingList') + { + $inWaitingQueue=1; + next file; + } + # Skip file already in the collection + next file if(($self->{options}->{skipFileAlreadyInCollection} eq 'SkipFileFullPath') && (exists $fileNameKnown{$file})); + next file if(($self->{options}->{skipFileAlreadyInCollection} eq 'SkipFileFileName') && (exists $fileNameKnown{basename($file)})); + if(($self->{options}->{skipFileAlreadyInCollection} eq 'SkipFileFileNameAndUpdate') && (exists $fileNameKnown{basename($file)})) + { + # if filename already in collection, and collection full path invalid : correct it + if (!(-e $fileNameKnown{basename($file)}->{$fileField})) + { + print "Path updated : ",$fileNameKnown{basename($file)}->{$fileField},"\n"; + print " --> ",$file,"\n"; + $fileNameKnown{basename($file)}->{$fileField}=$file; + } + next file; + } + + # Get info from the file (avi, mp3, ...) + my $extracter = $self->{model}->getExtracter($self, $file, $self, $self->{model}); + my $extracted = $extracter->getInfo; + # Add info from file + my $infoFromFile={$fileField => $file}; + foreach my $field(keys %$extracted) + { + $infoFromFile->{$field} = $extracted->{$field}->{value}; + } + + # Test if subtitle is present + if ($self->{model}->getName eq 'GCfilms') + { + my @subtitlesExt=qw(sub srt); + my @subtitlesFiles; + my $startFileName=$file; + $startFileName=~s/\.[^.]*$//; + for my $ext(@subtitlesExt) + { + my $fileSubsName=$startFileName.'.'.$ext; + if(-e $fileSubsName) + { + #TODO Try to guess the language see cpan + my $lang=["Yes"]; + push @subtitlesFiles,$lang; + } + } + $infoFromFile->{subt}=\@subtitlesFiles if (@subtitlesFiles); + } + my $infoFromFileName; + my $name = basename($file); + # Filter the name + # Remove suffix + $name =~ s/\.[^.]*$//; + # Try to apply regexp on filename + if ($self->{options}->{infoFromFileNameRegExp} ne '') + { + $infoFromFileName=&$infoFromName($name); + $name = $infoFromFileName->{$titleField} if ($infoFromFileName->{$titleField} ne ''); + #TODO: Use this known info to search with plugin + } + # Remove everything between () {} [] + $name =~ s/[\(\[\{].*?[\)\]\}]/ /g; + # Remove special characters + $name =~ s/[-\._,#@"']/ /g; + #'" + # Remove info from extracter for movies + if ($self->{model}->getName eq 'GCfilms') + { + my $info = $extracted->{video}->{value}.'|'.$extracted->{audio}->{value}->[0]->[1]; + $info =~ s/ (.*?)//g; + $name =~ s/$info//g; + } + $name =~ s/$removed//gi; + + # $name contains the title to search + $plugin->{title} = $name; + $plugin->{type} = 'load'; + $plugin->{urlField} = $self->{model}->{commonFields}->{url}; + $plugin->{searchField} = $titleField; + + #Initialize what will be pushed in the array + my $infoPlugin = {$titleField => $name}; + + $self->{options}->{parent}->setWaitCursor($self->{options}->{lang}->{StatusSearch}.' ('.$name.')'); + $plugin->load; + + my $itemNumber = $plugin->getItemsNumber; + + if ($itemNumber == 0) + { + goto endPluginGetItemInfo if (($self->{options}->{noResult} eq 'AddEmpty')); + next file if (($self->{options}->{noResult} eq 'DontAdd')); + } + else + { + $plugin->{type} = 'info'; + if (($itemNumber == 1) || ($self->{options}->{multipleResult} eq 'TakeFirst')) + { + $plugin->{wantedIdx} = 0; + } + elsif($self->{options}->{multipleResult} eq 'AddWithoutInfo' ) + { + goto endPluginGetItemInfo; + } + elsif($self->{options}->{multipleResult} eq 'DontAdd' ) + { + next file; + } + elsif($self->{options}->{multipleResult} eq 'AskEnd' && !$inWaitingQueue) + { + # re push the filename at the end of the list, to be proceded + push @filesList,'WaitingList' if !$hasFileWaiting; + push @filesList,$file; + $hasFileWaiting=1; + next file; + } + else + { + # Ask the user to choose + my $withNext = 0; + my @items = $plugin->getItems; + $resultsDialog->setWithNext(0); + $resultsDialog->setSearchPlugin($plugin); + $resultsDialog->setList($name, @items); + $resultsDialog->show; + if ($resultsDialog->{validated}) + { + $plugin->{wantedIdx} = $resultsDialog->getItemsIndexes->[0]; + } + } + $infoPlugin = $plugin->getItemInfo; + my $title = $infoPlugin->{$titleField}; + $self->{options}->{parent}->{defaultPictureSuffix} = $plugin->getDefaultPictureSuffix; + foreach my $field(@{$self->{model}->{managedImages}}) + { + $infoPlugin->{$field} = '' if $infoPlugin->{$field} eq 'empty'; + next if !$infoPlugin->{$field}; + ($infoPlugin->{$field}) = $self->{options}->{parent}->downloadPicture($infoPlugin->{$field}, $title); + } + $infoPlugin->{plugin} =$plugin->getName(); + $infoPlugin->{comment} = $self->getLang->{CommentAuto} + . "\n" + . $self->getLang->{CommentSite} + . $plugin->getName() + . "\n" + . $self->getLang->{CommentTitle} + . $name + . "\n" + . $extracted->{comment}->{displayed}; + } + endPluginGetItemInfo: + + # Add the default value + my $defaultInfo = $self->{model}->getDefaultValues; + + my $info; + # TODO : ask the user for order, or even for order on each fields + my @order=($defaultInfo,$infoFromFile,$infoFromFileName,$infoPlugin); + for my $infoSource(@order) + { + foreach my $field(keys %$infoSource) + { + $info->{$field} =$infoSource->{$field} if $infoSource->{$field}; + } + } + push @result, $info; + $self->{options}->{parent}->restoreCursor; + } + return \@result; + } + + + sub getEndInfo + { + my $self = shift; + my $message; + + return $message; + } +} + +1; |