예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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
예제 #4
0
    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()
예제 #5
0
    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)
예제 #6
0
    def childChecked(self, index):
        for checkedKey in self.selectedFolders():
            if toUtf8(checkedKey).startswith( toUtf8(self.key( index )) + '/' ):
                return True

        return False
예제 #7
0
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()