ADD mise à jour de la liste des films
[pompage.git] / src / films.rb
index e93e615..7b1e625 100644 (file)
-# Représente un ensemble de films\r
-\r
-require 'rexml/document'\r
-require 'thwait'\r
-\r
-require 'film.rb'\r
-require 'pays.rb'\r
-require 'genre.rb'\r
-require 'personne.rb'\r
-require 'constantes.rb'\r
-require 'iconv'\r
-\r
-class Films\r
-   def initialize(xmlFile, modClasse)\r
-      @xmlFile = xmlFile\r
-      \r
-      @modClasse = modClasse\r
-      \r
-      # repertoire de base, par exemple C:/Divx/\r
-      @repBase = ''   \r
-         \r
-      # Les films indexé par leur titre\r
-      @films = {}\r
-      \r
-      # Les films indexé par leur nom de fichier, deux fichiers différents peuvent pointer sur le même film\r
-      @filmsFichier = {}\r
-      \r
-      # Les films qui ont plusieurs réponses lors de la recherche, traité à la fin\r
-      @filmsPlusieursReponses = []\r
-\r
-      # Les films qui ont plusieurs réponses lors de la recherche, traité à la fin\r
-      @filmsAucuneReponse = []\r
-\r
-      # permet de traiter facilement des groupes de thread\r
-      @threadsWait = ThreadsWait::new\r
-      @nbConn = 0 # le nombre de connexion\r
-      \r
-      # le prochain id disponible\r
-      @idDisponible = 1\r
-      \r
-      chargerFilms\r
-   end\r
-\r
-   # Lit un repertoire de manière recursive et va chercher les informations concernant le film sur le net\r
-   def pomper(r)\r
-      @repBase = r\r
-      repPrecedant = Dir::getwd\r
-      Dir::chdir(r)\r
-      \r
-      t = Time::now\r
-      \r
-      pomperR('.')\r
-      \r
-      # on attends que les threads se terminent\r
-      @threadsWait.all_waits\r
-      \r
-      puts "Pompage terminé, temps : #{Time::now - t} secondes"\r
-      \r
-      # traite les films qui avaient plusieurs réponses lors de la recherche\r
-      # l'utilisateur doit faire un choix\r
-      i = 1\r
-      @filmsPlusieursReponses.each{|f|\r
-         puts\r
-         puts "Plop, ya un conflit #{i} / #{@filmsPlusieursReponses.length} :"\r
-         case f.reglerConflitPlusieursReponses\r
-            when 1\r
-               ajouterFilm(f)            \r
-            when 3\r
-               break\r
-         end\r
-         i += 1\r
-      }\r
-      \r
-      i = 1\r
-      @filmsAucuneReponse.each{|f|\r
-         puts\r
-         puts "Plop, Ce film n'a pas été trouvé #{i} / #{@filmsAucuneReponse.length} :"\r
-         case f.reglerConflitPlusieursReponses\r
-            when 1\r
-               ajouterFilm(f)\r
-            when 3\r
-               break\r
-         end\r
-         i += 1\r
-      }\r
-      \r
-      @films.each{|t,f|\r
-         f.mod.finish\r
-      }\r
-      \r
-      Dir::chdir(repPrecedant)      \r
-   end\r
-   \r
-   # Sauve les films dans un fichier XML\r
-   def sauverFilms\r
-      # le document\r
-      docXml = REXML::Document::new\r
-      docXml.xml_decl().encoding = "UTF-8"  # normalement UTF-8\r
-      docXml.xml_decl().dowrite\r
-            \r
-      # la racine du document\r
-      racine = REXML::Element::new('filmographie')\r
-      docXml.add(racine)\r
-      pi = REXML::Instruction.new("xml-stylesheet", "type=\"text/xsl\" href=\"../xsl/yopyop.xsl\"")\r
-      racine.previous_sibling = pi\r
-      \r
-      # on ajoute chaque film à la racine\r
-      @films.each{|nom, f|\r
-         racine.add(f.getXml)\r
-      } \r
-      \r
-      # sauve le document\r
-      docXml.write(File::new(@xmlFile, 'w'), 0)\r
-   end   \r
-   \r
-   private\r
-      \r
-   # Charge les films depuis le fichier XML\r
-   def chargerFilms\r
-      # si le fichier n'existe pas il n'y a rien à charger\r
-      if !File.exists?(@xmlFile)\r
-         return\r
-      end\r
-      \r
-      racine = REXML::Document::new(File::new(@xmlFile)).root\r
-      racine.each_element{|e|       \r
-         id = e.attribute('id').to_s.to_i\r
-       \r
-         if id >= @idDisponible\r
-            @idDisponible = id + 1   \r
-         end\r
-         \r
-         titre = e.get_elements('titre')[0].get_text\r
-         url = e.get_elements('url')[0].get_text         \r
-         fichiers = e.get_elements('fichiers')[0].get_elements('fichier')\r
-         annee = e.get_elements('annee')[0].get_text\r
-         duree = e.get_elements('duree')[0].get_text\r
-         critiquePresse = e.get_elements('critiquePresse')[0].get_text\r
-         critiqueSpectateur = e.get_elements('critiqueSpectateur')[0].get_text\r
-         synopsis = e.get_elements('synopsis')[0].get_elements('p')\r
-         budget = e.get_elements('budget')[0].get_text  \r
-         realisateurs = e.get_elements('realisateurs')[0].get_elements('realisateur')\r
-         acteurs = e.get_elements('acteurs')[0].get_elements('acteur')\r
-         pays = e.get_elements('lespays')[0].get_elements('pays')\r
-         genres = e.get_elements('genres')[0].get_elements('genre')\r
-         \r
-         film = Film::new(fichiers[0].get_text.value, @modClasse::new)\r
-         \r
-         film.id = id\r
-         film.titre = titre.value unless titre.nil?\r
-         \r
-         film.url = url.value unless url.nil?\r
-         \r
-         fichiers.each{|e|\r
-            film.addFichier(e.get_text.value)\r
-            @filmsFichier[e.get_text.value] = film\r
-         }\r
-         film.annee = annee.value unless annee.nil?\r
-         acteurs.each{|e|\r
-            film.acteurs << Personne::ajouter(e.get_text.value)\r
-         }\r
-         pays.each{|e|\r
-            film.pays << Pays::ajouter(e.get_text.value)\r
-         }\r
-         film.duree = duree.value unless duree.nil?\r
-         film.critiquePresse = critiquePresse.value unless critiquePresse.nil?\r
-         film.critiqueSpectateur = critiqueSpectateur.value unless critiqueSpectateur.nil?\r
-         genres.each{|e|\r
-            film.genres << Genre::ajouter(e.get_text.value) if e.get_text != nil\r
-         }\r
-         debut = true\r
-         film.synopsis = ""\r
-         synopsis.each{|e|\r
-            film.synopsis += "\n" unless debut\r
-            film.synopsis += e.get_text.value if e.get_text != nil\r
-            debut = false\r
-         }\r
-         film.budget = budget.value unless budget.nil?\r
-         @films[film.titre] = film\r
-      }\r
-   end\r
-   \r
-   # Retourne un nouvel id, utilisé alors de la création d'un nouveau film\r
-   def getNewId\r
-      id = @idDisponible\r
-      @idDisponible += 1\r
-      return id\r
-   end   \r
-   \r
-   # Ajoute un film\r
-   def ajouterFilm(film)\r
-      if film.plusieursReponses?\r
-         @filmsPlusieursReponses << film\r
-         return\r
-      end\r
-      \r
-      if film.nbReponses == 0\r
-         @filmsAucuneReponse << film\r
-         return\r
-      end\r
-      \r
-      if @films.has_key?(film.titre)\r
-         # le fichier n'est pas connu -> nième partie d'un film\r
-         if !@filmsFichier.has_key?(film.fichiers[0])\r
-            puts "[i] movie #{film.titre} has a another file part : #{film.fichiers[0]}"\r
-            @films[film.titre].addFichier(film.fichiers[0])\r
-            @filmsFichier[film.fichiers[0]] = @films[film.titre]                     \r
-         else\r
-            puts "[!] Duplicate movie : #{film.titre} (#{film.fichiers[0]})"\r
-         end\r
-      else\r
-         puts "[i] movie added : #{film.titre} (#{film.fichiers[0]})"\r
-         @films[film.titre] = film\r
-         @filmsFichier[film.fichiers[0]] = film\r
-      end\r
-   end\r
-   \r
-   # Appelé par 'pomper'. Cette méthode est récursive.\r
-   def pomperR(r)\r
-      Dir::foreach(r){|f|\r
-         next if f[0,1] == '.'\r
-         fichier = (r == '.' ? '' : r + "/") + f\r
-         if File::directory?(fichier)\r
-            pomperR(fichier) \r
-         else\r
-            \r
-            # véfication de l'extension\r
-            /^.*?\.([^.]{3,4})$/ =~ fichier\r
-            if !FILMS_EXTENSIONS.include?($1)\r
-               next\r
-            end\r
-            \r
-            fichier = CGI::escapeHTML(Iconv.iconv("UTF-8", "ISO-8859-1", fichier)[0])\r
-            \r
-            # on skip si le film est déjà dans la BD\r
-            if film = @filmsFichier[fichier]\r
-               puts "[i] Already exists in DB : #{film.titre} (#{fichier})"\r
-               next\r
-            end\r
-            \r
-            film = nil\r
-             \r
-            # pour limiter le nombre de connexion simultanée\r
-            if @nbConn >= NB_CONN_MAX\r
-               @threadsWait.next_wait\r
-            end\r
-             \r
-            @nbConn += 1    \r
-            @threadsWait.join_nowait(\r
-               Thread::new{\r
-                  begin                  \r
-                     film = Film::new(fichier, @modClasse::new)\r
-                     film.id = getNewId # on lui donne un nouvel ID\r
-                     film.loadData # on charge ses données\r
-                     \r
-                     unless film.nil? # le film a été correctement construit\r
-                        ajouterFilm(film)\r
-                     end\r
-                  rescue Exception => e\r
-                     puts e.message\r
-                     puts e.backtrace\r
-                  end\r
-                  @nbConn -= 1\r
-               }\r
-            )\r
-         end\r
-      }\r
-   end\r
-end
\ No newline at end of file
+# coding: utf-8
+
+require 'rexml/document'
+require 'thwait'
+
+require 'film.rb'
+require 'pays.rb'
+require 'genre.rb'
+require 'personne.rb'
+require 'constantes.rb'
+require 'iconv'
+
+# Représente un ensemble de films.
+class Films
+   def initialize(xmlFile, modClasse)
+      @xmlFile = xmlFile
+      
+      @modClasse = modClasse
+      
+      # repertoire de base, par exemple C:/Divx/
+      @repBase = ''   
+         
+      # Les films indexé par leur titre
+      @films = {}
+      
+      # Les films indexé par leur nom de fichier, deux fichiers différents peuvent pointer sur le même film
+      @filmsFichier = {}
+      
+      # Les films qui ont plusieurs réponses lors de la recherche, traité à la fin
+      @filmsPlusieursReponses = []
+
+      # Les films qui n'ont aucune réponse après une recherche, traité à la fin
+      @filmsAucuneReponse = []
+
+      # permet de traiter facilement des groupes de thread
+      @threadsWait = ThreadsWait::new
+      @nbConn = 0 # le nombre de connexion
+      
+      @mutexAjout = Mutex::new # mutex pour protéger l'ajout
+      @mutexId = Mutex::new # mutex pour protéger la génération d'id
+      
+      # le prochain id disponible
+      @idDisponible = 1
+      
+      chargerFilms
+   end
+   
+   def each
+      @films.each{|t,f|
+         yield f
+      }
+   end
+
+   # Lit un repertoire de manière recursive et va chercher les informations concernant le film sur le net.
+   def pomper(r)
+      @repBase = r
+      repPrecedant = Dir::getwd
+      Dir::chdir(r)
+      
+      t = Time::now
+      
+      pomperR('.')
+      
+      # on attends que les threads se terminent
+      @threadsWait.all_waits
+      
+      puts "Pompage terminé, temps : #{Time::now - t} secondes"
+      
+      # traite les films qui avaient plusieurs réponses lors de la recherche
+      # l'utilisateur doit faire un choix
+      i = 1
+      @filmsPlusieursReponses.each{|f|
+         puts
+         puts "Plop, ya un conflit #{i} / #{@filmsPlusieursReponses.length} :"
+         case f.reglerConflitPlusieursReponses
+            when 1
+               ajouterFilm(f)            
+            when 3
+               break
+         end
+         i += 1
+      }
+      
+      # traite les films qui n'avaient aucune réponse
+      i = 1
+      @filmsAucuneReponse.each{|f|
+         puts
+         puts "Plop, Ce film n'a pas été trouvé #{i} / #{@filmsAucuneReponse.length} :"
+         case f.reglerConflitPlusieursReponses
+            when 1
+               ajouterFilm(f)
+            when 3
+               break
+         end
+         i += 1
+      }
+      
+      # annonce à chaque module d'importation que c'est fini
+      @films.each{|t,f|
+         f.mod.finish
+      }
+      
+      Dir::chdir(repPrecedant)      
+   end
+   
+   # Mise à jour des films dans la BD.
+   # p1 string : un motif Regex correspondant à un ou plusieurs champs
+   def update(champ, titre)
+      @films.each{|t, f|
+         next if !f.titre.match(Regexp::new(titre, true))
+                  
+         ## si le film est complet on ne fait rien
+         if $force || f.url == nil || f.titre == '' || f.annee == nil ||
+            f.realisateurs.empty? || f.acteurs.empty? || f.pays.empty? ||
+            f.genres.empty? || f.synopsis == nil || !f.possedeImage?
+            
+            f.update(champ)
+         end
+      }
+   end
+   
+   # Sauve les films dans un fichier XML
+   def sauverFilms
+      #puts self # print all files before saving in XML
+
+      # le document
+      docXml = REXML::Document::new
+      docXml.xml_decl().encoding = "UTF-8"  # normalement UTF-8
+      docXml.xml_decl().dowrite
+            
+      # la racine du document
+      racine = REXML::Element::new('filmographie')
+      docXml.add(racine)
+      pi = REXML::Instruction.new("xml-stylesheet", "type=\"text/xsl\" href=\"../xsl/yopyop.xsl\"")
+      racine.previous_sibling = pi
+      
+      # on ajoute chaque film à la racine
+      @films.each{|nom, f|
+         racine.add(f.getXml)
+      } 
+      
+      # sauve le document
+     docXml.write(File::new(@xmlFile, 'w'))
+   end   
+
+   def to_s
+     acc = ""
+     @films.each_value{|f|
+       acc += f.to_s
+     }
+     return acc
+   end
+   
+   private
+   
+   # Enlève les \n et espace au début et à la fin de 'texte' et retourne le résultat
+   def nettoyer_texte(texte)
+      texte =~ /^[\n ]*(.*?)[\n ]*$/
+      return $1
+   end
+      
+   # Charge les films depuis le fichier XML
+   def chargerFilms
+      # si le fichier n'existe pas il n'y a rien à charger
+      if !File.exists?(@xmlFile)
+         return
+      end
+            
+      racine = REXML::Document::new(File::new(@xmlFile)).root
+      racine.elements.each("film"){|e| 
+         id = e.attribute('id').to_s.to_i
+       
+         if id >= @idDisponible
+            @idDisponible = id + 1
+         end
+         
+         film = Film::new(nil, @modClasse::new)
+         film.id = id
+         
+         film.titre = e.get_text('titre')
+         film.titre = nettoyer_texte(film.titre.value) if film.titre != nil
+         
+         print "#{film.titre}.. "
+         
+         film.url = e.get_text('url')
+         film.url = nettoyer_texte(film.url.value) if film.url != nil
+
+         film.annee = e.get_text('annee')
+         film.annee = nettoyer_texte(film.annee.value) if film.annee != nil         
+         
+         film.duree = e.get_text('duree')
+         film.duree = nettoyer_texte(film.duree.value) if film.duree != nil
+         
+         film.critiquePresse = e.get_text('critiquePresse')
+         film.critiquePresse = nettoyer_texte(film.critiquePresse.value) if film.critiquePresse != nil
+         
+         film.critiqueSpectateur = e.get_text('critiqueSpectateur')
+         film.critiqueSpectateur = nettoyer_texte(film.critiqueSpectateur.value) if film.critiqueSpectateur != nil
+         
+         film.budget = e.get_text('budget')
+         film.budget = nettoyer_texte(film.budget.value) if film.budget != nil
+         
+         e.elements.each('fichiers/fichier'){|f|
+            next if f.get_text == nil
+            film.addFichier(nettoyer_texte(f.get_text.value))
+            @filmsFichier[nettoyer_texte(f.get_text.value)] = film
+         }
+         
+         e.elements.each('realisateurs/realisateur'){|f|
+            film.realisateurs << Personne::ajouter(nettoyer_texte(f.get_text.value))
+         }
+         
+         e.elements.each('acteurs/acteur'){|f|
+            film.acteurs << Personne::ajouter(nettoyer_texte(f.get_text.value))
+         }
+         
+         e.elements.each('lespays/pays'){|f|
+            film.pays << Pays::ajouter(nettoyer_texte(f.get_text.value))
+         }
+         
+         e.elements.each('genres/genre'){|f|
+            film.genres << Genre::ajouter(nettoyer_texte(f.get_text.value))
+         }       
+         
+         debut = true
+         film.synopsis = ""
+         e.elements.each('synopsis/p'){|f|
+            film.synopsis += "\n" unless debut            
+            film.synopsis += nettoyer_texte(f.get_text.value) if f.get_text != nil
+            debut = false
+         }                  
+         film.synopsis = nil if film.synopsis == ""
+                  
+         @films[film.titre] = film
+      }
+   end
+   
+   # Retourne un nouvel id, utilisé alors de la création d'un nouveau film
+   def getNewId
+      id = @idDisponible
+      @idDisponible += 1
+      return id
+   end   
+   
+   # Ajoute un film à l'ensemble des films.
+   def ajouterFilm(film)
+      if film.plusieursReponses?
+         @filmsPlusieursReponses << film
+         return
+      end
+      
+      if film.nbReponses == 0
+         @filmsAucuneReponse << film
+         return
+      end
+      
+      if @films.has_key?(film.titre)
+         if !@filmsFichier.has_key?(film.fichiers[0])
+            puts "[i] Le film #{film.titre} possède une autre partie : #{film.fichiers[0]}"
+            @films[film.titre].addFichier(film.fichiers[0])
+            @filmsFichier[film.fichiers[0]] = @films[film.titre]                     
+         else
+            puts "[!] Film déjà dans la BD : #{film.titre} (#{film.fichiers[0]})"
+         end
+      else
+         puts "[i] Film ajouté : (#{film.id}) #{film.titre} (#{film.fichiers[0]}) #{film.id}"
+         @films[film.titre] = film
+         @filmsFichier[film.fichiers[0]] = film
+      end
+   end
+   
+   # Appelé par 'pomper'. Cette méthode itère récursivement sur l'arborescence d'un repertoire.
+   def pomperR(r)
+      Dir::foreach(r){|f|
+         next if f[0,1] == '.'
+         fichier = (r == '.' ? '' : r + "/") + f
+         if File::directory?(fichier)
+            pomperR(fichier) 
+         else            
+            #fichier = Iconv.iconv("UTF-8", "ISO-8859-1", fichier)[0]
+                        
+            # véfication de l'extension
+            /^.*?\.([^.]{3,4})$/ =~ fichier
+            if !FILMS_EXTENSIONS.include?($1)
+               next
+            end
+                                    
+            # on skip si le film est déjà dans la BD
+            if film = @filmsFichier[fichier]
+              puts "[!] Film déjà dans la BD : (#{film.id}) #{film.titre} (#{film.fichiers[0]})"
+               next
+            end
+             
+            # pour limiter le nombre de connexion simultanée
+            if @nbConn >= NB_CONN_MAX
+               @threadsWait.next_wait
+            end
+             
+            @nbConn += 1    
+            @threadsWait.join_nowait(
+               Thread::start{
+                  begin
+                     film = Film::new(fichier, @modClasse::new)
+                     @mutexId.synchronize{
+                        film.id = getNewId # on lui donne un nouvel ID
+                     }
+                     
+                     film.loadData # chargement de ses données
+                     
+                     @mutexAjout.synchronize{
+                        ajouterFilm(film)
+                     }
+                  rescue Exception => e
+                     puts e.message
+                     puts e.backtrace
+                  end
+                  @nbConn -= 1
+               }
+            )
+         end
+      }
+   end
+end