-# 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
-\r
-class Films\r
- def initialize(xmlFile)\r
- @xmlFile = xmlFile\r
- \r
- # repertoire de base, par exemple C:/Divx/\r
- @repBase = '' \r
- \r
- # Les films indexés par leur titre\r
- @films = {}\r
- \r
- # Les films indexés 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és à la fin\r
- @filmsPlusieursReponses = []\r
-\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
- pomperR('.')\r
- \r
- # on attends que les threads se terminent\r
- @threadsWait.all_waits\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
- if f.reglerConflitPlusieursReponses\r
- ajouterFilm(f)\r
- end\r
- i += 1\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
- \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)\r
- \r
- film.titre = titre.value unless titre.nil?\r
- film.id = id\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é lors 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
- # le film existe déjà\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
- litRepertoireR(fichier) \r
- else\r
- \r
- # vérification de l'extension\r
- /^.*?\.(.{3,4})$/ =~ fichier\r
- if !FILMS_EXTENSIONS.include?($1)\r
- next\r
- end\r
- \r
- fichier = CGI::escapeHTML(fichier.unpack("C*").pack("U*"))\r
- \r
- # on skip si le film est déjàa 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).loadData\r
- film.id = getNewId # on lui donne un nouvel ID\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