def post(self, series_slug=None, path_param=None): """Add a new series.""" if series_slug is not None: return self._bad_request('Series slug should not be specified') data = json_decode(self.request.body) if not data or 'id' not in data: return self._bad_request('Invalid series data') ids = {k: v for k, v in viewitems(data['id']) if k != 'imdb'} if len(ids) != 1: return self._bad_request( 'Only 1 indexer identifier should be specified') identifier = SeriesIdentifier.from_slug('{slug}{id}'.format( slug=list(ids)[0], id=list(itervalues(ids))[0])) if not identifier: return self._bad_request('Invalid series identifier') series = Series.find_by_identifier(identifier) if series: return self._conflict('Series already exist added') series = Series.from_identifier(identifier) if not Series.save_series(series): return self._not_found('Series not found in the specified indexer') return self._created(series.to_json(), identifier=identifier.slug)
def http_post(self, series_slug=None, path_param=None): """Add a new series.""" if series_slug is not None: return self._bad_request('Series slug should not be specified') data = json_decode(self.request.body) if not data or 'id' not in data: return self._bad_request('Invalid series data') ids = {k: v for k, v in viewitems(data['id']) if k != 'imdb'} if len(ids) != 1: return self._bad_request('Only 1 indexer identifier should be specified') identifier = SeriesIdentifier.from_slug('{slug}{id}'.format(slug=list(ids)[0], id=list(itervalues(ids))[0])) if not identifier: return self._bad_request('Invalid series identifier') series = Series.find_by_identifier(identifier) if series: return self._conflict('Series already exist added') series = Series.from_identifier(identifier) if not Series.save_series(series): return self._not_found('Series not found in the specified indexer') return self._created(series.to_json(), identifier=identifier.slug)
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))) show_slug = indexer_id_to_slug(self.indexer, self.indexer_id) series = Series.from_identifier(SeriesIdentifier.from_slug(show_slug)) step = [] # Small helper, to reduce code for messaging def message_step(new_step): step.append(new_step) ws.Message('QueueItemShowAdd', dict(step=step, **self.to_json)).push() try: try: # Push an update to any open Web UIs through the WebSocket message_step('load show from {indexer}'.format( indexer=indexerApi(self.indexer).name)) api = series.identifier.get_indexer_api(self.options) if getattr(api[self.indexer_id], '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._finish_early() raise SaveSeriesException( 'Indexer is missing a showname in this language: {0!r}' ) series.load_from_indexer(tvapi=api) message_step('load info from imdb') series.load_imdb_info() except IndexerException as error: log.warning( 'Unable to load series from indexer: {0!r}'.format(error)) raise SaveSeriesException( 'Unable to load series from indexer: {0!r}'.format(error)) message_step('check if show is already added') try: message_step('configure show options') series.configure(self) except KeyError as error: log.error( 'Unable to add show {series_name} due to an error with one of the provided options: {error}', { 'series_name': series.name, 'error': error }) ui.notifications.error( 'Unable to add show {series_name} due to an error with one of the provided options: {error}' .format(series_name=series.name, error=error)) raise SaveSeriesException( 'Unable to add show {series_name} due to an error with one of the provided options: {error}' .format(series_name=series.name, error=error)) except Exception as error: log.error('Error trying to configure show: {0}', error) log.debug(traceback.format_exc()) raise app.showList.append(series) series.save_to_db() try: message_step('load episodes from {indexer}'.format( indexer=indexerApi(self.indexer).name)) series.load_episodes_from_indexer(tvapi=api) # If we provide a default_status_after through the apiv2 series route options object. # set it after we've added the episodes. self.default_ep_status = self.options[ 'default_status_after'] or app.STATUS_DEFAULT_AFTER except IndexerException as error: log.warning( 'Unable to load series episodes from indexer: {0!r}'. format(error)) raise SaveSeriesException( 'Unable to load series episodes from indexer: {0!r}'. format(error)) message_step('create metadata in show folder') series.write_metadata() series.update_metadata() series.populate_cache() build_name_cache(series) # update internal name cache series.flush_episodes() series.sync_trakt() message_step('add scene numbering') series.add_scene_numbering() except SaveSeriesException as error: log.warning('Unable to add series: {0!r}'.format(error)) self.success = False self._finish_early() log.debug(traceback.format_exc()) default_status = self.options['default_status'] or app.STATUS_DEFAULT if statusStrings[default_status] == 'Wanted': message_step('trigger backlog search') app.backlog_search_scheduler.action.search_backlog([series]) self.success = True ws.Message( 'showAdded', series.to_json(detailed=False)).push() # Send ws update to client message_step('finished') self.finish()
def run(self): """Run QueueItemChangeIndexer queue item.""" step = [] # Small helper, to reduce code for messaging def message_step(new_step): step.append(new_step) ws.Message( 'QueueItemShow', dict(step=step, oldShow=self.old_show.to_json() if self.old_show else {}, newShow=self.new_show.to_json() if self.new_show else {}, **self.to_json)).push() ShowQueueItem.run(self) def get_show_from_slug(slug): identifier = SeriesIdentifier.from_slug(slug) if not identifier: raise ChangeIndexerException( f'Could not create identifier with slug {slug}') show = Series.find_by_identifier(identifier) return show try: # Create reference to old show, before starting the remove it. self.old_show = get_show_from_slug(self.old_slug) # Store needed options. self._store_options() # Start of removing the old show log.info('{id}: Removing {show}', { 'id': self.old_show.series_id, 'show': self.old_show.name }) message_step(f'Removing old show {self.old_show.name}') # Need to first remove the episodes from the Trakt collection, because we need the list of # Episodes from the db to know which eps to remove. if app.USE_TRAKT: message_step('Removing episodes from trakt collection') try: app.trakt_checker_scheduler.action.remove_show_trakt_library( self.old_show) except TraktException as error: log.warning( '{id}: Unable to delete show {show} from Trakt.' ' Please remove manually otherwise it will be added again.' ' Error: {error_msg}', { 'id': self.old_show.series_id, 'show': self.old_show.name, 'error_msg': error }) except Exception as error: log.exception( 'Exception occurred while trying to delete show {show}, error: {error', { 'show': self.old_show.name, 'error': error }) self.old_show.delete_show(full=False) # Send showRemoved to frontend, so we can remove it from localStorage. ws.Message('showRemoved', self.old_show.to_json( detailed=False)).push() # Send ws update to client # Double check to see if the show really has been removed, else bail. if get_show_from_slug(self.old_slug): raise ChangeIndexerException( f'Could not create identifier with slug {self.old_slug}') # Start adding the new show log.info('Starting to add show by {0}', ('show_dir: {0}'.format(self.show_dir) if self.show_dir else 'New slug: {0}'.format(self.new_slug))) self.new_show = Series.from_identifier( SeriesIdentifier.from_slug(self.new_slug)) try: # Push an update to any open Web UIs through the WebSocket message_step('load show from {indexer}'.format( indexer=indexerApi(self.new_show.indexer).name)) api = self.new_show.identifier.get_indexer_api(self.options) if getattr(api[self.new_show.series_id], '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.new_show.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.new_show.indexer).name)) self._finish_early() raise SaveSeriesException( 'Indexer is missing a showname in this language: {0!r}' ) self.new_show.load_from_indexer(tvapi=api) message_step('load info from imdb') self.new_show.load_imdb_info() except IndexerException as error: log.warning( 'Unable to load series from indexer: {0!r}'.format(error)) raise SaveSeriesException( 'Unable to load series from indexer: {0!r}'.format(error)) try: message_step('configure show options') self.new_show.configure(self) except KeyError as error: log.error( 'Unable to add show {series_name} due to an error with one of the provided options: {error}', { 'series_name': self.new_show.name, 'error': error }) ui.notifications.error( 'Unable to add show {series_name} due to an error with one of the provided options: {error}' .format(series_name=self.new_show.name, error=error)) raise SaveSeriesException( 'Unable to add show {series_name} due to an error with one of the provided options: {error}' .format(series_name=self.new_show.name, error=error)) except Exception as error: log.error('Error trying to configure show: {0}', error) log.debug(traceback.format_exc()) raise app.showList.append(self.new_show) self.new_show.save_to_db() try: message_step('load episodes from {indexer}'.format( indexer=indexerApi(self.new_show.indexer).name)) self.new_show.load_episodes_from_indexer(tvapi=api) # If we provide a default_status_after through the apiv2 series route options object. # set it after we've added the episodes. self.new_show.default_ep_status = self.options[ 'default_status_after'] or app.STATUS_DEFAULT_AFTER except IndexerException as error: log.warning( 'Unable to load series episodes from indexer: {0!r}'. format(error)) raise SaveSeriesException( 'Unable to load series episodes from indexer: {0!r}'. format(error)) message_step('create metadata in show folder') self.new_show.write_metadata() self.new_show.update_metadata() self.new_show.populate_cache() build_name_cache(self.new_show) # update internal name cache self.new_show.flush_episodes() self.new_show.sync_trakt() message_step('add scene numbering') self.new_show.add_scene_numbering() if self.show_dir: # If a show dir was passed, this was added as an existing show. # For new shows we shouldn't have any files on disk. message_step('refresh episodes from disk') try: app.show_queue_scheduler.action.refreshShow(self.new_show) except CantRefreshShowException as error: log.warning( 'Unable to rescan episodes from disk: {0!r}'.format( error)) except (ChangeIndexerException, SaveSeriesException) as error: log.warning('Unable to add series: {0!r}'.format(error)) self.success = False self._finish_early() log.debug(traceback.format_exc()) default_status = self.options['default_status'] or app.STATUS_DEFAULT if statusStrings[default_status] == 'Wanted': message_step('trigger backlog search') app.backlog_search_scheduler.action.search_backlog([self.new_show]) self.success = True ws.Message('showAdded', self.new_show.to_json( detailed=False)).push() # Send ws update to client message_step('finished') self.finish()