diff options
Diffstat (limited to 'lib/gcstar/GCImport')
-rw-r--r-- | lib/gcstar/GCImport/GCImportAMC.pm | 234 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportAlexandria.pm | 205 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportBase.pm | 217 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportCSV.pm | 313 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportDVDProfiler.pm | 192 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportFolder.pm | 510 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportGCfilms.pm | 190 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportGCstar.pm | 106 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportList.pm | 202 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportMyMovies.pm | 211 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportScanner.pm | 394 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportTarGz.pm | 152 | ||||
-rw-r--r-- | lib/gcstar/GCImport/GCImportTellico.pm | 496 |
13 files changed, 3422 insertions, 0 deletions
diff --git a/lib/gcstar/GCImport/GCImportAMC.pm b/lib/gcstar/GCImport/GCImportAMC.pm new file mode 100644 index 0000000..c5d38c9 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportAMC.pm @@ -0,0 +1,234 @@ +package GCImport::GCImportAMC; + +################################################### +# +# 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::GCImporterAMC; + use base qw(GCImport::GCImportBaseClass); + + use File::Basename; + use File::Copy; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + $self->{fileId} = " AMC_X.Y Ant Movie Catalog 3.5.x www.buypin.com www.antp.be "; + + bless ($self, $class); + return $self; + } + + sub getName + { + return "Ant Movie Catalog (.amc)"; + } + + sub getFilePatterns + { + return (['Ant Movie Catalog (.amc)', '*.amc']); + } + + #Return supported models name + sub getModels + { + return ['GCfilms']; + } + + #Return current model name + sub getModelName + { + return 'GCfilms'; + } + + sub getOptions + { + my $self = shift; + my @options; + return \@options; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub getEndInfo + { + return ""; + } + + sub readBool + { + my $self = shift; + + my $value; + read $self->{file}, $value, 1; + return unpack('C',$value); + } + + sub readInt + { + my $self = shift; + + my $value; + read $self->{file}, $value, 4; + $value = unpack('L',$value); + return undef if $value == 4294967295; + return $value; + } + + sub readString + { + my $self = shift; + my $binary = shift; + + my $length = $self->readInt; + my $string; + + return '' if $length == 0; + read $self->{file}, $string, $length; + + #$string =~ s/\n/<br\/>/gm if !$binary; + $string =~ s/\|/,/gm if !$binary; + + return $string; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my @result; + + open ITEMS, $file; + binmode ITEMS; + $self->{file} = \*ITEMS; + + my $identifier; + read ITEMS, $identifier, length($self->{fileId}); + ($self->{AMCVersion} = $identifier) =~ s/.*?AMC_(\d+)\.(\d+).*/$1.$2/; + my @versions = split m/\./, $self->{AMCVersion}; + $self->{AMCMajorVersion} = $versions[0]; + $self->{AMCMinorVersion} = $versions[1]; + + $self->readString; # name + $self->readString; # mail + if (($self->{AMCMinorVersion} <= 3) && ($self->{AMCMinorVersion} < 5)) + { + $self->readString; # icq + } + $self->readString; # site + $self->readString; # description + + my $baseDir = dirname($file); + + my $i = 0; + + while (! eof ITEMS) + { + $result[$i]->{identifier} = $self->readInt; #Id + $self->readInt; #Add date + $result[$i]->{rating} = $self->readInt; + + if (($self->{AMCMinorVersion} >= 3) && ($self->{AMCMinorVersion} >= 5)) + { + use integer; + $result[$i]->{rating} /= 10; + } + + $result[$i]->{date} = $self->readInt; + $result[$i]->{time} = $self->readInt; + my $ vb = $self->readInt; #Video bitrate + my $ab = $self->readInt; #Audio bitrate + $result[$i]->{number} = $self->readInt; + + $self->readBool; #Checked + + $result[$i]->{place} = $self->readString; #Media label + $result[$i]->{format} = $self->readString; + $self->readString; #Source + $result[$i]->{borrower} = $self->readString; + $result[$i]->{borrower} = 'none' if ! $result[$i]->{borrower}; + $result[$i]->{original} = $self->readString; + $result[$i]->{title} = $self->readString; + $result[$i]->{title} = $result[$i]->{original} if !$result[$i]->{title}; + + $result[$i]->{director} = $self->readString; + $self->readString; #Producer + $result[$i]->{country} = $self->readString; + $result[$i]->{genre} = [[$self->readString]]; + $result[$i]->{actors} = $self->readString; + $result[$i]->{webPage} = $self->readString; + $result[$i]->{synopsis} = $self->readString; + $result[$i]->{comment} = $self->readString; + $result[$i]->{video} = $self->readString; + my $encodings = $self->readString; #Audio format + my $res = $self->readString; #Resolution + $self->readString; #Framerate + $result[$i]->{audio} = $self->readString; + if ($result[$i]->{audio}) + { + my @encodings = split /,/,$encodings; + $result[$i]->{audio} =~ s/(^|,)([^;]*?)(,|$)/$1$2;$_$3/ foreach (@encodings); + $result[$i]->{audio} =~ s/, +/,/g; + $result[$i]->{audio} =~ s/; +/;/g; + } + $result[$i]->{subt} = [[$self->readString]]; + $self->readString; #File size + $result[$i]->{image} = $self->readString; + + my $picture = $self->readString(1); + + if ($result[$i]->{image} =~ /^\..{3}/) + { + my $pictureName = $self->{options}->{parent}->getUniqueImageFileName($result[$i]->{image}, + $result[$i]->{title}); + open PIC, "> $pictureName"; + binmode PIC; + print PIC $picture; + close PIC; + $result[$i]->{image} = $self->{options}->{parent}->transformPicturePath($pictureName); + } + else + { + if (! File::Spec->file_name_is_absolute($result[$i]->{image})) + { + $result[$i]->{image} = $baseDir . $result[$i]->{image}; + } + #copy $result[$i]->{image}, $pictureName; + } + + $i++; + } + + close ITEMS; + + return \@result; + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportAlexandria.pm b/lib/gcstar/GCImport/GCImportAlexandria.pm new file mode 100644 index 0000000..6233ed7 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportAlexandria.pm @@ -0,0 +1,205 @@ +package GCImport::GCImportAlexandria; + +################################################### +# +# 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::GCImporterAlexandria; + + use base qw(GCImport::GCImportBaseClass); + use File::Copy; + use Encode; + use GCUtils 'glob'; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + $self->{errors} = ''; + + return $self; + } + + sub getName + { + return "Alexandria"; + } + + sub getOptions + { + my $self = shift; + return [ + { + name => 'where', + type => 'options', + label => 'Where', + default => 'Default', + valuesList => 'Default,Specified' + } + ]; + } + + sub getFilePatterns + { + my $self = shift; + + return (); + } + + #Return supported models name + sub getModels + { + return ['GCbooks']; + } + + sub getModelName + { + my $self = shift; + + return 'GCbooks'; + } + + sub wantsFieldsSelection + { + return 0; + } + + sub wantsFileSelection + { + return 0; + } + + sub wantsDirectorySelection + { + return 1; + } + + sub getEndInfo + { + my $self = shift; + + return ''; + } + + sub getItemsArray + { + my ($self, $directory) = @_; + + my @result = (); + + my @files; + $directory = $ENV{HOME}.'/.alexandria' + if $self->{options}->{where} eq 'Default'; + + foreach (glob "$directory/*") + { + if (-d $_) + { + my @array = glob "$_/*"; + foreach my $file(glob "$_/*") + { + push @files, $file if $file =~ /yaml$/; + } + } + push @files, $_ if /yaml$/; + } + + foreach (@files) + { + push @result, $self->getBook($_); + } + + return \@result; + } + + sub transformValue + { + my ($self, $value) = @_; + + $value =~ s/^"(.*)"$/$1/; + $value =~ s/\\x([0-9a-fA-F]{2})/pack("H2",$1)/ge; + $value = decode('UTF-8', $value); + + return $value; + } + + sub getBook + { + my ($self, $file) = @_; + + my %book; + open BOOK, "<$file"; + binmode(BOOK, ':utf8'); + # 1st line contain ruby information + my $line = <BOOK>; + my $current = ''; + my $value = ''; + foreach (<BOOK>) + { + next if /^#/; + if (/^([a-z_]*): (.*)$/) + { + $current = $1; + next if $current eq 'saved_ident'; + # Tag conversion + $current = 'lendDate' if $current eq 'loaned_since'; + $current = 'borrower' if $current eq 'loaned_to'; + $book{$current} = $self->transformValue($2); + } + elsif (/^\s*- (.*)$/) + { + $book{$current} ||= []; + push @{$book{$current}}, [$self->transformValue($1)]; + } + } + close BOOK; + #Some adjustments + $book{rating} *= 2; + $book{lendDate} =~ s|^([0-9]{4})-([0-9]{2})-([0-9]{2}).*$|$3/$2/$1|; + if ($book{loaned} eq 'false') + { + $book{borrower} = 'none'; + $book{lendDate} = ''; + } + delete $book{loaned}; + #cover + $file =~ s/yaml$/cover/; + if (-e $file) + { + my $pic = $self->{options}->{parent}->getUniqueImageFileName('jpg', $book{title}); + copy $file, $pic; + $book{cover} = $pic; + } + return \%book; + } + +} + + + + +1;
\ No newline at end of file diff --git a/lib/gcstar/GCImport/GCImportBase.pm b/lib/gcstar/GCImport/GCImportBase.pm new file mode 100644 index 0000000..026be19 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportBase.pm @@ -0,0 +1,217 @@ +package GCImport::GCImportBase; + +################################################### +# +# 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 GCExportImport; + +{ + package GCImport::GCImportBaseClass; + + use base 'GCExportImportBase'; + use File::Basename; + use File::Copy; + + #Methods to be overriden in specific classes + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new; + + $self->{parsingError} = ''; + $self->{modelAlreadySet} = 0; + + bless ($self, $class); + return $self; + } + + sub getFilePatterns + { + return (['*.*', '*.*']); + } + + sub getSuffix + { + my $self = shift; + return '' if ! ($self->getFilePatterns)[0]; + (my $pattern = ($self->getFilePatterns)[0]->[1]) =~ s/.*?([[:alnum:]]+)/$1/; + return $pattern; + } + + #Return supported models name + sub getModels + { + return []; + } + + #Return current model name + sub getModelName + { + return 'GCfilms'; + } + + sub getOptions + { + } + + sub wantsFieldsSelection + { + return 0; + } + + sub wantsIgnoreField + { + return 0; + } + + sub wantsImagesSelection + { + return 0; + } + + sub wantsFileSelection + { + return 1; + } + + sub wantsDirectorySelection + { + return 0; + } + + # Returns true if the module should be hidden from + # the menu when a collection of an incompatible kind is open. + sub shouldBeHidden + { + return 0; + } + + sub generateId + { + return 1; + } + + sub getEndInfo + { + } + + sub getItemsArray + { + } + + #End of methods to be overriden + + # If you need really specific processing, you can instead override the process method + + sub process + { + my ($self, $options) = @_; + $self->{options} = $options; + + $options->{parent}->{items}->updateSelectedItemInfoFromPanel; + my $alreadySaved = 0; + if ($options->{newList}) + { + return if !$options->{parent}->checkAndSave; + $alreadySaved = 1; + $options->{parent}->setFile(''); + } + $self->{options}->{parent}->setWaitCursor($self->{options}->{lang}->{ImportListTitle}.' ('.$options->{file}.')'); + my @tmpArray = @{$self->getItemsArray($options->{file})}; + + if ($self->{parsingError}) + { + $self->{options}->{parent}->restoreCursor; + return $self->getEndInfo; + } + + my $realModel = $self->getModelName; + + # Here we really know the model so we force a new list if needed + if (($options->{newList}) + || ($options->{parent}->{model}->getName ne $realModel)) + { + $options->{parent}->newList($realModel, $self->{modelAlreadySet}, $alreadySaved); + } + + my $generateId = $self->generateId; + foreach (@tmpArray) + { + $options->{parent}->{items}->addItem($_, !$generateId, 1); + } + $options->{parent}->{items}->unselect; + $self->{options}->{parent}->restoreCursor; + + $options->{parent}->checkPanelVisibility; + $options->{parent}->selectFirst; + $options->{parent}->markAsUpdated; + $options->{parent}->viewAllItems; + return $self->getEndInfo; + } + + # This method could only be use if $self->{model} has been initialized + sub copyPictures + { + my ($self, $itemsArray, $file) = @_; + return if !$self->{model}; + foreach my $item(@$itemsArray) + { + my $title = $item->{$self->{model}->{commonFields}->{title}}; + foreach my $field(@{$self->{model}->{fieldsImage}}) + { + (my $suffix = $item->{$field}) =~ s/.*?(\.[^.]*)$/$1/; + my $imageFile = $self->{options}->{parent}->getUniqueImageFileName($suffix, $title); + copy(GCUtils::getDisplayedImage($item->{$field}, '', $file), + $imageFile) + if $item->{$field}; + $item->{$field} = $imageFile; + } + } + } + + # 3 methods below are created to implement interface + # from GCFrame plugins could need to simulate if using + # some backends + sub preloadModel + { + my ($self, $model) = @_; + # Preload the model into the factory cache + $self->{modelsFactory}->getModel($model); + } + + sub setCurrentModel + { + my ($self, $model) = @_; + $self->{model} = $self->{modelsFactory}->getModel($model); + } + + sub setCurrentModelFromInline + { + my ($self, $container) = @_; + $self->{model} = GCModelLoader->newFromInline($self, $container); + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportCSV.pm b/lib/gcstar/GCImport/GCImportCSV.pm new file mode 100644 index 0000000..efb3e5d --- /dev/null +++ b/lib/gcstar/GCImport/GCImportCSV.pm @@ -0,0 +1,313 @@ +package GCImport::GCImportCSV; + +################################################### +# +# 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 utf8; + +use GCImport::GCImportBase; + +{ + package GCImport::GCImporterCSV; + + use base qw(GCImport::GCImportBaseClass); + use Encode; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + + bless ($self, $class); + return $self; + } + + sub wantsFieldsSelection + { + return 1; + } + + sub wantsIgnoreField + { + return 1; + } + + sub wantsFileSelection + { + return 1; + } + + sub getName + { + my $self = shift; + + return "CSV"; + } + + sub getFilePatterns + { + return (['CSV (*.csv)', '*.csv']); + } + + sub getOptions + { + my $self = shift; + + my $charsets = ''; + my @charsetList = Encode->encodings(':all'); + foreach (@charsetList) + { + $charsets .= $_.','; + } + + my $pluginsList = $self->{model}->{parent}->{lang}->{PluginDisabled}.','; + foreach (@{$self->{model}->getPluginsNames}) + { + my $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$_}; + $pluginsList .= $plugin->getName . ','; + } + + my $searchFieldsList; + foreach (@{$self->{model}->getSearchFields}) + { + $searchFieldsList->{$_} = $self->{model}->getDisplayedText($self->{model}->{fieldsInfo}->{$_}->{label}); + } + + return [ + { + name => 'sep', + type => 'short text', + label => 'Separator', + default => ';' + }, + + { + name => 'charset', + type => 'options', + label => 'Charset', + valuesList => $charsets, + default => 'utf8', + }, + + { + name => 'withHeader', + type => 'yesno', + label => 'Header', + default => '1' + }, + + { + name => 'plugin', + type => 'options', + label => 'Plugin', + valuesList => $pluginsList + }, + + { + name => 'searchfield', + type => 'options', + label => 'SearchField', + valuesList => $searchFieldsList, + default => $self->{model}->{commonFields}->{title} + }, + + { + name => 'first', + type => 'yesno', + label => 'UseFirst', + default => '1' + }, + + ]; + } + + sub getModelName + { + my $self = shift; + return $self->{model}->getName; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my @result; + + # First we try to get the correct plugin + my $plugin; + my $titleField; + my $pluginEnabled; + $pluginEnabled = 1 if $self->{options}->{plugin} + && ($self->{options}->{plugin} ne $self->{options}->{lang}->{PluginDisabled}); + if ($pluginEnabled) + { + $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$self->{options}->{plugin}}; + $titleField = $self->{options}->{searchfield}; + + # Force values of search field if it's incompatible with current plugin + my $compatible = 1; + $compatible = grep /^$titleField$/, @{$plugin->getSearchFieldsArray} + if $titleField; + if (!$compatible) + { + # If it is not, we use the 1st compatible one + $titleField = $plugin->getSearchFieldsArray->[0]; + } + + } + + open ITEMS, $file; + binmode(ITEMS, ':utf8') + if $self->{options}->{charset} eq 'utf8';; + + my $sep = $self->{options}->{sep}; + my $ignoreFirstLine = $self->{options}->{withHeader}; + + my $resultsDialog; + if ((!$self->{options}->{first}) && ($pluginEnabled)) + { + $resultsDialog = $self->{options}->{parent}->getDialog('Results'); + $resultsDialog->setModel($self->{model}, $self->{model}->{fieldsInfo}); + $resultsDialog->setMultipleSelection(0); + } + + my $i = 0; + + while (<ITEMS>) + { + if ($ignoreFirstLine) + { + $ignoreFirstLine = 0; + next; + } + + chomp; + # Special characters are escaped + my @values = split m/\Q$sep\E/; + + $result[$i] = {} if (!$pluginEnabled); + + my $j = 0; + my $searchTitle = ''; + foreach (@{$self->{options}->{fields}}) + { + $values[$j] = decode($self->{options}->{charset}, $values[$j]) + if $self->{options}->{charset} ne 'utf8'; + $result[$i]->{$_} = $values[$j] if (!$pluginEnabled); + $searchTitle = $values[$j] if (($_ eq $titleField) && ($pluginEnabled)); + $j++; + } + + if (($pluginEnabled) && ($searchTitle ne '')) + { + $plugin->{title} = $searchTitle; + $plugin->{type} = 'load'; + $plugin->{urlField} = $self->{model}->{commonFields}->{url}; + $plugin->{searchField} = $titleField; + + #Initialize what will be pushed in the array + my $info = {$titleField => $searchTitle}; + + $self->{options}->{parent}->setWaitCursor($self->{options}->{lang}->{StatusSearch}.' ('.$_.')'); + $plugin->load; + + my $itemNumber = $plugin->getItemsNumber; + + if ($itemNumber != 0) + { + $plugin->{type} = 'info'; + if (($itemNumber == 1) || ($self->{options}->{first})) + { + $plugin->{wantedIdx} = 0; + } + else + { + my $withNext = 0; + my @items = $plugin->getItems; + $resultsDialog->setWithNext(0); + $resultsDialog->setSearchPlugin($plugin); + $resultsDialog->setList($_, @items); + $resultsDialog->show; + if ($resultsDialog->{validated}) + { + $plugin->{wantedIdx} = $resultsDialog->getItemsIndexes->[0]; + } + } + $info = $plugin->getItemInfo; + my $title = $info->{$titleField}; + $self->{options}->{parent}->{defaultPictureSuffix} = $plugin->getDefaultPictureSuffix; + foreach my $field(@{$self->{model}->{managedImages}}) + { + $info->{$field} = '' if $info->{$field} eq 'empty'; + next if !$info->{$field}; + ($info->{$field}) = $self->{options}->{parent}->downloadPicture($info->{$field}, $title); + } + $info->{comment} = $self->getLang->{CommentAuto} + . "\n" + . $self->getLang->{CommentSite} + . $plugin->getName() + . "\n" + . $self->getLang->{CommentTitle} + . $_ + . "\n"; + + # Add the default value + my $defaultInfo = $self->{model}->getDefaultValues; + foreach my $field(keys %$defaultInfo) + { + next if exists $info->{$field}; + $info->{$field} = $defaultInfo->{$field}; + } + my $j = 0; + foreach (@{$self->{options}->{fields}}) + { + $values[$j] = decode($self->{options}->{charset}, $values[$j]) + if $self->{options}->{charset} ne 'utf8'; + $info->{$_} = $values[$j]; + $j++; + } + } + + push @result, $info; + $self->{options}->{parent}->restoreCursor; + } + + $i++; + } + close ITEMS; + + + return \@result; + } + + + sub getEndInfo + { + my $self = shift; + my $message; + + return $message; + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportDVDProfiler.pm b/lib/gcstar/GCImport/GCImportDVDProfiler.pm new file mode 100644 index 0000000..6f47d7b --- /dev/null +++ b/lib/gcstar/GCImport/GCImportDVDProfiler.pm @@ -0,0 +1,192 @@ +package GCImport::GCImportDVDProfiler; + +################################################### +# +# 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::GCImporterDVDProfiler; + + use base qw(GCImport::GCImportBaseClass); + + use XML::Simple; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + + return $self; + } + + sub getName + { + return "DVDProfiler (.xml)"; + } + + sub getOptions + { + my $self = shift; + my @options; + return \@options; + } + + sub getFilePatterns + { + return (['DVDProfiler (.xml)', '*.xml']); + } + + #Return supported models name + sub getModels + { + return ['GCfilms']; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub getEndInfo + { + return ""; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my $xml; + my $data; + # creer un objet + $xml = XML::Simple->new; # sans keyAttr les dvd seront dans une liste ou chaque dvd sera identifie par l'emplacement qu'il a dans cette liste + $data = $xml->XMLin ("$file"); + + + my @result; + my $film; + + foreach $film(@{$data->{DVD}}){ + my $item; + + $item->{title} = $film->{Title}; + $item->{date} = $film->{ProductionYear}; + $item->{time} = $film->{RunningTime}.' mn'; + $item->{synopsis} = $film->{Overview}; + ####### DIRECTOR ######### + my $director; + + if (ref ($film->{Credits}->{Credit}) eq "ARRAY") { + foreach $director(@{$film->{Credits}->{Credit}}){ + if (($director->{CreditType}) eq 'Direction') { + $item->{director} .= $director->{FirstName}.' '.$director->{LastName}.', '; + + } + } + } + else { + if (($film->{Credits}->{Credit}->{CreditType}) eq 'Direction') { + $item->{director} .= $film->{Credits}->{Credit}->{FirstName}.' '.$film->{Credits}->{Credit}->{LastName}; + } + } + ###### END DIRECTOR ###### + + ####### ACTORS ######### + my $actor; + if (ref ($film->{Actors}->{Actor}) eq "ARRAY") { + foreach $actor(@{$film->{Actors}->{Actor}}){ + $item->{actors} .= $actor->{FirstName}.' '.$actor->{LastName}.' '.'('.$actor->{Role}.')'.', '; + + } + } + else { + $item->{actors} .= $film->{Actors}->{Actor}->{'FirstName'}.' '.$film->{Actors}->{Actor}->{LastName}.' '.'('.$film->{Actors}->{Actor}->{Role}.')'; + } + ###### END ACTORS ###### + + ####### AUDIO ######### + my $audio; + if (ref ($film->{Audio}->{AudioFormat}) eq "ARRAY"){ + foreach $audio(@{$film->{Audio}->{AudioFormat}}){ + $item->{audio} .= $audio->{AudioLanguage}.', '; + + } + } + else { + $item->{audio} .= $film->{Audio}->{AudioFormat}->{'AudioLanguage'}; + } + ###### END AUDIO ###### + ####### SUBT ######### + my $subt; + if (ref ($film->{Subtitles}->{Subtitle}) eq "ARRAY"){ + foreach $subt(@{$film->{Subtitles}->{Subtitle}}){ + $item->{subt} .= $subt.', '; + + } + } + else { + $item->{subt} = $film->{Subtitles}->{Subtitle}; + } + ####### END SUBT ######### + ####### TYPE ######### + my $type; + if (ref ($film->{Genres}->{Genre}) eq "ARRAY"){ + foreach $type(@{$film->{Genres}->{Genre}}){ + $item->{type} .= $type.','; + + } + } + else { + $item->{type} = $film->{Genres}->{Genre}; + } + ####### END TYPE ######### + + #$item->{original} = $film->{Title}; + #$item->{subt} = $film->{Subtitles}->{Subtitle}; + #$item->{borrower} = $film->{Title}; + #$item->{lendDate} = $film->{Title}; + #$item->{history} = $film->{Title}; + #$item->{seen} = $film->{Title};# non par defaut ? + #$item->{comment} = $film->{Title}; + #$item->{image} = $film->{Title}; + #$item->{country} = $film->{Title}; + #$item->{number} = $film->{CollectionNumber}; + #$item->{rating} = $film->{Title};# note par defaut + #$item->{format} = $film->{Title};#DVD par d�faut ? + #$item->{webPage} = $film->{Title}; + #$item->{place} = $film->{Title}; + $item->{director} =~ s/, $//; + $item->{actors} =~ s/, $//; + $item->{audio} =~ s/, $//; + $item->{subt} =~ s/, $//; + $item->{type} =~ s/, $//; + push @result, $item; + } + return \@result; + + } +} + +1;
\ No newline at end of file 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; diff --git a/lib/gcstar/GCImport/GCImportGCfilms.pm b/lib/gcstar/GCImport/GCImportGCfilms.pm new file mode 100644 index 0000000..285e17d --- /dev/null +++ b/lib/gcstar/GCImport/GCImportGCfilms.pm @@ -0,0 +1,190 @@ +package GCImport::GCImportGCfilms; + +################################################### +# +# 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::GCImporterGCfilms; + use base qw(GCImport::GCImportBaseClass); + use File::Basename; + use File::Copy; + use GCUtils; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + + bless ($self, $class); + $self->{errors} = ''; + + #The fields as they were in GCfilms 6.1 + # If name has changed in GCstar, the comment contains the original one + $self->{fields} = [ + 'id', + 'title', + 'date', + 'time', + 'director', + 'country', # nat + 'genre', # type + 'image', + 'actors', + 'original', # orig + 'synopsis', + 'webPage', # url + 'seen', + 'format', + 'number', + 'place', + 'rating', + 'comment', + 'audio', + 'subt', + 'borrower', + 'lendDate', + 'borrowings', # history + 'age', + 'video', + 'serie', # collection + 'rank', + 'trailer', + ]; + + return $self; + } + + sub getName + { + return "GCfilms (.gcf)"; + } + + sub getFilePatterns + { + return (['GCfilms (.gcf)', '*.gcf']); + } + + #Return supported models name + sub getModels + { + return ['GCfilms']; + } + + sub getOptions + { + my $self = shift; + return [ + { + name => 'generate', + type => 'yesno', + label => 'ImportGenerateId', + default => '1' + }, + ]; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub generateId + { + my $self = shift; + return $self->{options}->{generate}; + } + sub getEndInfo + { + return ""; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my @result; + + open MOVIES, "<$file"; + my $gotFirstLine = 0; + my $i = 0; + while (<MOVIES>) + { + chomp; + my @values = split m/\|/; + + if (!$gotFirstLine) + { + $gotFirstLine = 1; + if ($values[0] eq 'GCfilms') + { + binmode( MOVIES, ':utf8' ) if $values[2] eq 'UTF8'; + next; + } + } + my $idx = 0; + for my $field (@{$self->{fields}}) + { + my $value = $values[$idx]; + if ($field eq 'image') + { + my $origPath = GCUtils::getDisplayedImage($value, '', $file); + my $origFile = basename($origPath); + $origFile = $origPath = '' if ! -f $origPath; + # We copy the image only if it was a generated one and if we use the default path + if ($origFile =~ /^gcfilms_/) + { + # We don't change the filename as gcstar has a different pattern for automatic files + my $destPath = $self->{options}->{parent}->getImagesDir; + copy($origPath, $destPath) if $origPath ne $destPath; + $result[$i]->{image} = $destPath.$origFile; + } + else + { + # We use the full path + $result[$i]->{image} = $origPath; + } + } + else + { + $value =~ s|:|;|gm if $field eq 'borrowings'; + $value =~ s|<br>|\n|gm; + $value =~ s|<.*?>||gm; + if (!$value) + { + $value = 0 if $field eq 'age'; + $value = 'none' if $field eq 'borrower'; + } + $result[$i]->{$field} = $value; + } + $idx++; + } + $i++; + } + return \@result; + + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportGCstar.pm b/lib/gcstar/GCImport/GCImportGCstar.pm new file mode 100644 index 0000000..1bff9c2 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportGCstar.pm @@ -0,0 +1,106 @@ +package GCImport::GCImportGCstar; + +################################################### +# +# 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::GCImporterGCstar; + use base qw(GCImport::GCImportBaseClass); + + use GCBackend::GCBackendXmlParser; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + return $self; + } + + sub getName + { + return "GCstar (.gcs)"; + } + + sub getFilePatterns + { + return (['GCstar (.gcs)', '*.gcs']); + } + + sub getModelName + { + my $self = shift; + return $self->{model}->getName; + } + + sub getOptions + { + my $self = shift; + return [ + { + name => 'copyPics', + type => 'yesno', + label => 'CopyPictures', + default => '1' + }]; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub getEndInfo + { + return ""; + } + + sub getItemsArray + { + my ($self, $file) = @_; + + my $parent = $self->{options}->{parent}; + $self->{modelsFactory} = $parent->{modelsFactory}; + $self->{modelAlreadySet} = 0; + + my $copyPics = 1; + $copyPics = $self->{options}->{copyPics} + if exists $self->{options}->{copyPics}; + + my $backend = new GCBackend::GCBeXmlParser($self); + $backend->setParameters(file => $file); + my $loaded = $backend->load(0); + my $itemsArray = $loaded->{data}; + if ($copyPics) + { + $self->copyPictures($itemsArray, $file); + } + return $itemsArray; + + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportList.pm b/lib/gcstar/GCImport/GCImportList.pm new file mode 100644 index 0000000..a2b2ec2 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportList.pm @@ -0,0 +1,202 @@ +package GCImport::GCImportList; + +################################################### +# +# 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::GCImporterList; + + 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 getFilePatterns + { + return (); + } + + sub getOptions + { + my $self = shift; + + my $pluginsList = ''; + foreach (@{$self->{model}->getPluginsNames}) + { + my $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$_}; + $pluginsList .= $plugin->getName . ','; + } + + + return [ + { + name => 'plugin', + type => 'options', + label => 'Plugin', + valuesList => $pluginsList + }, + + { + name => 'first', + type => 'yesno', + label => 'UseFirst', + default => '1' + }, + ]; + + + } + + sub getModelName + { + my $self = shift; + return $self->{model}->getName; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my @result; + + #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}; + + open ITEMS, $file; + binmode(ITEMS, ':utf8'); + + my $i = 0; + + my $resultsDialog; + if (!$self->{options}->{first}) + { + $resultsDialog = $self->{options}->{parent}->getDialog('Results'); + $resultsDialog->setModel($self->{model}, $self->{model}->{fieldsInfo}); + $resultsDialog->setMultipleSelection(0); + } + while (<ITEMS>) + { + chomp; + next if ! $_; + # $_ contains the title to search + $plugin->{title} = $_; + $plugin->{type} = 'load'; + $plugin->{urlField} = $self->{model}->{commonFields}->{url}; + $plugin->{searchField} = $titleField; + #Initialize what will be pushed in the array + my $info = {$titleField => $_}; + + $self->{options}->{parent}->setWaitCursor($self->{options}->{lang}->{StatusSearch}.' ('.$_.')'); + $plugin->load; + + my $itemNumber = $plugin->getItemsNumber; + + if ($itemNumber != 0) + { + $plugin->{type} = 'info'; + if (($itemNumber == 1) || ($self->{options}->{first})) + { + $plugin->{wantedIdx} = 0; + } + else + { + my $withNext = 0; + my @items = $plugin->getItems; + $resultsDialog->setWithNext(0); + $resultsDialog->setSearchPlugin($plugin); + $resultsDialog->setList($_, @items); + $resultsDialog->show; + if ($resultsDialog->{validated}) + { + $plugin->{wantedIdx} = $resultsDialog->getItemsIndexes->[0]; + } + } + $info = $plugin->getItemInfo; + my $title = $info->{$titleField}; + $self->{options}->{parent}->{defaultPictureSuffix} = $plugin->getDefaultPictureSuffix; + foreach my $field(@{$self->{model}->{managedImages}}) + { + $info->{$field} = '' if $info->{$field} eq 'empty'; + next if !$info->{$field}; + ($info->{$field}) = $self->{options}->{parent}->downloadPicture($info->{$field}, $title); + } + $info->{comment} = $self->getLang->{CommentAuto} + . "\n" + . $self->getLang->{CommentSite} + . $plugin->getName() + . "\n" + . $self->getLang->{CommentTitle} + . $_ + . "\n"; + + # Add the default value + my $defaultInfo = $self->{model}->getDefaultValues; + foreach my $field(keys %$defaultInfo) + { + next if exists $info->{$field}; + $info->{$field} = $defaultInfo->{$field}; + } + } + + push @result, $info; + $self->{options}->{parent}->restoreCursor; + } + close ITEMS; + return \@result; + } + + + sub getEndInfo + { + my $self = shift; + my $message; + + return $message; + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportMyMovies.pm b/lib/gcstar/GCImport/GCImportMyMovies.pm new file mode 100644 index 0000000..a51b1c4 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportMyMovies.pm @@ -0,0 +1,211 @@ +package GCImport::GCImportMyMovies; + +################################################################################# +# +# Created by Rob Maas rob@progob.nl | http://www.robmaas.eu (2008) +# +# +# This file is strongly based op the already existing DVDProfiler +# import class. It is also my first perl script :-) +# +# Since MyMovies has some different fields then GCStar, there are some work +# arounds to get as much of the original data. +# +# If the field ExtraFeatures is filled, it will appear in the General tab in +# the synopsis. +# +# The rating system will be calculated back to the Dutch rating system. +# +# If data was imported from IMDB, the webpage button will link to the specific +# movie site on IMDB. +# +# Cause GCstar hasn´t (yet?) a real EAN field, the EAN code is placed on the +# details tab under comments. +# +# Special thanks goes to Tian who helped me with some array trouble :-P and +# for creating this software. +# +################################################################################# + +use strict; +use GCImport::GCImportBase; + +{ + package GCImport::GCImporterMyMovies; + + use base qw(GCImport::GCImportBaseClass); + + use XML::Simple; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + + return $self; + } + + sub getName + { + return "MyMovies (.xml)"; + } + + sub getOptions + { + my $self = shift; + my @options; + return \@options; + } + + sub getFilePatterns + { + return (['MyMovies (.xml)', '*.xml']); + } + + #Return supported models name + sub getModels + { + return ['GCfilms']; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub getEndInfo + { + return ""; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my $xml; + my $data; + # Creates an object / Skip empty ellements + $xml = new XML::Simple(suppressempty => 1); + $data = $xml->XMLin ("$file"); + + my @result; + my $film; + + # For each "Title" in the XML file + foreach $film(@{$data->{Title}}){ + my $item; + + #General fields + $item->{title} = $film->{LocalTitle}; + $item->{original} = $film->{OriginalTitle}; + $item->{date} = $film->{ProductionYear}; + $item->{time} = $film->{RunningTime}.' min'; + $item->{synopsis} = $film->{Description}; + + #Extra's on the disc + if ($film->{ExtraFeatures}->{content}){ + $item->{synopsis} .= "\n\nEXTRA\n"; + $item->{synopsis} .= $film->{ExtraFeatures}->{content}; + } + + #Based on the Dutch ratings! + + $item->{age} = + ($film->{ParentalRating}->{Value} == 1) ? 1 + : ($film->{ParentalRating}->{Value} == 2) ? 2 + : ($film->{ParentalRating}->{Value} == 3) ? 5 + : ($film->{ParentalRating}->{Value} == 4) ? 12 + : 16; + + if ($film->{DataProvider} eq 'IMDB.com'){ + $item->{webPage} = 'http://www.imdb.com/title/'.$film->{DataProviderId}; + } + $item->{country} = $film->{Country}; + + ###### GENRE ######### + my $type; + if (ref ($film->{Genres}->{Genre}) eq "ARRAY"){ + foreach $type(@{$film->{Genres}->{Genre}}){ + $item->{genre} .= $type.','; + } + } + else{ + $item->{genre} = $film->{Genres}->{Genre}; + } + ###### END GENRE ######### + ####### DIRECTOR AND ACTORS ######### + my $actor; + if (ref ($film->{Persons}->{Person}) eq "ARRAY") { + foreach $actor(@{$film->{Persons}->{Person}}){ + if ($actor->{Type} eq 'Director'){ + $item->{director} = $actor->{Name}; + } + else{ + $item->{actors}.= $actor->{Name}.' ('.$actor->{Role}.'), '; + } + } + } + else{ + $item->{actors}.= $film->{Persons}->{Person}->{Name}.' ('.$film->{Persons}->{Person}->{Role}.')'; + } + ###### END DIRECTOR AND ACTORS ###### + + ##DETAIL + $item->{format} = $film->{Type}; + $item->{video} = $film->{VideoStandard}; + $item->{added} = $film->{Added}; + $item->{identifier} = $film->{CollectionNumber}; + + #Temporately cause a real barcode field is missing + if (length($film->{Barcode}) gt 0){ + $item->{comment} = 'EAN: '.$film->{Barcode}; + } + + ###### AUDIO ######### + my $audio; + my @audioTracks; + if (ref ($film->{AudioTracks}->{AudioTrack}) eq "ARRAY"){ + foreach $audio(@{$film->{AudioTracks}->{AudioTrack}}){ + push @audioTracks, [$audio->{Language}, $audio->{Type}.' '.$audio->{Channels}]; + } + $item->{audio} = \@audioTracks; + } + else{ + $item->{audio} = [[$audio->{Language}, $audio->{Type}]]; + } + ###### END AUDIO ######### + ###### SUBTITLES ######### + my $subt; + if (ref ($film->{Subtitles}->{Subtitle}) eq "ARRAY"){ + foreach $subt(@{$film->{Subtitles}->{Subtitle}}){ + $item->{subt} .= $subt->{Language}.','; + } + } + else{ + $item->{subt} = $subt->{Language}; + } + ###### END SUBTITLES ######### + + #$item->{borrower} = $film->{Title}; + #$item->{lendDate} = $film->{Title}; + #$item->{history} = $film->{Title}; + #$item->{seen} = $film->{Title};# non par defaut ? + #$item->{image} = $film->{Title}; + #$item->{number} = $film->{CollectionNumber}; + #$item->{rating} = $film->{Title};# note par defaut + #$item->{place} = $film->{Title}; + + $item->{director} =~ s/, $//; + $item->{actors} =~ s/, $//; + $item->{audio} =~ s/, $//; + $item->{subt} =~ s/, $//; + $item->{genre} =~ s/, $//; + push @result, $item; + } + return \@result; + + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportScanner.pm b/lib/gcstar/GCImport/GCImportScanner.pm new file mode 100644 index 0000000..92c5bba --- /dev/null +++ b/lib/gcstar/GCImport/GCImportScanner.pm @@ -0,0 +1,394 @@ +package GCImport::GCImportList; + +################################################### +# +# 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 GCScannerDialog; + use base 'GCModalDialog'; + use XML::Simple; + + sub new + { + my ($proto, $parent, $lang, $model, $serverSocket) = @_; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new($parent, + $lang->{Waiting}); + bless($self, $class); + + $self->{lang} = $lang; + $self->{model} = $model; + $self->{accepted} = 0; + if ($serverSocket) + { + $self->{network} = 1; + $self->{serverSocket} = $serverSocket; + } + my $table = new Gtk2::Table(2, 2); + $table->set_row_spacings($GCUtils::halfMargin); + $table->set_col_spacings($GCUtils::margin); + $table->set_border_width($GCUtils::margin); + $self->{previousLabel} = new GCLabel(''); + $self->{promptLabel} = new GCLabel($lang->{ScanPrompt}); + $table->attach($self->{previousLabel}, 0, 1, 0, 1, 'fill', 'fill', 0, 0); + $table->attach($self->{promptLabel}, 0, 1, 1, 2, 'fill', 'fill', 0, 0); + my $eanLabel = new GCLabel($lang->{EAN}); + $self->{ean} = new GCShortText; + $self->{ean}->signal_connect('activate' => sub {$self->response('ok')} ); + if (!$self->{network}) + { + $table->attach($eanLabel, 0, 1, 2, 3, 'fill', 'fill', 0, 0); + $table->attach($self->{ean}, 1, 2, 2, 3, ['fill', 'expand'], 'fill', 0, 0); + } + $self->vbox->pack_start($table, 1, 1, 0); + $table->show_all; + $self->setCancelLabel($lang->{Terminate}); + $self->action_area->remove(($self->action_area->get_children)[$self->{okPosition}]); + return $self; + } + + sub setPrevious + { + my ($self, $previous) = @_; + if (!$self->{first}) + { + $self->{first} = 1; + return; + } + my $label; + if ($previous) + { + ($label = $self->{lang}->{Previous}) =~ s|%s|<b>$previous</b>|; + } + else + { + my $previous = $self->{previousCode}; + ($label = $self->{lang}->{NothingFound}) =~ s|%s|<b>$previous</b>|; + } + $self->{previousLabel}->set_markup($label); + $self->{promptLabel}->set_label($self->{lang}->{ScanOtherPrompt}); + } + + sub readSocket + { + my ($self) = @_; + Glib::Source->remove($self->{socketWatch}); + my $socket = $self->{socket}; + my $line = <$socket>; + $self->response('cancel') if !$line; + my $xs = XML::Simple->new; + my $scan = $xs->XMLin($line); + my $code = $scan->{scan}->{content}; + $code = $self->eanToIsbn($code) + if $self->{model} eq 'GCbooks'; + $self->{ean}->setValue($code); + $self->{previousCode} = $code; + $self->response('ok'); + } + + sub waitForCode + { + my $self = shift; + $self->{socketWatch} = Glib::IO->add_watch($self->{socket}->fileno, + 'in', + sub { + $self->readSocket; + }); + } + + sub eanToIsbn + { + my ($self, $code) = @_; + return $code if $code !~ /978(\d{9})/; + my $sub = $1; + my $multiplier = 1; + my $checkSum = 0; + foreach (split(//, $sub)) + { + $checkSum += $_ * $multiplier++; + } + $checkSum %= 11; + $checkSum = 'X' if $checkSum == 10; + return $sub.$checkSum; + } + + sub show + { + my $self = shift; + $self->SUPER::show(); + $self->show_all; + $self->showMe; + if ($self->{network}) + { + if (!$self->{accepted}) + { + $self->{serverWatch} = Glib::IO->add_watch($self->{serverSocket}->fileno, + 'in', + sub { + $self->{socket} = $self->{serverSocket}->accept; + $self->{accepted} = 1; + $self->waitForCode; + }); + } + else + { + $self->waitForCode; + } + } + else + { + $self->{ean}->setValue(''); + $self->{ean}->grab_focus; + } + my $code = $self->run; + $self->hide; + return $self->{ean}->getValue if $code eq 'ok'; + $self->{socket}->close; + return undef; + } +} + +{ + package GCImport::GCImporterScanner; + + use base qw(GCImport::GCImportBaseClass); + + use IO::Socket; + 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 0; + } + + sub hideFileSelection + { + return 1; + } + + sub getFilePatterns + { + return (); + } + + sub checkPortField + { + my ($self, $data) = @_; + my ($parent, $list) = @{$data}; + my $model = $list->getValue ; + $parent->{options}->{port}->set_sensitive($model eq 'Network'); + } + + sub getOptions + { + my $self = shift; + + my $pluginsList = ''; + foreach (@{$self->{model}->getPluginsNames}) + { + my $plugin = $GCPlugins::pluginsMap{$self->{model}->getName}->{$_}; + $pluginsList .= $plugin->getName . ',' + if $plugin->getEanField; + } + + + return [ + { + name => 'type', + type => 'options', + label => 'Type', + valuesList => 'Local,Network', + default => 'Local', + changedCallback => sub {shift; $self->checkPortField(@_)}, + }, + + { + name => 'port', + type => 'number', + label => 'Port', + default => 50007, + min => 1024, + max => 65536, + }, + + { + name => 'plugin', + type => 'options', + label => 'Plugin', + valuesList => $pluginsList + }, + + { + name => 'first', + type => 'yesno', + label => 'UseFirst', + default => '1' + }, + ]; + } + + sub getModelName + { + my $self = shift; + return $self->{model}->getName; + } + + sub getBarCode + { + my ($self, $previous) = @_; + #my $dialog = new + $self->{dialog}->setPrevious($previous); + return $self->{dialog}->show; + } + + sub getItemsArray + { + my ($self, $file) = @_; + my @result; + + #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 $searchField = $plugin->getEanField; + + my $i = 0; + + my $resultsDialog; + if (!$self->{options}->{first}) + { + $resultsDialog = $self->{options}->{parent}->getDialog('Results'); + $resultsDialog->setModel($self->{model}, $self->{model}->{fieldsInfo}); + $resultsDialog->setMultipleSelection(0); + } + my $search; + + my $socket; + if ($self->{options}->{type} eq 'Network') + { + $socket = new IO::Socket::INET( + LocalPort => $self->{options}->{port}, + Proto => 'tcp', + Listen => 1, + Reuse => 1 + ); + } + + $self->{dialog} = new GCScannerDialog($self->{options}->{parent}, + $self->getLang, + $self->{model}->getName, + $socket); + my $previous = ''; + while ($search = $self->getBarCode($previous)) + { + chomp $search; + next if ! $search; + # $_ contains the title to search + $plugin->{title} = $search; + $plugin->{type} = 'load'; + $plugin->{urlField} = $self->{model}->{commonFields}->{url}; + $plugin->{searchField} = $searchField; + #Initialize what will be pushed in the array + my $info = {$searchField => $search}; + + $self->{options}->{parent}->setWaitCursor($self->{options}->{lang}->{StatusSearch}.' ('.$search.')'); + $plugin->load; + + my $itemNumber = $plugin->getItemsNumber; + + if ($itemNumber != 0) + { + $plugin->{type} = 'info'; + if (($itemNumber == 1) || ($self->{options}->{first})) + { + $plugin->{wantedIdx} = 0; + } + else + { + my $withNext = 0; + my @items = $plugin->getItems; + $resultsDialog->setWithNext(0); + $resultsDialog->setSearchPlugin($plugin); + $resultsDialog->setList($search); + $resultsDialog->show; + if ($resultsDialog->{validated}) + { + $plugin->{wantedIdx} = $resultsDialog->getItemsIndexes->[0]; + } + } + $info = $plugin->getItemInfo; + my $title = $info->{$titleField}; + $self->{options}->{parent}->{defaultPictureSuffix} = $plugin->getDefaultPictureSuffix; + foreach my $field(@{$self->{model}->{managedImages}}) + { + $info->{$field} = '' if $info->{$field} eq 'empty'; + next if !$info->{$field}; + ($info->{$field}) = $self->{options}->{parent}->downloadPicture($info->{$field}, $title); + } + + # Add the default value + my $defaultInfo = $self->{model}->getDefaultValues; + foreach my $field(keys %$defaultInfo) + { + next if exists $info->{$field}; + $info->{$field} = $defaultInfo->{$field}; + } + } + $previous = $info->{$titleField}; + push @result, $info; + $self->{options}->{parent}->restoreCursor; + } + $socket->close if $socket; + return \@result; + } + + + sub getEndInfo + { + my $self = shift; + my $message; + return $message; + } +} + + +1; diff --git a/lib/gcstar/GCImport/GCImportTarGz.pm b/lib/gcstar/GCImport/GCImportTarGz.pm new file mode 100644 index 0000000..b995b82 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportTarGz.pm @@ -0,0 +1,152 @@ +package GCImport::GCImportTarGz; + +################################################### +# +# 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::GCImporterTarGz; + + use base qw(GCImport::GCImportBaseClass); + + use GCBackend::GCBackendXmlParser; + + use File::Spec; + use File::Temp qw/ tempfile tempdir /; + use Cwd; + use File::Copy; + + #use GCData; + + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + + $self->checkModule('Compress::Zlib'); + $self->checkModule('Archive::Tar'); + $self->checkModule('File::Path'); + + return $self; + } + + sub getName + { + return ".tar.gz"; + } + + sub getFilePatterns + { + return (['Tar gzip (.tar.gz)', '*.tar.gz']); + } + + sub getModelName + { + my $self = shift; + + return $self->{model}->getName; + } + + sub getOptions + { + my $self = shift; + my @options; + return \@options; + } + + # Ignored for the moment + sub wantsFieldsSelection + { + return 0; + } + sub getEndInfo + { + my $self = shift; + return ($self->{parsingError}, 'error'); + } + + sub addFieldsToDefaultModel + { + my ($self, $inlineModel) = @_; + my $model = GCModelLoader->newFromInline($self, {inlineModel => $inlineModel, defaultModifier => 1}); + $self->{model}->addFields($model); + $self->{options}->{parent}->setCurrentModel($self->{model}); + $self->{modelAlreadySet} = 1; + } + + sub getItemsArray + { + my ($self, $file) = @_; + + my ($tarFh, $tarFilename) = tempfile(); + my $gz = Compress::Zlib::gzopen($file, "rb"); + my $buffer; + print $tarFh $buffer while $gz->gzread($buffer) > 0 ; + close $tarFh; + $gz->gzclose; + + my $tmpDir = tempdir(); + my $oldCwd = getcwd; + chdir $tmpDir; + my $tar = Archive::Tar->new($tarFilename); + $tar->extract; + my $listFile = './collection.gcs'; + + my $parent = $self->{options}->{parent}; + $self->{modelsFactory} = $parent->{modelsFactory}; + $self->{modelAlreadySet} = 0; + + my $backend = new GCBackend::GCBeXmlParser($self); + $backend->setParameters(file => $listFile); + my $loaded = $backend->load(0); + my $itemsArray = []; + if ($loaded->{error}) + { + $self->{parsingError} = GCUtils::formatOpenSaveError( + $parent->{lang}, + $file, + $loaded->{error} + ); + } + else + { + $itemsArray = $loaded->{data}; + + #Copying pictures + $self->copyPictures($itemsArray, $file); + } + + #Cleaning + chdir $oldCwd; + File::Path::rmtree($tmpDir); + unlink $tarFilename; + + return $itemsArray; + } +} + +1; diff --git a/lib/gcstar/GCImport/GCImportTellico.pm b/lib/gcstar/GCImport/GCImportTellico.pm new file mode 100644 index 0000000..033b474 --- /dev/null +++ b/lib/gcstar/GCImport/GCImportTellico.pm @@ -0,0 +1,496 @@ +package GCImport::GCImportTellico; + +################################################### +# +# 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::GCImporterTellico; + + use base qw(GCImport::GCImportBaseClass); + use File::Spec; + + sub new + { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(); + bless ($self, $class); + + $self->checkModule('Archive::Zip'); + $self->checkModule('MIME::Base64'); + + # Associate a Tellico type to a GCstar model + $self->{models} = { + 2 => 'GCbooks', + 3 => 'GCfilms', + 4 => 'GCmusics', + 8 => 'GCcoins', + 11 => 'GCgames' + }; + + return $self; + } + + sub getName + { + return "Tellico (.tc)"; + } + + sub getOptions + { + my $self = shift; + my @options; + return \@options; + } + + sub getFilePatterns + { + my $self = shift; + + return (['Tellico Format (.tc)', '*.tc'], ['Tellico XML (.xml)', '*.xml']); + } + + #Return supported models name + sub getModels + { + my $self = shift; + my @models = values %{$self->{models}}; + return \@models; + } + + sub getModelName + { + my $self = shift; + + return $self->{extractedModel}; + } + + sub wantsFieldsSelection + { + return 0; + } + + sub getEndInfo + { + my $self = shift; + + return $self->{parsingError}; + } + + sub getItemsArray + { + my ($self, $file) = @_; + + my @result = (); + + my $xml; + + # File type is based on suffix + # T is for Tellico (zipped file) + # X is for XML + $self->{type} = ($file =~ m/tc$/) ? 'T' : 'X'; + #Then we test to be sure + eval + { + $self->{zip} = Archive::Zip->new($file); + }; + #First we uncompress file + if (($self->{type} eq 'T') && ($self->{zip})) + { + $xml = $self->{zip}->contents('tellico.xml'); + } + else + { + $self->{type} = 'X'; + open XML, $file; + $xml = do {local $/; <XML>}; + close XML; + } + + #Then we parse XML data + my $xs = XML::Simple->new; + my $tellico = $xs->XMLin($xml, + SuppressEmpty => '', + ForceArray => 1); + my $collection = $tellico->{collection}->[0]; + + $self->{extractedModel} = $self->{models}->{$collection->{type}}; + #We check we know this model + if (! $self->{extractedModel}) + { + $self->{parsingError} = $self->getLang->{NotSupported}; + return \@result; + } + + my %tmpMap; + # If there are no ids, we have an array in $collection + if (ref ($collection->{entry}) eq 'ARRAY') + { + my $i = 0; + #Then we prepare a map + foreach (@{$collection->{entry}}) + { + $tmpMap{$i} = $_; + $i++; + } + } + else + { + %tmpMap = %{$collection->{entry}}; + } + #Loop on entries + my $i = 0; + + my $methodName = 'get'.$self->{extractedModel}.'Item'; + + while (my ($id, $entry) = each (%tmpMap)) + { + $result[$i] = $self->$methodName($entry, $collection); + $i++; + } + return \@result; + + } + + sub getGCfilmsItem + { + my ($self, $entry, $collection) = @_; + + my %result; + + $result{title} = $entry->{title}->[0]; + $result{format} = $entry->{medium}->[0]; + $result{date} = $entry->{year}->[0]; + my $certification = $entry->{certification}->[0]; + if ($certification eq 'U (USA)') + { + $result{age} = 1; + } + elsif ($certification eq 'G (USA)') + { + $result{age} = 2; + } + elsif ($certification eq 'PG (USA)') + { + $result{age} = 5; + } + elsif ($certification eq 'PG-13 (USA)') + { + $result{age} = 13; + } + elsif ($certification eq 'R (USA)') + { + $result{age} = 17; + } + $result{genre} = []; + if ($entry->{genres}->[0]) + { + for my $genre(@{$entry->{genres}->[0]->{genre}}) + { + push @{$result{genre}}, [$genre]; + } + } + if ($entry->{nationalitys}->[0]) + { + for my $country(@{$entry->{nationalitys}->[0]->{nationality}}) + { + $result{country} .= $country.', '; + } + } + $result{country} =~ s/, $//; + + $result{video} = $entry->{format}->[0]; + if ($entry->{casts}->[0]) + { + for my $cast(@{$entry->{casts}->[0]->{cast}}) + { + $result{actors} .= $cast->{column}->[0]; + $result{actors} .= ' ('.$cast->{column}->[1].')' if $cast->{column}->[1]; + $result{actors} .= ', '; + } + } + $result{actors} =~ s/, $//; + + if ($entry->{directors}->[0]) + { + for my $director(@{$entry->{directors}->[0]->{director}}) + { + $result{director} .= $director.', '; + } + } + $result{director} =~ s/, $//; + + $result{audio} = []; + if ($entry->{languages}->[0]) + { + for my $language(@{$entry->{languages}->[0]->{language}}) + { + push @{$result{audio}}, [$language]; + } + } + $result{subt} = []; + if ($entry->{subtitles}->[0]) + { + for my $subtitle(@{$entry->{subtitles}->[0]->{subtitle}}) + { + push @{$result{subt}}, [$subtitle]; + } + } + $result{time} = $entry->{'running-time'}->[0]; + $result{synopsis} = $entry->{plot}->[0]; + $result{synopsis} =~ s{(<|<)br/>}{\n}g; + + $result{rating} = $self->convertRating($entry->{rating}->[0]); + #$result{borrower} = 'none' if (! $entry->{loaned}); + $result{borrower} = 'Unknown' if ($entry->{loaned}->[0] eq 'true'); + $result{comment} = $entry->{comments}->[0]; + + #Picture management + $result{image} = $self->getPicture($collection, $entry->{cover}->[0], $result{title}); + + return \%result; + } + + sub getGCgamesItem + { + my ($self, $entry, $collection) = @_; + + my %result; + + $result{name} = $entry->{title}->[0]; + $result{platform} = $entry->{platform}->[0]; + $result{released} = $entry->{year}->[0]; + $result{genre} = []; + if ($entry->{genres}->[0]) + { + for my $genre(@{$entry->{genres}->[0]->{genre}}) + { + push @{$result{genre}}, [$genre]; + } + } + if ($entry->{publishers}->[0]) + { + for my $editor(@{$entry->{publishers}->[0]->{publisher}}) + { + $result{editor} .= $editor.', '; + } + $result{editor} =~ s/, $//; + } + if ($entry->{developers}->[0]) + { + for my $developer(@{$entry->{developers}->[0]->{developer}}) + { + $result{developer} .= $developer.', '; + } + $result{developer} =~ s/, $//; + } + $result{description} = $entry->{description}->[0]; + $result{rating} = $self->convertRating($entry->{rating}->[0]); + $result{completion} = 100 if $entry->{completed}->[0] eq 'true'; + $result{borrower} = 'Unknown' if ($entry->{loaned}->[0] eq 'true'); + $result{boxpic} = $self->getPicture($collection, $entry->{cover}->[0], $result{name}); + return \%result; + } + + sub getGCbooksItem + { + my ($self, $entry, $collection) = @_; + + my %result; + + $result{title} = $entry->{title}->[0]; + $result{isbn} = $entry->{isbn}->[0]; + $result{authors} = []; + if ($entry->{authors}->[0]) + { + for my $author(@{$entry->{authors}->[0]->{author}}) + { + push @{$result{authors}}, [$author]; + } + } + $result{publisher} = $entry->{publisher}->[0]; + $result{publication} = $entry->{pub_year}->[0]; + if ($entry->{languages}->[0]) + { + for my $language(@{$entry->{languages}->[0]->{language}}) + { + $result{language} .= $language.', '; + } + $result{language} =~ s/, $//; + } + $result{serie} = $entry->{series}->[0]; + $result{rank} = $entry->{series_num}->[0]; + $result{edition} = $entry->{edition}->[0]; + $result{format} = $entry->{binding}->[0]; + $result{description} = $entry->{comments}->[0]; + $result{pages} = $entry->{pages}->[0]; + $result{read} = 1 if ($entry->{read}->[0] eq 'true'); + $result{acquisition} = $entry->{pur_date}->[0]; + $result{genre} = []; + if ($entry->{genres}->[0]) + { + for my $genre(@{$entry->{genres}->[0]->{genre}}) + { + push @{$result{genre}}, [$genre]; + } + } + $result{rating} = $self->convertRating($entry->{rating}->[0]); + $result{borrower} = 'Unknown' if ($entry->{loaned}->[0] eq 'true'); + $result{cover} = $self->getPicture($collection, $entry->{cover}->[0], $result{title}); + return \%result; + } + + sub getGCmusicsItem + { + my ($self, $entry, $collection) = @_; + + my %result; + + $result{title} = $entry->{title}->[0]; + $result{format} = $entry->{medium}->[0]; + if ($entry->{artists}->[0]) + { + for my $artist(@{$entry->{artists}->[0]->{artist}}) + { + $result{artist} .= $artist.', '; + } + $result{artist} =~ s/, $//; + } + if ($entry->{labels}->[0]) + { + for my $label(@{$entry->{labels}->[0]->{label}}) + { + $result{label} .= $label.', '; + } + $result{label} =~ s/, $//; + } + $result{release} = $entry->{year}->[0]; + $result{genre} = []; + if ($entry->{genres}->[0]) + { + for my $genre(@{$entry->{genres}->[0]->{genre}}) + { + push @{$result{genre}}, [$genre]; + } + } + if ($entry->{tracks}->[0]) + { + my $trackNum = 1; + for my $track(@{$entry->{tracks}->[0]->{track}}) + { + push @{$result{tracks}}, [$trackNum, + $track->{column}->[0], + $track->{column}->[2]]; + $trackNum++; + } + } + $result{comment} = $entry->{comments}->[0]; + $result{rating} = $self->convertRating($entry->{rating}->[0]); + $result{borrower} = 'Unknown' if ($entry->{loaned}->[0] eq 'true'); + $result{cover} = $self->getPicture($collection, $entry->{cover}->[0], $result{title}); + return \%result; + } + + sub getGCcoinsItem + { + my ($self, $entry, $collection) = @_; + + my $i = 0; + my %result; + + #$result{name} = $entry->{title}->[0]; + + $result{currency} = $entry->{type}->[0]; + $result{value} = $entry->{denomination}->[0]; + $result{year} = $entry->{years}->[0]->{year}->[0]; + $result{country} = $entry->{country}->[0]; + $result{type} = ($entry->{set}->[0] eq 'true') ? 'coin' : 'banknote'; + # TODO: Import grade + $result{added} = $entry->{pur_date}->[0]; + $result{estimate} = $entry->{pur_price}->[0]; + $result{location} = $entry->{location}->[0]; + + $result{comments} = $entry->{comments}->[0]; + + $result{name} = $result{currency}.' '.$result{value}.' ('.$result{year}.')'; + + $result{picture} = $self->getPicture($collection, $entry->{obverse}->[0], $result{name}); + $result{front} = $self->getPicture($collection, $entry->{obverse}->[0], $result{name}.'_front'); + $result{back} = $self->getPicture($collection, $entry->{reverse}->[0], $result{name}.'_back'); + return \%result; + } + + sub getPicture + { + my ($self, $collection, $imageId, $title) = @_; + + my $result = undef; + if ($imageId && (ref($imageId) ne 'HASH')) + { + (my $suffix = $imageId) =~ s/.*?(\.[^.]*)$/$1/; + my $fileName = $self->{options}->{parent}->getUniqueImageFileName($suffix, $title); + if ((exists $collection->{images}->[0]->{image}->{$imageId}) && + (exists $collection->{images}->[0]->{image}->{$imageId}->{content})) + { + # Picture is embedded + my $data = MIME::Base64::decode_base64($collection->{images}->[0]->{image}->{$imageId}->{content}); + open PIC, ">$fileName"; + print PIC $data; + close PIC; + } + else + { + if ($self->{type} eq 'T') + { + # Only zipped file may have external pictures + my $picName = 'images/'.$imageId; + $self->{zip}->extractMember($picName, $fileName); + } + else + { + $fileName = ''; + } + } + $result = $self->{options}->{parent}->transformPicturePath($fileName); + } + return $result; + } + + sub convertRating + { + my ($self, $rating) = @_; + return 10 if $rating =~ /^5/; + return 7 if $rating =~ /^4/; + return 3 if $rating =~ /^2/; + return 0 if $rating =~ /^1/; + return 5; #if ($rating =~ /^3/) || ($rating == undef); + } + +} + + + + +1; |