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