def update_movie_info(self, tmdb_api_key=None, tmdb_id=None):
        # todo (2): organize into methods or functions.

        if tmdb_api_key is not None and tmdb_id is not None:
            details_data = self.get_tmdb_details_data(tmdb_api_key, tmdb_id)
            self.tmdb_id = details_data['id']
            self.movie_title = details_data['title']
            self.movie_original_title = details_data['original_title']
            self.movie_title_keywords = tools.get_keyword_list(details_data['title'])

            if len(details_data['release_date'][:4]) == 4:
                self.movie_release_year = int(details_data['release_date'][:4])
            else:
                self.movie_release_year = None

        else:
            clean_name_tuple = tools.get_clean_string(self.name).split(' ')

            if any(clean_name_tuple[-1] == str(year) for year in range(1700, 2045)):
                self.movie_release_year = int(clean_name_tuple[-1])
                self.movie_title = ' '.join(clean_name_tuple[:-1])

            else:
                self.movie_release_year = None
                self.movie_title = ' '.join(clean_name_tuple)

        if tmdb_api_key is None:
            return

        search_data = self.get_tmdb_search_data(tmdb_api_key)

        if search_data is None or search_data['total_results'] == 0:
            return

        movie_data = None
        movie_backup_data = None
        similar_movies_data = list()

        if self.movie_release_year is None:
            movie_data = search_data['results'][0]
            similar_movies_data = search_data['results'][1:]

        elif self.tmdb_id is not None:
            for result in search_data['results']:
                if self.tmdb_id == result['id'] and movie_data is None:
                    movie_data = result
                else:
                    similar_movies_data.append(result)

            if movie_data is None:
                print('None of the search results had the correct id. matching by year.')

        if movie_data is None:
            for result in search_data['results']:
                if str(self.movie_release_year) in result['release_date'][:4] \
                        and movie_data is None:
                    movie_data = result
                elif movie_backup_data is None:
                    if result['release_date'][6:8] in ['09', '10', '11', '12'] \
                            and str(self.movie_release_year + 1) in result['release_date'][:4]:
                        movie_backup_data = result

                    elif result['release_date'][6:8] in ['01', '02', '03'] \
                            and str(self.movie_release_year - 1 in result['release_date'][:4]):
                        movie_backup_data = result
                else:
                    similar_movies_data.append(result)

            if movie_data is None:
                if movie_backup_data is not None:
                    print('None of the search results had a correct release year, picking the next best result')
                    movie_data = movie_backup_data
                    similar_movies_data = similar_movies_data[1:6]
                else:
                    print('None of the search results had a correct release year, picking the next best result')
                    movie_data = search_data['results'][0]
                    similar_movies_data = [movie_backup_data] + similar_movies_data[1:5]
            else:
                if movie_backup_data is not None:
                    similar_movies_data = [movie_backup_data] + similar_movies_data[1:5]

        if self.tmdb_id is None:
            self.tmdb_id = movie_data['id']
            self.movie_title = tools.get_clean_string(movie_data['title'])
            self.movie_original_title = tools.get_clean_string(movie_data['original_title'])
            self.movie_title_keywords = tools.get_keyword_list(movie_data['title'])

            if len(movie_data['release_date'][:4]) == 4:
                self.movie_release_year = int(movie_data['release_date'][:4])
            else:
                self.movie_release_year = None

        if len(similar_movies_data) > 5:
            similar_movies_data = similar_movies_data[:5]
            print('failed: similar list some how got larger than 5?')

        self.banned_similar_keywords = list()
        self.banned_similar_release_years = list()
        for similar_movie in similar_movies_data:
            for word in tools.get_keyword_list(similar_movie['title']):
                if word.lower() not in self.movie_title.lower() and word.lower() not in self.banned_similar_keywords:
                    self.banned_similar_keywords.append(word)
            if len(similar_movie['release_date'][:4]) == 4\
                    and int(similar_movie['release_date'][:4]) not in ([self.movie_release_year - 1,
                                                                        self.movie_release_year,
                                                                        self.movie_release_year + 1] +
                                                                        self.banned_similar_release_years):
                self.banned_similar_release_years.append(int(similar_movie['release_date'][:4]))
    def __init__(self, url, score=0, preferred_container='mp4', min_resolution=360,
                 max_resolution=1080, force_preferred_container=False):

        ########################################
        self.url = None
        self.source = None
        self.delete = None
        self.complete = None
        self.is_play_trailer = None

        self.title = None
        self.thumbnail_url = None
        self.channel = None
        self.tags = list()

        self.view_count = None
        self.rating = None
        self.adjusted_rating = None
        self.resolution = None
        self.quality_score = None
        self.length = None
        self.resolution_ratio = None

        self.streams = list()
        self.best_video_stream = None
        self.best_audio_stream = None
        self.best_combined_stream = None
        ########################################

        self.url = url
        self.delete = False
        self.is_play_trailer = False
        self.complete = True

        tries = 0
        while True:
            try:
                self.source = YouTube(url)
            except KeyError as e:
                if e.args[0] == 'url':
                    self.delete = True
                    self.is_play_trailer = True
                    # todo (1): add youtube-dl info grabber/downloader
                    # stuff I need: title, length, keywords?
                    return
                elif e.args[0] == 'url_encoded_fmt_stream_map':
                    if tries > 4:
                        print('Failed to load youtube data, retrying. Reason: ' + str(e))
                        self.delete = True
                        return

                    print('Failed to load youtube data, retrying. Reason: ' + str(e))
                    time.sleep(2)
                    tries += 1

                else:
                    raise
            except RegexMatchError as e:
                print('Pytube failed to load video info. Reason: ' + url + ': ' + str(e))
                self.delete = True
                return
            except timeout as e:
                if tries > 4:
                    print('Pytube failed to load video info. Reason: ' + str(e))
                    self.complete = False
                    if Stream.conn_errors > 2:
                        raise
                    else:
                        Stream.conn_errors += 1
                    return

                print('Pytube failed to load video info. Reason: ' + str(e) + ', retrying...')
                tries += 1
                time.sleep(1)
            except URLError as e:
                if tries > 2:
                    print('Pytube failed to load video info. Reason: ' + str(e))
                    self.complete = False
                    if YoutubeVideo.conn_errors > 2:
                        raise
                    else:
                        YoutubeVideo.conn_errors += 1
                    return

                print('Pytube failed to load video info. Reason: ' + str(e) + ', retrying...')
                time.sleep(1)
                tries += 1
            else:
                YoutubeVideo.conn_errors = 0
                break

        self.score = score

        self.title = self.source.title
        self.title = tools.get_clean_string(self.title)
        self.rating = float(self.source.player_config_args['avg_rating'])
        self.view_count = int(self.source.player_config_args['view_count'])
        self.channel = self.source.player_config_args['author']
        self.length = self.source.player_config_args['length_seconds']

        self.thumbnail_url = self.source.thumbnail_url
        try:
            self.thumbnail_url = self.source.thumbnail_url
        except KeyError:
            self.thumbnail_url = None

        try:
            self.tags = self.source.player_config_args['keywords'].split(',')
        except KeyError:
            self.tags = ''

        if self.view_count < 100:
            self.view_count = 100

        self.adjusted_rating = self.rating * (1 - 1 / ((self.view_count / 60) ** 0.5))

        self.load_streams(min_resolution, max_resolution)
        self.update_quality_score(preferred_container)
        self.update_best_audio_stream(preferred_container, force_preferred_container)
        self.update_best_video_stream(preferred_container, force_preferred_container)
        self.update_best_combined_stream(preferred_container, force_preferred_container)

        if self.is_play_trailer:
            self.update_youtube_dl_info()