ADD mise à jour de la liste des films
[pompage.git] / src / films.rb
1 # coding: utf-8
2
3 require 'rexml/document'
4 require 'thwait'
5
6 require 'film.rb'
7 require 'pays.rb'
8 require 'genre.rb'
9 require 'personne.rb'
10 require 'constantes.rb'
11 require 'iconv'
12
13 # Représente un ensemble de films.
14 class Films
15 def initialize(xmlFile, modClasse)
16 @xmlFile = xmlFile
17
18 @modClasse = modClasse
19
20 # repertoire de base, par exemple C:/Divx/
21 @repBase = ''
22
23 # Les films indexé par leur titre
24 @films = {}
25
26 # Les films indexé par leur nom de fichier, deux fichiers différents peuvent pointer sur le même film
27 @filmsFichier = {}
28
29 # Les films qui ont plusieurs réponses lors de la recherche, traité à la fin
30 @filmsPlusieursReponses = []
31
32 # Les films qui n'ont aucune réponse après une recherche, traité à la fin
33 @filmsAucuneReponse = []
34
35 # permet de traiter facilement des groupes de thread
36 @threadsWait = ThreadsWait::new
37 @nbConn = 0 # le nombre de connexion
38
39 @mutexAjout = Mutex::new # mutex pour protéger l'ajout
40 @mutexId = Mutex::new # mutex pour protéger la génération d'id
41
42 # le prochain id disponible
43 @idDisponible = 1
44
45 chargerFilms
46 end
47
48 def each
49 @films.each{|t,f|
50 yield f
51 }
52 end
53
54 # Lit un repertoire de manière recursive et va chercher les informations concernant le film sur le net.
55 def pomper(r)
56 @repBase = r
57 repPrecedant = Dir::getwd
58 Dir::chdir(r)
59
60 t = Time::now
61
62 pomperR('.')
63
64 # on attends que les threads se terminent
65 @threadsWait.all_waits
66
67 puts "Pompage terminé, temps : #{Time::now - t} secondes"
68
69 # traite les films qui avaient plusieurs réponses lors de la recherche
70 # l'utilisateur doit faire un choix
71 i = 1
72 @filmsPlusieursReponses.each{|f|
73 puts
74 puts "Plop, ya un conflit #{i} / #{@filmsPlusieursReponses.length} :"
75 case f.reglerConflitPlusieursReponses
76 when 1
77 ajouterFilm(f)
78 when 3
79 break
80 end
81 i += 1
82 }
83
84 # traite les films qui n'avaient aucune réponse
85 i = 1
86 @filmsAucuneReponse.each{|f|
87 puts
88 puts "Plop, Ce film n'a pas été trouvé #{i} / #{@filmsAucuneReponse.length} :"
89 case f.reglerConflitPlusieursReponses
90 when 1
91 ajouterFilm(f)
92 when 3
93 break
94 end
95 i += 1
96 }
97
98 # annonce à chaque module d'importation que c'est fini
99 @films.each{|t,f|
100 f.mod.finish
101 }
102
103 Dir::chdir(repPrecedant)
104 end
105
106 # Mise à jour des films dans la BD.
107 # p1 string : un motif Regex correspondant à un ou plusieurs champs
108 def update(champ, titre)
109 @films.each{|t, f|
110 next if !f.titre.match(Regexp::new(titre, true))
111
112 ## si le film est complet on ne fait rien
113 if $force || f.url == nil || f.titre == '' || f.annee == nil ||
114 f.realisateurs.empty? || f.acteurs.empty? || f.pays.empty? ||
115 f.genres.empty? || f.synopsis == nil || !f.possedeImage?
116
117 f.update(champ)
118 end
119 }
120 end
121
122 # Sauve les films dans un fichier XML
123 def sauverFilms
124 #puts self # print all files before saving in XML
125
126 # le document
127 docXml = REXML::Document::new
128 docXml.xml_decl().encoding = "UTF-8" # normalement UTF-8
129 docXml.xml_decl().dowrite
130
131 # la racine du document
132 racine = REXML::Element::new('filmographie')
133 docXml.add(racine)
134 pi = REXML::Instruction.new("xml-stylesheet", "type=\"text/xsl\" href=\"../xsl/yopyop.xsl\"")
135 racine.previous_sibling = pi
136
137 # on ajoute chaque film à la racine
138 @films.each{|nom, f|
139 racine.add(f.getXml)
140 }
141
142 # sauve le document
143 docXml.write(File::new(@xmlFile, 'w'))
144 end
145
146 def to_s
147 acc = ""
148 @films.each_value{|f|
149 acc += f.to_s
150 }
151 return acc
152 end
153
154 private
155
156 # Enlève les \n et espace au début et à la fin de 'texte' et retourne le résultat
157 def nettoyer_texte(texte)
158 texte =~ /^[\n ]*(.*?)[\n ]*$/
159 return $1
160 end
161
162 # Charge les films depuis le fichier XML
163 def chargerFilms
164 # si le fichier n'existe pas il n'y a rien à charger
165 if !File.exists?(@xmlFile)
166 return
167 end
168
169 racine = REXML::Document::new(File::new(@xmlFile)).root
170 racine.elements.each("film"){|e|
171 id = e.attribute('id').to_s.to_i
172
173 if id >= @idDisponible
174 @idDisponible = id + 1
175 end
176
177 film = Film::new(nil, @modClasse::new)
178 film.id = id
179
180 film.titre = e.get_text('titre')
181 film.titre = nettoyer_texte(film.titre.value) if film.titre != nil
182
183 print "#{film.titre}.. "
184
185 film.url = e.get_text('url')
186 film.url = nettoyer_texte(film.url.value) if film.url != nil
187
188 film.annee = e.get_text('annee')
189 film.annee = nettoyer_texte(film.annee.value) if film.annee != nil
190
191 film.duree = e.get_text('duree')
192 film.duree = nettoyer_texte(film.duree.value) if film.duree != nil
193
194 film.critiquePresse = e.get_text('critiquePresse')
195 film.critiquePresse = nettoyer_texte(film.critiquePresse.value) if film.critiquePresse != nil
196
197 film.critiqueSpectateur = e.get_text('critiqueSpectateur')
198 film.critiqueSpectateur = nettoyer_texte(film.critiqueSpectateur.value) if film.critiqueSpectateur != nil
199
200 film.budget = e.get_text('budget')
201 film.budget = nettoyer_texte(film.budget.value) if film.budget != nil
202
203 e.elements.each('fichiers/fichier'){|f|
204 next if f.get_text == nil
205 film.addFichier(nettoyer_texte(f.get_text.value))
206 @filmsFichier[nettoyer_texte(f.get_text.value)] = film
207 }
208
209 e.elements.each('realisateurs/realisateur'){|f|
210 film.realisateurs << Personne::ajouter(nettoyer_texte(f.get_text.value))
211 }
212
213 e.elements.each('acteurs/acteur'){|f|
214 film.acteurs << Personne::ajouter(nettoyer_texte(f.get_text.value))
215 }
216
217 e.elements.each('lespays/pays'){|f|
218 film.pays << Pays::ajouter(nettoyer_texte(f.get_text.value))
219 }
220
221 e.elements.each('genres/genre'){|f|
222 film.genres << Genre::ajouter(nettoyer_texte(f.get_text.value))
223 }
224
225 debut = true
226 film.synopsis = ""
227 e.elements.each('synopsis/p'){|f|
228 film.synopsis += "\n" unless debut
229 film.synopsis += nettoyer_texte(f.get_text.value) if f.get_text != nil
230 debut = false
231 }
232 film.synopsis = nil if film.synopsis == ""
233
234 @films[film.titre] = film
235 }
236 end
237
238 # Retourne un nouvel id, utilisé alors de la création d'un nouveau film
239 def getNewId
240 id = @idDisponible
241 @idDisponible += 1
242 return id
243 end
244
245 # Ajoute un film à l'ensemble des films.
246 def ajouterFilm(film)
247 if film.plusieursReponses?
248 @filmsPlusieursReponses << film
249 return
250 end
251
252 if film.nbReponses == 0
253 @filmsAucuneReponse << film
254 return
255 end
256
257 if @films.has_key?(film.titre)
258 if !@filmsFichier.has_key?(film.fichiers[0])
259 puts "[i] Le film #{film.titre} possède une autre partie : #{film.fichiers[0]}"
260 @films[film.titre].addFichier(film.fichiers[0])
261 @filmsFichier[film.fichiers[0]] = @films[film.titre]
262 else
263 puts "[!] Film déjà dans la BD : #{film.titre} (#{film.fichiers[0]})"
264 end
265 else
266 puts "[i] Film ajouté : (#{film.id}) #{film.titre} (#{film.fichiers[0]}) #{film.id}"
267 @films[film.titre] = film
268 @filmsFichier[film.fichiers[0]] = film
269 end
270 end
271
272 # Appelé par 'pomper'. Cette méthode itère récursivement sur l'arborescence d'un repertoire.
273 def pomperR(r)
274 Dir::foreach(r){|f|
275 next if f[0,1] == '.'
276 fichier = (r == '.' ? '' : r + "/") + f
277 if File::directory?(fichier)
278 pomperR(fichier)
279 else
280 #fichier = Iconv.iconv("UTF-8", "ISO-8859-1", fichier)[0]
281
282 # véfication de l'extension
283 /^.*?\.([^.]{3,4})$/ =~ fichier
284 if !FILMS_EXTENSIONS.include?($1)
285 next
286 end
287
288 # on skip si le film est déjà dans la BD
289 if film = @filmsFichier[fichier]
290 puts "[!] Film déjà dans la BD : (#{film.id}) #{film.titre} (#{film.fichiers[0]})"
291 next
292 end
293
294 # pour limiter le nombre de connexion simultanée
295 if @nbConn >= NB_CONN_MAX
296 @threadsWait.next_wait
297 end
298
299 @nbConn += 1
300 @threadsWait.join_nowait(
301 Thread::start{
302 begin
303 film = Film::new(fichier, @modClasse::new)
304 @mutexId.synchronize{
305 film.id = getNewId # on lui donne un nouvel ID
306 }
307
308 film.loadData # chargement de ses données
309
310 @mutexAjout.synchronize{
311 ajouterFilm(film)
312 }
313 rescue Exception => e
314 puts e.message
315 puts e.backtrace
316 end
317 @nbConn -= 1
318 }
319 )
320 end
321 }
322 end
323 end