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