FIX Gestion de l'utf8
[pompage.git] / src / film.rb
1 require 'rexml/document'
2 require 'net/http'
3 require 'thread'
4 require 'thwait'
5 require 'cgi'
6
7 require 'pays.rb'
8 require 'genre.rb'
9 require 'personne.rb'
10
11 require 'constantes.rb'
12
13 class Film
14 attr_accessor :titre, :fichier, :annee, :realisateurs, :acteurs, :pays, :duree, :critiquePresse, :critiqueSpectateur, :genres, :synopsis, :budget
15
16 # Les films indexés par leur titre
17 @@films = {}
18
19 # Les films indexés par leur nom de fichier
20 @@filmsFichier = {}
21
22 @@mutex = Mutex::new
23 @@threadsWait = ThreadsWait::new
24 @@nbConn = 0
25
26
27 # Lit un repertoire de manière recursive
28 def Film::litRepertoire(r)
29 Film::litRepertoireR(r)
30 # on attends que les threads se terminent
31 @@threadsWait.all_waits
32 end
33
34 # Charge les films contenus dans un fichier XML.
35 def Film::loadFilmsXml(xmlFile)
36 # si le fichier n'existe pas il n'y a rien à charger
37 if !File.exists?(xmlFile)
38 return
39 end
40
41 racine = REXML::Document::new(File::new(xmlFile)).root
42 racine.each_element{|e|
43 fichier = e.get_elements('fichier')[0].get_text
44 next if fichier == nil
45 titre = e.get_elements('titre')[0].get_text
46 annee = e.get_elements('annee')[0].get_text
47 duree = e.get_elements('duree')[0].get_text
48 critiquePresse = e.get_elements('critiquePresse')[0].get_text
49 critiqueSpectateur = e.get_elements('critiqueSpectateur')[0].get_text
50 synopsis = e.get_elements('synopsis')[0].get_text
51 budget = e.get_elements('budget')[0].get_text
52 realisateurs = e.get_elements('realisateur')
53 acteurs = e.get_elements('acteur')
54 pays = e.get_elements('pays')
55 genres = e.get_elements('genres')
56
57
58 film = Film::new(fichier.value)
59 film.titre = titre.value unless titre.nil?
60 film.annee = annee.value unless annee.nil?
61 realisateurs.each{|e|
62 film.realisateurs << Personne::ajouter(e.get_text.value)
63 }
64 acteurs.each{|e|
65 film.acteurs << Personne::ajouter(e.get_text.value)
66 }
67 pays.each{|e|
68 film.pays << Pays::ajouter(e.get_text.value)
69 }
70 film.duree = duree.value unless duree.nil?
71 film.critiquePresse = critiquePresse.value unless critiquePresse.nil?
72 film.critiqueSpectateur = critiqueSpectateur.value unless critiqueSpectateur.nil?
73 genres.each{|e|
74 film.genres << Genre::ajouter(e.get_text.value)
75 }
76 film.synopsis = synopsis.value unless synopsis.nil?
77 film.budget = budget.value unless budget.nil?
78 @@films[film.titre] = film
79 @@filmsFichier[film.fichier] = film
80 }
81 end
82
83 # Renvoie tous les films sous la forme d'un document XML.
84 def Film::getFilmsXml
85 # le document
86 docXml = REXML::Document::new
87 docXml.xml_decl().encoding = "UTF-8" # normalement UTF-8
88 docXml.xml_decl().dowrite
89
90 # la racine du document
91 racine = REXML::Element::new('filmographie')
92 docXml.add(racine)
93
94 # on ajoute chaque film à la racine
95 @@films.each{|nom, f|
96 racine.add(f.getXml)
97 }
98
99 # revoie le document
100 docXml
101 end
102
103 private
104
105 def Film::filmsFactory(fichier)
106 /^.*?\.(.{3,4})$/ =~ fichier
107 if FILMS_EXTENSIONS.include?($1)
108 Film::new(fichier).loadData
109 end
110 end
111
112 def Film::litRepertoireR(r)
113 Dir::foreach(r){|f|
114 next if f == '.' or f == '..'
115 fichier = r + "/" + f
116 if File::directory?(fichier)
117 litRepertoireR(fichier)
118 else
119
120 #si le film n'existe pas déjà dans la liste
121 if film = @@filmsFichier[fichier]
122 puts "[i] Already exists in DB : #{film.titre} (#{film.fichier})"
123 next
124 end
125
126 film = nil
127
128 @@nbConn += 1
129 @@threadsWait.join_nowait(
130 Thread::new{
131 begin
132 @@mutex.lock if @@nbConn >= NB_CONN_MAX
133 film = Film::filmsFactory(fichier)
134 unless film.nil?
135 if @@films.has_key?(film.titre)
136 puts "[!] Duplicate movie : #{film.titre} (#{film.fichier})"
137 else
138 puts "[i] movie added : #{film.titre} (#{film.fichier})"
139 @@films[film.titre] = film
140 @@filmsFichier[film.fichier] = film
141 end
142 end
143 @@nbConn -= 1
144 #p @@nbConn
145 @@mutex.unlock
146 rescue Exception => e
147 puts e.message
148 puts e.backtrace
149 end
150 }
151 )
152 end
153 }
154 end
155
156
157 def initialize(fichier)
158 #convertit le code latin-1 en UTF8
159 @fichier = fichier.unpack("C*").pack("U*")
160
161 @titre = ''
162 @annee = nil
163 @realisateurs = []
164 @acteurs = []
165 @pays = []
166 @duree = nil
167 @critiquePresse = nil
168 @critiqueSpectateur = nil
169 @genres = []
170 @synopsis = nil
171 @budget = nil
172 @budgetUnite = 'euro'
173 @url
174 end
175
176 public
177
178 # Charge les informations du films à partir d'allocine.fr
179 # ret [Film]
180 def loadData
181 unless LOAD_DATA
182 @titre = @fichier
183 return self
184 end
185
186 connexionHttp = Net::HTTP::new('www.allocine.fr');
187
188 #extrait le nom à partir du nom du fichier
189 /^.*?([^\/]*?)\.(.{3,4})$/ =~ @fichier
190 #remplace undescores et points par des espaces
191 titre = $1.gsub(/[_\.]/, ' ')
192 #remplace les suites d'espaces par un seul
193 titre.gsub!(/ {2,}/,' ')
194 titre.gsub!(/\[.*?\]/,'')
195 titre.gsub!(/\(.*?\)/,'')
196 titre.gsub!(/\{.*?\}/,'')
197 #vire les espaces au début et à la fin
198 titre.strip!
199
200 @titre = titre.dup
201
202 donneesHtml = nil
203 begin
204 reponse, donneesHtml = connexionHttp.get("/recherche/?motcle=#{CGI::escape(titre)}")
205
206 #convertit le code latin-1 en UTF8
207 donneesHtml = donneesHtml.unpack("C*").pack("U*")
208
209 #si pas trouvé alors on enlève un mot à la fin
210 if /.*?Pas de résultats.*?/ =~ donneesHtml
211 /(.*?)[^ ]+?$/ =~ titre.strip
212 titre = $1
213 titre.strip!
214 else
215 break;
216 end
217 end while not titre.nil? and not titre.empty?
218
219 unless titre.nil? or titre.empty?
220 /<a href="\/film\/fichefilm_gen_cfilm=(\d+)\.html" class="link1">/ =~ donneesHtml
221 if $1
222 r, ficheHtml = connexionHttp.get("/film/fichefilm_gen_cfilm=#{$1}.html")
223
224 #convertit le code latin-1 en UTF8
225 ficheHtml = ficheHtml.unpack("C*").pack("U*")
226
227 #url
228 @url = "http://www.allocine.fr/film/fichefilm_gen_cfilm=#{$1}.html"
229
230 # Titre
231 /<title>(.*?)<\/title>/ =~ ficheHtml
232 @titre = $1 unless $1.nil?
233
234 puts "Movie found : #{@titre} (#{@fichier})"
235
236 # Année
237 /<h4>Année de production : (\d+)<\/h4>/ =~ ficheHtml
238 @annee = $1.to_i unless $1.nil?
239
240 # Réalisateurs
241 /<h4>Réalisé par(.*?)<\/h4>/ =~ ficheHtml
242 $1.scan(/<a class="link1" href=".*?">(.*?)<\/a>/m){|a|
243 @realisateurs << Personne::ajouter(a[0]) unless a[0].nil?
244 } unless $1.nil?
245
246 # Acteurs
247 /<h4>Avec(.*?)<\/h4>/ =~ ficheHtml
248 $1.scan(/<a class="link1" href="\/personne\/fichepersonne_gen_cpersonne=\d+\.html">(.+?)<\/a>/m){|a|
249 @acteurs << Personne::ajouter(a[0]) unless a[0].nil?
250 } unless $1.nil?
251
252
253 # Pays
254 /<h4>Film (.*?)\.&nbsp;<\/h4>/ =~ ficheHtml
255 $1.split(',').each{|pays|
256 @pays << Pays::ajouter(pays) unless pays.nil?
257 } unless $1.nil?
258
259 # Duree
260 /<h4>Durée : (\d+)h (\d+)min./ =~ ficheHtml
261 @duree = $1.nil? ? $2.to_i : $1.to_i * 60 + $2.to_i
262
263 # Critiques presse et spectateur
264 /Presse.*etoile_([012345]).*Spectateurs.*etoile_([012345])"/m =~ ficheHtml
265 @critiquePresse = $1.to_i unless $1.nil?
266 @critiqueSpectateur = $2.to_i unless $2.nil?
267
268 # Genre
269 /<h4>Genre : (.*?)<\/h4>/ =~ ficheHtml
270 $1.scan(/<a href="\/film\/alaffiche_genre_gen_genre=.*?" class="link1">(.+?)<\/a>/m){|g|
271 @genres << Genre::ajouter(g[0]) unless g[0].nil?
272 } unless $1.nil?
273
274 # Synopsis
275 /Synopsis.*?<h4>(.+?)<\/h4>/m =~ ficheHtml
276 @synopsis = $1 unless $1.nil?
277
278 # Budget
279 /Budget<\/b> : (.+?) millions d'euros<\/h4>/ =~ ficheHtml
280 @budget = $1.to_i unless $1.nil?
281 else
282 puts "[!] Movie not found : #{@titre} (#{@fichier})"
283 end
284 end
285 self
286 end
287
288 # Renvoie un film sous la forme d'un élément XML de type REXML
289 def getXml
290 racine = REXML::Element::new('film')
291 racine.add(REXML::Element::new('fichier').add_text(@fichier))
292 racine.add(REXML::Element::new('titre').add_text(@titre))
293 racine.add(REXML::Element::new('annee').add_text(@annee.to_s))
294
295 realisateurs = REXML::Element::new('realisateurs')
296 @realisateurs.each{|r|
297 realisateurs.add(REXML::Element::new('realisateur').add_text(r.nom))
298 }
299 racine.add(realisateurs)
300
301 acteurs = REXML::Element::new('acteurs')
302 @acteurs.each{|a|
303 acteurs.add(REXML::Element::new('acteur').add_text(a.nom))
304 }
305 racine.add(acteurs)
306
307 lespays = REXML::Element::new('lespays')
308 @pays.each{|p|
309 lespays.add(REXML::Element::new('pays').add_text(p.nom))
310 }
311 racine.add(lespays)
312
313 racine.add(REXML::Element::new('duree').add_text(@duree.to_s))
314
315 racine.add(REXML::Element::new('critiquePresse').add_text(@critiquePresse.to_s))
316 racine.add(REXML::Element::new('critiqueSpectateur').add_text(@critiqueSpectateur.to_s))
317
318 genres = REXML::Element::new('genres')
319 @genres.each{|g|
320 genres.add(REXML::Element::new('genre').add_text(g.nom))
321 }
322 racine.add(genres)
323
324 racine.add(REXML::Element::new('synopsis').add_text(@synopsis))
325 budgetElement = REXML::Element::new('budget')
326 budgetElement.add_text(@budget.to_s)
327 budgetElement.add_attribute('unite', @budgetUnite)
328 racine.add(budgetElement)
329
330 racine.add(REXML::Element::new('url').add_text(@url))
331
332 racine
333 end
334 end
335