Exemple #1
0
def generateDataFromURL(urls):

	total = len(urls)
	size=30
	data = []
	print "Downloading data for " + str(len(urls)) + " movies..."

	for i,url in enumerate(urls):
		progress = (i+1.0)/total
		print str(i) + " " + str(len(data)) + " [" + str(progress) + "] " + url
		code = getCode(url)
		if code:
			response = omdb.imdbid(code, tomatoes=True, fullplot=True)
			if response:
				FA = FARating(response['title'],response['year'])
				response['FA_rating']=str(FA)
				#response['user_rating'] = movie[2]
				data.append(response) 
			else:
				data.append(dict.fromkeys(keys))
		else:
			data.append(dict.fromkeys(keys))
		
		# sys.stdout.write("\r[" + "=" * (int(round((progress*size)))-1) +">" +  " " * int(round((1-progress)*size)) 
		# 				+ "] "+ str(i+1) + "/" + str(total))
		# sys.stdout.flush()
		
	print
	return data
Exemple #2
0
def generateDataFromID(ids):

	total = len(ids)
	size=30
	data = []
	print "Downloading data for " + str(len(ids)) + " movies..."

	for i,link in enumerate(ids):

		print str(i) + " " + str(len(data)) + " [" + str(i+1) + "/" + str(total) + "] " + link['imdbId']

		response = omdb.imdbid("tt" + link['imdbId'], tomatoes=True, fullplot=True)
		if response:
			response['year']= response['year'].encode('utf-8')
			response['year'] = response['year'].replace('–',"")		#Weird special case

			FA = FARating(response['title'],response['year'])
			response['FA_rating']=str(FA)
			response['movieId'] = link['movieId']
			#response['user_rating'] = movie[2]
			data.append(response) 
		else:
			data.append(dict.fromkeys(keys))

		progress = (i+1.0)/total		
		# sys.stdout.write("\r[" + "=" * (int(round((progress*size)))-1) +">" +  " " * int(round((1-progress)*size)) 
		# 				+ "] "+ str(i+1) + "/" + str(total))
		# sys.stdout.flush()
		
	print
	return data
Exemple #3
0
 def get(self, key, query):
     if not x.auth(key):
         return {'message': 'Unauthorized'}
     
     data = omdb.imdbid(query)
     if len(data) == 0:
         return {'result': 'not a valid imdb id: {}'.format(data)}
     if query is None:
         return {'result': 'missing argument'}
     logging.info('Trying to request {}'.format(query))
     if len(data) == 0:
         return False
     _type = data['type']
     if _type == 'series':
         return_data = me.request(query, data)
     elif _type == 'movie' or 'documentary':
         return_data = cp.request(query, data=data)
     # WE NEED TO IMPLEMENT A CORRECT RETURN FOR THIS FUNCTION BELOW.
         if return_data == 'exists':
             return {'message': 'already exists on system'}
         elif return_data == 'already_queued':
             return {'message': 'movie is already queued on the system'}
         elif return_data == 'requested':
             return {'result': 'movie was added'}
         elif return_data == 'backend_api_error':
             return {'message': 'backend api error'}
         else:
             return {'message': return_data}
Exemple #4
0
    def test_get_model_fields_series(self):
        expected_fields = [
            'actors',
            'awards',
            'country',
            'director',
            'episode',
            'genre',
            'language',
            'metascore',
            'plot',
            'poster',
            'season',
            'series_id',
            'rated',
            'released',
            'response',
            'runtime',
            'title',
            'type',
            'writer',
            'year',
            'imdb_id',
            'imdb_rating',
            'imdb_votes'
        ]

        self.assertEqual(set(omdb.imdbid('tt2400770').keys()),
                         set(expected_fields))
Exemple #5
0
def test_get_fields():
    expected_fields = [
        'actors',
        'awards',
        'box_office',
        'country',
        'director',
        'dvd',
        'genre',
        'language',
        'metascore',
        'plot',
        'poster',
        'production',
        'rated',
        'ratings',
        'released',
        'response',
        'runtime',
        'title',
        'type',
        'website',
        'writer',
        'year',
        'imdb_id',
        'imdb_rating',
        'imdb_votes'
    ]

    result = omdb.title('True Grit')
    assert set(result.keys()) == set(expected_fields)

    result = omdb.imdbid('tt0065126')
    assert set(result.keys()) == set(expected_fields)
Exemple #6
0
def get_films():
    _raw = omdb.request(s="The H", plot="short", r="json").json()
    if "Search" in _raw:
        films = _raw["Search"]
        for f in films:
            film = omdb.imdbid(f["imdbID"])
            yield dict( (k.lower(), (None if v == 'N/A' else v)) for k,v in film.items() )
def process_view():
    '''Provides a view for a movie selected from the Search Panel'''
    # Retrieve the Request data from the client
    json = request.get_json()
    imdb_id = json['imdb_id']

    # Search the Online Movie Database using an IMDB id
    imdbInfo = omdb.imdbid(imdb_id)

    #  See if it's already in Favorites
    if media.isFavorite(imdbInfo.title):
        viewedMovie = media.getMovie(imdbInfo.title)
    # Movie isn't favored already, so create a new instance
    else:
        viewedMovie = media.Movie(imdbInfo.title,
                                  imdbInfo.plot,
                                  imdbInfo.poster,
                                  None,
                                  imdb_id,
                                  imdbInfo.year)
        # Pull the Trailer Url from TrailerAddict.com
        viewedMovie.set_trailer_info()

    # Render the Movie into a view on the Client
    return render_template("movie_view.html", movieInfo=viewedMovie)
Exemple #8
0
    def test_get_model_fields(self):
        expected_fields = [
            'actors',
            'awards',
            'director',
            'country',
            'genre',
            'language',
            'metascore',
            'plot',
            'poster',
            'rated',
            'released',
            'response',
            'runtime',
            'title',
            'type',
            'writer',
            'year',
            'imdb_id',
            'imdb_rating',
            'imdb_votes'
        ]

        self.assertEqual(set(omdb.title('True Grit').keys()),
                         set(expected_fields))
        self.assertEqual(set(omdb.imdbid('tt0065126').keys()),
                         set(expected_fields))
Exemple #9
0
async def imdb(ctx, *movie_full_name):
    movie = ''

    if len(movie_full_name) > 1:
        for element in movie_full_name:
            movie = movie + element + ' '

    else:
        movie = movie_full_name[0]

    info = omdb.search_movie(movie_full_name)

    if len(info) > 0:
        info = omdb.imdbid(info[0]['imdb_id'])

    else:
        await ctx.send('No results found')
        return

    embed = discord.Embed(title=info['title'],
                          description=info['plot'],
                          colour=discord.Colour.blue())

    embed.set_footer(text='A ' + info['production'] + ' production')
    embed.set_image(url=info['poster'])
    embed.add_field(name="Release Date", value=info['released'], inline=False)
    embed.add_field(name="Director(s)", value=info['director'], inline=False)
    embed.add_field(name="MetaScore", value=info['metascore'], inline=True)
    embed.add_field(name="IMDB Score", value=info['imdb_rating'], inline=True)

    await ctx.send(embed=embed)
Exemple #10
0
def getMovieScore(movieData):
    print '###################'
    print 'Now we are calculating the score'
    invalid_metascore = []
    good_movies = []
    i=0

    for key, value in movieData.iteritems():
        movieFound = False
        i = i + 1
        print i
        if value == '':
            continue
        else:
            for movieMetaData in value:
                if movieMetaData['title'].encode('utf-8') == key and (movieMetaData['type'] == 'movie' or movieMetaData['type'] == 'series'):
                    movieFound = True
                    imdb_metascore = omdb.imdbid(movieMetaData['imdb_id'])['metascore'] or ''
                    if imdb_metascore == 'N/A' or not imdb_metascore.isdigit():
                        invalid_metascore.append(key)
                    else:
                        good_movies.append({key : imdb_metascore})
                    break
            if movieFound == False:
                invalid_metascore.append(key)
    return invalid_metascore, good_movies
def index(request):
    """ Creates an HTTP response for requests made to the index route. """

    if request.method == 'POST':
        try:
            movie_dict = omdb.imdbid(request.POST['imdb_id'])
            #TODO fix this so that movie_dict is passed directly to Movie.objects.create()
            Movie.objects.create(
                title=movie_dict['title'],
                year=movie_dict['year'],
                imdb_id=movie_dict['imdb_id'],
                runtime=movie_dict['runtime'],
                rated=movie_dict['rated'],
            )
            return redirect('/')
        except MultiValueDictKeyError:

            messages.add_message(
                request, messages.WARNING,
                'You didn\'t select a movie to save, look for another?')
            return render(request, 'movies/search.html')

    movies = Movie.objects.all()

    return render(request, 'movies/index.html', {'movie_list': movies})
Exemple #12
0
def feed(request):
    template = loader.get_template('index.html')

    typesFiltered = Filter.objects.values_list('type', flat=True)
    print("list of the types filtered : ")
    print(typesFiltered)

    #we parse the imdb rss feed in order to have a list of DVD Release
    #this is an example of source where we can find the info
    d = feedparser.parse('http://rss.imdb.com/list/ls016522954/')
    entries = d.entries
    listMovies = list()
    for post in entries:
        guidFetched = post.guid.split('/')[-2]
        #we fetch the type on omdb with the imdbid
        typeFetched = omdb.imdbid(guidFetched).genre.replace(" ",
                                                             "").split(',')
        print("typeFetched = ")
        print(typeFetched)
        #if the type is not filtered then we keep it
        if not set(typeFetched) & set(typesFiltered):
            listMovies.append(
                Movie(title=post.title, guid=guidFetched, type=typeFetched))

    context = {'listMovies': listMovies, 'listTypesFiltered': typesFiltered}
    return HttpResponse(template.render(context, request))
Exemple #13
0
def test_get_series_fields():
    expected_fields = [
        'actors',
        'awards',
        'country',
        'director',
        'episode',
        'genre',
        'language',
        'metascore',
        'plot',
        'poster',
        'season',
        'series_id',
        'rated',
        'ratings',
        'released',
        'response',
        'runtime',
        'title',
        'type',
        'writer',
        'year',
        'imdb_id',
        'imdb_rating',
        'imdb_votes'
    ]

    result = omdb.imdbid('tt2400770')
    assert set(result.keys()) == set(expected_fields)
Exemple #14
0
def getMovieScore(movieData):
    print '###################'
    print 'Now we are calculating the score'
    invalid_metascore = []
    good_movies = []
    i=0
    for key, value in movieData.iteritems():
        movieFound = False
        i = i + 1
        print i
        if value == '':
            continue
        else:
            for movieMetaData in value:
                if movieMetaData['title'].encode('utf-8') == key and (movieMetaData['type'] == 'movie' or movieMetaData['type'] == 'series'):
                    movieFound = True
                    imdb_metascore = omdb.imdbid(movieMetaData['imdb_id'])['metascore'] or ''
                    if imdb_metascore == 'N/A' or not imdb_metascore.isdigit():
                        invalid_metascore.append(key)
                    else:
                        good_movies.append({key : imdb_metascore})
                    break
            if movieFound == False:
                invalid_metascore.append(key)

    return invalid_metascore, good_movies
def collectData(imdb_id):
    omdb.set_default('apikey', 'b5e3df7f')
    info = omdb.imdbid(imdb_id)

    print(info)

    inst = Tv_details.objects.create(imdb_id=imdb_id,
                                     title=info['title'],
                                     image_url=info['poster'],
                                     description=info['plot'],
                                     imdb_rating=info['imdb_rating'],
                                     language=info['language'],
                                     country=info['country'],
                                     year=info['year'],
                                     tv_rating=info['rated'])
    inst.save()

    genres = info['genre'].split(', ')
    for genre in genres:
        try:
            g = Genres.objects.get(genre=genre)
        except Genres.DoesNotExist:
            g = Genres.objects.create(genre=genre)
            g.save()

    for genre in genres:
        g = Genres.objects.get(genre=genre)
        mg = Tv_genre.objects.create(tv_id=inst, genre_id=g)
        mg.save()
Exemple #16
0
    def new_file(self, num):
        if __name__ == '__main__':
            c = [5, 5]
        else:
            c = [settings.START_X, settings.START_Y]
        self.save_file['current'] = {
            'player': {
                'strength': 1,
                'dir': 0,
                'ball': 5000,
                'coord': c,
            },
            'movie': {},
        }

        omdb.set_default('apikey', settings.OMDBAPI_KEY)
        movies = []
        for movie in settings.MOVIE_LIST:
            data = omdb.imdbid(movie)
            movies.append({
                'name': data['title'],
                'strength': int(float(data['imdb_rating'])),
                'rating': data['imdb_rating'],
                'actors': data['actors'],
                'year': data['released'].split(' ')[2],
                'image': data['poster'],
                'director': data['director'],
                'catched': False,
            })

        self.save_file['current']['movie'] = movies
Exemple #17
0
 def main(self, *data, message=None, thread=None, ttype=None, name=None, author=None, nickname=None, msg=None):
     if thread in self._disallowed:
         return('Bruk plexchatten tell det her.')
     data = data[0].split()
     if len(data) is not 3:
         return('Syntax: !missing <imdbid> <sesong> <episode>\n🚫!missing mor di \n👍!missing tt12354 2 8')
     try:
         imdbid = data[0]
         season = int(data[1])
         episode = int(data[2])
     except:
         return('Syntax: !missing <imdbid> <sesong> <episode>\n🚫!missing {} {} {} \n👍!missing tt12354 2 8'.format(data[0], data[1], data[2]))
     me = bot.api.medusa()
     ttdbid = ttdb(imdbid)
     result = json.loads(me.get('episode', indexerid=ttdbid, season=season, episode=episode))
     title = omdb.imdbid(imdbid)
     title = title['title']
     api_result = result['result']
     if api_result == 'success':
         episode_name = title + ' - ' + result['data']['name']
         episode_status = result['data']['status']
         if re.match('(Downloaded|Archived)', episode_status):
             # This episode already exists, but we'll force download another version.
             setstatus = json.loads(me.get('episode.setstatus', status='wanted', indexerid=ttdbid, season=season, episode=episode, force=1))
             logging.info('Set status of {} to "wanted"\n{}'.format(imdbid,setstatus))
             if setstatus['result'] == 'success':
                 return('{} eksistert på systemet fra før av, men den bi henta ned i ny version.'.format(episode_name))
             elif setstatus['result'] == 'failure':
                 return('Error: {}'.format(setstatus)) # Need to print the entire message to debug.
             elif setstatus['result'] == 'error':
                 return('Error: {}'.format(setstatus))
             print(setstatus)
         if episode_status == 'Wanted':
             # This episode is already in wanted status, but we can force a direct search instead. #TODO: await this function
             search = json.loads(me.get('episode.search', indexerid=ttdbid, season=season, episode=episode))
             logging.info('Did a search for wanted episode of {}\n{}'.format(ttdbid, search))
             if search['result'] == 'success':
                 return('Gjor et nytt forsøk på å finn "{}", og fant en episode! Kommer fortløpende!'.format(episode_name))
             elif search['result'] == 'failure':
                 return('Gjor et nytt forsøk på å finn "{}", klart ikke å finn en episode i det hele tatt :('.format(episode_name))
             elif search['result'] == 'error':
                 return('Det skjedd nå feil under søket av episoden:\n{}'.format(search))
         if re.match('(Skipped|Ignored|Snatched)', episode_status):
             # This episode has been skipped, ignored or has already been snatched. We'll force a new search. 
             search = json.loads(me.get('episode.search', indexerid=ttdbid, season=season, episode=episode))
             logging.info('Forced a new search of skipped episode from {}\n{}'.format(ttdbid, search))
             if search['result'] == 'success':
                 return('OOps, episoden mangla, Fant {} med {} under søket, kommer på plex Asap. '.format(title, result['data']['name']))
             elif search['result'] == 'failure':
                 return('Gjor et nytt forsøk på å finn "{}", klart ikke å finn en episode i det hele tatt :('.format(episode_name))
             elif search['result'] == 'error':
                 return('Det skjedd nå feil under søket av episoden:\n{}'.format(search))
     elif api_result == 'error':
         # User is likely out of bounds. Episode/Season range doesnt match what we have on file.
         logging.info('Moom, {} is being an idiot again!'.format(name))
         # print(me.get('episode', indexerid=ttdbid, season=1, episode=1)) # debug
         return('Feil:\n{} {}x{} e ikke en gyldig kombinasjon av sesonga å episoda'.format(title, season, episode))
     elif api_result == 'failure':
         return('Serien fins ikke på plex enda, den må !requestes først.')
Exemple #18
0
 def give_movie_information_from_imdb_id(imdb_id):
     movie = omdb.imdbid(imdb_id)
     speech = "%s was released in %s, directed by %s of genre %s has a runtime of about %s" \
              "garnered a rating of %s featuring %s had a plot such as %s" % (movie.title, movie.released,
                                                                              movie.director, movie.genre,
                                                                              movie.runtime, movie.imdb_rating,
                                                                              movie.actors, movie.plot)
     return speech
Exemple #19
0
def search(names):
    title = []
    invnames = []
    metascore = []
    for n in names:
        try:
            omdb.imdbid(omdb.search(n)[0].imdb_id).metascore
        except:
            invnames.append(n)
        else:
            title.append(omdb.search(n)[0].title)
            if not omdb.imdbid(omdb.search(n)[0].imdb_id).metascore:
                invnames.append(n)
            else:
                metascore.append(
                    omdb.imdbid(omdb.search(n)[0].imdb_id).metascore)
    return title, invnames, metascore
Exemple #20
0
def find_omdb_movie(title, year):
    for movie in omdb.search(title):
        if movie.year[-1] == '-':
            movie.year = movie.year.replace('-', '')
        if movie.year == str(year):
            return omdb.imdbid(movie.imdb_id)
        print(movie.title)
    return np.nan
Exemple #21
0
def deleteMovie(id):
    result = mydb.movies.find({"_id": id})
    if count_iterable(result) > 0:
        movieInfo = omdb.imdbid(id)
        movieInfo["_id"] = movieInfo["imdb_id"]
        mydb.movies.delete_many({"_id": id})
        print movieInfo.title + " Deleted!"
        calculate_movies_count()
    return jsonify({"message": "success"})
Exemple #22
0
 def missing(self, key, query, season, episode):
     data = omdb.imdbid(query)
     if not data:
         return {'result': 'not a valid imdb id'}
     if query is None:
         return {'result': 'missing argument'}
     # check if this show exists with another indexer first and use that ID.
     ttdbid = ttdb(query)
     result = json.loads(me.get('episode', indexerid=ttdbid, season=season, episode=episode))
     title = data['title']
     api_result = result['result']
     if api_result == 'success':
         episode_name = title + ' - ' + result['data']['name']
         episode_status = result['data']['status']
         if re.match('(Downloaded|Archived)', episode_status):
             # This episode already exists, but we'll force download another version.
             setstatus = json.loads(me.get(
                 'episode.setstatus', status='wanted', indexerid=ttdbid, season=season, episode=episode, force=1))
             logging.info(
                 'Set status of {} to "wanted"\n{}'.format(query, setstatus))
             if setstatus['result'] == 'success':
                 return('Retrieved a new version of {}'.format(episode_name))
             elif setstatus['result'] == 'failure':
                 # Need to print the entire message to debug.
                 return('{}'.format(setstatus))
             elif setstatus['result'] == 'error':
                 return(' {}'.format(setstatus))
             print(setstatus)
         if episode_status == 'Wanted':
             # This episode is already in wanted status, but we can force a direct search instead. #TODO: await this function
             search = json.loads(
                 me.get('episode.search', indexerid=ttdbid, season=season, episode=episode))
             logging.info(
                 'Did a search for wanted episode of {}\n{}'.format(ttdbid, search))
             if search['result'] == 'success':
                 return('Did a new try to find {} and found it, episode coming soon.'.format(episode_name))
             elif search['result'] == 'failure':
                 return('couldnt find the episode {}'.format(episode_name))
             elif search['result'] == 'error':
                 return('an error occured: {}'.format(search))
         if re.match('(Skipped|Ignored|Snatched)', episode_status):
             # This episode has been skipped, ignored or has already been snatched. We'll force a new search.
             search = json.loads(
                 me.get('episode.search', indexerid=ttdbid, season=season, episode=episode))
             logging.info(
                 'Forced a new search of skipped episode from {}\n{}'.format(ttdbid, search))
             if search['result'] == 'success':
                 return('Oops, that episode was missing. Got {}x{} for you.'.format(title, result['data']['name']))
             elif search['result'] == 'failure':
                 return('Tried to find the episode {}, but couldnt find any matches.'.format(episode_name))
             elif search['result'] == 'error':
                 return('something wrong happened{}'.format(search))
     elif api_result == 'error':
         # print(me.get('episode', indexerid=ttdbid, season=1, episode=1)) # debug
         return('{} {}x{} is not a valid combination of seasons and episodes'.format(title, season, episode))
     elif api_result == 'failure':
         return('this show doesnt exist yet.')
Exemple #23
0
 def getmovie(self, imdbid):
     ''' returns data from imdb '''
     if omdb.imdbid(imdbid) is False:
         print('{"error: "This movie doesnt exist on imdb"}')
         return False
     data = json.loads(couchpotato().get('media.get', id=imdbid))
     if data['success'] == False:
         return False
     return data['media']
Exemple #24
0
def test_get_series_fields():
    expected_fields = [
        'actors', 'awards', 'country', 'director', 'episode', 'genre',
        'language', 'metascore', 'plot', 'poster', 'season', 'series_id',
        'rated', 'ratings', 'released', 'response', 'runtime', 'title', 'type',
        'writer', 'year', 'imdb_id', 'imdb_rating', 'imdb_votes'
    ]

    result = omdb.imdbid('tt2400770')
    assert set(result.keys()) == set(expected_fields)
Exemple #25
0
    def test_get_model_fields_series(self):
        expected_fields = [
            'actors', 'awards', 'country', 'director', 'episode', 'genre',
            'language', 'metascore', 'plot', 'poster', 'season', 'series_id',
            'rated', 'released', 'response', 'runtime', 'title', 'type',
            'writer', 'year', 'imdb_id', 'imdb_rating', 'imdb_votes'
        ]

        self.assertEqual(set(omdb.imdbid('tt2400770').keys()),
                         set(expected_fields))
Exemple #26
0
def saveMovie(id):
    result = mydb.movies.find({"_id": id})
    if count_iterable(result) < 1:
        movieInfo = omdb.imdbid(id)
        movieInfo["_id"] = movieInfo["imdb_id"]
        movieInfo["time_stamp"] = datetime.datetime.now().isoformat()
        mydb.movies.insert_one(movieInfo)
        print movieInfo.title + " Inserted!"
        calculate_movies_count()
    return jsonify({"message": "success"})
def write_movie_data(movies):
    """
    Write data about movies to single json file
    :param movies: list of movie titles
    :return: json file of movies data
    """
    all_movies = []
    lines = []
    for movie in movies:
        search = omdb.search(movie)
        if len(search) > 0:
            hit = search[0]
            # collect data for every movie
            if hit.type == 'movie':
                # list of all movies with links
                imdb_id = hit.imdb_id
                link = get_imdb_link(imdb_id)
                poster = hit.poster
                year = hit.year
                # list of all movies
                line = movie + "," + link + "\n"
                lines.append(line)
                # extract other movies data
                movie_data = {}
                movie_data['title'] = movie
                movie_data['id'] = link
                movie_data['poster'] = poster
                movie_data['imdb_id'] = imdb_id
                movie_data['year'] = year
                omdb_data = omdb.imdbid(imdb_id)
                movie_data['imdb_rating'] = get_attribute_value(omdb_data, 'imdb_rating')
                movie_data['genre'] = get_attribute_value(omdb_data, 'genre')
                movie_data['country'] = get_attribute_value(omdb_data, 'country')
                movie_data['released'] = get_attribute_value(omdb_data, 'released')
                movie_data['runtime'] = get_attribute_value(omdb_data, 'runtime')
                movie_data['language'] = get_attribute_value(omdb_data, 'language')
                movie_data['actors'] = get_attribute_value(omdb_data, 'actors')
                movie_data['plot'] = get_attribute_value(omdb_data, 'plot')
                all_movies.append(movie_data)
                print("Completed: " + movie)
            else:
                print("Skipped: " + movie)
        else:
            print("No results: " + movie)



    # write movies
    with open('movies.json', 'w') as fp:
        json.dump(all_movies, fp, indent=4)

    # write movies with links
    f = open('links.txt', 'w')
    f.writelines(lines)
    f.close()
Exemple #28
0
def submit_entry(imdb_id):

    if not g.user.is_confirmed():
        return redirect(url_for('admin.unconfirmed'))

    form = AddEntryForm()

    if form.validate_on_submit():

        res = omdb.imdbid(imdb_id)

        wishlist = int(form.wishlist.data)
        if wishlist == 1:
            wishlist = True
        else:
            wishlist = False

        entry = Entry.query.filter_by(user_id=g.user.id,
                                      imdb_id=imdb_id,
                                      wishlist=wishlist).first()

        if entry:
            flash('This entry already exists in your collection')
            return redirect(url_for('admin.home'))

        entry = Entry(user_id=g.user.id,
                      timestamp=datetime.utcnow(),
                      wishlist=wishlist)

        title = res['title']
        entry.title = res['title']
        entry.year = res['year']
        if res['poster'] != 'N/A':
            entry.image = res['poster']

        entry.imdb_id = res['imdb_id']

        db.session.add(entry)
        db.session.commit()

        if wishlist:
            message = Markup('Entry added successfully. <strong><a href="' +
                             url_for('admin.add_wishlist') +
                             '">Add another?</a></strong>')
        else:
            message = Markup('Entry added successfully. <strong><a href="' +
                             url_for('admin.add_entry') +
                             '">Add another?</a></strong>')

        flash(message)

        if wishlist:
            return redirect(url_for('admin.wishlist'))
        else:
            return redirect(url_for('admin.home'))
Exemple #29
0
def get_movie(imdb_id, api_key):
    """Get movie from imdb_id.

    Args:
        imdb_id: imdb ID number for movie
        api_key: API key for omdb

    Returns:
        omdb info from imdb_id
    """
    omdb.set_default('apikey', api_key)
    return omdb.imdbid(imdb_id)
Exemple #30
0
 def get(self, key, query):
     if not x.auth(key):
         return {'message': 'Unauthorized'}
     data = omdb.imdbid(query)
     try:
         if data['type'] in ('movie', 'documentary', 'standup'):
             plex.library.section('Films').get(data['title']).refresh()
         elif data['type'] == 'series':
             plex.library.section('Series').get(data['title']).refresh()
         return {'result': 'Refreshing {}'.format(data['title'])}
     except NotFound:
         return {'message': 'Could not update item'}
Exemple #31
0
    def test_get_model_fields(self):
        expected_fields = [
            'actors', 'awards', 'country', 'director', 'genre', 'language',
            'metascore', 'plot', 'poster', 'rated', 'released', 'response',
            'runtime', 'title', 'type', 'writer', 'year', 'imdb_id',
            'imdb_rating', 'imdb_votes'
        ]

        self.assertEqual(set(omdb.title('True Grit').keys()),
                         set(expected_fields))
        self.assertEqual(set(omdb.imdbid('tt0065126').keys()),
                         set(expected_fields))
def imdb_by_code(input_text):
    message_list = []
    if len(input_text) == 0:
        text = "Command format: imdbtt  <imdb_id>"
        message_list.append((text, []))
    else:
        om = omdb.imdbid(input_text, tomatoes=True)
        if "title" in om.keys():
            message_list = output_movie(input_text, om)
        else:
            text = "Sorry, " + input_text + " doesn't seem to be valid."
            message_list.append((text, []))
    return message_list
Exemple #33
0
def test_get_fields():
    expected_fields = [
        'actors', 'awards', 'box_office', 'country', 'director', 'dvd',
        'genre', 'language', 'metascore', 'plot', 'poster', 'production',
        'rated', 'ratings', 'released', 'response', 'runtime', 'title', 'type',
        'website', 'writer', 'year', 'imdb_id', 'imdb_rating', 'imdb_votes'
    ]

    result = omdb.title('True Grit')
    assert set(result.keys()) == set(expected_fields)

    result = omdb.imdbid('tt0065126')
    assert set(result.keys()) == set(expected_fields)
Exemple #34
0
def show_results(name):
    """Print on stdout the results obtained from omdb"""
    movies = omdb.search(name)
    if not movies:
        sys.exit(f'Movie "{name}" not found')
    for movie in omdb.search(name):
        m = omdb.imdbid(movie['imdb_id'])
        rating_str = 'No rating info'
        rating = get_rotten_tomato_rating(m)
        if rating:
            rating_str = f'Rotten Tomatoes {rating}'
        print(f'{m["title"]}/{m["year"]} ➡ {rating_str}')
        print('-' * 80)
 def get_title(self, imdb_id):
     """
     Получение названия фильма по его imdb_id
     Args:
         imdb_id (int): id фильма на сайте *imdb.com*
     Returns:
         (str): название фильма
     """
     data = omdb.imdbid("tt%s" % imdb_id)
     if "title" in data:
         return data.title
     else:
         return None
Exemple #36
0
def get_item (found_movies, item_to_obtain):
        correct_metascore={}
        invalid_metascore=[]
        for searched_movie in found_movies:
            pattern_abbr = re.compile('[0-9]')
            movie_id = searched_movie['imdb_id']
            movie_info_by_id = omdb.imdbid(movie_id)

            if not re.search(pattern_abbr, movie_info_by_id[item_to_obtain]):
                invalid_metascore.append(searched_movie['title'].encode('utf-8'))
            else:
                correct_metascore[searched_movie['title']] = movie_info_by_id[item_to_obtain]
        return correct_metascore, invalid_metascore
Exemple #37
0
def index(request):
    """ Creates an HTTP response for requests made to the index route. """

    if request.method == 'POST':
        movie_dict = omdb.imdbid(request.POST['imdb_id'])
        #TODO fix this so that movie_dict is passed directly to Movie.objects.create()
        Movie.objects.create(title=movie_dict['title'],year=movie_dict['year'],
                        imdb_id=movie_dict['imdb_id'],runtime=movie_dict['runtime'],
                        rated=movie_dict['rated'],)
        return redirect('/')
    movies = Movie.objects.all()

    return render(request, 'movies/index.html', {'movie_list': movies})
Exemple #38
0
    def get_imdsb_info(self, id, type='movie'):
        API_KEY = "68735ac"

        omdb.set_default('apikey', API_KEY)
        omdb.set_default('tomatoes', True)

        id = format_id(id)
        movie = omdb.imdbid(id, fullplot=True, tomatoes=True)

        url = 'https://www.imdb.com/title/' + movie['imdb_id'] + '/'
        print(url)
        print(json.dumps(movie, indent=4, sort_keys=True))

        #return and info about the movie
        return movie
Exemple #39
0
def submit_entry(imdb_id):

    if not g.user.is_confirmed():
        return redirect(url_for('admin.unconfirmed'))

    form = AddEntryForm()

    if form.validate_on_submit():

        res = omdb.imdbid(imdb_id)

        wishlist = int(form.wishlist.data)
        if wishlist == 1:
            wishlist = True
        else:
            wishlist = False

        entry = Entry.query.filter_by(user_id = g.user.id, imdb_id = imdb_id, wishlist = wishlist).first()

        if entry:
            flash('This entry already exists in your collection')
            return redirect(url_for('admin.home'))

        entry = Entry(user_id = g.user.id, timestamp = datetime.utcnow(), wishlist = wishlist)

        title = res['title']
        entry.title = res['title']
        entry.year = res['year']
        if res['poster'] != 'N/A':
            entry.image = res['poster']

        entry.imdb_id = res['imdb_id']

        db.session.add(entry)
        db.session.commit()

        if wishlist:
            message = Markup('Entry added successfully. <strong><a href="' + url_for('admin.add_wishlist') + '">Add another?</a></strong>')
        else:
            message = Markup('Entry added successfully. <strong><a href="' + url_for('admin.add_entry') + '">Add another?</a></strong>')

        flash(message)

        if wishlist:
            return redirect(url_for('admin.wishlist'))
        else:
            return redirect(url_for('admin.home'))
Exemple #40
0
def test_get_tomatoes_fields():
    expected_fields = [
        'actors',
        'awards',
        'box_office',
        'country',
        'director',
        'dvd',
        'genre',
        'language',
        'metascore',
        'plot',
        'poster',
        'production',
        'rated',
        'ratings',
        'released',
        'response',
        'runtime',
        'title',
        'type',
        'website',
        'writer',
        'year',
        'imdb_id',
        'imdb_rating',
        'imdb_votes',
        'tomato_consensus',
        'tomato_fresh',
        'tomato_image',
        'tomato_meter',
        'tomato_rating',
        'tomato_reviews',
        'tomato_rotten',
        'tomato_url',
        'tomato_user_meter',
        'tomato_user_rating',
        'tomato_user_reviews'
    ]

    result = omdb.title('True Grit', tomatoes=True)
    assert set(result.keys()) == set(expected_fields)

    result = omdb.imdbid('tt0065126', tomatoes=True)
    assert set(result.keys()) == set(expected_fields)
    def test_get_model_fields_tomatoes(self):
        expected_fields = [
            'actors',
            'director',
            'genre',
            'plot',
            'poster',
            'rated',
            'released',
            'runtime',
            'title',
            'type',
            'writer',
            'year',
            'imdb_id',
            'imdb_rating',
            'imdb_votes',

            'box_office',
            'dvd',
            'production',
            'website',
            'tomato_consensus',
            'tomato_fresh',
            'tomato_image',
            'tomato_meter',
            'tomato_rating',
            'tomato_reviews',
            'tomato_rotten',
            'tomato_user_meter',
            'tomato_user_rating',
            'tomato_user_reviews'
        ]

        self.assertEqual(set(omdb.title('True Grit', tomatoes=True).keys()), set(expected_fields))
        self.assertEqual(set(omdb.imdbid('tt0065126', tomatoes=True).keys()), set(expected_fields))
Exemple #42
0
    def test_imdbid(self):
        i = 'tt0065126'
        data = omdb.imdbid(i)

        self.assertEqual(data.imdb_id, i)
def retrieve(mongo):

    progressInterval = 100     # How often should we print a progress report to the console?
    progressTotal = 34208      # Approximate number of total lines in the file.
    bulkSize = 100             # How many documents should we store in memory before inserting them into the database in bulk?
    # List of documents that will be given to the database to be inserted to the collection in bulk.
    bulkPayload = pymongo.bulk.BulkOperationBuilder(mongo.db["movie"], ordered = False)
    count = 0
    skipCount = 0

    print("[movieLensToIMDB] Starting retrieve of movie info from IMDB...")
    startTime = time.time()

    # save all data in dict
    # output the data into MongoDB
    cursor = mongo.db["movie"].find({}, no_cursor_timeout=True)
    for cur_movie in cursor:
        count += 1
        if count % progressInterval == 0:
            print("[movieLensToIMDB] %5d lines processed so far. (%d%%) (%0.2fs)" % (count, int(count * 100 / progressTotal), time.time() - startTime))

        cur_mid = cur_movie["mid"]
        cur_imdbid_len = len(str(cur_movie["imdbid"]))
        # Construct the real imdbid
        cur_imdbid = "tt"
        for i in range(7 - cur_imdbid_len):
            cur_imdbid += "0"
        cur_imdbid += str(cur_movie["imdbid"])

        # retrieve movie info from IMDB
        imdb_movie = omdb.imdbid(cur_imdbid)
        cur_genres = []
        for genre in imdb_movie["genre"].split(","):
            cur_genres.append(genre.strip())
        cur_actors = []
        for actor in imdb_movie["actors"].split(","):
            cur_actors.append(actor.strip())

        bulkPayload.find({"mid": cur_mid}).update({"$set": {
            "year": imdb_movie["year"], 
            "country": imdb_movie["country"], 
            "language": imdb_movie["language"], 
            "poster": imdb_movie["poster"], 
            "type": imdb_movie["type"], 
            "runtime": imdb_movie["runtime"], 
            "plot": imdb_movie["plot"], 
            "metascore": imdb_movie["metascore"], 
            "rated": imdb_movie["rated"], 
            "imdb_rating": imdb_movie["imdb_rating"], 
            "imdb_votes": imdb_movie["imdb_votes"], 
            "genres": cur_genres, 
            "director": imdb_movie["director"], 
            "actors": cur_actors, 
            "writer": imdb_movie["writer"],
            "title_imdb": imdb_movie["title"]
            }})

        if count % bulkSize == 0:
            try:
                bulkPayload.execute()
            except pymongo.errors.OperationFailure as e:
                skipCount += len(e.details["writeErrors"])
            bulkPayload = pymongo.bulk.BulkOperationBuilder(mongo.db["movie"], ordered = False)
    if count % bulkSize > 0:
        try:
            bulkPayload.execute()
        except pymongo.errors.OperationFailure as e:
            skipCount += len(e.details["writeErrors"])

    print("[movieLensToIMDB] Parse Complete (%0.2fs)" % (time.time() - startTime))
    print("[movieLensToIMDB] Found " + str(count) + " movies.")
    print("[movieLensToIMDB] Skipped " + str(skipCount) + " insertions.")
Exemple #44
0
def get_movie(imdbID):
    movie = omdb.imdbid(imdbID)
    return movie
 def load(self, id):
     if not isinstance(id, (str, unicode)):
         id = 'tt' + format(id, '07')
     return dict(omdb.imdbid(id, tomatoes=True).items())
 def com_omdb_imdb(self, imdbid):
     """
     Info by IMDB id
     """
     omdb.imdbid(imdbid)
Exemple #47
0
    def test_empty_data(self):
        invalid = 'asdfghjkl'

        self.assertEqual(omdb.search(invalid), [])
        self.assertEqual(omdb.title(invalid), {})
        self.assertEqual(omdb.imdbid(invalid), {})
    def handle(self, *args, **options):
        # Base path of the project.
        base_path = os.getcwd()
        # Path for 'languages.json' file.
        full_path = (base_path +
                     "\\api_root\management\commands\languages.json")
        try:
            with open(full_path, encoding="utf8") as language_file:
                language_data = json.load(language_file)
                language_dict = language_data['languages']
        except OSError:
            print("File not found.")

        tmdb.API_KEY = '700e07d6e002c4a46ec229242049b0f3'
        # Creates a TMDB movie object.
        movie = tmdb.Movies()
        '''
        Gets the latest movie id from the database.
        If there is not any movie in the database, initial movie id will be 0.
        '''
        try:
            movie_id = Movie.objects.latest('id').id + 1
        except IntegrityError:
            movie_id = 0

        # Gets the latest movie in TMDB.
        latest_movie_id = movie.latest(timeout=10)['id']
        # The maximum actor count is 10.
        max_cast_count = 10

        while movie_id <= latest_movie_id:
            # Declarations of arrays that manipulated below.
            genres = []
            keywords = []
            spoken_languages = []
            prod_countries = []
            cast = []
            crew = []
            # Certification and average rating are null by default.
            certification = None
            average_rating = None
            # We need an initial value for them.
            total_rating = 0
            rating_count = 0

            try:
                # Creates a new TMDB movie object by id.
                movie = tmdb.Movies(movie_id)

                try:
                    # Queries TMDB information for the id above.
                    tmdb_info = movie.info(
                        timeout=10,
                        append_to_response='releases,keywords,credits'
                    )
                    imdb_id = tmdb_info['imdb_id']

                    # Checks if there is an 'imdb_id' in 'tmdb_info' dict.
                    if imdb_id == '' or imdb_id is None:
                        print("No imdb id in TMDB query.")
                        movie_id += 1
                        continue

                    # Queries OMDB information by 'imdb_id'.
                    try:
                        omdb_info = omdb.imdbid(imdb_id, timeout=10,
                                                tomatoes=True)
                    except json.decoder.JSONDecodeError:
                        movie_id += 1
                        continue
                    # Imdb id should be an integer for the database.
                    try:
                        imdb_id = int(imdb_id.replace('tt', ''))
                    except ValueError:
                        print(
                            'IMDB Id is not valid. Movie id: {}, '
                            'IMDB id: {}'.format(
                                movie_id, imdb_id
                            )
                        )
                        movie_id += 1
                        continue
                # Handles Read Timeout Error.
                except request_exceptions.ReadTimeout:
                    print('HTTP Read Timeout occurred.')
                    continue

                '''
                If release date is empty string(''), it causes an error.
                To prevent the error, a null value is assigned.
                '''
                release_date = tmdb_info['release_date'] \
                    if tmdb_info['release_date'] != '' else None

                '''
                If OMDB API returns an empty object if block will be executed
                Otherwise else block will be executed and average rating
                will be calculated.
                '''
                if not omdb_info:
                    omdb_info = {
                        'imdb_rating': None,
                        'imdb_votes': None,
                        'metascore': None,
                        'tomato_meter': None,
                        'tomato_user_meter': None,
                        'tomato_user_reviews': None,
                        'tomato_reviews': None
                    }
                else:
                    for key in omdb_info:
                        if omdb_info[key] in ['NA', 'N/A', '']:
                            omdb_info[key] = None
                        else:
                            if key == 'imdb_rating':
                                total_rating += float(omdb_info[key]) * 10
                                rating_count += 1
                            if key == 'imdb_votes':
                                omdb_info[key] = int(
                                    omdb_info[key].replace(',', '')
                                )
                            if key in ['metascore', 'tomato_meter',
                                       'tomato_user_meter']:
                                total_rating += float(omdb_info[key])
                                rating_count += 1
                    if rating_count >= 1:
                        average_rating = round(total_rating / rating_count)

                # Gets the certification for The United States.
                for cert_info in tmdb_info['releases']['countries']:
                    if cert_info['iso_3166_1'].upper() == 'US':
                        if cert_info['certification'] in ['Approved', 'G',
                                                          'NC-17', 'NR',
                                                          'PG', 'PG-13',
                                                          'R', 'UR']:
                            certification = cert_info['certification']

                '''
                Some fields in returned API calls have more than one object.
                For the array fields in the DB, these loops make them an array
                object.
                '''
                for genre_info in tmdb_info['genres']:
                    genres.append(genre_info['name'])

                for keyword_info in tmdb_info['keywords']['keywords']:
                    keywords.append(keyword_info['name'])

                for lang_info in tmdb_info['spoken_languages']:
                    spoken_language = language_dict[lang_info['iso_639_1']]
                    spoken_languages.append(spoken_language)

                for production_info in tmdb_info['production_countries']:
                    prod_countries.append(production_info['name'])

                for cast_info in tmdb_info['credits']['cast']:
                    if len(cast) < max_cast_count:
                        cast.append(cast_info['id'])

                for crew_info in tmdb_info['credits']['crew']:
                    if crew_info['job'] == 'Director':
                        crew.append(crew_info['id'])

                try:
                    # This statement guarantees atomicity of the database.
                    with transaction.atomic():
                        # Creates and saves a movie object to database.
                        movie = Movie.objects.create(
                            id=movie_id,
                            imdb_id=imdb_id,
                            budget=tmdb_info['budget'],
                            revenue=tmdb_info['revenue'],
                            poster_path=tmdb_info['poster_path'],
                            overview=tmdb_info['overview'],
                            genres=genres,
                            keywords=keywords,
                            certification=certification,
                            title=tmdb_info['title'],
                            spoken_languages=spoken_languages,
                            production_countries=prod_countries,
                            tagline=tmdb_info['tagline'],
                            backdrop_path=tmdb_info['backdrop_path'],
                            release_date=release_date,
                            original_title=tmdb_info['original_title'],
                            runtime=tmdb_info['runtime']
                        )
                        # Creates and saves a rating object to database.
                        MovieRatings.objects.create(
                            movie=movie,
                            imdb_rating=omdb_info['imdb_rating'],
                            imdb_votes=omdb_info['imdb_votes'],
                            metascore=omdb_info['metascore'],
                            tomato_meter=omdb_info['tomato_meter'],
                            tomato_user_meter=omdb_info['tomato_user_meter'],
                            tomato_user_reviews=omdb_info[
                                'tomato_user_reviews'],
                            tomato_reviews=omdb_info['tomato_reviews'],
                            tmdb_vote_count=tmdb_info['vote_count'],
                            tmdb_vote_average=tmdb_info['vote_average'],
                            average_rating=average_rating
                        )
                    print('Latest saved movie id: {}'.format(movie_id))
                except IntegrityError:
                    print('Movie id {} already exists.'.format(movie_id))
                    movie_id += 1
                    continue

                cast_info = Command.get_person_information(cast)

                # TODO These lines below should be in a function.
                # Creates relations between movies and actors.
                for actor in cast_info:
                    try:
                        Person.objects.create(
                            id=actor['id'],
                            name=actor['name'],
                            biography=actor['biography'],
                            person_image_path=actor['profile_path']
                        )
                        print('Latest saved person id: {}'.format(actor['id']))
                    except IntegrityError:
                        print('Person already exists. Id: {}'.format(
                            actor['id'])
                        )

                    try:
                        MovieActorIndex.objects.create(
                            actor_id=actor['id'],
                            movie_id=movie_id
                        )
                        print(
                            'Movie-actor index created. Movie id: {}, '
                            'Actor id: {}'.format(
                                movie_id, actor['id']
                            )
                        )
                    except IntegrityError:
                        print(
                            'Movie-actor relation already exists. '
                            'Movie id: {}, Actor id: {}'.format(
                                movie_id, actor['id']
                            )
                        )

                crew_info = Command.get_person_information(crew)

                # TODO These lines below should be in a function as well.
                # Creates relations between movies and directors.
                for director in crew_info:
                    try:
                        Person.objects.create(
                            id=director['id'],
                            name=director['name'],
                            biography=director['biography'],
                            person_image_path=director['profile_path']
                        )
                        print('Latest saved person id: {}'.format(
                            director['id'])
                        )
                    except IntegrityError:
                        print('Person already exists. Id: {}'.format(
                            director['id'])
                        )

                    try:
                        MovieDirectorIndex.objects.create(
                            director_id=director['id'],
                            movie_id=movie_id
                        )
                        print(
                            'Movie-director index created. Movie id: {}, '
                            'Director id: {}'.format(
                                movie_id, director['id']
                            )
                        )
                    except IntegrityError:
                        print(
                            'Movie-director relation already exists. '
                            'Movie id: {}, Director id: {}'.format(
                                movie_id, director['id']
                            )
                        )
                movie_id += 1
            # Handles 404 Not Found Error.
            except request_exceptions.HTTPError:
                print('Movie not found. Id: {}'.format(movie_id))
                movie_id += 1

        print('The database is up to date.')
Exemple #49
0
def scrape_movie(url):
	soup=BeautifulSoup(requests.session().get(url).text, "lxml")

	#Scrape Movie Title & Release Date
	title=soup.find("title").text
	title=title.split("(")[0].strip()
	release_date=scrape_value(soup, "Release Date:")


	#Convert Release Date to Python Datetime Object and Derive Release Month and Year
	release_date=parse(release_date)
	release_month=release_date.month
	release_year=release_date.year


	#Scrape Genre, Rating, Runtime, and Budget
	genre=scrape_value(soup, "Genre:")
	rating=scrape_value(soup, "Rating:")
	runtime=scrape_value(soup, "Runtime:")
	budget=scrape_value(soup, "Production Budget:")

	#Clean-Up Runtime and Budget
	runtime=clean_runtime(runtime)
	budget=clean_budget(budget)
	budget=inflation_adjust(release_year, budget)


	#Scrape Number of Oscar Noms, Number Oscar Wins, and List of Oscar Nominations
	url=url.replace("/movies/","/oscar/movies/")
	soup=BeautifulSoup(requests.session().get(url).text, "lxml") 
	oscar_links=soup.find_all("a", href=True)
	
	oscar_noms=0
	oscar_wins=0
	oscar_list=[]

	for link in soup.find_all("a", href=True):
		if link["href"].find("oscar/chart/")>0:
			oscar=str(link.contents[0].encode('utf-8'))

			if re.search("View All", oscar.title())==None:
				oscar_noms+=1

				if re.search("(WIN)", oscar.upper())>0:
					oscar_wins+=1

				oscar_list.append(oscar)


	#Pull in Rotten Tomato Ratings & Plot Description from OMDB API
	search_results=omdb.search_movie(title)

	imdb_id=None
	for result in search_results:
		if int(result["year"])==release_year:
			imdb_id=result["imdb_id"]
			break

	if imdb_id != None:	
		omdb_content=omdb.imdbid(imdb_id, tomatoes=True)
		
		metascore=omdb_content["metascore"]
		imdb_rating=omdb_content["imdb_rating"]
		tomato_meter=omdb_content["tomato_meter"]
		tomato_user_meter=omdb_content["tomato_user_meter"]
		plot=omdb_content["plot"]

	else:
		metascore=None
		imdb_rating=None
		tomato_meter=None
		tomato_user_meter=None
		plot=None

	#Store Data for One movie in dictionary
	keys=["title","release_date","release_year","genre","rating","runtime","budget","imdb_id","metascore","imdb_rating","tomato_meter","tomato_user_meter","plot","oscar_noms","oscar_wins"]
	values=[title,release_date,release_year,genre,rating,runtime,budget,imdb_id,metascore,imdb_rating,tomato_meter,tomato_user_meter,plot,oscar_noms,oscar_wins]

	d=dict(zip(keys,values))

	return d
Exemple #50
0
def test_imdbid():
    i = 'tt0065126'
    result = omdb.imdbid(i)

    assert result['imdb_id'] == i
Exemple #51
0
def test_empty_data():
    invalid = 'asdfghjkl'

    assert omdb.search(invalid) == []
    assert omdb.title(invalid) == {}
    assert omdb.imdbid(invalid) == {}