def perform(self, query): log.info('EpisodeTagger tagging episode: %s' % toUtf8(query.find_one(Media).filename)) filenameMetadata = SolvingChain(EpisodeFilename()).solve(query) log.info('EpisodeTagger found info from filename: %s' % filenameMetadata.find_one(Episode)) result = SolvingChain(EpisodeTVDB(), SimpleSolver(Episode)).solve(filenameMetadata) media = result.find_one(Media) # if we didn't find a valid episode but we still have a series, let's create a syntactically # valid episode anyway so it can be imported if not media.metadata.get('episodeNumber'): media.metadata.episodeNumber = -1 # import subtitles correctly if media.type() == 'subtitle': subs = [] for language in utils.guessCountryCodes(media.filename): log.info('Found %s sub in file %s' % (toUtf8(language.english_name), toUtf8(media.filename))) subs += [ result.Subtitle(metadata = media.metadata, language = language.alpha2) ] media.metadata = subs self.cleanup(result) log.debug('Finished tagging: %s' % media.filename) return result
def parentChecked(self, index): key = self.key( index ) for checkedKey in [folder for folder in self.selectedFolders() if folder != key ]: if toUtf8(key).startswith(toUtf8(checkedKey) + '/'): return True return False
def perform(self, query): log.info('MovieTagger tagging movie: %s' % toUtf8(query.find_one(Media).filename)) filenameMetadata = MovieFilename().perform(query) filenameMovie = filenameMetadata.find_one(Movie) log.info('MovieTagger found info from filename: %s' % filenameMovie) result = MovieTMDB().perform(filenameMetadata) media = result.find_one(Media) if not media.metadata: log.warning('Could not find any tag for: %s' % media) # import the info we got from the filename if nothing better came in with MovieTMDB for prop in filenameMovie.keys(): if prop not in media.metadata and prop not in media: media[prop] = filenameMovie[prop] # import subtitles correctly if media.type() == 'subtitle': # FIXME: problem for vobsubs: as a media points to a single metadata object, we cannot # represent a .sub for 3 different languages... subs = [] for language in utils.guessCountryCodes(media.filename): subs += [ result.Subtitle(metadata = media.metadata, language = language.alpha2) ] media.metadata = subs self.cleanup(result) log.debug('Finished tagging: %s' % media) return result
def importFiles(self, files): for f in files: # new import task log.info('Import in %s collection: %s' % (self.name, toUtf8(f))) if self.taskManager: importTask = ImportTask(self.graph, self.mediaTagger, f) self.taskManager.add(importTask) # save newly imported files self.saveSettings()
def perform(self, query): self.checkValid(query) log.debug('MovieTvdb: finding more info on %s' % query.find_one(Movie)) movie = query.find_one(Movie) try: mdprovider = TVDBMetadataProvider() result = mdprovider.startMovie(movie.title) except SmewtException, e: # movie could not be found, return a dummy Unknown movie instead so we can group them somewhere log.warning('Could not find info for movie: %s' % toUtf8(query.find_one(Media).filename)) noposter = smewtDirectory('smewt', 'media', 'common', 'images', 'noposter.png') result = MemoryObjectGraph() result.Movie(title = 'Unknown', loresImage = noposter, hiresImage = noposter)
def childChecked(self, index): for checkedKey in self.selectedFolders(): if toUtf8(checkedKey).startswith( toUtf8(self.key( index )) + '/' ): return True return False
class TVDBMetadataProvider(object): def __init__(self): super(TVDBMetadataProvider, self).__init__() self.tvdb = thetvdbapi.TheTVDB("65D91F0290476F3E") self.tmdb = tmdbsimple.TMDB('a8b9f96dde091408a03cb4c78477bd14') self.tmdb.server_config = self.tmdb.Configuration() self.tmdb.server_config.info() self.tmdb.lang = 'en' @cachedmethod def getSeries(self, name): """Get the TVDBPy series object given its name.""" results = self.tvdb.get_matching_shows(name) ''' for id, name, lang in results: # FIXME: that doesn't look correct: either yield or no for return id raise SmewtException("EpisodeTVDB: Could not find series '%s'" % name) ''' if len(results) == 0: raise SmewtException("EpisodeTVDB: Could not find series '%s'" % name) return results @cachedmethod def getEpisodes(self, series, language): """From a given TVDBPy series object, return a graph containing its information as well as its episodes nodes.""" show, episodes = self.tvdb.get_show_and_episodes(series, language=language) # TODO: debug to see if this is the correct way to access the series' title result = MemoryObjectGraph() smewtSeries = result.Series(title=show.name) for episode in episodes: ep = result.Episode(series=smewtSeries, season=episode.season_number, episodeNumber=episode.episode_number) ep.set('title', episode.name) ep.set('synopsis', episode.overview) ep.set('originalAirDate', str(episode.first_aired)) return result @cachedmethod def getMovie(self, name): """Get the IMDBPy movie object given its name.""" if not name: raise SmewtException( 'You need to specify at least a probable name for the movie...' ) log.debug('MovieTMDB: looking for movie %s', name) results = self.tmdb.Search().movie({'query': name})['results'] for r in results: return r['id'] raise SmewtException("MovieTMDB: Could not find movie '%s'" % name) @cachedmethod def getMovieData(self, movieId): """From a given TVDBPy movie object, return a graph containing its information.""" m = self.tmdb.Movies(movieId) resp = m.info({'language': self.tmdb.lang}) result = MemoryObjectGraph() movie = result.Movie(title=unicode(resp['title'])) movie.original_title = resp['original_title'] if resp.get('release_date'): movie.set( 'year', datetime.datetime.strptime(resp['release_date'], '%Y-%m-%d').year) movie.set('genres', [unicode(g['name']) for g in resp['genres']]) movie.set('rating', resp['vote_average']) movie.set('plot', [unicode(resp['overview'])]) resp = m.credits() movie.set('director', [ unicode(c['name']) for c in resp['crew'] if c['job'] == 'Director' ]) movie.set( 'writer', [unicode(c['name']) for c in resp['crew'] if c['job'] == 'Author']) try: movie.cast = [ unicode(actor['name']) + ' -- ' + unicode(actor['character']) for actor in resp['cast'] ] except KeyError: movie.cast = [] return result def savePoster(self, posterUrl, localId): hiresFilename = path(smewt.dirs.user_data_dir, 'images', '%s_hires.jpg' % localId, createdir=True) loresFilename = path(smewt.dirs.user_data_dir, 'images', '%s_lores.jpg' % localId) # TODO: use requests instead of urlopen open(hiresFilename, 'wb').write(urlopen(posterUrl).read()) # NOTE: we do the resizing here because if we leave it to the browser, # it will use a fast resampling algorithm, which will be of lower # quality than what we achieve here # lores = 80px high width, height = 60, 80 header_msg = 'Creating %dx%d screenshot' % (width, height) log.info('%s for %s...', header_msg, hiresFilename) im = Image.open(hiresFilename) log.debug('%s: resizing...', header_msg) im.thumbnail((width, height), Image.ANTIALIAS) log.debug('%s: saving to png...', header_msg) im.save(loresFilename, "PNG") log.debug('%s: done!', header_msg) return ('/user/images/%s_lores.jpg' % localId, '/user/images/%s_hires.jpg' % localId) @cachedmethod def getSeriesPoster(self, tvdbID): """Return the low- and high-resolution posters of a tvdb object.""" noposter = '/static/images/noposter.png' urls = self.tvdb.get_show_image_choices(tvdbID) posters = [url for url in urls if url[1] == 'poster'] if posters: return self.savePoster(posters[0][0], 'series_%s' % tvdbID) else: log.warning('Could not find poster for tvdb ID %s' % tvdbID) return (noposter, noposter) @cachedmethod def getMoviePoster(self, movieId): """Return the low- and high-resolution posters (if available) of an tvdb object.""" noposter = '/static/images/noposter.png' resp = self.tmdb.Movies(movieId).info({'language': self.tmdb.lang}) image_size = 'original' image_base = self.tmdb.server_config.images[ 'base_url'] + '/' + image_size + '/' if resp['poster_path']: return self.savePoster(image_base + resp['poster_path'], 'movie_%s' % movieId) else: log.warning('Could not find poster for tmdb ID %s' % movieId) return (noposter, noposter) def startEpisode(self, episode): self.tmdb.lang = guiLanguage().alpha2 if episode.get('series') is None: raise SmewtException( "TVDBMetadataProvider: Episode doesn't contain 'series' field: %s", episode) name = episode.series.title name = name.replace(',', ' ') matching_series = self.getSeries(name) # Try first with the languages from guessit, and then with english languages = tolist(episode.get('language', [])) + ['en'] # Sort the series by id (stupid heuristic about most popular series # might have been added sooner to the db and the db id # follows the insertion order) # TODO: we should do something smarter like comparing series name distance, # episodes count and/or episodes names #print '\n'.join(['%s %s --> %f [%s] %s' % (x[1], name, textutils.levenshtein(x[1], name), x[2], x[0]) for x in matching_series]) matching_series.sort( key=lambda x: (textutils.levenshtein(x[1], name), int(x[0]))) series = None language = 'en' for lang in languages: try: language = lang ind = zip(*matching_series)[2].index(lang) series = matching_series[ind][0] break except ValueError, e: language = matching_series[0][2] series = matching_series[0][0] # TODO: at the moment, overwrite the detected language with the one # from the settings. It would be better to use the detected # language if it was more reliable (see previous TODO)... language = guiLanguage().alpha2 eps = self.getEpisodes(series, language) try: lores, hires = self.getSeriesPoster(series) eps.find_one(Series).update({ 'loresImage': lores, 'hiresImage': hires }) return eps except Exception, e: log.warning(str(e) + ' -- ' + str(textutils.toUtf8(episode))) return MemoryObjectGraph()