def setUpClass(cls): cls.shows = [] show = Series(1, 121361) show.name = "Italian Works" show.episodes = [] episode = Episode(show, 5, 10) episode.name = "Pines of Rome" episode.scene_season = 5 episode.scene_episode = 10 show.episodes.append(episode) cls.shows.append(show)
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): series = Series(indexer=1, indexerid=12345, lang='en') series.name = 'Show Name' series.genre = 'Comedy' if anime_type: series.anime = 1 # make a fake episode object ep = Episode(series=series, season=2, episode=3) ep.status = DOWNLOADED ep.quality = Quality.HDTV ep.airdate = datetime.date(2011, 3, 9) ep.name = 'Ep Name' ep.absolute_number = 13 ep.release_name = 'Show.Name.S02E03.HDTV.x264-RLSGROUP' ep.is_proper = True if abd: ep.release_name = 'Show.Name.2011.03.09.HDTV.x264-RLSGROUP' ep.series.air_by_date = 1 elif sports: ep.release_name = 'Show.Name.2011.03.09.HDTV.x264-RLSGROUP' ep.series.sports = 1 elif anime_type: ep.release_name = 'Show.Name.013.HDTV.x264-RLSGROUP' if multi is not None: ep.name = 'Ep Name (1)' ep.release_name = 'Show.Name.S02E03E04E05.HDTV.x264-RLSGROUP' if anime_type: ep.release_name = 'Show.Name.013-015.HDTV.x264-RLSGROUP' second_ep = Episode(series, 2, 4) second_ep.name = 'Ep Name (2)' second_ep.status = DOWNLOADED second_ep.quality = Quality.HDTV second_ep.absolute_number = 14 second_ep.release_name = ep.release_name third_ep = Episode(series, 2, 5) third_ep.name = 'Ep Name (3)' third_ep.status = DOWNLOADED third_ep.quality = Quality.HDTV third_ep.absolute_number = 15 third_ep.release_name = ep.release_name ep.related_episodes.append(second_ep) ep.related_episodes.append(third_ep) return ep
def generate_sample_ep(multi=None, abd=False, sports=False, anime_type=None): series = Series(indexer=1, indexerid=12345, lang='en') series.name = 'Show Name' series.genre = 'Comedy' if anime_type: series.anime = 1 # make a fake episode object ep = Episode(series=series, season=2, episode=3) ep._status = DOWNLOADED ep.quality = Quality.HDTV ep.airdate = datetime.date(2011, 3, 9) ep.name = 'Ep Name' ep.absolute_number = 13 ep.release_name = 'Show.Name.S02E03.HDTV.x264-RLSGROUP' ep.is_proper = True if abd: ep.release_name = 'Show.Name.2011.03.09.HDTV.x264-RLSGROUP' ep.series.air_by_date = 1 elif sports: ep.release_name = 'Show.Name.2011.03.09.HDTV.x264-RLSGROUP' ep.series.sports = 1 elif anime_type: ep.release_name = 'Show.Name.013.HDTV.x264-RLSGROUP' if multi is not None: ep.name = 'Ep Name (1)' ep.release_name = 'Show.Name.S02E03E04E05.HDTV.x264-RLSGROUP' if anime_type: ep.release_name = 'Show.Name.013-015.HDTV.x264-RLSGROUP' second_ep = Episode(series, 2, 4) second_ep.name = 'Ep Name (2)' second_ep._status = DOWNLOADED second_ep.quality = Quality.HDTV second_ep.absolute_number = 14 second_ep.release_name = ep.release_name third_ep = Episode(series, 2, 5) third_ep.name = 'Ep Name (3)' third_ep._status = DOWNLOADED third_ep.quality = Quality.HDTV third_ep.absolute_number = 15 third_ep.release_name = ep.release_name ep.related_episodes.append(second_ep) ep.related_episodes.append(third_ep) return ep
def _test_all_possible_show_names(self, name, indexerid=0, expected=None): """Test all possible show names. :param name: :param indexerid: :param expected: :return: """ expected = [] if expected is None else expected show = Series(1, indexerid) show.name = name result = show.get_all_possible_names(show) self.assertTrue(len(set(expected).intersection(set(result))) == len(expected))
def _test_all_possible_show_names(self, name, indexerid=0, expected=None): """Test all possible show names. :param name: :param indexerid: :param expected: :return: """ expected = [] if expected is None else expected show = Series(1, indexerid) show.name = name result = show.get_all_possible_names(show) self.assertTrue( len(set(expected).intersection(set(result))) == len(expected))
def test_init_empty_db(self): show = Series(1, 1, "en") episode = Episode(show, 1, 1) episode.name = "asdasdasdajkaj" episode.save_to_db() episode.load_from_db(1, 1) self.assertEqual(episode.name, "asdasdasdajkaj")
def backlogShow(self, showslug): identifier = SeriesIdentifier.from_slug(showslug) series_obj = Series.find_by_identifier(identifier) if series_obj: app.backlog_search_scheduler.action.search_backlog([series_obj]) return self.redirect('/manage/backlogOverview/')
def load_from_db(): """Populate the showList with shows from the database.""" test_main_db_con = test.db.DBConnection() sql_results = test_main_db_con.select("SELECT * FROM tv_shows") for sql_show in sql_results: try: cur_show = Series(int(sql_show["indexer"]), int(sql_show["indexer_id"])) app.showList.append(cur_show) except Exception as error: # pylint: disable=broad-except print("There was an error creating the show {}".format(error))
def setUpClass(cls): """Set up class for tests.""" num_legacy_shows = 3 num_shows = 3 num_episodes_per_show = 5 cls.mydb = db.DBConnection() cls.legacy_shows = [] cls.shows = [] # Per-show-notifications were originally added for email notifications only. To add # this feature to other notifiers, it was necessary to alter the way text is stored in # one of the DB columns. Therefore, to test properly, we must create some shows that # store emails in the old method (legacy method) and then other shows that will use # the new method. for show_counter in list(range(100, 100 + num_legacy_shows)): show = Series(1, show_counter) show.name = "Show " + text_type(show_counter) show.episodes = [] for episode_counter in list(range(0, num_episodes_per_show)): episode = Episode(show, test.SEASON, episode_counter) episode.name = "Episode " + text_type(episode_counter + 1) episode.quality = "SDTV" show.episodes.append(episode) show.save_to_db() cls.legacy_shows.append(show) for show_counter in list(range(200, 200 + num_shows)): show = Series(1, show_counter) show.name = "Show " + text_type(show_counter) show.episodes = [] for episode_counter in list(range(0, num_episodes_per_show)): episode = Episode(show, test.SEASON, episode_counter) episode.name = "Episode " + text_type(episode_counter + 1) episode.quality = "SDTV" show.episodes.append(episode) show.save_to_db() cls.shows.append(show)
def create(indexer=INDEXER_TVDBV2, indexerid=0, lang='', quality=SD, season_folders=1, enabled_subtitles=0, **kwargs): monkeypatch.setattr(Series, '_load_from_db', lambda method: None) target = Series(indexer=indexer, indexerid=indexerid, lang=lang, quality=quality, season_folders=season_folders, enabled_subtitles=enabled_subtitles) return _patch_object(monkeypatch, target, **kwargs)
def test_should_refresh(p): """Run the test.""" # Given cur_status = p['cur_status'] same_file = p['same_file'] check_quality_again = p['check_quality_again'] anime = p['anime'] filepath = p['filepath'] expected = p['expected'] # When replace, msg = Series.should_refresh_file(cur_status, same_file, check_quality_again, anime, filepath) actual = replace # Then if expected != actual: print msg assert expected == actual
def test_process(self): show = Series(1, 3) show.name = test.SHOW_NAME show.location = test.SHOW_DIR show.save_to_db() app.showList = [show] episode = Episode(show, test.SEASON, test.EPISODE) episode.name = "some episode name" episode.save_to_db() addNameToCache('show name', 3) app.PROCESS_METHOD = 'move' post_processor = PostProcessor(test.FILE_PATH) self.assertTrue(post_processor.process())
def do_test(): """Test to perform.""" global search_items # pylint: disable=global-statement search_items = cur_data["i"] show = Series(1, tvdb_id) show.name = show_name show.quality = cur_data["q"] show.save_to_db() app.showList.append(show) episode = None for epNumber in cur_data["e"]: episode = Episode(show, cur_data["s"], epNumber) episode.status = common.WANTED episode.save_to_db() best_result = search_providers(show, episode.episode, force_search) if not best_result: assert cur_data["b"] == best_result # pylint: disable=no-member assert cur_data["b"] == best_result.name # first is expected, second is chosen one
def test_get_episode(): show = Series(1, 1, "en") show.name = "show name" show.network = "cbs" show.genre = "crime" show.runtime = 40 show.status = "Ended" show.default_ep_status = "5" show.airs = "monday" show.start_year = 1987 show.save_to_db() app.showList = [show]
def test_set_name(self): show = Series(1, 1, "en") show.name = "newName" show.save_to_db() show._load_from_db() self.assertEqual(show.name, "newName")
def test_change_indexerid(self): show = Series(1, 1, "en") show.name = "show name" show.network = "cbs" show.genre = "crime" show.runtime = 40 show.status = "Ended" show.default_ep_status = "5" show.airs = "monday" show.start_year = 1987 show.save_to_db() show._load_from_db() show.indexerid = 2 show.save_to_db() show._load_from_db() self.assertEqual(show.indexerid, 2)
def do_test(self): """Test to perform.""" series = Series(1, int(cur_data["tvdbid"])) series.name = cur_name series.quality = common.ANY | common.Quality.UNKNOWN | common.Quality.RAWHDTV # series.save_to_db() # app.showList.append(series) for ep_number in cur_data["e"]: episode = Episode(series, cur_data["s"], ep_number) episode.status = common.WANTED # We aren't updating scene numbers, so fake it here episode.scene_season = cur_data["s"] episode.scene_episode = ep_number # episode.save_to_db() cur_provider.series = series season_strings = cur_provider._get_season_search_strings(episode) # pylint: disable=protected-access episode_strings = cur_provider._get_episode_search_strings(episode) # pylint: disable=protected-access fail = False cur_string = '' for cur_string in season_strings, episode_strings: if not all([isinstance(cur_string, list), isinstance(cur_string[0], dict)]): print(" %s is using a wrong string format!" % cur_provider.name) print(cur_string) fail = True continue if fail: continue try: assert season_strings == cur_data["s_strings"] assert episode_strings == cur_data["e_strings"] except AssertionError: print (" %s is using a wrong string format!" % cur_provider.name) print (cur_string) continue search_strings = episode_strings[0] # search_strings.update(season_strings[0]) # search_strings.update({"RSS":['']}) # print(search_strings) if not cur_provider.public: continue items = cur_provider.search(search_strings) # pylint: disable=protected-access if not items: print("No results from cur_provider?") continue title, url = cur_provider._get_title_and_url(items[0]) # pylint: disable=protected-access for word in series.name.split(" "): if not word.lower() in title.lower(): print("Show cur_name not in title: %s. URL: %s" % (title, url)) continue if not url: print("url is empty") continue quality = cur_provider.get_quality(items[0]) size = cur_provider._get_size(items[0]) # pylint: disable=protected-access if not series.quality & quality: print("Quality not in common.ANY, %r %s" % (quality, size)) continue
def run(self): ShowQueueItem.run(self) logger.log(u"Starting to add show {0}".format( "by ShowDir: {0}".format(self.showDir) if self. showDir else u"by Indexer Id: {0}".format(self.indexer_id))) # make sure the Indexer IDs are valid try: l_indexer_api_params = indexerApi(self.indexer).api_params.copy() if self.lang: l_indexer_api_params['language'] = self.lang logger.log(u"" + str(indexerApi(self.indexer).name) + ": " + repr(l_indexer_api_params)) indexer_api = indexerApi( self.indexer).indexer(**l_indexer_api_params) s = indexer_api[self.indexer_id] # Let's try to create the show Dir if it's not provided. This way we force the show dir # to build build using the Indexers provided series name if not self.showDir and self.root_dir: show_name = get_showname_from_indexer(self.indexer, self.indexer_id, self.lang) if show_name: self.showDir = os.path.join(self.root_dir, sanitize_filename(show_name)) dir_exists = make_dir(self.showDir) if not dir_exists: logger.log( u"Unable to create the folder {0}, can't add the show" .format(self.showDir)) return chmod_as_parent(self.showDir) else: logger.log( u"Unable to get a show {0}, can't add the show".format( self.showDir)) return # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that # has no proper english version of the show if getattr(s, 'seriesname', None) is None: logger.log( u"Show in {0} has no name on {1}, probably searched with the wrong language." .format(self.showDir, indexerApi(self.indexer).name), logger.ERROR) ui.notifications.error( 'Unable to add show', 'Show in {0} has no name on {1}, probably the wrong language. \ Delete .nfo and manually add the correct language.' .format(self.showDir, indexerApi(self.indexer).name)) self._finishEarly() return # if the show has no episodes/seasons if not s: logger.log(u"Show " + str(s['seriesname']) + u" is on " + str(indexerApi(self.indexer).name) + u" but contains no season/episode data.") ui.notifications.error( "Unable to add show", "Show {0} is on {1} but contains no season/episode data.". format(s['seriesname'], indexerApi(self.indexer).name)) self._finishEarly() return # Check if we can already find this show in our current showList. try: check_existing_shows(s, self.indexer) except IndexerShowAllreadyInLibrary as e: logger.log( u"Could not add the show %s, as it already is in your library." u" Error: %s" % (s['seriesname'], e.message), logger.WARNING) ui.notifications.error('Unable to add show', 'reason: {0}'.format(e.message)) self._finishEarly() # Clean up leftover if the newly created directory is empty. delete_empty_folders(self.showDir) return # TODO: Add more specific indexer exceptions, that should provide the user with some accurate feedback. except IndexerShowIncomplete as e: logger.log( u"%s Error while loading information from indexer %s. " u"Error: %s" % (self.indexer_id, indexerApi(self.indexer).name, e.message), logger.WARNING) ui.notifications.error( "Unable to add show", "Unable to look up the show in {0} on {1} using ID {2} " "Reason: {3}".format(self.showDir, indexerApi(self.indexer).name, self.indexer_id, e.message)) self._finishEarly() return except IndexerShowNotFoundInLanguage as e: logger.log( u'{id}: Data retrieved from {indexer} was incomplete. The indexer does not provide ' u'show information in the searched language {language}. Aborting: {error_msg}' .format(id=self.indexer_id, indexer=indexerApi(self.indexer).name, language=e.language, error_msg=e.message), logger.WARNING) ui.notifications.error( 'Error adding show!', 'Unable to add show {indexer_id} on {indexer} with this language: {language}' .format(indexer_id=self.indexer_id, indexer=indexerApi(self.indexer).name, language=e.language)) self._finishEarly() return except Exception as e: logger.log( u"%s Error while loading information from indexer %s. " u"Error: %r" % (self.indexer_id, indexerApi(self.indexer).name, e.message), logger.ERROR) ui.notifications.error( "Unable to add show", "Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. " "Delete .nfo and try adding manually again.".format( self.showDir, indexerApi(self.indexer).name, self.indexer_id)) self._finishEarly() return try: newShow = Series(self.indexer, self.indexer_id, self.lang) newShow.load_from_indexer(indexer_api) self.show = newShow # set up initial values self.show.location = self.showDir self.show.subtitles = self.subtitles if self.subtitles is not None else app.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else app.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None \ else app.FLATTEN_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else app.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else app.SCENE_DEFAULT self.show.paused = self.paused if self.paused is not None else False # set up default new/missing episode status logger.log( u"Setting all previously aired episodes to the specified status: {status}" .format(status=statusStrings[self.default_status])) self.show.default_ep_status = self.default_status if self.show.anime: self.show.release_groups = BlackAndWhiteList( self.show.indexerid) if self.blacklist: self.show.release_groups.set_black_keywords(self.blacklist) if self.whitelist: self.show.release_groups.set_white_keywords(self.whitelist) # # be smartish about this # if self.show.genre and "talk show" in self.show.genre.lower(): # self.show.air_by_date = 1 # if self.show.genre and "documentary" in self.show.genre.lower(): # self.show.air_by_date = 0 # if self.show.classification and "sports" in self.show.classification.lower(): # self.show.sports = 1 except IndexerException as e: logger.log( u"Unable to add show due to an error with " + indexerApi(self.indexer).name + ": " + e.message, logger.ERROR) if self.show: ui.notifications.error("Unable to add " + str(self.show.name) + " due to an error with " + indexerApi(self.indexer).name + "") else: ui.notifications.error( "Unable to add show due to an error with " + indexerApi(self.indexer).name + "") self._finishEarly() return except MultipleShowObjectsException: logger.log( u"The show in " + self.showDir + " is already in your show list, skipping", logger.WARNING) ui.notifications.error( 'Show skipped', "The show in " + self.showDir + " is already in your show list") self._finishEarly() return except Exception as e: logger.log(u"Error trying to add show: " + e.message, logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finishEarly() raise logger.log(u"Retrieving show info from IMDb", logger.DEBUG) try: self.show.load_imdb_info() except ImdbAPIError as e: logger.log(u"Something wrong on IMDb api: " + e.message, logger.INFO) except Exception as e: logger.log(u"Error loading IMDb info: " + e.message, logger.ERROR) try: self.show.save_to_db() except Exception as e: logger.log(u"Error saving the show to the database: " + e.message, logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finishEarly() raise # add it to the show list app.showList.append(self.show) try: self.show.load_episodes_from_indexer(tvapi=indexer_api) except Exception as e: logger.log( u"Error with " + indexerApi(self.show.indexer).name + ", not creating episode list: " + e.message, logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) # update internal name cache name_cache.build_name_cache(self.show) try: self.show.load_episodes_from_dir() except Exception as e: logger.log(u"Error searching dir for episodes: " + e.message, logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) # if they set default ep status to WANTED then run the backlog to search for episodes # FIXME: This needs to be a backlog queue item!!! if self.show.default_ep_status == WANTED: logger.log( u"Launching backlog for this show since its episodes are WANTED" ) app.backlog_search_scheduler.action.search_backlog([self.show]) self.show.write_metadata() self.show.update_metadata() self.show.populate_cache() self.show.flush_episodes() if app.USE_TRAKT: # if there are specific episodes that need to be added by trakt app.trakt_checker_scheduler.action.manage_new_show(self.show) # add show to trakt.tv library if app.TRAKT_SYNC: app.trakt_checker_scheduler.action.add_show_trakt_library( self.show) if app.TRAKT_SYNC_WATCHLIST: logger.log(u"update watchlist") notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer, force=True) # check if show has XEM mapping so we can determine if searches # should go by scene numbering or indexer numbering. if not self.scene and scene_numbering.get_xem_numbering_for_show( self.show.indexerid, self.show.indexer): self.show.scene = 1 # After initial add, set to default_status_after. self.show.default_ep_status = self.default_status_after self.finish()
def run(self): ShowQueueItem.run(self) log.info('Starting to add show by {0}', ('show_dir: {0}'.format(self.show_dir) if self.show_dir else 'Indexer Id: {0}'.format(self.indexer_id))) # make sure the Indexer IDs are valid try: l_indexer_api_params = indexerApi(self.indexer).api_params.copy() if self.lang: l_indexer_api_params['language'] = self.lang log.info( '{indexer_name}: {indexer_params!r}', { 'indexer_name': indexerApi(self.indexer).name, 'indexer_params': l_indexer_api_params }) indexer_api = indexerApi( self.indexer).indexer(**l_indexer_api_params) s = indexer_api[self.indexer_id] # Let's try to create the show Dir if it's not provided. This way we force the show dir # to build build using the Indexers provided series name if not self.show_dir and self.root_dir: show_name = get_showname_from_indexer(self.indexer, self.indexer_id, self.lang) if show_name: self.show_dir = os.path.join(self.root_dir, sanitize_filename(show_name)) dir_exists = make_dir(self.show_dir) if not dir_exists: log.info( "Unable to create the folder {0}, can't add the show", self.show_dir) return chmod_as_parent(self.show_dir) else: log.info("Unable to get a show {0}, can't add the show", self.show_dir) return # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that # has no proper english version of the show if getattr(s, 'seriesname', None) is None: log.error( 'Show in {path} has no name on {indexer}, probably searched with the wrong language.', { 'path': self.show_dir, 'indexer': indexerApi(self.indexer).name }) ui.notifications.error( 'Unable to add show', 'Show in {path} has no name on {indexer}, probably the wrong language.' ' Delete .nfo and manually add the correct language.'. format(path=self.show_dir, indexer=indexerApi(self.indexer).name)) self._finishEarly() return # Check if we can already find this show in our current showList. try: check_existing_shows(s, self.indexer) except IndexerShowAlreadyInLibrary as error: log.warning( 'Could not add the show {series}, as it already is in your library.' ' Error: {error}', { 'series': s['seriesname'], 'error': error }) ui.notifications.error('Unable to add show', 'reason: {0}'.format(error)) self._finishEarly() # Clean up leftover if the newly created directory is empty. delete_empty_folders(self.show_dir) return # TODO: Add more specific indexer exceptions, that should provide the user with some accurate feedback. except IndexerShowNotFound as error: log.warning( '{id}: Unable to look up the show in {path} using id {id} on {indexer}.' ' Delete metadata files from the folder and try adding it again.\n' 'With error: {error}', { 'id': self.indexer_id, 'path': self.show_dir, 'indexer': indexerApi(self.indexer).name, 'error': error }) ui.notifications.error( 'Unable to add show', 'Unable to look up the show in {path} using id {id} on {indexer}.' ' Delete metadata files from the folder and try adding it again.' .format(path=self.show_dir, id=self.indexer_id, indexer=indexerApi(self.indexer).name)) self._finishEarly() return except IndexerShowNotFoundInLanguage as error: log.warning( '{id}: Data retrieved from {indexer} was incomplete. The indexer does not provide' ' show information in the searched language {language}. Aborting: {error_msg}', { 'id': self.indexer_id, 'indexer': indexerApi(self.indexer).name, 'language': error.language, 'error_msg': error }) ui.notifications.error( 'Error adding show!', 'Unable to add show {indexer_id} on {indexer} with this language: {language}' .format(indexer_id=self.indexer_id, indexer=indexerApi(self.indexer).name, language=error.language)) self._finishEarly() return except Exception as error: log.error( '{id}: Error while loading information from indexer {indexer}. Error: {error!r}', { 'id': self.indexer_id, 'indexer': indexerApi(self.indexer).name, 'error': error }) ui.notifications.error( 'Unable to add show', 'Unable to look up the show in {path} on {indexer} using ID {id}.' .format(path=self.show_dir, indexer=indexerApi(self.indexer).name, id=self.indexer_id)) self._finishEarly() return try: newShow = Series(self.indexer, self.indexer_id, self.lang) newShow.load_from_indexer(indexer_api) self.show = newShow # set up initial values self.show.location = self.show_dir self.show.subtitles = self.subtitles if self.subtitles is not None else app.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else app.QUALITY_DEFAULT self.show.season_folders = self.season_folders if self.season_folders is not None \ else app.SEASON_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else app.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else app.SCENE_DEFAULT self.show.paused = self.paused if self.paused is not None else False # set up default new/missing episode status log.info( 'Setting all previously aired episodes to the specified status: {status}', {'status': statusStrings[self.default_status]}) self.show.default_ep_status = self.default_status if self.show.anime: self.show.release_groups = BlackAndWhiteList(self.show) if self.blacklist: self.show.release_groups.set_black_keywords(self.blacklist) if self.whitelist: self.show.release_groups.set_white_keywords(self.whitelist) except IndexerException as error: log.error( 'Unable to add show due to an error with {indexer}: {error}', { 'indexer': indexerApi(self.indexer).name, 'error': error }) ui.notifications.error( 'Unable to add {series_name} due to an error with {indexer_name}' .format(series_name=self.show.name if self.show else 'show', indexer_name=indexerApi(self.indexer).name)) self._finishEarly() return except MultipleShowObjectsException: log.warning( 'The show in {show_dir} is already in your show list, skipping', {'show_dir': self.show_dir}) ui.notifications.error( 'Show skipped', 'The show in {show_dir} is already in your show list'.format( show_dir=self.show_dir)) self._finishEarly() return except Exception as error: log.error('Error trying to add show: {0}', error) log.debug(traceback.format_exc()) self._finishEarly() raise log.debug('Retrieving show info from IMDb') try: self.show.load_imdb_info() except ImdbAPIError as error: log.info('Something wrong on IMDb api: {0}', error) except RequestException as error: log.warning('Error loading IMDb info: {0}', error) try: log.debug('{id}: Saving new show to database', {'id': self.show.series_id}) self.show.save_to_db() except Exception as error: log.error('Error saving the show to the database: {0}', error) log.debug(traceback.format_exc()) self._finishEarly() raise # add it to the show list app.showList.append(self.show) try: self.show.load_episodes_from_indexer(tvapi=indexer_api) except Exception as error: log.error( 'Error with {indexer}, not creating episode list: {error}', { 'indexer': indexerApi(self.show.indexer).name, 'error': error }) log.debug(traceback.format_exc()) # update internal name cache name_cache.build_name_cache(self.show) try: self.show.load_episodes_from_dir() except Exception as error: log.error('Error searching dir for episodes: {0}', error) log.debug(traceback.format_exc()) # if they set default ep status to WANTED then run the backlog to search for episodes if self.show.default_ep_status == WANTED: log.info( 'Launching backlog for this show since its episodes are WANTED' ) wanted_segments = self.show.get_wanted_segments() for season, segment in viewitems(wanted_segments): cur_backlog_queue_item = BacklogQueueItem(self.show, segment) app.forced_search_queue_scheduler.action.add_item( cur_backlog_queue_item) log.info('Sending forced backlog for {show} season {season}' ' because some episodes were set to wanted'.format( show=self.show.name, season=season)) self.show.write_metadata() self.show.update_metadata() self.show.populate_cache() self.show.flush_episodes() if app.USE_TRAKT: # if there are specific episodes that need to be added by trakt app.trakt_checker_scheduler.action.manage_new_show(self.show) # add show to trakt.tv library if app.TRAKT_SYNC: app.trakt_checker_scheduler.action.add_show_trakt_library( self.show) if app.TRAKT_SYNC_WATCHLIST: log.info('update watchlist') notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show scene_numbering.xem_refresh(self.show, force=True) # check if show has XEM mapping so we can determine if searches # should go by scene numbering or indexer numbering. Warn the user. if not self.scene and scene_numbering.get_xem_numbering_for_show( self.show): log.warning( '{id}: while adding the show {title} we noticed thexem.de has an episode mapping available' '\nyou might want to consider enabling the scene option for this show.', { 'id': self.show.series_id, 'title': self.show.name }) ui.notifications.message( 'consider enabling scene for this show', 'for show {title} you might want to consider enabling the scene option' .format(title=self.show.name)) # After initial add, set to default_status_after. self.show.default_ep_status = self.default_status_after try: log.debug('{id}: Saving new show info to database', {'id': self.show.series_id}) self.show.save_to_db() except Exception as error: log.warning( '{id}: Error saving new show info to database: {error_msg}', { 'id': self.show.series_id, 'error_msg': error }) log.error(traceback.format_exc()) # Send ws update to client ws.Message('showAdded', self.show.to_json(detailed=False)).push() self.finish()
def massEditSubmit(self, paused=None, default_ep_status=None, dvd_order=None, anime=None, sports=None, scene=None, season_folders=None, quality_preset=None, subtitles=None, air_by_date=None, allowed_qualities=None, preferred_qualities=None, toEdit=None, *args, **kwargs): allowed_qualities = allowed_qualities or [] preferred_qualities = preferred_qualities or [] dir_map = {} for cur_arg in kwargs: if not cur_arg.startswith('orig_root_dir_'): continue which_index = cur_arg.replace('orig_root_dir_', '') end_dir = kwargs['new_root_dir_{index}'.format(index=which_index)] dir_map[kwargs[cur_arg]] = end_dir series_slugs = toEdit.split('|') if toEdit else [] errors = 0 for series_slug in series_slugs: identifier = SeriesIdentifier.from_slug(series_slug) series_obj = Series.find_by_identifier(identifier) if not series_obj: continue cur_root_dir = os.path.dirname(series_obj._location) cur_show_dir = os.path.basename(series_obj._location) if cur_root_dir in dir_map and cur_root_dir != dir_map[ cur_root_dir]: new_show_dir = os.path.join(dir_map[cur_root_dir], cur_show_dir) logger.log( u'For show {show.name} changing dir from {show._location} to {location}' .format(show=series_obj, location=new_show_dir)) else: new_show_dir = series_obj._location if paused == 'keep': new_paused = series_obj.paused else: new_paused = True if paused == 'enable' else False new_paused = 'on' if new_paused else 'off' if default_ep_status == 'keep': new_default_ep_status = series_obj.default_ep_status else: new_default_ep_status = default_ep_status if anime == 'keep': new_anime = series_obj.anime else: new_anime = True if anime == 'enable' else False new_anime = 'on' if new_anime else 'off' if sports == 'keep': new_sports = series_obj.sports else: new_sports = True if sports == 'enable' else False new_sports = 'on' if new_sports else 'off' if scene == 'keep': new_scene = series_obj.is_scene else: new_scene = True if scene == 'enable' else False new_scene = 'on' if new_scene else 'off' if air_by_date == 'keep': new_air_by_date = series_obj.air_by_date else: new_air_by_date = True if air_by_date == 'enable' else False new_air_by_date = 'on' if new_air_by_date else 'off' if dvd_order == 'keep': new_dvd_order = series_obj.dvd_order else: new_dvd_order = True if dvd_order == 'enable' else False new_dvd_order = 'on' if new_dvd_order else 'off' if season_folders == 'keep': new_season_folders = series_obj.season_folders else: new_season_folders = True if season_folders == 'enable' else False new_season_folders = 'on' if new_season_folders else 'off' if subtitles == 'keep': new_subtitles = series_obj.subtitles else: new_subtitles = True if subtitles == 'enable' else False new_subtitles = 'on' if new_subtitles else 'off' if quality_preset == 'keep': allowed_qualities, preferred_qualities = series_obj.current_qualities elif try_int(quality_preset, None): preferred_qualities = [] exceptions_list = [] errors += self.editShow(identifier.indexer.slug, identifier.id, new_show_dir, allowed_qualities, preferred_qualities, exceptions_list, defaultEpStatus=new_default_ep_status, season_folders=new_season_folders, paused=new_paused, sports=new_sports, dvd_order=new_dvd_order, subtitles=new_subtitles, anime=new_anime, scene=new_scene, air_by_date=new_air_by_date, directCall=True) if errors: ui.notifications.error( 'Errors', '{num} error{s} while saving changes. Please check logs'. format(num=errors, s='s' if errors > 1 else '')) return self.redirect('/manage/')
def do_test(self): """Test to perform.""" series = Series(1, int(cur_data["tvdbid"])) series.name = cur_name series.quality = common.ANY | common.Quality.UNKNOWN | common.Quality.RAWHDTV # series.save_to_db() # app.showList.append(series) for ep_number in cur_data["e"]: episode = Episode(series, cur_data["s"], ep_number) episode.status = common.WANTED # We aren't updating scene numbers, so fake it here episode.scene_season = cur_data["s"] episode.scene_episode = ep_number # episode.save_to_db() cur_provider.series = series season_strings = cur_provider._get_season_search_strings(episode) # pylint: disable=protected-access episode_strings = cur_provider._get_episode_search_strings(episode) # pylint: disable=protected-access fail = False cur_string = '' for cur_string in season_strings, episode_strings: if not all([isinstance(cur_string, list), isinstance(cur_string[0], dict)]): print("%s is using a wrong string format!" % cur_provider.name) print(cur_string) fail = True continue if fail: continue try: assert season_strings == cur_data["s_strings"] assert episode_strings == cur_data["e_strings"] except AssertionError: print("%s is using a wrong string format!" % cur_provider.name) print(cur_string) continue search_strings = episode_strings[0] # search_strings.update(season_strings[0]) # search_strings.update({"RSS":['']}) # print(search_strings) if not cur_provider.public: continue items = cur_provider.search(search_strings) # pylint: disable=protected-access if not items: print("No results from cur_provider?") continue title, url = cur_provider._get_title_and_url(items[0]) # pylint: disable=protected-access for word in series.name.split(" "): if not word.lower() in title.lower(): print("Show cur_name not in title: %s. URL: %s" % (title, url)) continue if not url: print("url is empty") continue quality = cur_provider.get_quality(items[0]) size = cur_provider._get_size(items[0]) # pylint: disable=protected-access if not series.quality & quality: print("Quality not in common.ANY, %r %s" % (quality, size)) continue
def test_scene_ex_babylon_5(self): series_obj = Series(1, 70726) self.assertEqual( sorted(scene_exceptions.get_scene_exceptions(series_obj, 1)), sorted({'Babylon 5', 'Babylon5'}))
def test_init_indexerid(self): show = Series(1, 1, "en") self.assertEqual(show.indexerid, 1)
def setUpClass(cls): """Set up class for tests.""" num_legacy_shows = 3 num_shows = 3 num_episodes_per_show = 5 cls.mydb = db.DBConnection() cls.legacy_shows = [] cls.shows = [] # Per-show-notifications were originally added for email notifications only. To add # this feature to other notifiers, it was necessary to alter the way text is stored in # one of the DB columns. Therefore, to test properly, we must create some shows that # store emails in the old method (legacy method) and then other shows that will use # the new method. for show_counter in range(100, 100 + num_legacy_shows): show = Series(1, show_counter) show.name = "Show " + str(show_counter) show.episodes = [] for episode_counter in range(0, num_episodes_per_show): episode = Episode(show, test.SEASON, episode_counter) episode.name = "Episode " + str(episode_counter + 1) episode.quality = "SDTV" show.episodes.append(episode) show.save_to_db() cls.legacy_shows.append(show) for show_counter in range(200, 200 + num_shows): show = Series(1, show_counter) show.name = "Show " + str(show_counter) show.episodes = [] for episode_counter in range(0, num_episodes_per_show): episode = Episode(show, test.SEASON, episode_counter) episode.name = "Episode " + str(episode_counter + 1) episode.quality = "SDTV" show.episodes.append(episode) show.save_to_db() cls.shows.append(show)
def test_default_media_name(self): series_obj = Series(1, 70726) self.assertEqual(ShowNetworkLogo(series_obj, '').default_media_name, os.path.join('network', 'nonetwork.png'))
def massEdit(self, toEdit=None): t = PageTemplate(rh=self, filename='manage_massEdit.mako') if not toEdit: return self.redirect('/manage/') series_slugs = toEdit.split('|') show_list = [] show_names = [] for slug in series_slugs: identifier = SeriesIdentifier.from_slug(slug) series_obj = Series.find_by_identifier(identifier) if series_obj: show_list.append(series_obj) show_names.append(series_obj.name) season_folders_all_same = True last_season_folders = None paused_all_same = True last_paused = None default_ep_status_all_same = True last_default_ep_status = None anime_all_same = True last_anime = None sports_all_same = True last_sports = None quality_all_same = True last_quality = None subtitles_all_same = True last_subtitles = None scene_all_same = True last_scene = None air_by_date_all_same = True last_air_by_date = None dvd_order_all_same = True last_dvd_order = None root_dir_list = [] for cur_show in show_list: cur_root_dir = os.path.dirname(cur_show._location) # pylint: disable=protected-access if cur_root_dir not in root_dir_list: root_dir_list.append(cur_root_dir) # if we know they're not all the same then no point even bothering if paused_all_same: # if we had a value already and this value is different then they're not all the same if last_paused not in (None, cur_show.paused): paused_all_same = False else: last_paused = cur_show.paused if default_ep_status_all_same: if last_default_ep_status not in (None, cur_show.default_ep_status): default_ep_status_all_same = False else: last_default_ep_status = cur_show.default_ep_status if anime_all_same: # if we had a value already and this value is different then they're not all the same if last_anime not in (None, cur_show.is_anime): anime_all_same = False else: last_anime = cur_show.anime if season_folders_all_same: if last_season_folders not in (None, cur_show.season_folders): season_folders_all_same = False else: last_season_folders = cur_show.season_folders if quality_all_same: if last_quality not in (None, cur_show.quality): quality_all_same = False else: last_quality = cur_show.quality if subtitles_all_same: if last_subtitles not in (None, cur_show.subtitles): subtitles_all_same = False else: last_subtitles = cur_show.subtitles if scene_all_same: if last_scene not in (None, cur_show.scene): scene_all_same = False else: last_scene = cur_show.scene if sports_all_same: if last_sports not in (None, cur_show.sports): sports_all_same = False else: last_sports = cur_show.sports if air_by_date_all_same: if last_air_by_date not in (None, cur_show.air_by_date): air_by_date_all_same = False else: last_air_by_date = cur_show.air_by_date if dvd_order_all_same: if last_dvd_order not in (None, cur_show.dvd_order): dvd_order_all_same = False else: last_dvd_order = cur_show.dvd_order default_ep_status_value = last_default_ep_status if default_ep_status_all_same else None paused_value = last_paused if paused_all_same else None anime_value = last_anime if anime_all_same else None season_folders_value = last_season_folders if season_folders_all_same else None quality_value = last_quality if quality_all_same else None subtitles_value = last_subtitles if subtitles_all_same else None scene_value = last_scene if scene_all_same else None sports_value = last_sports if sports_all_same else None air_by_date_value = last_air_by_date if air_by_date_all_same else None dvd_order_value = last_dvd_order if dvd_order_all_same else None root_dir_list = root_dir_list return t.render(showList=toEdit, showNames=show_names, default_ep_status_value=default_ep_status_value, dvd_order_value=dvd_order_value, paused_value=paused_value, anime_value=anime_value, season_folders_value=season_folders_value, quality_value=quality_value, subtitles_value=subtitles_value, scene_value=scene_value, sports_value=sports_value, air_by_date_value=air_by_date_value, root_dir_list=root_dir_list)
def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toRemove=None, toMetadata=None, toSubtitle=None, toImageUpdate=None): to_update = toUpdate.split('|') if toUpdate else [] to_refresh = toRefresh.split('|') if toRefresh else [] to_rename = toRename.split('|') if toRename else [] to_subtitle = toSubtitle.split('|') if toSubtitle else [] to_delete = toDelete.split('|') if toDelete else [] to_remove = toRemove.split('|') if toRemove else [] to_metadata = toMetadata.split('|') if toMetadata else [] to_image_update = toImageUpdate.split('|') if toImageUpdate else [] errors = [] refreshes = [] updates = [] renames = [] subtitles = [] image_update = [] for slug in set(to_update + to_refresh + to_rename + to_subtitle + to_delete + to_remove + to_metadata + to_image_update): identifier = SeriesIdentifier.from_slug(slug) series_obj = Series.find_by_identifier(identifier) if not series_obj: continue if slug in to_delete + to_remove: app.show_queue_scheduler.action.removeShow( series_obj, slug in to_delete) continue # don't do anything else if it's being deleted or removed if slug in to_update: try: app.show_queue_scheduler.action.updateShow(series_obj) updates.append(series_obj.name) except CantUpdateShowException as msg: errors.append( 'Unable to update show: {error}'.format(error=msg)) elif slug in to_refresh: # don't bother refreshing shows that were updated try: app.show_queue_scheduler.action.refreshShow(series_obj) refreshes.append(series_obj.name) except CantRefreshShowException as msg: errors.append( 'Unable to refresh show {show.name}: {error}'.format( show=series_obj, error=msg)) if slug in to_rename: app.show_queue_scheduler.action.renameShowEpisodes(series_obj) renames.append(series_obj.name) if slug in to_subtitle: app.show_queue_scheduler.action.download_subtitles(series_obj) subtitles.append(series_obj.name) if slug in to_image_update: image_cache.replace_images(series_obj) if errors: ui.notifications.error('Errors encountered', '<br />\n'.join(errors)) message = '' if updates: message += '\nUpdates: {0}'.format(len(updates)) if refreshes: message += '\nRefreshes: {0}'.format(len(refreshes)) if renames: message += '\nRenames: {0}'.format(len(renames)) if subtitles: message += '\nSubtitles: {0}'.format(len(subtitles)) if image_update: message += '\nImage updates: {0}'.format(len(image_update)) if message: ui.notifications.message('Queued actions:', message) return self.redirect('/manage/')
def massEditSubmit(self, paused=None, default_ep_status=None, dvd_order=None, anime=None, sports=None, scene=None, season_folders=None, quality_preset=None, subtitles=None, air_by_date=None, allowed_qualities=None, preferred_qualities=None, toEdit=None, *args, **kwargs): allowed_qualities = allowed_qualities or [] preferred_qualities = preferred_qualities or [] dir_map = {} for cur_arg in kwargs: if not cur_arg.startswith('orig_root_dir_'): continue which_index = cur_arg.replace('orig_root_dir_', '') end_dir = kwargs['new_root_dir_{index}'.format(index=which_index)] dir_map[kwargs[cur_arg]] = end_dir series_slugs = toEdit.split('|') if toEdit else [] errors = 0 for series_slug in series_slugs: identifier = SeriesIdentifier.from_slug(series_slug) series_obj = Series.find_by_identifier(identifier) if not series_obj: continue cur_root_dir = os.path.dirname(series_obj._location) cur_show_dir = os.path.basename(series_obj._location) if cur_root_dir in dir_map and cur_root_dir != dir_map[cur_root_dir]: new_show_dir = os.path.join(dir_map[cur_root_dir], cur_show_dir) logger.log(u'For show {show.name} changing dir from {show._location} to {location}'.format (show=series_obj, location=new_show_dir)) else: new_show_dir = series_obj._location if paused == 'keep': new_paused = series_obj.paused else: new_paused = True if paused == 'enable' else False new_paused = 'on' if new_paused else 'off' if default_ep_status == 'keep': new_default_ep_status = series_obj.default_ep_status else: new_default_ep_status = default_ep_status if anime == 'keep': new_anime = series_obj.anime else: new_anime = True if anime == 'enable' else False new_anime = 'on' if new_anime else 'off' if sports == 'keep': new_sports = series_obj.sports else: new_sports = True if sports == 'enable' else False new_sports = 'on' if new_sports else 'off' if scene == 'keep': new_scene = series_obj.is_scene else: new_scene = True if scene == 'enable' else False new_scene = 'on' if new_scene else 'off' if air_by_date == 'keep': new_air_by_date = series_obj.air_by_date else: new_air_by_date = True if air_by_date == 'enable' else False new_air_by_date = 'on' if new_air_by_date else 'off' if dvd_order == 'keep': new_dvd_order = series_obj.dvd_order else: new_dvd_order = True if dvd_order == 'enable' else False new_dvd_order = 'on' if new_dvd_order else 'off' if season_folders == 'keep': new_season_folders = series_obj.season_folders else: new_season_folders = True if season_folders == 'enable' else False new_season_folders = 'on' if new_season_folders else 'off' if subtitles == 'keep': new_subtitles = series_obj.subtitles else: new_subtitles = True if subtitles == 'enable' else False new_subtitles = 'on' if new_subtitles else 'off' if quality_preset == 'keep': allowed_qualities, preferred_qualities = series_obj.current_qualities elif try_int(quality_preset, None): preferred_qualities = [] exceptions_list = [] errors += self.editShow(identifier.indexer.slug, identifier.id, new_show_dir, allowed_qualities, preferred_qualities, exceptions_list, defaultEpStatus=new_default_ep_status, season_folders=new_season_folders, paused=new_paused, sports=new_sports, dvd_order=new_dvd_order, subtitles=new_subtitles, anime=new_anime, scene=new_scene, air_by_date=new_air_by_date, directCall=True) if errors: ui.notifications.error('Errors', '{num} error{s} while saving changes. Please check logs'.format (num=errors, s='s' if errors > 1 else '')) return self.redirect('/manage/')
def test_default_media_name(self): series_obj = Series(1, 70726) self.assertEqual(GenericMedia(series_obj, '').default_media_name, '')
def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toRemove=None, toMetadata=None, toSubtitle=None, toImageUpdate=None): to_update = toUpdate.split('|') if toUpdate else [] to_refresh = toRefresh.split('|') if toRefresh else [] to_rename = toRename.split('|') if toRename else [] to_subtitle = toSubtitle.split('|') if toSubtitle else [] to_delete = toDelete.split('|') if toDelete else [] to_remove = toRemove.split('|') if toRemove else [] to_metadata = toMetadata.split('|') if toMetadata else [] to_image_update = toImageUpdate.split('|') if toImageUpdate else [] errors = [] refreshes = [] updates = [] renames = [] subtitles = [] image_update = [] for slug in set(to_update + to_refresh + to_rename + to_subtitle + to_delete + to_remove + to_metadata + to_image_update): identifier = SeriesIdentifier.from_slug(slug) series_obj = Series.find_by_identifier(identifier) if not series_obj: continue if slug in to_delete + to_remove: app.show_queue_scheduler.action.removeShow(series_obj, slug in to_delete) continue # don't do anything else if it's being deleted or removed if slug in to_update: try: app.show_queue_scheduler.action.updateShow(series_obj) updates.append(series_obj.name) except CantUpdateShowException as msg: errors.append('Unable to update show: {error}'.format(error=msg)) elif slug in to_refresh: # don't bother refreshing shows that were updated try: app.show_queue_scheduler.action.refreshShow(series_obj) refreshes.append(series_obj.name) except CantRefreshShowException as msg: errors.append('Unable to refresh show {show.name}: {error}'.format (show=series_obj, error=msg)) if slug in to_rename: app.show_queue_scheduler.action.renameShowEpisodes(series_obj) renames.append(series_obj.name) if slug in to_subtitle: app.show_queue_scheduler.action.download_subtitles(series_obj) subtitles.append(series_obj.name) if slug in to_image_update: image_cache.replace_images(series_obj) if errors: ui.notifications.error('Errors encountered', '<br />\n'.join(errors)) message = '' if updates: message += '\nUpdates: {0}'.format(len(updates)) if refreshes: message += '\nRefreshes: {0}'.format(len(refreshes)) if renames: message += '\nRenames: {0}'.format(len(renames)) if subtitles: message += '\nSubtitles: {0}'.format(len(subtitles)) if image_update: message += '\nImage updates: {0}'.format(len(image_update)) if message: ui.notifications.message('Queued actions:', message) return self.redirect('/manage/')
def test_scene_ex_empty(self): series_obj = Series(1, 70725) self.assertEqual(scene_exceptions.get_scene_exceptions(series_obj, 0), set())
def test_default_media_name(self): series_obj = Series(1, 70726) self.assertEqual(ShowBanner(series_obj, '').default_media_name, 'banner.png')
def test_default_media_name(self): series_obj = Series(1, 70726) self.assertEqual(ShowFanArt(series_obj, '').default_media_name, 'fanart.png')