be1ebf959788636ce2846bda3c4505de2fd0c6c8
[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 # le document
125 docXml = REXML::Document::new
126 docXml.xml_decl().encoding = "UTF-8" # normalement UTF-8
127 docXml.xml_decl().dowrite
128
129 # la racine du document
130 racine = REXML::Element::new('filmographie')
131 docXml.add(racine)
132 pi = REXML::Instruction.new("xml-stylesheet", "type=\"text/xsl\" href=\"../xsl/yopyop.xsl\"")
133 racine.previous_sibling = pi
134
135 # on ajoute chaque film à la racine
136 @films.each{|nom, f|
137 racine.add(f.getXml)
138 }
139
140 # sauve le document
141 docXml.write(File::new(@xmlFile, 'w'), 0)
142 end
143
144 private
145
146 # Charge les films depuis le fichier XML
147 def chargerFilms
148 # si le fichier n'existe pas il n'y a rien à charger
149 if !File.exists?(@xmlFile)
150 return
151 end
152
153 racine = REXML::Document::new(File::new(@xmlFile)).root
154 racine.each_element{|e|
155 id = e.attribute('id').to_s.to_i
156
157 if id >= @idDisponible
158 @idDisponible = id + 1
159 end
160
161 titre = e.get_elements('titre')[0].get_text
162 url = e.get_elements('url')[0].get_text
163 fichiers = e.get_elements('fichiers')[0].get_elements('fichier')
164 annee = e.get_elements('annee')[0].get_text
165 duree = e.get_elements('duree')[0].get_text
166 critiquePresse = e.get_elements('critiquePresse')[0].get_text
167 critiqueSpectateur = e.get_elements('critiqueSpectateur')[0].get_text
168 synopsis = e.get_elements('synopsis')[0].get_elements('p')
169 budget = e.get_elements('budget')[0].get_text
170 realisateurs = e.get_elements('realisateurs')[0].get_elements('realisateur')
171 acteurs = e.get_elements('acteurs')[0].get_elements('acteur')
172 pays = e.get_elements('lespays')[0].get_elements('pays')
173 genres = e.get_elements('genres')[0].get_elements('genre')
174
175 film = Film::new(fichiers[0].get_text.value, @modClasse::new)
176
177 film.id = id
178 film.titre = titre.value unless titre.nil?
179
180 film.url = url.value unless url.nil?
181
182 fichiers.each{|e|
183 film.addFichier(e.get_text.value)
184 @filmsFichier[e.get_text.value] = film
185 }
186 film.annee = annee.value unless annee.nil?
187 acteurs.each{|e|
188 film.acteurs << Personne::ajouter(e.get_text.value)
189 }
190 realisateurs.each{|e|
191 film.realisateurs << Personne::ajouter(e.get_text.value)
192 }
193 pays.each{|e|
194 film.pays << Pays::ajouter(e.get_text.value)
195 }
196 film.duree = duree.value unless duree.nil?
197 film.critiquePresse = critiquePresse.value unless critiquePresse.nil?
198 film.critiqueSpectateur = critiqueSpectateur.value unless critiqueSpectateur.nil?
199 genres.each{|e|
200 film.genres << Genre::ajouter(e.get_text.value) if e.get_text != nil
201 }
202 debut = true
203 film.synopsis = ""
204 synopsis.each{|e|
205 film.synopsis += "\n" unless debut
206 film.synopsis += e.get_text.value if e.get_text != nil
207 debut = false
208 }
209 film.synopsis = nil if film.synopsis == ""
210 film.budget = budget.value unless budget.nil?
211 @films[film.titre] = film
212 }
213 end
214
215 # Retourne un nouvel id, utilisé alors de la création d'un nouveau film
216 def getNewId
217 id = @idDisponible
218 @idDisponible += 1
219 return id
220 end
221
222 # Ajoute un film à l'ensemble des films.
223 def ajouterFilm(film)
224 if film.plusieursReponses?
225 @filmsPlusieursReponses << film
226 return
227 end
228
229 if film.nbReponses == 0
230 @filmsAucuneReponse << film
231 return
232 end
233
234 if @films.has_key?(film.titre)
235 if !@filmsFichier.has_key?(film.fichiers[0])
236 puts "[i] Le film #{film.titre} possède une autre partie : #{film.fichiers[0]}"
237 @films[film.titre].addFichier(film.fichiers[0])
238 @filmsFichier[film.fichiers[0]] = @films[film.titre]
239 else
240 puts "[!] Film déjà dans la BD : #{film.titre} (#{film.fichiers[0]})"
241 end
242 else
243 puts "[i] Film ajouté : #{film.titre} (#{film.fichiers[0]})"
244 @films[film.titre] = film
245 @filmsFichier[film.fichiers[0]] = film
246 end
247 end
248
249 # Appelé par 'pomper'. Cette méthode itère récursivement sur l'arborescence d'un repertoire.
250 def pomperR(r)
251 Dir::foreach(r){|f|
252 next if f[0,1] == '.'
253 fichier = (r == '.' ? '' : r + "/") + f
254 if File::directory?(fichier)
255 pomperR(fichier)
256 else
257
258 #CGI::escapeHTML(
259 fichier = Iconv.iconv("UTF-8", "ISO-8859-1", fichier)[0]
260
261 # véfication de l'extension
262 /^.*?\.([^.]{3,4})$/ =~ fichier
263 if !FILMS_EXTENSIONS.include?($1)
264 next
265 end
266
267 # on skip si le film est déjà dans la BD
268 if film = @filmsFichier[fichier]
269 puts "[!] Film déjà dans la BD : #{film.titre} (#{film.fichiers[0]})"
270 next
271 end
272
273 # pour limiter le nombre de connexion simultanée
274 if @nbConn >= NB_CONN_MAX
275 @threadsWait.next_wait
276 end
277
278 @nbConn += 1
279 @threadsWait.join_nowait(
280 Thread::start{
281 begin
282 film = Film::new(fichier, @modClasse::new)
283 @mutexId.synchronize {
284 film.id = getNewId # on lui donne un nouvel ID
285 }
286 film.loadData # on charge ses données
287
288 @mutexAjout.synchronize {
289 ajouterFilm(film)
290 }
291 rescue Exception => e
292 puts e.message
293 puts e.backtrace
294 end
295 @nbConn -= 1
296 }
297 )
298 end
299 }
300 end
301 end