Merge lp:~mblayman/entertainer/videolibz into lp:entertainer

Proposed by Matt Layman
Status: Merged
Approved by: Matt Layman
Approved revision: 478
Merged at revision: not available
Proposed branch: lp:~mblayman/entertainer/videolibz
Merge into: lp:entertainer
Diff against target: 1557 lines (+290/-836)
12 files modified
entertainerlib/client/media_player.py (+4/-11)
entertainerlib/client/medialibrary/videos.py (+216/-704)
entertainerlib/gui/screens/factory.py (+1/-0)
entertainerlib/gui/screens/movie.py (+12/-13)
entertainerlib/gui/screens/tv_episodes.py (+13/-19)
entertainerlib/gui/screens/tv_series.py (+9/-8)
entertainerlib/gui/tabs/movies_tab.py (+6/-6)
entertainerlib/gui/tabs/series_tab.py (+3/-4)
entertainerlib/gui/tabs/video_clips_tab.py (+2/-2)
entertainerlib/tests/mock.py (+21/-66)
entertainerlib/tests/test_mediaplayer.py (+1/-2)
entertainerlib/tests/test_screenfactory.py (+2/-1)
To merge this branch: bzr merge lp:~mblayman/entertainer/videolibz
Reviewer Review Type Date Requested Status
Matt Layman Approve
Review via email: mp+22770@code.launchpad.net

Commit message

Video classes are now more Pythonic and do not talk directly to the database anymore.

Description of the change

I did the same clean up to the video library as I did early to the music library. Now all the video classes are just plain Python objects. Any method that talks to the database has been pushed into some factory methods in the VideoLibrary. This leaves only the VideoLibrary to work with when we move away from directly using the database directly (first to Storm, then to Twisted probably).

To post a comment you must log in.
Revision history for this message
Matt Layman (mblayman) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'entertainerlib/client/media_player.py'
--- entertainerlib/client/media_player.py 2009-12-21 22:21:55 +0000
+++ entertainerlib/client/media_player.py 2010-04-03 23:02:16 +0000
@@ -15,17 +15,10 @@
15from entertainerlib.logger import Logger15from entertainerlib.logger import Logger
1616
17class MediaPlayer(gobject.GObject, object):17class MediaPlayer(gobject.GObject, object):
18 '''18 '''MediaPlayer uses Gstreamer to play all video and audio files. Entertainer
19 MediaPlayer class for Entertainer19 has only one MediaPlayer object at runtime. MediaPlayer can play objects
2020 that implement Playable interface.'''
21 MediaPlayer uses Gstreamer backend and is able to play all video and audio21
22 files that gstreamer supports. Entertainer has only one MediaPlayer object
23 at runtime.
24
25 MediaPlayer can play objects that implement Playable interface. These
26 classes are Track, Movie, TVEpisode, Movie, VideoClip and CompactDiscTrack.
27 (and Channel in the future)
28 '''
29 __gsignals__ = {22 __gsignals__ = {
30 'play' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),23 'play' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
31 'pause' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),24 'pause' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, () ),
3225
=== modified file 'entertainerlib/client/medialibrary/videos.py'
--- entertainerlib/client/medialibrary/videos.py 2010-04-03 14:33:37 +0000
+++ entertainerlib/client/medialibrary/videos.py 2010-04-03 23:02:16 +0000
@@ -2,15 +2,14 @@
2'''Video Library - Interface for Entertainer video library cache'''2'''Video Library - Interface for Entertainer video library cache'''
33
4import os4import os
5
5from pysqlite2 import dbapi2 as sqlite6from pysqlite2 import dbapi2 as sqlite
67
7from entertainerlib.client.medialibrary.playable import Playable8from entertainerlib.client.medialibrary.playable import Playable
8from entertainerlib.configuration import Configuration9from entertainerlib.configuration import Configuration
9from entertainerlib.logger import Logger10
1011class VideoLibrary(object):
1112 '''Interface for Entertainer's video cache.'''
12class VideoLibrary:
13 """Interface for Entertainer's video cache."""
1413
15 def __init__(self):14 def __init__(self):
16 self.config = Configuration()15 self.config = Configuration()
@@ -18,778 +17,291 @@
18 if not os.path.exists(self.config.VIDEO_DB):17 if not os.path.exists(self.config.VIDEO_DB):
19 raise Exception("Video database doesn't exist!")18 raise Exception("Video database doesn't exist!")
2019
20 self.connection = sqlite.connect(self.config.VIDEO_DB)
21 self.cursor = self.connection.cursor()
22
23 def __del__(self):
24 '''Close the db connection when this object is deleted.'''
25 self.connection.close()
26
21 def get_movies(self):27 def get_movies(self):
22 """28 '''Get all the movies.'''
23 Get all movies29 self.cursor.execute("""SELECT videofile.filename
24 @return: List of Movie objects
25 """
26 connection = sqlite.connect(self.config.VIDEO_DB)
27 cursor = connection.cursor()
28 cursor.execute("""SELECT videofile.filename
29 FROM videofile, metadata30 FROM videofile, metadata
30 WHERE type='MOVIE'31 WHERE type='MOVIE'
31 AND videofile.filename=metadata.filename32 AND videofile.filename=metadata.filename
32 ORDER BY title""")33 ORDER BY title""")
33 movies = []34 movies = []
34 for row in cursor:35 for row in self.cursor.fetchall():
35 movies.append(Movie(row[0]))36 movies.append(self._create_movie(row[0]))
36 connection.close()
37 return movies37 return movies
3838
39 def _create_movie(self, filename):
40 '''Factory method to create a movie.'''
41 self.cursor.execute(
42 """SELECT metadata.filename, hash, length, resolution,
43 title, runtime, genres, rating, year,
44 plot_outline, plot, actor_1, actor_2,
45 actor_3, actor_4, actor_5, writer_1,
46 writer_2, director_1, director_2
47 FROM videofile, metadata
48 WHERE metadata.filename=:fn
49 AND videofile.filename=metadata.filename
50 ORDER BY title""", { "fn" : filename })
51 result = self.cursor.fetchall()
52 db_movie = result[0]
53
54 movie = Movie()
55 movie.filename = db_movie[0]
56 movie.art_hash = db_movie[1]
57 movie.title = db_movie[4]
58 movie.runtime = db_movie[5]
59 movie.genres = db_movie[6].split(',')
60 movie.plot = db_movie[10]
61 movie.rating = db_movie[7]
62 movie.short_plot = db_movie[9]
63 movie.year = db_movie[8]
64
65 for i in range(11, 16):
66 if len(db_movie[i]) > 0:
67 movie.actors.append(db_movie[i])
68
69 for i in [16, 17]:
70 if len(db_movie[i]) > 0:
71 movie.writers.append(db_movie[i])
72
73 for i in [18, 19]:
74 if len(db_movie[i]) > 0:
75 movie.directors.append(db_movie[i])
76
77 return movie
78
39 def get_tv_series(self):79 def get_tv_series(self):
40 """80 '''Get all the TV series.'''
41 Get all TV-series.81 self.cursor.execute("""SELECT DISTINCT series_title
42 @return: List of TV-series titles (strings)
43 """
44 connection = sqlite.connect(self.config.VIDEO_DB)
45 cursor = connection.cursor()
46 cursor.execute("""SELECT DISTINCT series_title
47 FROM metadata82 FROM metadata
48 WHERE type='TV-SERIES'83 WHERE type='TV-SERIES'
49 ORDER BY title""")84 ORDER BY title""")
50 series = []85 series = []
51 for row in cursor:86 for row in self.cursor.fetchall():
52 series.append(TVSeries(row[0]))87 series.append(self._create_tv_series(row[0]))
53 connection.close()
54 return series88 return series
5589
90 def _create_tv_series(self, title):
91 '''Factory method to create a TV series.'''
92 tv_series = TVSeries(title)
93
94 self.cursor.execute(
95 "SELECT DISTINCT season FROM metadata WHERE series_title=:title",
96 { "title" : title })
97 for row in self.cursor.fetchall():
98 tv_series.seasons.append(row[0])
99
100 self.cursor.execute(
101 "SELECT COUNT(filename) FROM metadata WHERE series_title=:title",
102 { "title" : title })
103 result = self.cursor.fetchall()
104 tv_series.number_of_episodes = result[0][0]
105
106 return tv_series
107
56 def get_video_clips(self):108 def get_video_clips(self):
57 """109 '''Get all the video clips.'''
58 Get List of videos that or not movies or tv-series episodes.110 self.cursor.execute("""SELECT filename
59 @return: List of VideoClip objects
60 """
61 connection = sqlite.connect(self.config.VIDEO_DB)
62 cursor = connection.cursor()
63 cursor.execute("""SELECT filename
64 FROM metadata111 FROM metadata
65 WHERE type='CLIP'112 WHERE type='CLIP'
66 ORDER BY title""")113 ORDER BY title""")
67 clips = []114 clips = []
68 for row in cursor:115 for row in self.cursor.fetchall():
69 clips.append(VideoClip(row[0]))116 clips.append(self._create_video_clip(row[0]))
70 connection.close()
71 return clips117 return clips
72118
119 def _create_video_clip(self, filename):
120 '''Factory method to create a video clip.'''
121 self.cursor.execute(
122 """SELECT videofile.filename, hash, title
123 FROM videofile, metadata
124 WHERE videofile.filename=:fn
125 AND videofile.filename=metadata.filename
126 ORDER BY title""", { "fn" : filename })
127 result = self.cursor.fetchall()
128
129 video_item = VideoItem()
130 video_item.filename = result[0][0]
131 video_item.art_hash = result[0][1]
132 video_item.title = result[0][2]
133 return video_item
134
73 def get_number_of_movies(self):135 def get_number_of_movies(self):
74 """136 '''Get the number of movies.'''
75 Get number of movies in the video library137 self.cursor.execute(
76 @return: Integer138 """SELECT COUNT(filename) FROM metadata WHERE type='MOVIE'""")
77 """139 result = self.cursor.fetchall()
78 connection = sqlite.connect(self.config.VIDEO_DB)
79 cursor = connection.cursor()
80 cursor.execute("""SELECT COUNT(filename)
81 FROM metadata
82 WHERE type='MOVIE'""")
83 result = cursor.fetchall()
84 connection.close()
85 return result[0][0]140 return result[0][0]
86141
87 def get_number_of_tv_series(self):142 def get_number_of_tv_series(self):
88 """143 '''Get the number of TV series.'''
89 Get number of TV-series in the video library144 self.cursor.execute("""SELECT DISTINCT COUNT(series_title)
90 @return: Integer
91 """
92 connection = sqlite.connect(self.config.VIDEO_DB)
93 cursor = connection.cursor()
94 cursor.execute("""SELECT DISTINCT COUNT(series_title)
95 FROM metadata145 FROM metadata
96 WHERE type='TV-SERIES'""")146 WHERE type='TV-SERIES'""")
97 result = cursor.fetchall()147 result = self.cursor.fetchall()
98 connection.close()
99 return result[0][0]148 return result[0][0]
100149
101 def get_number_of_video_clips(self):150 def get_number_of_video_clips(self):
102 """151 '''Get the number of video clips.'''
103 Get number of misc. VideoClips in the video library152 self.cursor.execute(
104 @return: Integer153 """SELECT COUNT(filename) FROM metadata WHERE type='CLIP'""")
105 """154 result = self.cursor.fetchall()
106 connection = sqlite.connect(self.config.VIDEO_DB)155 return result[0][0]
107 cursor = connection.cursor()156
108 cursor.execute("""SELECT COUNT(filename)157 def get_episodes_from_season(self, series_title, season_number):
158 '''Get TV episodes from the series' season.'''
159 self.cursor.execute("""SELECT filename
109 FROM metadata160 FROM metadata
110 WHERE type='CLIP'""")161 WHERE series_title=:title
111 result = cursor.fetchall()162 AND season=:season
112 connection.close()163 ORDER BY episode""",
113 return result[0][0]164 { "title" : series_title, "season" : season_number })
165 episodes = []
166 for row in self.cursor.fetchall():
167 episodes.append(self._create_tv_episode(row[0]))
168 return episodes
169
170 def _create_tv_episode(self, filename):
171 '''Factory method to create a TV episode.'''
172 self.cursor.execute(
173 """SELECT videofile.filename, hash, title, plot, episode
174 FROM videofile, metadata
175 WHERE videofile.filename=:fn
176 AND videofile.filename=metadata.filename
177 ORDER BY title""", { "fn" : filename })
178 result = self.cursor.fetchall()
179 db_episode = result[0]
180
181 tv_episode = TVEpisode()
182 tv_episode.filename = db_episode[0]
183 tv_episode.art_hash = db_episode[1]
184 tv_episode.title = db_episode[2]
185 tv_episode.plot = db_episode[3]
186 tv_episode.number = db_episode[4]
187
188 return tv_episode
114189
115190
116class VideoItem(Playable):191class VideoItem(Playable):
117 """192 '''Representation of a playable video item.'''
118 Objects from this class represents video items
119 """
120193
121 def __init__(self):194 def __init__(self):
122 """Initialize the VideoItem object"""195 # XXX: laymansterms - VideoItem should really have a few mandatory
196 # parameters. title, filename, maybe more.
123 Playable.__init__(self)197 Playable.__init__(self)
124 self.config = Configuration()198 self.config = Configuration()
125199
126 #Setting default values200 self._title = ""
127 self.logger = Logger().getLogger(201 self.filename = ""
128 'client.medialibrary.videos.VideoItem')202 self.art_hash = ""
129 self.__title = ""203
130 self.__filename = ""204 def _get_title(self):
131 self.__length = 0205 '''Get the title.'''
132 self.__resolution = ""206 if (self._title == "") or (self._title == None):
133 self.__art_hash = ""207 return self.filename
134208 else:
135 def get_cover_art_url(self):209 return self._title
136 """210
137 Get absolute filename of the cover art image file.211 def _set_title(self, title):
138 @return: String212 '''Set the title.'''
139 """213 self._title = title
140 return os.path.join(self.config.MOVIE_ART_DIR,214
141 self.get_title() + ".jpg")215 title = property(_get_title, _set_title)
142
143 def get_filename(self):
144 """
145 Get filename (abs path) of the VideoItem
146 @return: String
147 """
148 return self.__filename
149
150 def set_filename(self, filename):
151 """
152 Sets the filename of the VideoItem
153 @param filename String
154 """
155 self.__filename = filename
156
157 def get_title(self):
158 """
159 Get title of the VideoItem
160 @return: String
161 """
162 if (self.__title == "") or (self.__title == None):
163 return self.get_filename()
164 else:
165 return self.__title
166
167 def set_title(self, title):
168 """
169 Sets the title of the VideoItem
170 @param title String
171 """
172 self.__title = title
173
174 def get_length(self):
175 """
176 Get length of the VideoItem
177 @return: Integer
178 """
179 return self.__length
180
181 def set_length(self, length):
182 """
183 Sets the length of the VideoItem
184 @param length Integer
185 """
186 self.__length = length
187
188 def get_resolution(self):
189 """
190 Get resolution of the VideoItem
191 @return: String
192 """
193 return self.__resolution
194
195 def set_resolution(self, res):
196 """
197 Sets the resolution of the VideoItem
198 @param res String
199 """
200 self.__resolution = res
201
202 def get_thumbnail_url(self):
203 """
204 Get absolute path of the thumbnail image file.
205 @return: String
206 """
207 if self.get_art_hash() is not None:
208 thumb = os.path.join(self.config.VIDEO_THUMB_DIR,
209 self.get_art_hash() + ".jpg")
210 if os.path.exists(thumb):
211 return thumb
212 else:
213 self.logger.error("Thumbnail does not exist for " + \
214 self.get_filename() + ", using default art instead")
215 return os.path.join(self.config.theme_path,
216 "images/default_movie_art.png")
217 else:
218 self.logger.error("Thumbnail does not exist for " + \
219 self.get_filename() + ", using default art instead")
220 return os.path.join(self.config.theme_path,
221 "images/default_movie_art.png")
222216
223 def has_thumbnail(self):217 def has_thumbnail(self):
224 """218 '''Test if there is a thumbnail.'''
225 Is there a thumbnail for this VideoItem
226 @return Boolean
227 """
228 thumb_path = os.path.join(self.config.VIDEO_THUMB_DIR,219 thumb_path = os.path.join(self.config.VIDEO_THUMB_DIR,
229 self.get_art_hash() + ".jpg")220 self.art_hash + ".jpg")
230 return os.path.exists(thumb_path)221 return os.path.exists(thumb_path)
231222
232 def get_art_hash(self):223 @property
233 """224 def thumbnail_url(self):
234 Gets the art hash225 '''Get the path to the thumbnail or a default.'''
235 @return String226 thumb = os.path.join(self.config.VIDEO_THUMB_DIR,
236 """227 self.art_hash + ".jpg")
237 return self.__art_hash228 if os.path.exists(thumb):
238229 return thumb
239 def set_art_hash(self, arthash):230 else:
240 """231 return os.path.join(self.config.theme_path,
241 Sets the art hash232 "images/default_movie_art.png")
242 @param arthash String
243 """
244 self.__art_hash = arthash
245
246 def has_cover_art(self):
247 """
248 Is there cover art file for this VideoItem
249 @return: Boolean
250 """
251 art_path = os.path.join(self.config.MOVIE_ART_DIR,
252 self.get_title() + ".jpg")
253 return os.path.exists(art_path)
254233
255 # Implement playable interface234 # Implement playable interface
235 def get_title(self):
236 '''Get the title.'''
237 return self.title
238
256 def get_type(self):239 def get_type(self):
257 """240 '''Get the type.'''
258 Track is an video stream.
259 @return: Integer
260 """
261 return Playable.VIDEO_STREAM241 return Playable.VIDEO_STREAM
262242
263 def get_uri(self):243 def get_uri(self):
264 """244 '''Get the URI.'''
265 Get URI of the video file245 return "file://" + self.filename
266 @return: String
267 """
268 return "file://" + self.get_filename()
269246
270247
271class VideoFilm(VideoItem):248class VideoFilm(VideoItem):
272 '''Objects from this class represents video films'''249 '''Generic representation of a film.'''
250
273 def __init__(self):251 def __init__(self):
274 VideoItem.__init__(self)252 VideoItem.__init__(self)
275 #initialise values253 self.actors = []
276 self.__plot_outline = ""254 self.directors = []
277 self.__plot = ""255 self.genres = []
278 self.__actors = []256 self.plot = ''
279 self.__writers = []257 self.runtime = ''
280 self.__directors = []258 self.short_plot = ''
281 self.__runtime = ""259 self.writers = []
282 self.__genres = []260 self.rating = 0
283 self.__rating = 0.0261 self.year = 2000
284 self.__year = 2000
285
286 def get_short_plot(self):
287 """
288 Get plot outline text.
289 @return: String
290 """
291 return self.__plot_outline
292
293 def set_short_plot(self, plot):
294 """
295 Set plot outline
296 @param plot String
297 """
298 self.__plot_outline = plot
299
300 def get_plot(self):
301 """
302 Get long plot text.
303 @return: String
304 """
305 return self.__plot
306
307 def set_plot(self, plot):
308 """
309 Sets the long plot
310 @param plot String
311 """
312 self.__plot = plot
313
314 def get_actors(self):
315 """
316 Get list of actors
317 @return: List of strings
318 """
319 return self.__actors
320
321 def set_actors(self, actors):
322 """
323 Sets list of actors
324 @param actors List of Strings
325 """
326 self.__actors = actors
327
328 def get_writers(self):
329 """
330 Get list of writers
331 @return: List of strings
332 """
333 return self.__writers
334
335 def set_writers(self, writers):
336 """
337 Sets list of writers
338 @param writers List of Strings
339 """
340 self.__writers = writers
341
342 def get_directors(self):
343 """
344 Get list of directors
345 @return: List of strings
346 """
347 return self.__directors
348
349 def set_directors(self, directors):
350 """
351 Sets list of directors
352 @param directors List of Strings
353 """
354 self.__directors = directors
355
356 def get_runtime(self):
357 """
358 Get runtime of the VideoFilm
359 @return: String
360 """
361 return self.__runtime
362
363 def set_runtime(self, run):
364 """
365 Set runtime of the VideoFilm
366 @param run String
367 """
368 self.__runtime = run
369
370 def get_genres(self):
371 """
372 Get list of genre strings
373 @return: List of strings
374 """
375 return self.__genres
376
377 def set_genres(self, genres):
378 """
379 Sets list of genres
380 @param genres List of Strings
381 """
382 self.__genres = genres
383
384 def get_rating(self):
385 """
386 Get rating of the VideoFilm (1-5)
387 @return: Integer
388 """
389 return int(self.__rating)
390
391 def set_rating(self, rating):
392 """
393 Sets rating of the VideoFilm (1-5)
394 @param rating Integer
395 """
396 self.__rating = int(rating)
397
398 def get_year(self):
399 """
400 Get release year of the VideoFilm.
401 @return: String
402 """
403 return int(self.__year)
404
405 def set_year(self, year):
406 """
407 Sets the year of the VideoFilm
408 @param year String
409 """
410 try:
411 self.__year = int(year)
412 except ValueError:
413 self.__year = 0
414 print "Year for Video should be an integer, not: ", year
415
416
417class VideoClip(VideoItem):
418 """
419 Objects from this class represents video files.
420 """
421
422 def __init__(self, filename):
423 """
424 Initialize Clip information
425 @param filename: Absolute path of the video clip file
426 """
427 VideoItem.__init__(self)
428 connection = sqlite.connect(self.config.VIDEO_DB)
429 cursor = connection.cursor()
430 cursor.execute(
431 """SELECT videofile.filename, hash, length, resolution, title
432 FROM videofile, metadata
433 WHERE videofile.filename=:fn
434 AND videofile.filename=metadata.filename
435 ORDER BY title""", { "fn" : filename })
436 result = cursor.fetchall()
437 self.set_filename(result[0][0]) # Filename of the clip
438 self.set_art_hash(result[0][1]) # Cover art hash
439 self.set_length(result[0][2]) # Lenght of the movie
440 self.set_resolution(result[0][3]) # Video resolution
441 self.set_title(result[0][4]) # Clip title
442 connection.close()
443262
444263
445class Movie(VideoFilm):264class Movie(VideoFilm):
446 """265 '''Representation of a movie.'''
447 Objects from this class represents movie.266
448 """267 def has_cover_art(self):
449268 '''Test if there is cover art in the cache.'''
450269 art_path = os.path.join(self.config.MOVIE_ART_DIR, self.title + ".jpg")
451 def __init__(self, filename):270 return os.path.exists(art_path)
452 """271
453 Initialize Movie information272 @property
454 @param filename: Absolute path of the Movie file273 def cover_art_url(self):
455 """274 '''Get the URL to the cover art.'''
456 VideoFilm.__init__(self)275 return os.path.join(self.config.MOVIE_ART_DIR, self.title + ".jpg")
457 connection = sqlite.connect(self.config.VIDEO_DB)
458 cursor = connection.cursor()
459 cursor.execute("""SELECT metadata.filename, hash, length, resolution,
460 title, runtime, genres, rating, year,
461 plot_outline, plot, actor_1, actor_2,
462 actor_3, actor_4, actor_5, writer_1,
463 writer_2, director_1, director_2
464 FROM videofile, metadata
465 WHERE metadata.filename=:fn
466 AND videofile.filename=metadata.filename
467 ORDER BY title""", { "fn" : filename })
468 result = cursor.fetchall()
469 self.set_filename(result[0][0])
470 self.set_art_hash(result[0][1])
471 self.set_length(result[0][2])
472 self.set_resolution(result[0][3])
473 self.set_title(result[0][4])
474 self.set_runtime(result[0][5])
475 self.set_genres(result[0][6].split(','))
476 self.set_rating(result[0][7])
477 self.set_year(result[0][8])
478 self.set_short_plot(result[0][9])
479 self.set_plot(result[0][10])
480 self.set_actors([])
481 self.set_art_hash([])
482 self.set_directors([])
483
484 # Actors
485 if len(result[0][11]) > 0:
486 self.get_actors().append(result[0][11])
487 if len(result[0][12]) > 0:
488 self.get_actors().append(result[0][12])
489 if len(result[0][13]) > 0:
490 self.get_actors().append(result[0][13])
491 if len(result[0][14]) > 0:
492 self.get_actors().append(result[0][14])
493 if len(result[0][15]) > 0:
494 self.get_actors().append(result[0][15])
495
496 # Writers
497 if len(result[0][16]) > 0:
498 self.get_writers().append(result[0][16])
499 if len(result[0][17]) > 0:
500 self.get_writers().append(result[0][17])
501
502 # Directors
503 if len(result[0][18]) > 0:
504 self.get_directors().append(result[0][18])
505 if len(result[0][19]) > 0:
506 self.get_directors().append(result[0][19])
507
508 connection.close()
509276
510277
511class TVSeries(object):278class TVSeries(object):
512 """279 '''TV Series contains TVEpisodes organized by seasons.'''
513 TV Series
514
515 TV Series contains TVEpisodes organized by seasons.
516 """
517280
518 def __init__(self, title):281 def __init__(self, title):
519 """
520 Initialize TV-Series
521 @param title: Series title
522 """
523 self.config = Configuration()282 self.config = Configuration()
524283
525 connection = sqlite.connect(self.config.VIDEO_DB)284 self.number_of_episodes = 0
526 cursor = connection.cursor()285 # Season list of numbers. For example [1,2,3,5] in case that user
527 cursor.execute("""SELECT DISTINCT series_title286 # doesn't have episodes from season 4.
528 FROM metadata287 self.seasons = []
529 WHERE series_title=:title""", { "title" : title })288 self.title = title
530 result = cursor.fetchall()
531 self.__title = None
532 if len(result) == 0:
533 raise Exception("No such TV-series as " + title)
534 else:
535 self.__title = title
536 connection.close()
537
538 def get_title(self):
539 """
540 Get title of the series
541 @return: String
542 """
543 return self.__title
544
545 def set_title(self, title):
546 """
547 Sets title of the series
548 @param title String
549 """
550 self.__title = title
551289
552 def has_cover_art(self):290 def has_cover_art(self):
553 """291 '''Test if there is cover art in the cache.'''
554 Is there cover art file for this TV-serie292 art_path = os.path.join(self.config.MOVIE_ART_DIR, self.title + ".jpg")
555 @return: String
556 """
557 art_path = os.path.join(self.config.MOVIE_ART_DIR,
558 self.get_title() + ".jpg")
559 return os.path.exists(art_path)293 return os.path.exists(art_path)
560294
561 def get_cover_art_url(self):295 @property
562 """296 def cover_art_url(self):
563 Get absolute filename of the cover art image file.297 '''Get the URL to the cover art.'''
564 @return: String298 return os.path.join(self.config.MOVIE_ART_DIR, self.title + ".jpg")
565 """
566 return os.path.join(self.config.MOVIE_ART_DIR,
567 self.get_title() + ".jpg")
568
569 def get_seasons(self):
570 """
571 Return list of numbers. For example [1,2,3,5] in case that user
572 doesn't have episodes from season 4.
573 @return: List of Integers
574 """
575 seasons = []
576 connection = sqlite.connect(self.config.VIDEO_DB)
577 cursor = connection.cursor()
578 cursor.execute("""SELECT DISTINCT season
579 FROM metadata
580 WHERE series_title=:title""",
581 { "title" : self.get_title() })
582 for row in cursor:
583 seasons.append(row[0])
584 connection.close()
585 return seasons
586
587 def get_number_of_episodes(self):
588 """
589 Get number of episodes available on this series
590 @return: Integer
591 """
592 connection = sqlite.connect(self.config.VIDEO_DB)
593 cursor = connection.cursor()
594 cursor.execute("""SELECT COUNT(filename)
595 FROM metadata
596 WHERE series_title=:title""",
597 { "title" : self.get_title() })
598 result = cursor.fetchall()
599 connection.close()
600 return result[0][0]
601
602 def get_number_of_seasons(self):
603 """
604 Get number of seasons available on this series
605 @return: Integer
606 """
607 connection = sqlite.connect(self.config.VIDEO_DB)
608 cursor = connection.cursor()
609 cursor.execute("""SELECT COUNT(DISTINCT season)
610 FROM metadata
611 WHERE series_title=:title""",
612 { "title" : self.get_title() })
613 result = cursor.fetchall()
614 connection.close()
615 return result[0][0]
616
617 def get_episodes_from_season(self, season):
618 """
619 Get all episodes of the season.
620 @param season: Season number (Integer)
621 """
622 episodes = []
623 connection = sqlite.connect(self.config.VIDEO_DB)
624 cursor = connection.cursor()
625 cursor.execute("""SELECT filename, episode
626 FROM metadata
627 WHERE series_title=:title
628 AND season=:season
629 ORDER BY episode""",
630 { "title" : self.get_title(), "season" : season })
631 for row in cursor:
632 episodes.append(TVEpisode(row[0], self))
633 connection.close()
634 return episodes
635
636 def get_episode_from_season(self, season, episode):
637 """
638 Get specific episode from this series.
639 @param season: Season number (Integer)
640 @param episode: Episode number (Integer)
641 @return TVEpisode object
642 """
643 connection = sqlite.connect(self.config.VIDEO_DB)
644 cursor = connection.cursor()
645 cursor.execute("""SELECT filename
646 FROM metadata
647 WHERE series_title=:title
648 AND episode=:episode
649 AND season=:season""",
650 { "title" : self.get_title(),
651 "season" : season,
652 "episode" : episode })
653 result = cursor.fetchall()
654 episode = TVEpisode(result[0][0], self)
655 connection.close()
656 return episode
657
658 def get_episodes(self):
659 """
660 Get all episodes of this series.
661 @return: List of TVEpisode objects
662 """
663 episodes = []
664 connection = sqlite.connect(self.config.VIDEO_DB)
665 cursor = connection.cursor()
666 cursor.execute("""SELECT filename, season, episode
667 FROM metadata
668 WHERE series_title=:title
669 ORDER BY season, episode""",
670 { "title" : self.get_title() })
671 for row in cursor:
672 episodes.append(TVEpisode(row[0], self))
673 connection.close()
674 return episodes
675299
676300
677class TVEpisode(VideoFilm):301class TVEpisode(VideoFilm):
678 """302 '''Representation of a TV show episode.'''
679 Objects from this class represents TV-Episode video file.
680 """
681303
682 def __init__(self, filename, series):304 def __init__(self):
683 """
684 Initialize episode information.
685 @param filename: Name of the video file
686 @param series: TVSeries object
687 """
688 VideoFilm.__init__(self)305 VideoFilm.__init__(self)
689 connection = sqlite.connect(self.config.VIDEO_DB)306 self.number = 0
690 cursor = connection.cursor()
691 cursor.execute("""SELECT videofile.filename, hash, length, resolution,
692 title, runtime, genres, rating, year,
693 plot_outline, plot, actor_1, actor_2,
694 actor_3, actor_4, actor_5, writer_1,
695 writer_2, director_1, director_2,
696 series_title, season, episode
697 FROM videofile, metadata
698 WHERE videofile.filename=:fn
699 AND videofile.filename=metadata.filename
700 ORDER BY title""", { "fn" : filename })
701 result = cursor.fetchall()
702 self.set_filename(result[0][0])
703 self.set_art_hash(result[0][1])
704 self.set_length(result[0][2])
705 self.set_resolution(result[0][3])
706 self.set_title(result[0][4])
707 self.set_runtime(result[0][5])
708 self.set_genres(result[0][6].split(','))
709 self.set_rating(result[0][7])
710 self.set_year(result[0][8])
711 self.set_short_plot(result[0][9])
712 self.set_plot(result[0][10])
713
714 # Actors
715 self.set_actors([])
716 if len(result[0][11]) > 0:
717 self.get_actors().append(result[0][11])
718 if len(result[0][12]) > 0:
719 self.get_actors().append(result[0][12])
720 if len(result[0][13]) > 0:
721 self.get_actors().append(result[0][13])
722 if len(result[0][14]) > 0:
723 self.get_actors().append(result[0][14])
724 if len(result[0][15]) > 0:
725 self.get_actors().append(result[0][15])
726
727 # Writers
728 self.set_writers([])
729 if len(result[0][16]) > 0:
730 self.get_writers().append(result[0][16])
731 if len(result[0][17]) > 0:
732 self.get_writers().append(result[0][17])
733
734 # Directors
735 self.set_directors([])
736 if len(result[0][18]) > 0:
737 self.get_directors().append(result[0][18])
738 if len(result[0][19]) > 0:
739 self.get_directors().append(result[0][19])
740
741 self.__series = series
742 self.__season = result[0][21]
743 self.__episode_number = result[0][22]
744 connection.close()
745
746 def get_cover_art_url(self):
747 """
748 Get absolute filename of the cover art image file.
749 @return: String
750 """
751 return os.path.join(self.config.MOVIE_ART_DIR,
752 self.get_series() + ".jpg")
753
754 def get_series(self):
755 """
756 Get TV-series
757 @return: TVSeries objects
758 """
759 return self.__series
760
761 def set_series(self, series):
762 """
763 Sets TV-Series
764 @param series TVSeries
765 """
766 self.__series = series
767
768 def get_episode_number(self):
769 """
770 Get number of the episode
771 @return: Integer
772 """
773 return int(self.__episode_number)
774
775 def set_episode_number(self, num):
776 """
777 Sets the number of the episode
778 @param num Integer
779 """
780 self.__episode_number = int(num)
781
782 def get_season(self):
783 """
784 Get number of the season
785 @return: Interger
786 """
787 return int(self.__season)
788
789 def set_season(self, season):
790 """
791 Sets number of the season
792 @param season Integer
793 """
794 self.__season = int(season)
795307
796308
=== modified file 'entertainerlib/gui/screens/factory.py'
--- entertainerlib/gui/screens/factory.py 2010-04-02 22:28:04 +0000
+++ entertainerlib/gui/screens/factory.py 2010-04-03 23:02:16 +0000
@@ -135,6 +135,7 @@
135 def _generate_tv_series(self, kwargs):135 def _generate_tv_series(self, kwargs):
136 '''Generate a TvSeries screen.'''136 '''Generate a TvSeries screen.'''
137 kwargs['move_to_new_screen_callback'] = self.move_to_new_screen_callback137 kwargs['move_to_new_screen_callback'] = self.move_to_new_screen_callback
138 kwargs['video_library'] = self.video_library
138 return TvSeries(**kwargs)139 return TvSeries(**kwargs)
139140
140 def _generate_tv_episodes(self, kwargs):141 def _generate_tv_episodes(self, kwargs):
141142
=== modified file 'entertainerlib/gui/screens/movie.py'
--- entertainerlib/gui/screens/movie.py 2009-12-22 00:07:29 +0000
+++ entertainerlib/gui/screens/movie.py 2010-04-03 23:02:16 +0000
@@ -45,8 +45,7 @@
4545
46 # Movie art texture46 # Movie art texture
47 if self.movie.has_cover_art():47 if self.movie.has_cover_art():
48 pixbuf = gtk.gdk.pixbuf_new_from_file(48 pixbuf = gtk.gdk.pixbuf_new_from_file(self.movie.cover_art_url)
49 self.movie.get_cover_art_url())
50 else:49 else:
51 pixbuf = gtk.gdk.pixbuf_new_from_file(50 pixbuf = gtk.gdk.pixbuf_new_from_file(
52 self.theme.getImage("default_movie_art"))51 self.theme.getImage("default_movie_art"))
@@ -54,21 +53,21 @@
54 self.add(movie_art)53 self.add(movie_art)
5554
56 # Movie title55 # Movie title
57 title = Label(0.04, "title", 0.47, 0.1, self.movie.get_title(),56 title = Label(0.04, "title", 0.47, 0.1, self.movie.title,
58 font_weight="bold")57 font_weight="bold")
59 title.set_ellipsize(pango.ELLIPSIZE_END)58 title.set_ellipsize(pango.ELLIPSIZE_END)
60 title.set_size(0.5124, 0.05208)59 title.set_size(0.5124, 0.05208)
61 self.add(title)60 self.add(title)
6261
63 # Movie release year62 # Movie release year
64 year_text = _("Released in %(year)s") % {'year': self.movie.get_year()}63 year_text = _("Released in %(year)s") % {'year': self.movie.year}
65 year = Label(0.032, "subtitle", 0.47, 0.3, year_text)64 year = Label(0.032, "subtitle", 0.47, 0.3, year_text)
66 year.set_ellipsize(pango.ELLIPSIZE_END)65 year.set_ellipsize(pango.ELLIPSIZE_END)
67 year.set_size(0.5124, 0.05208)66 year.set_size(0.5124, 0.05208)
68 self.add(year)67 self.add(year)
6968
70 # Show only 2 genres (or one if there is only one)69 # Show only 2 genres (or one if there is only one)
71 genres_list = self.movie.get_genres()70 genres_list = self.movie.genres
72 if len(genres_list) == 0:71 if len(genres_list) == 0:
73 genres_text = _("Unknown")72 genres_text = _("Unknown")
74 else:73 else:
@@ -76,7 +75,7 @@
7675
77 # Runtime and genres76 # Runtime and genres
78 info_text = _("%(runtime)s min, %(genre)s") % \77 info_text = _("%(runtime)s min, %(genre)s") % \
79 {'runtime': self.movie.get_runtime(), 'genre': genres_text}78 {'runtime': self.movie.runtime, 'genre': genres_text}
80 info = Label(0.032, "subtitle", 0.47, 0.24, info_text)79 info = Label(0.032, "subtitle", 0.47, 0.24, info_text)
81 info.set_ellipsize(pango.ELLIPSIZE_END)80 info.set_ellipsize(pango.ELLIPSIZE_END)
82 info.set_size(0.5124, 0.05208)81 info.set_size(0.5124, 0.05208)
@@ -90,7 +89,7 @@
90 star2.hide()89 star2.hide()
91 self.add(star2)90 self.add(star2)
9291
93 for i in range(self.movie.get_rating()):92 for i in range(self.movie.rating):
94 tex = clutter.Clone(star)93 tex = clutter.Clone(star)
95 tex.set_position(94 tex.set_position(
96 self.get_abs_x(0.47) + (self.get_abs_x(0.0366) * i),95 self.get_abs_x(0.47) + (self.get_abs_x(0.0366) * i),
@@ -98,16 +97,16 @@
98 tex.set_size(self.get_abs_x(0.024), self.get_abs_y(0.04))97 tex.set_size(self.get_abs_x(0.024), self.get_abs_y(0.04))
99 self.add(tex)98 self.add(tex)
10099
101 dark_star = 5 - self.movie.get_rating()100 dark_star = 5 - self.movie.rating
102 for i in range(dark_star):101 for i in range(dark_star):
103 tex = clutter.Clone(star2)102 tex = clutter.Clone(star2)
104 tex.set_position(self.get_abs_x(0.47) + (self.get_abs_x(0.0366) * \103 tex.set_position(self.get_abs_x(0.47) + (self.get_abs_x(0.0366) * \
105 (i+ self.movie.get_rating())), self.get_abs_y(0.17))104 (i + self.movie.rating)), self.get_abs_y(0.17))
106 tex.set_size(self.get_abs_x(0.024), self.get_abs_y(0.04))105 tex.set_size(self.get_abs_x(0.024), self.get_abs_y(0.04))
107 self.add(tex)106 self.add(tex)
108107
109 # Plot108 # Plot
110 plot = Label(0.029, "subtitle", 0, 0, self.movie.get_plot())109 plot = Label(0.029, "subtitle", 0, 0, self.movie.plot)
111 plot.set_justify(True)110 plot.set_justify(True)
112 plot.set_line_wrap_mode(pango.WRAP_WORD)111 plot.set_line_wrap_mode(pango.WRAP_WORD)
113 plot.set_line_wrap(True)112 plot.set_line_wrap(True)
@@ -118,7 +117,7 @@
118 # Actors117 # Actors
119 self.add(Label(0.032, "title", 0.33, 0.8, _("Starring")))118 self.add(Label(0.032, "title", 0.33, 0.8, _("Starring")))
120119
121 actors_list = self.movie.get_actors()120 actors_list = self.movie.actors
122 if len(actors_list) == 0:121 if len(actors_list) == 0:
123 actors_text = _("Unknown")122 actors_text = _("Unknown")
124 else:123 else:
@@ -131,7 +130,7 @@
131 # Directors130 # Directors
132 self.add(Label(0.032, "title", 0.33, 0.86, _("Directed by")))131 self.add(Label(0.032, "title", 0.33, 0.86, _("Directed by")))
133132
134 directors_list = self.movie.get_directors()133 directors_list = self.movie.directors
135 if len(directors_list) == 0:134 if len(directors_list) == 0:
136 directors_text = _("Unknown")135 directors_text = _("Unknown")
137 else:136 else:
@@ -144,7 +143,7 @@
144 # Writers143 # Writers
145 self.add(Label(0.032, "title", 0.33, 0.92, _("Written by")))144 self.add(Label(0.032, "title", 0.33, 0.92, _("Written by")))
146145
147 writers_list = self.movie.get_writers()146 writers_list = self.movie.writers
148 if len(directors_list) == 0:147 if len(directors_list) == 0:
149 writers_text = _("Unknown")148 writers_text = _("Unknown")
150 else:149 else:
151150
=== modified file 'entertainerlib/gui/screens/tv_episodes.py'
--- entertainerlib/gui/screens/tv_episodes.py 2009-12-22 00:34:27 +0000
+++ entertainerlib/gui/screens/tv_episodes.py 2010-04-03 23:02:16 +0000
@@ -14,18 +14,17 @@
14class TvEpisodes(Screen):14class TvEpisodes(Screen):
15 '''Screen contains list of all episodes of one specific season.'''15 '''Screen contains list of all episodes of one specific season.'''
1616
17 def __init__(self, media_player, move_to_new_screen_callback,17 def __init__(self, media_player, move_to_new_screen_callback, episodes,
18 season_number, tv_series):18 tv_series):
19 Screen.__init__(self, 'TvEpisodes', move_to_new_screen_callback)19 Screen.__init__(self, 'TvEpisodes', move_to_new_screen_callback)
2020
21 self.episodes = episodes
21 self.media_player = media_player22 self.media_player = media_player
22 self.theme = self.config.theme23 self.theme = self.config.theme
23 self.tv_series = tv_series24 self.tv_series = tv_series
24 self.season_number = season_number
2525
26 # Screen Title (Displayed at the bottom left corner)26 # Screen Title (Displayed at the bottom left corner)
27 screen_title = Label(0.13, "screentitle", 0, 0.87,27 screen_title = Label(0.13, "screentitle", 0, 0.87, self.tv_series.title)
28 self.tv_series.get_title())
29 self.add(screen_title)28 self.add(screen_title)
3029
31 self.scroll_area = None30 self.scroll_area = None
@@ -37,8 +36,7 @@
3736
38 #List indicator37 #List indicator
39 self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)38 self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)
40 self.li.set_maximum(39 self.li.set_maximum(len(self.episodes))
41 len(self.tv_series.get_episodes_from_season(self.season_number)))
42 self.add(self.li)40 self.add(self.li)
4341
44 self.menu.connect("moved", self._update_episode_info)42 self.menu.connect("moved", self._update_episode_info)
@@ -49,10 +47,9 @@
49 """Create a list of available seasons."""47 """Create a list of available seasons."""
50 menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)48 menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)
5149
52 episodes = self.tv_series.get_episodes_from_season(self.season_number)
53 episodes_list = [[_("%(num)d. %(title)s") % \50 episodes_list = [[_("%(num)d. %(title)s") % \
54 {'num': episode.get_episode_number(), 'title': episode.get_title()},51 {'num': episode.number, 'title': episode.title},
55 None, episode] for episode in episodes]52 None, episode] for episode in self.episodes]
56 menu.async_add(episodes_list)53 menu.async_add(episodes_list)
5754
58 menu.active = True55 menu.active = True
@@ -65,7 +62,7 @@
65 self.thumb.hide()62 self.thumb.hide()
6663
67 # Thumbnail. Use cover art if thumbnail doesn't exist64 # Thumbnail. Use cover art if thumbnail doesn't exist
68 thumbnail = self.menu.selected_userdata.get_thumbnail_url()65 thumbnail = self.menu.selected_userdata.thumbnail_url
69 if(thumbnail is not None):66 if(thumbnail is not None):
70 pixbuf = gtk.gdk.pixbuf_new_from_file(thumbnail)67 pixbuf = gtk.gdk.pixbuf_new_from_file(thumbnail)
71 thumb_width = 0.292868 thumb_width = 0.2928
@@ -79,7 +76,7 @@
79 thumb_y = 0.1576 thumb_y = 0.15
80 if(self.tv_series.has_cover_art()):77 if(self.tv_series.has_cover_art()):
81 pixbuf = gtk.gdk.pixbuf_new_from_file(78 pixbuf = gtk.gdk.pixbuf_new_from_file(
82 self.tv_series.get_cover_art_url())79 self.tv_series.cover_art_url)
83 else:80 else:
84 pixbuf = gtk.gdk.pixbuf_new_from_file(81 pixbuf = gtk.gdk.pixbuf_new_from_file(
85 self.theme.getImage("default_movie_art"))82 self.theme.getImage("default_movie_art"))
@@ -97,16 +94,14 @@
9794
98 # Title95 # Title
99 self.title = Label(0.04, "title", 0.05, 0.55,96 self.title = Label(0.04, "title", 0.05, 0.55,
100 self.menu.selected_userdata.get_title(),97 self.menu.selected_userdata.title, font_weight="bold")
101 font_weight="bold")
102 self.title.set_ellipsize(pango.ELLIPSIZE_END)98 self.title.set_ellipsize(pango.ELLIPSIZE_END)
103 self.title.set_line_wrap(False)99 self.title.set_line_wrap(False)
104 self.title.width = 0.4100 self.title.width = 0.4
105 self.add(self.title)101 self.add(self.title)
106102
107 # Plot103 # Plot
108 plot = Label(0.029, "subtitle", 0, 0,104 plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
109 self.menu.selected_userdata.get_plot())
110 plot.width = 0.4105 plot.width = 0.4
111106
112 self.scroll_area = ScrollArea(0.05, 0.63, 0.4, 0.15, plot)107 self.scroll_area = ScrollArea(0.05, 0.63, 0.4, 0.15, plot)
@@ -118,11 +113,10 @@
118 self.li.set_current(self.menu.selected_index + 1)113 self.li.set_current(self.menu.selected_index + 1)
119114
120 self._create_thumbnail_texture()115 self._create_thumbnail_texture()
121 self.title.set_text(self.menu.selected_userdata.get_title())116 self.title.set_text(self.menu.selected_userdata.title)
122 self.title.width = 0.4117 self.title.width = 0.4
123118
124 plot = Label(0.029, "subtitle", 0, 0,119 plot = Label(0.029, "subtitle", 0, 0, self.menu.selected_userdata.plot)
125 self.menu.selected_userdata.get_plot())
126 plot.width = 0.4120 plot.width = 0.4
127 self.scroll_area.set_content(plot)121 self.scroll_area.set_content(plot)
128122
129123
=== modified file 'entertainerlib/gui/screens/tv_series.py'
--- entertainerlib/gui/screens/tv_series.py 2009-07-29 03:09:34 +0000
+++ entertainerlib/gui/screens/tv_series.py 2010-04-03 23:02:16 +0000
@@ -12,15 +12,15 @@
12class TvSeries(Screen):12class TvSeries(Screen):
13 '''Screen that contains all seasons of one TV series.'''13 '''Screen that contains all seasons of one TV series.'''
1414
15 def __init__(self, move_to_new_screen_callback, tv_series):15 def __init__(self, video_library, move_to_new_screen_callback, tv_series):
16 Screen.__init__(self, 'TvSeries', move_to_new_screen_callback)16 Screen.__init__(self, 'TvSeries', move_to_new_screen_callback)
1717
18 self.theme = self.config.theme18 self.theme = self.config.theme
19 self.tv_series = tv_series19 self.tv_series = tv_series
20 self.video_library = video_library
2021
21 # Screen Title (Displayed at the bottom left corner)22 # Screen Title (Displayed at the bottom left corner)
22 screen_title = Label(0.13, "screentitle", 0, 0.87,23 screen_title = Label(0.13, "screentitle", 0, 0.87, self.tv_series.title)
23 self.tv_series.get_title())
24 self.add(screen_title)24 self.add(screen_title)
2525
26 self.art = None26 self.art = None
@@ -31,7 +31,7 @@
3131
32 #List indicator32 #List indicator
33 self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)33 self.li = ListIndicator(0.8, 0.9, 0.2, 0.045, ListIndicator.VERTICAL)
34 self.li.set_maximum(len(self.tv_series.get_seasons()))34 self.li.set_maximum(len(self.tv_series.seasons))
35 self.add(self.li)35 self.add(self.li)
3636
37 self.menu.connect("moved", self._update_season_info)37 self.menu.connect("moved", self._update_season_info)
@@ -43,7 +43,7 @@
43 """43 """
44 menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)44 menu = TextMenu(0.4978, 0.1563, 0.4393, 0.0781)
4545
46 seasons = self.tv_series.get_seasons()46 seasons = self.tv_series.seasons
47 seasons.sort()47 seasons.sort()
4848
49 seasons_list = [[_("Season %(num)s") % {'num': season}, None, season] \49 seasons_list = [[_("Season %(num)s") % {'num': season}, None, season] \
@@ -60,8 +60,7 @@
60 displays album cover art.60 displays album cover art.
61 """61 """
62 if(self.tv_series.has_cover_art()):62 if(self.tv_series.has_cover_art()):
63 pixbuf = gtk.gdk.pixbuf_new_from_file(63 pixbuf = gtk.gdk.pixbuf_new_from_file(self.tv_series.cover_art_url)
64 self.tv_series.get_cover_art_url())
65 else:64 else:
66 pixbuf = gtk.gdk.pixbuf_new_from_file(65 pixbuf = gtk.gdk.pixbuf_new_from_file(
67 self.theme.getImage("default_movie_art"))66 self.theme.getImage("default_movie_art"))
@@ -83,6 +82,8 @@
83 def _handle_select(self, event=None):82 def _handle_select(self, event=None):
84 '''Handle UserEvent.NAVIGATE_SELECT.'''83 '''Handle UserEvent.NAVIGATE_SELECT.'''
85 season = self.menu.selected_userdata84 season = self.menu.selected_userdata
86 kwargs = { 'tv_series' : self.tv_series, 'season_number' : season }85 episodes = self.video_library.get_episodes_from_season(
86 self.tv_series.title, season)
87 kwargs = { 'episodes' : episodes, 'tv_series' : self.tv_series }
87 self.callback("tv_episodes", kwargs)88 self.callback("tv_episodes", kwargs)
8889
8990
=== modified file 'entertainerlib/gui/tabs/movies_tab.py'
--- entertainerlib/gui/tabs/movies_tab.py 2009-12-21 17:22:33 +0000
+++ entertainerlib/gui/tabs/movies_tab.py 2010-04-03 23:02:16 +0000
@@ -80,7 +80,7 @@
80 menu.visible_cols = 780 menu.visible_cols = 7
8181
82 movies = self.video_library.get_movies()82 movies = self.video_library.get_movies()
83 movies_list = [[movie.get_cover_art_url(), movie] for movie in movies]83 movies_list = [[movie.cover_art_url, movie] for movie in movies]
84 menu.async_add_videos(movies_list)84 menu.async_add_videos(movies_list)
8585
86 # Create list indicator86 # Create list indicator
@@ -114,17 +114,17 @@
114 '''Update the movie information labels.'''114 '''Update the movie information labels.'''
115 if self.active:115 if self.active:
116 movie = self.menu.selected_userdata116 movie = self.menu.selected_userdata
117 genres = movie.get_genres()117 genres = movie.genres
118 if len(genres) > 1:118 if len(genres) > 1:
119 genre = genres[0] + "/" + genres[1]119 genre = genres[0] + "/" + genres[1]
120 else:120 else:
121 genre = genres[0]121 genre = genres[0]
122122
123 self.movie_title.set_text(_("%(title)s (%(year)d)") % \123 self.movie_title.set_text(_("%(title)s (%(year)s)") % \
124 {'title': movie.get_title(), 'year': movie.get_year()})124 {'title': movie.title, 'year': movie.year})
125 self.movie_info.set_text(_("%(min)d min, (%(genre)s)") % \125 self.movie_info.set_text(_("%(min)d min, (%(genre)s)") % \
126 {'min': movie.get_runtime(), 'genre': genre})126 {'min': movie.runtime, 'genre': genre})
127 self.movie_plot.set_text(movie.get_short_plot())127 self.movie_plot.set_text(movie.short_plot)
128 self.list_indicator.show()128 self.list_indicator.show()
129 self.list_indicator.set_current(self.menu.selected_index + 1)129 self.list_indicator.set_current(self.menu.selected_index + 1)
130 else:130 else:
131131
=== modified file 'entertainerlib/gui/tabs/series_tab.py'
--- entertainerlib/gui/tabs/series_tab.py 2009-12-21 17:22:33 +0000
+++ entertainerlib/gui/tabs/series_tab.py 2010-04-03 23:02:16 +0000
@@ -79,7 +79,7 @@
79 menu.visible_cols = 779 menu.visible_cols = 7
8080
81 series = self.video_library.get_tv_series()81 series = self.video_library.get_tv_series()
82 series_list = [[serie.get_cover_art_url(), serie] for serie in series]82 series_list = [[serie.cover_art_url, serie] for serie in series]
83 menu.async_add_videos(series_list)83 menu.async_add_videos(series_list)
8484
85 # Create list indicator85 # Create list indicator
@@ -107,11 +107,10 @@
107 if self.active:107 if self.active:
108 series = self.menu.selected_userdata108 series = self.menu.selected_userdata
109 info = _("%(season)d Seasons\n%(episode)d Episodes") % {'season':109 info = _("%(season)d Seasons\n%(episode)d Episodes") % {'season':
110 series.get_number_of_seasons(), 'episode':110 len(series.seasons), 'episode': series.number_of_episodes}
111 series.get_number_of_episodes()}
112111
113 self.series_info.set_text(info)112 self.series_info.set_text(info)
114 self.series_title.set_text(series.get_title())113 self.series_title.set_text(series.title)
115 self.list_indicator.show()114 self.list_indicator.show()
116 self.list_indicator.set_current(self.menu.selected_index + 1)115 self.list_indicator.set_current(self.menu.selected_index + 1)
117 else:116 else:
118117
=== modified file 'entertainerlib/gui/tabs/video_clips_tab.py'
--- entertainerlib/gui/tabs/video_clips_tab.py 2009-12-21 17:22:33 +0000
+++ entertainerlib/gui/tabs/video_clips_tab.py 2010-04-03 23:02:16 +0000
@@ -79,7 +79,7 @@
79 menu.visible_cols = 479 menu.visible_cols = 4
8080
81 clips = self.video_library.get_video_clips()81 clips = self.video_library.get_video_clips()
82 clips_list = [[clip.get_thumbnail_url(), clip] for clip in clips]82 clips_list = [[clip.thumbnail_url, clip] for clip in clips]
83 menu.async_add_clips(clips_list)83 menu.async_add_clips(clips_list)
8484
85 # Create list indicator85 # Create list indicator
@@ -109,7 +109,7 @@
109 '''Update the VideoClip information labels.'''109 '''Update the VideoClip information labels.'''
110 if self.active:110 if self.active:
111 clip = self.menu.selected_userdata111 clip = self.menu.selected_userdata
112 (folder, filename) = os.path.split(clip.get_filename())112 (folder, filename) = os.path.split(clip.filename)
113 self.clip_title.set_text(filename)113 self.clip_title.set_text(filename)
114 self.clip_info.set_text(folder)114 self.clip_info.set_text(folder)
115 self.list_indicator.show()115 self.list_indicator.show()
116116
=== modified file 'entertainerlib/tests/mock.py'
--- entertainerlib/tests/mock.py 2010-04-02 23:13:48 +0000
+++ entertainerlib/tests/mock.py 2010-04-03 23:02:16 +0000
@@ -84,43 +84,15 @@
84 '''Mock entertainerlib.client.medialibrary.videos.Movie'''84 '''Mock entertainerlib.client.medialibrary.videos.Movie'''
8585
86 def __init__(self, filename=None):86 def __init__(self, filename=None):
87 '''Override init to prevent a database connection'''87 self.actors = ['Tim Robbins']
8888 self.directors = ['Frank Darabont']
89 def get_actors(self):89 self.genres = ['Drama']
90 '''See `Movie.get_actors`.'''90 self.plot = 'An innocent man is sent to prison'
91 return ['Tim Robbins']91 self.rating = 5
9292 self.runtime = ''
93 def get_directors(self):93 self.title = 'The Shawshank Redemption'
94 '''See `Movie.get_directors`.'''94 self.writers = ['Frank Darabont']
95 return ['Frank Darabont']95 self.year = 1994
96
97 def get_genres(self):
98 '''See `Movie.get_genres`.'''
99 return ['Drama']
100
101 def get_plot(self):
102 '''See `Movie.get_plot`.'''
103 return 'An innocent man is sent to prison'
104
105 def get_rating(self):
106 '''See `Movie.get_rating`.'''
107 return 5
108
109 def get_runtime(self):
110 '''See `Movie.get_runtime`.'''
111 return ""
112
113 def get_title(self):
114 '''See `Movie.get_title`.'''
115 return 'The Shawshank Redemption'
116
117 def get_writers(self):
118 '''See `Movie.get_writers`.'''
119 return ['Frank Darabont']
120
121 def get_year(self):
122 '''See `Movie.get_year`.'''
123 return 1994
12496
125 def has_cover_art(self):97 def has_cover_art(self):
126 '''See `Movie.has_cover_art`.'''98 '''See `Movie.has_cover_art`.'''
@@ -158,42 +130,22 @@
158130
159 def __init__(self, title=None):131 def __init__(self, title=None):
160 '''Override init to prevent a database connection'''132 '''Override init to prevent a database connection'''
161133 self.number = 1
162 def get_episode_number(self):134 self.title = 'Something clever'
163 '''See `TVEpisode.get_episode_number`.'''135 self.plot = 'Dr. House continues to be a jerk'
164 return 1136
165137 @property
166 def get_plot(self):138 def thumbnail_url(self):
167 '''See `TVEpisode.get_plot`.'''139 '''Thumbnail URL getter.'''
168 return 'Dr. House continues to be a jerk'
169
170 def get_thumbnail_url(self):
171 '''See `TVEpisode.get_thumbnail_url`.'''
172 return None140 return None
173141
174 def get_title(self):
175 '''See `TVEpisode.get_title`.'''
176 return 'Something clever'
177
178
179class MockTVSeries(TVSeries):142class MockTVSeries(TVSeries):
180 '''Mock entertainerlib.client.medialibrary.videos.TVSeries'''143 '''Mock entertainerlib.client.medialibrary.videos.TVSeries'''
181144
182 def __init__(self, title=None):145 def __init__(self, title=None):
183 '''Override init to prevent a database connection'''146 '''Override init to prevent a database connection'''
184147 self.seasons = []
185 def get_episodes_from_season(self, season_number=1):148 self.title = 'House'
186 '''See `TVSeries.get_episodes_from_season`.'''
187 mock_episode = MockTVEpisode()
188 return [mock_episode]
189
190 def get_seasons(self):
191 '''See `TVSeries.get_seasons`.'''
192 return []
193
194 def get_title(self):
195 '''See `TVSeries.get_title`.'''
196 return 'House'
197149
198 def has_cover_art(self):150 def has_cover_art(self):
199 '''See `TVSeries.has_cover_art`.'''151 '''See `TVSeries.has_cover_art`.'''
@@ -205,6 +157,9 @@
205 def __init__(self):157 def __init__(self):
206 '''Override the intial behavior.'''158 '''Override the intial behavior.'''
207159
160 def __del__(self):
161 '''Override the delete behavior.'''
162
208 def get_number_of_movies(self):163 def get_number_of_movies(self):
209 '''See `VideoLibrary.get_number_of_movies`.'''164 '''See `VideoLibrary.get_number_of_movies`.'''
210 return 0165 return 0
211166
=== modified file 'entertainerlib/tests/test_mediaplayer.py'
--- entertainerlib/tests/test_mediaplayer.py 2009-07-14 04:56:55 +0000
+++ entertainerlib/tests/test_mediaplayer.py 2010-04-03 23:02:16 +0000
@@ -19,8 +19,7 @@
1919
20 self.player = MediaPlayer(clutter.Stage(), 100, 100)20 self.player = MediaPlayer(clutter.Stage(), 100, 100)
21 self.video_item = VideoItem()21 self.video_item = VideoItem()
22 self.video_item.set_filename(22 self.video_item.filename = THIS_DIR + '/data/VideoThumbnailer/test.avi'
23 THIS_DIR + '/data/VideoThumbnailer/test.avi')
24 self.player.set_media(self.video_item)23 self.player.set_media(self.video_item)
2524
26 def test_create(self):25 def test_create(self):
2726
=== modified file 'entertainerlib/tests/test_screenfactory.py'
--- entertainerlib/tests/test_screenfactory.py 2010-04-02 23:13:48 +0000
+++ entertainerlib/tests/test_screenfactory.py 2010-04-03 23:02:16 +0000
@@ -28,6 +28,7 @@
28from entertainerlib.tests.mock import MockMediaPlayer28from entertainerlib.tests.mock import MockMediaPlayer
29from entertainerlib.tests.mock import MockMovie29from entertainerlib.tests.mock import MockMovie
30from entertainerlib.tests.mock import MockMusicLibrary30from entertainerlib.tests.mock import MockMusicLibrary
31from entertainerlib.tests.mock import MockTVEpisode
31from entertainerlib.tests.mock import MockTVSeries32from entertainerlib.tests.mock import MockTVSeries
32from entertainerlib.tests.mock import MockVideoLibrary33from entertainerlib.tests.mock import MockVideoLibrary
3334
@@ -129,7 +130,7 @@
129130
130 def test__generate_tv_episodes(self):131 def test__generate_tv_episodes(self):
131 '''Test _generate_tv_episodes returns a TvEpisodes screen'''132 '''Test _generate_tv_episodes returns a TvEpisodes screen'''
132 self.kwargs['season_number'] = 1133 self.kwargs['episodes'] = [MockTVEpisode()]
133 self.kwargs['tv_series'] = MockTVSeries()134 self.kwargs['tv_series'] = MockTVSeries()
134 screen = self.factory._generate_tv_episodes(self.kwargs)135 screen = self.factory._generate_tv_episodes(self.kwargs)
135 self.assertTrue(isinstance(screen, TvEpisodes))136 self.assertTrue(isinstance(screen, TvEpisodes))

Subscribers

People subscribed via source and target branches