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 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 run(self): ShowQueueItem.run(self) log.debug('{id}: Beginning update of {show}', { 'id': self.show.series_id, 'show': self.show.name }) log.debug( '{id}: Retrieving show info from {indexer}', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name }) try: # Let's make sure we refresh the indexer_api object attached to the show object. self.show.create_indexer() self.show.load_from_indexer() except IndexerError as error: log.warning( '{id}: Unable to contact {indexer}. Aborting: {error_msg}', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name, 'error_msg': error }) return except IndexerAttributeNotFound as error: log.warning( '{id}: Data retrieved from {indexer} was incomplete. Aborting: {error_msg}', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name, 'error_msg': error }) 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.show.series_id, 'indexer': indexerApi(self.show.indexer).name, 'language': error.language, 'error_msg': error }) ui.notifications.error( 'Error changing language show!', 'Unable to change language for show {show_name}' ' on {indexer} to language: {language}'.format( show_name=self.show.name, indexer=indexerApi(self.show.indexer).name, language=error.language)) return log.debug('{id}: Retrieving show info from IMDb', {'id': self.show.series_id}) try: self.show.load_imdb_info() except ImdbAPIError as error: log.info('{id}: Something wrong on IMDb api: {error_msg}', { 'id': self.show.series_id, 'error_msg': error }) except RequestException as error: log.warning('{id}: Error loading IMDb info: {error_msg}', { 'id': self.show.series_id, 'error_msg': error }) # have to save show before reading episodes from db try: log.debug('{id}: Saving new IMDb show info to database', {'id': self.show.series_id}) self.show.save_to_db() except Exception as error: log.warning( '{id}: Error saving new IMDb show info to database: {error_msg}', { 'id': self.show.series_id, 'error_msg': error }) log.error(traceback.format_exc()) # get episode list from DB try: episodes_from_db = self.show.load_episodes_from_db() except IndexerException as error: log.warning( '{id}: Unable to contact {indexer}. Aborting: {error_msg}', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name, 'error_msg': error }) return # get episode list from the indexer try: episodes_from_indexer = self.show.load_episodes_from_indexer() except IndexerException as error: log.warning( '{id}: Unable to get info from {indexer}. The show info will not be refreshed.' ' Error: {error_msg}', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name, 'error_msg': error }) episodes_from_indexer = None if episodes_from_indexer is None: log.warning( '{id}: No data returned from {indexer} during full show update.' ' Unable to update this show', { 'id': self.show.series_id, 'indexer': indexerApi(self.show.indexer).name }) else: # for each ep we found on the Indexer delete it from the DB list for cur_season in episodes_from_indexer: for cur_episode in episodes_from_indexer[cur_season]: if cur_season in episodes_from_db and cur_episode in episodes_from_db[ cur_season]: del episodes_from_db[cur_season][cur_episode] # remaining episodes in the DB list are not on the indexer, just delete them from the DB for cur_season in episodes_from_db: for cur_episode in episodes_from_db[cur_season]: log.debug( '{id}: Permanently deleting episode {show} {ep} from the database', { 'id': self.show.series_id, 'show': self.show.name, 'ep': episode_num(cur_season, cur_episode) }) # Create the ep object only because Im going to delete it ep_obj = self.show.get_episode(cur_season, cur_episode) try: ep_obj.delete_episode() except EpisodeDeletedException: log.debug( '{id}: Episode {show} {ep} successfully deleted from the database', { 'id': self.show.series_id, 'show': self.show.name, 'ep': episode_num(cur_season, cur_episode) }) # Save only after all changes were applied try: log.debug('{id}: Saving all updated show info to database', {'id': self.show.series_id}) self.show.save_to_db() except Exception as error: log.warning( '{id}: Error saving all updated show info to database: {error_msg}', { 'id': self.show.series_id, 'error_msg': error }) log.error(traceback.format_exc()) # Replace the images in cache log.info('{id}: Replacing images for show {show}', { 'id': self.show.series_id, 'show': self.show.name }) replace_images(self.show) log.debug('{id}: Finished update of {show}', { 'id': self.show.series_id, 'show': self.show.name }) # Refresh show needs to be forced since current execution locks the queue app.show_queue_scheduler.action.refreshShow(self.show, True) self.finish()
def post(self): """Perform a mass update action.""" data = json_decode(self.request.body) update = data.get('update', []) rescan = data.get('rescan', []) rename = data.get('rename', []) subtitle = data.get('subtitle', []) delete = data.get('delete', []) remove = data.get('remove', []) image = data.get('image', []) result = { 'shows': defaultdict(list), 'totals': { 'update': 0, 'rescan': 0, 'rename': 0, 'subtitle': 0, 'delete': 0, 'remove': 0, 'image': 0 } } for slug in set(update + rescan + rename + subtitle + delete + remove + image): identifier = SeriesIdentifier.from_slug(slug) series_obj = Series.find_by_identifier(identifier) if not series_obj: result['shows'][slug].append('Unable to locate show: {show}'.format(show=slug)) continue if slug in delete + remove: app.show_queue_scheduler.action.removeShow(series_obj, slug in delete) if slug in delete: result['totals']['delete'] += 1 if slug in remove: result['totals']['remove'] += 1 continue # don't do anything else if it's being deleted or removed if slug in update: try: app.show_queue_scheduler.action.updateShow(series_obj) result['totals']['update'] += 1 except CantUpdateShowException as msg: result['shows'][slug].append('Unable to update show: {error}'.format(error=msg)) elif slug in rescan: # don't bother refreshing shows that were updated try: app.show_queue_scheduler.action.refreshShow(series_obj) result['totals']['rescan'] += 1 except CantRefreshShowException as msg: result['shows'][slug].append( 'Unable to refresh show {show.name}: {error}'.format(show=series_obj, error=msg) ) if slug in rename: app.show_queue_scheduler.action.renameShowEpisodes(series_obj) result['totals']['rename'] += 1 if slug in subtitle: app.show_queue_scheduler.action.download_subtitles(series_obj) result['totals']['subtitle'] += 1 if slug in image: image_cache.replace_images(series_obj) result['totals']['image'] += 1 if result['shows']: ui.notifications.error('Errors encountered', '<br />\n'.join(chain(*result['shows'].values()))) return self._created(data=result)