def update_one_series(series_id, action): logging.debug('BAZARR syncing this specific series from Sonarr: {}'.format(series_id)) # Check if there's a row in database for this series ID existing_series = TableShows.select(TableShows.path)\ .where(TableShows.sonarrSeriesId == series_id)\ .dicts()\ .get_or_none() # Delete series from DB if action == 'deleted' and existing_series: try: TableShows.delete().where(TableShows.sonarrSeriesId == int(series_id)).execute() except Exception as e: logging.error(f"BAZARR cannot delete series with sonarrSeriesId {series_id} because of {e}") else: TableEpisodes.delete().where(TableEpisodes.sonarrSeriesId == int(series_id)).execute() event_stream(type='series', action='delete', payload=int(series_id)) return serie_default_enabled = settings.general.getboolean('serie_default_enabled') if serie_default_enabled is True: serie_default_profile = settings.general.serie_default_profile if serie_default_profile == '': serie_default_profile = None else: serie_default_profile = None audio_profiles = get_profile_list() tagsDict = get_tags() try: # Get series data from sonarr api series = None series_data = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=settings.sonarr.apikey, sonarr_series_id=int(series_id)) if not series_data: return else: if action == 'updated' and existing_series: series = seriesParser(series_data, action='update', tags_dict=tagsDict, serie_default_profile=serie_default_profile, audio_profiles=audio_profiles) elif action == 'updated' and not existing_series: series = seriesParser(series_data, action='insert', tags_dict=tagsDict, serie_default_profile=serie_default_profile, audio_profiles=audio_profiles) except Exception: logging.debug('BAZARR cannot parse series returned by SignalR feed.') return # Update existing series in DB if action == 'updated' and existing_series: try: TableShows.update(series).where(TableShows.sonarrSeriesId == series['sonarrSeriesId']).execute() except IntegrityError as e: logging.error(f"BAZARR cannot update series {series['path']} because of {e}") else: sync_episodes(series_id=int(series_id), send_event=True) event_stream(type='series', action='update', payload=int(series_id)) logging.debug('BAZARR updated this series into the database:{}'.format(path_mappings.path_replace( series['path']))) # Insert new series in DB elif action == 'updated' and not existing_series: try: TableShows.insert(series).on_conflict(action='IGNORE').execute() except IntegrityError as e: logging.error(f"BAZARR cannot insert series {series['path']} because of {e}") else: event_stream(type='series', action='update', payload=int(series_id)) logging.debug('BAZARR inserted this series into the database:{}'.format(path_mappings.path_replace( series['path'])))
def sync_one_episode(episode_id): logging.debug( 'BAZARR syncing this specific episode from Sonarr: {}'.format( episode_id)) url = url_sonarr() apikey_sonarr = settings.sonarr.apikey # Check if there's a row in database for this episode ID try: existing_episode = TableEpisodes.select(TableEpisodes.path, TableEpisodes.episode_file_id)\ .where(TableEpisodes.sonarrEpisodeId == episode_id)\ .dicts()\ .get() except DoesNotExist: existing_episode = None try: # Get episode data from sonarr api episode = None episode_data = get_episodes_from_sonarr_api( url=url, apikey_sonarr=apikey_sonarr, episode_id=episode_id) if not episode_data: return else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results if not get_sonarr_info.is_legacy( ) and existing_episode and episode_data['hasFile']: episode_data['episodeFile'] = \ get_episodesFiles_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr, episode_file_id=existing_episode['episode_file_id']) episode = episodeParser(episode_data) except Exception: logging.debug( 'BAZARR cannot get episode returned by SignalR feed from Sonarr API.' ) return # Drop useless events if not episode and not existing_episode: return # Remove episode from DB if not episode and existing_episode: TableEpisodes.delete().where( TableEpisodes.sonarrEpisodeId == episode_id).execute() event_stream(type='episode', action='delete', payload=int(episode_id)) logging.debug( 'BAZARR deleted this episode from the database:{}'.format( path_mappings.path_replace(existing_episode['path']))) return # Update existing episodes in DB elif episode and existing_episode: TableEpisodes.update(episode).where( TableEpisodes.sonarrEpisodeId == episode_id).execute() event_stream(type='episode', action='update', payload=int(episode_id)) logging.debug( 'BAZARR updated this episode into the database:{}'.format( path_mappings.path_replace(episode['path']))) # Insert new episodes in DB elif episode and not existing_episode: TableEpisodes.insert(episode).on_conflict(action='IGNORE').execute() event_stream(type='episode', action='update', payload=int(episode_id)) logging.debug( 'BAZARR inserted this episode into the database:{}'.format( path_mappings.path_replace(episode['path']))) # Storing existing subtitles logging.debug('BAZARR storing subtitles for this episode: {}'.format( path_mappings.path_replace(episode['path']))) store_subtitles(episode['path'], path_mappings.path_replace(episode['path'])) # Downloading missing subtitles logging.debug( 'BAZARR downloading missing subtitles for this episode: {}'.format( path_mappings.path_replace(episode['path']))) episode_download_subtitles(episode_id)
def sync_episodes(series_id=None, send_event=True): logging.debug('BAZARR Starting episodes sync from Sonarr.') apikey_sonarr = settings.sonarr.apikey # Get current episodes id in DB current_episodes_db = TableEpisodes.select(TableEpisodes.sonarrEpisodeId, TableEpisodes.path, TableEpisodes.sonarrSeriesId)\ .where((TableEpisodes.sonarrSeriesId == series_id) if series_id else None)\ .dicts() current_episodes_db_list = [ x['sonarrEpisodeId'] for x in current_episodes_db ] current_episodes_sonarr = [] episodes_to_update = [] episodes_to_add = [] altered_episodes = [] # Get sonarrId for each series from database seriesIdList = get_series_from_sonarr_api( series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr, ) series_count = len(seriesIdList) for i, seriesId in enumerate(seriesIdList): if send_event: show_progress(id='episodes_progress', header='Syncing episodes...', name=seriesId['title'], value=i, count=series_count) # Get episodes data for a series from Sonarr episodes = get_episodes_from_sonarr_api( url=url_sonarr(), apikey_sonarr=apikey_sonarr, series_id=seriesId['sonarrSeriesId']) if not episodes: continue else: # For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results if not get_sonarr_info.is_legacy(): episodeFiles = get_episodesFiles_from_sonarr_api( url=url_sonarr(), apikey_sonarr=apikey_sonarr, series_id=seriesId['sonarrSeriesId']) for episode in episodes: if episode['hasFile']: item = [ x for x in episodeFiles if x['id'] == episode['episodeFileId'] ] if item: episode['episodeFile'] = item[0] for episode in episodes: if 'hasFile' in episode: if episode['hasFile'] is True: if 'episodeFile' in episode: if episode['episodeFile']['size'] > 20480: # Add episodes in sonarr to current episode list current_episodes_sonarr.append(episode['id']) # Parse episode data if episode['id'] in current_episodes_db_list: episodes_to_update.append( episodeParser(episode)) else: episodes_to_add.append( episodeParser(episode)) if send_event: hide_progress(id='episodes_progress') # Remove old episodes from DB removed_episodes = list( set(current_episodes_db_list) - set(current_episodes_sonarr)) for removed_episode in removed_episodes: episode_to_delete = TableEpisodes.select(TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId)\ .where(TableEpisodes.sonarrEpisodeId == removed_episode)\ .dicts()\ .get() TableEpisodes.delete().where( TableEpisodes.sonarrEpisodeId == removed_episode).execute() if send_event: event_stream(type='episode', action='delete', payload=episode_to_delete['sonarrEpisodeId']) # Update existing episodes in DB episode_in_db_list = [] episodes_in_db = TableEpisodes.select( TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId, TableEpisodes.title, TableEpisodes.path, TableEpisodes.season, TableEpisodes.episode, TableEpisodes.scene_name, TableEpisodes.monitored, TableEpisodes.format, TableEpisodes.resolution, TableEpisodes.video_codec, TableEpisodes.audio_codec, TableEpisodes.episode_file_id, TableEpisodes.audio_language, TableEpisodes.file_size).dicts() for item in episodes_in_db: episode_in_db_list.append(item) episodes_to_update_list = [ i for i in episodes_to_update if i not in episode_in_db_list ] for updated_episode in episodes_to_update_list: TableEpisodes.update(updated_episode).where( TableEpisodes.sonarrEpisodeId == updated_episode['sonarrEpisodeId']).execute() altered_episodes.append([ updated_episode['sonarrEpisodeId'], updated_episode['path'], updated_episode['sonarrSeriesId'] ]) # Insert new episodes in DB for added_episode in episodes_to_add: result = TableEpisodes.insert(added_episode).on_conflict( action='IGNORE').execute() if result > 0: altered_episodes.append([ added_episode['sonarrEpisodeId'], added_episode['path'], added_episode['monitored'] ]) if send_event: event_stream(type='episode', payload=added_episode['sonarrEpisodeId']) else: logging.debug( 'BAZARR unable to insert this episode into the database:{}'. format(path_mappings.path_replace(added_episode['path']))) # Store subtitles for added or modified episodes for i, altered_episode in enumerate(altered_episodes, 1): store_subtitles(altered_episode[1], path_mappings.path_replace(altered_episode[1])) logging.debug('BAZARR All episodes synced from Sonarr into database.')
def sync_episodes(): notifications.write(msg='Episodes sync from Sonarr started...', queue='get_episodes') logging.debug('BAZARR Starting episodes sync from Sonarr.') apikey_sonarr = settings.sonarr.apikey # Get current episodes id in DB current_episodes_db = TableEpisodes.select(TableEpisodes.sonarr_episode_id, TableEpisodes.path, TableEpisodes.sonarr_series_id) current_episodes_db_list = [ x.sonarr_episode_id for x in current_episodes_db ] current_episodes_sonarr = [] episodes_to_update = [] episodes_to_add = [] altered_episodes = [] # Get sonarrId for each series from database seriesIdList = TableShows.select(TableShows.sonarr_series_id, TableShows.title) seriesIdListLength = seriesIdList.count() for i, seriesId in enumerate(seriesIdList, 1): notifications.write(msg='Getting episodes data from Sonarr...', queue='get_episodes', item=i, length=seriesIdListLength) # Get episodes data for a series from Sonarr url_sonarr_api_episode = url_sonarr + "/api/episode?seriesId=" + str( seriesId.sonarr_series_id) + "&apikey=" + apikey_sonarr try: r = requests.get(url_sonarr_api_episode, timeout=60, verify=False) r.raise_for_status() except requests.exceptions.HTTPError as errh: logging.exception( "BAZARR Error trying to get episodes from Sonarr. Http error.") return except requests.exceptions.ConnectionError as errc: logging.exception( "BAZARR Error trying to get episodes from Sonarr. Connection Error." ) return except requests.exceptions.Timeout as errt: logging.exception( "BAZARR Error trying to get episodes from Sonarr. Timeout Error." ) return except requests.exceptions.RequestException as err: logging.exception( "BAZARR Error trying to get episodes from Sonarr.") return else: for episode in r.json(): if 'hasFile' in episode: if episode['hasFile'] is True: if 'episodeFile' in episode: if episode['episodeFile']['size'] > 20480: # Add shows in Sonarr to current shows list if 'sceneName' in episode['episodeFile']: sceneName = episode['episodeFile'][ 'sceneName'] else: sceneName = None try: format, resolution = episode[ 'episodeFile']['quality']['quality'][ 'name'].split('-') except: format = episode['episodeFile']['quality'][ 'quality']['name'] try: resolution = str( episode['episodeFile']['quality'] ['quality']['resolution']) + 'p' except: resolution = None if 'mediaInfo' in episode['episodeFile']: if 'videoCodec' in episode['episodeFile'][ 'mediaInfo']: videoCodec = episode['episodeFile'][ 'mediaInfo']['videoCodec'] videoCodec = SonarrFormatVideoCodec( videoCodec) else: videoCodec = None if 'audioCodec' in episode['episodeFile'][ 'mediaInfo']: audioCodec = episode['episodeFile'][ 'mediaInfo']['audioCodec'] audioCodec = SonarrFormatAudioCodec( audioCodec) else: audioCodec = None else: videoCodec = None audioCodec = None # Add episodes in sonarr to current episode list current_episodes_sonarr.append(episode['id']) if episode['id'] in current_episodes_db_list: episodes_to_update.append({ 'sonarr_series_id': episode['seriesId'], 'sonarr_episode_id': episode['id'], 'title': episode['title'], 'path': episode['episodeFile']['path'], 'season': episode['seasonNumber'], 'episode': episode['episodeNumber'], 'scene_name': sceneName, 'monitored': str(bool(episode['monitored'])), 'format': format, 'resolution': resolution, 'video_codec': videoCodec, 'audio_codec': audioCodec, 'episode_file_id': episode['episodeFile']['id'] }) else: episodes_to_add.append({ 'sonarr_series_id': episode['seriesId'], 'sonarr_episode_id': episode['id'], 'title': episode['title'], 'path': episode['episodeFile']['path'], 'season': episode['seasonNumber'], 'episode': episode['episodeNumber'], 'scene_name': sceneName, 'monitored': str(bool(episode['monitored'])), 'format': format, 'resolution': resolution, 'video_codec': videoCodec, 'audio_codec': audioCodec, 'episode_file_id': episode['episodeFile']['id'] }) # Update existing episodes in DB episode_in_db_list = [] episodes_in_db = TableEpisodes.select( TableEpisodes.sonarr_series_id, TableEpisodes.sonarr_episode_id, TableEpisodes.title, TableEpisodes.path, TableEpisodes.season, TableEpisodes.episode, TableEpisodes.scene_name, TableEpisodes.monitored, TableEpisodes.format, TableEpisodes.resolution, TableEpisodes.video_codec, TableEpisodes.audio_codec, TableEpisodes.episode_file_id).dicts() for item in episodes_in_db: episode_in_db_list.append(item) episodes_to_update_list = [ i for i in episodes_to_update if i not in episode_in_db_list ] for updated_episode in episodes_to_update_list: TableEpisodes.update(updated_episode).where( TableEpisodes.sonarr_episode_id == updated_episode['sonarr_episode_id']).execute() altered_episodes.append([ updated_episode['sonarr_episode_id'], updated_episode['path'], updated_episode['sonarr_series_id'] ]) # Insert new episodes in DB for added_episode in episodes_to_add: TableEpisodes.insert(added_episode).on_conflict_ignore().execute() altered_episodes.append([ added_episode['sonarr_episode_id'], added_episode['path'], added_episode['sonarr_series_id'] ]) # Remove old episodes from DB removed_episodes = list( set(current_episodes_db_list) - set(current_episodes_sonarr)) for removed_episode in removed_episodes: TableEpisodes.delete().where( TableEpisodes.sonarr_episode_id == removed_episode).execute() # Store subtitles for added or modified episodes for i, altered_episode in enumerate(altered_episodes, 1): notifications.write(msg='Indexing episodes embedded subtitles...', queue='get_episodes', item=i, length=len(altered_episodes)) store_subtitles(path_replace(altered_episode[1])) list_missing_subtitles(altered_episode[2]) logging.debug('BAZARR All episodes synced from Sonarr into database.') # Search for desired subtitles if no more than 5 episodes have been added. if len(altered_episodes) <= 5: logging.debug( "BAZARR No more than 5 episodes were added during this sync then we'll search for subtitles." ) for altered_episode in altered_episodes: episode_download_subtitles(altered_episode[0]) else: logging.debug( "BAZARR More than 5 episodes were added during this sync then we wont search for subtitles right now." )