def history_log_movie(action, radarr_id, description, video_path=None, language=None, provider=None, score=None, subs_id=None, subtitles_path=None): database.execute( "INSERT INTO table_history_movie (action, radarrId, timestamp, description, video_path, language, " "provider, score, subs_id, subtitles_path) VALUES (?,?,?,?,?,?,?,?,?,?)", (action, radarr_id, time.time(), description, video_path, language, provider, score, subs_id, subtitles_path)) event_stream(type='movieHistory')
def history_log(action, sonarr_series_id, sonarr_episode_id, description, video_path=None, language=None, provider=None, score=None, subs_id=None, subtitles_path=None): database.execute( "INSERT INTO table_history (action, sonarrSeriesId, sonarrEpisodeId, timestamp, description," "video_path, language, provider, score, subs_id, subtitles_path) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (action, sonarr_series_id, sonarr_episode_id, time.time(), description, video_path, language, provider, score, subs_id, subtitles_path)) event_stream(type='episodeHistory')
def update_throttled_provider(): changed = False if settings.general.enabled_providers: for provider in list(tp): if provider not in settings.general.enabled_providers: del tp[provider] set_throttled_providers(str(tp)) reason, until, throttle_desc = tp.get(provider, (None, None, None)) if reason: now = datetime.datetime.now() if now >= until: logging.info( "Using %s again after %s, (disabled because: %s)", provider, throttle_desc, reason) del tp[provider] set_throttled_providers(str(tp)) event_stream(type='badges_providers')
def post(self): radarrIdList = request.form.getlist('radarrid') profileIdList = request.form.getlist('profileid') for idx in range(len(radarrIdList)): radarrId = radarrIdList[idx] profileId = profileIdList[idx] if profileId in None_Keys: profileId = None else: try: profileId = int(profileId) except Exception: return '', 400 TableMovies.update({ TableMovies.profileId: profileId })\ .where(TableMovies.radarrId == radarrId)\ .execute() list_missing_subtitles_movies(no=radarrId, send_event=False) event_stream(type='movie', payload=radarrId) event_stream(type='movie-wanted', payload=radarrId) event_stream(type='badges') return '', 204
def history_log_movie(action, radarr_id, description, video_path=None, language=None, provider=None, score=None, subs_id=None, subtitles_path=None): TableHistoryMovie.insert({ TableHistoryMovie.action: action, TableHistoryMovie.radarrId: radarr_id, TableHistoryMovie.timestamp: time.time(), TableHistoryMovie.description: description, TableHistoryMovie.video_path: video_path, TableHistoryMovie.language: language, TableHistoryMovie.provider: provider, TableHistoryMovie.score: score, TableHistoryMovie.subs_id: subs_id, TableHistoryMovie.subtitles_path: subtitles_path }).execute() event_stream(type='movie-history')
def update_throttled_provider(): changed = False existing_providers = provider_registry.names() providers_list = [ x for x in get_array_from(settings.general.enabled_providers) if x in existing_providers ] for provider in list(tp): if provider not in providers_list: del tp[provider] settings.general.throtteled_providers = str(tp) changed = True reason, until, throttle_desc = tp.get(provider, (None, None, None)) if reason: now = datetime.datetime.now() if now < until: pass else: logging.info("Using %s again after %s, (disabled because: %s)", provider, throttle_desc, reason) del tp[provider] set_throttled_providers(str(tp)) reason, until, throttle_desc = tp.get(provider, (None, None, None)) if reason: now = datetime.datetime.now() if now >= until: logging.info( "Using %s again after %s, (disabled because: %s)", provider, throttle_desc, reason) del tp[provider] set_throttled_providers(str(tp)) event_stream(type='badges_providers')
def history_log(action, sonarr_series_id, sonarr_episode_id, description, video_path=None, language=None, provider=None, score=None, subs_id=None, subtitles_path=None): TableHistory.insert({ TableHistory.action: action, TableHistory.sonarrSeriesId: sonarr_series_id, TableHistory.sonarrEpisodeId: sonarr_episode_id, TableHistory.timestamp: time.time(), TableHistory.description: description, TableHistory.video_path: video_path, TableHistory.language: language, TableHistory.provider: provider, TableHistory.score: score, TableHistory.subs_id: subs_id, TableHistory.subtitles_path: subtitles_path }).execute() event_stream(type='episode-history')
def post(self): seriesIdList = request.form.getlist('seriesid') profileIdList = request.form.getlist('profileid') for idx in range(len(seriesIdList)): seriesId = seriesIdList[idx] profileId = profileIdList[idx] if profileId in None_Keys: profileId = None else: try: profileId = int(profileId) except Exception: return '', 400 TableShows.update({ TableShows.profileId: profileId }) \ .where(TableShows.sonarrSeriesId == seriesId) \ .execute() list_missing_subtitles(no=seriesId, send_event=False) event_stream(type='series', payload=seriesId) episode_id_list = TableEpisodes \ .select(TableEpisodes.sonarrEpisodeId) \ .where(TableEpisodes.sonarrSeriesId == seriesId) \ .dicts() for item in episode_id_list: event_stream(type='episode-wanted', payload=item['sonarrEpisodeId']) event_stream(type='badges') return '', 204
def post(self): enabled_languages = request.form.getlist('languages-enabled') if len(enabled_languages) != 0: TableSettingsLanguages.update({ TableSettingsLanguages.enabled: 0 }).execute() for code in enabled_languages: TableSettingsLanguages.update({ TableSettingsLanguages.enabled: 1 })\ .where(TableSettingsLanguages.code2 == code)\ .execute() event_stream("languages") languages_profiles = request.form.get('languages-profiles') if languages_profiles: existing_ids = TableLanguagesProfiles.select(TableLanguagesProfiles.profileId).dicts() existing_ids = list(existing_ids) existing = [x['profileId'] for x in existing_ids] for item in json.loads(languages_profiles): if item['profileId'] in existing: # Update existing profiles TableLanguagesProfiles.update({ TableLanguagesProfiles.name: item['name'], TableLanguagesProfiles.cutoff: item['cutoff'] if item['cutoff'] != 'null' else None, TableLanguagesProfiles.items: json.dumps(item['items']), TableLanguagesProfiles.mustContain: item['mustContain'], TableLanguagesProfiles.mustNotContain: item['mustNotContain'], })\ .where(TableLanguagesProfiles.profileId == item['profileId'])\ .execute() existing.remove(item['profileId']) else: # Add new profiles TableLanguagesProfiles.insert({ TableLanguagesProfiles.profileId: item['profileId'], TableLanguagesProfiles.name: item['name'], TableLanguagesProfiles.cutoff: item['cutoff'] if item['cutoff'] != 'null' else None, TableLanguagesProfiles.items: json.dumps(item['items']), TableLanguagesProfiles.mustContain: item['mustContain'], TableLanguagesProfiles.mustNotContain: item['mustNotContain'], }).execute() for profileId in existing: # Unassign this profileId from series and movies TableShows.update({ TableShows.profileId: None }).where(TableShows.profileId == profileId).execute() TableMovies.update({ TableMovies.profileId: None }).where(TableMovies.profileId == profileId).execute() # Remove deleted profiles TableLanguagesProfiles.delete().where(TableLanguagesProfiles.profileId == profileId).execute() update_profile_id_list() event_stream("languages") if settings.general.getboolean('use_sonarr'): scheduler.add_job(list_missing_subtitles, kwargs={'send_event': False}) if settings.general.getboolean('use_radarr'): scheduler.add_job(list_missing_subtitles_movies, kwargs={'send_event': False}) # Update Notification notifications = request.form.getlist('notifications-providers') for item in notifications: item = json.loads(item) TableSettingsNotifier.update({ TableSettingsNotifier.enabled: item['enabled'], TableSettingsNotifier.url: item['url'] }).where(TableSettingsNotifier.name == item['name']).execute() save_settings(zip(request.form.keys(), request.form.listvalues())) event_stream("settings") return '', 204
def list_missing_subtitles_movies(no=None, send_event=True): if no is not None: movies_subtitles_clause = " WHERE radarrId=" + str(no) else: movies_subtitles_clause = "" movies_subtitles = database.execute( "SELECT radarrId, subtitles, languages, forced, hearing_impaired FROM " "table_movies" + movies_subtitles_clause) if isinstance(movies_subtitles, str): logging.error( "BAZARR list missing subtitles query to DB returned this instead of rows: " + movies_subtitles) return missing_subtitles_global = [] use_embedded_subs = settings.general.getboolean('use_embedded_subs') for movie_subtitles in movies_subtitles: actual_subtitles_temp = [] desired_subtitles_temp = [] actual_subtitles = [] desired_subtitles = [] missing_subtitles = [] if movie_subtitles['subtitles'] is not None: if use_embedded_subs: actual_subtitles = ast.literal_eval( movie_subtitles['subtitles']) else: actual_subtitles_temp = ast.literal_eval( movie_subtitles['subtitles']) for subtitle in actual_subtitles_temp: if subtitle[1] is not None: actual_subtitles.append(subtitle) if movie_subtitles['languages'] is not None: desired_subtitles = ast.literal_eval(movie_subtitles['languages']) if desired_subtitles: desired_subtitles_enum = enumerate(desired_subtitles) else: desired_subtitles_enum = None if movie_subtitles[ 'hearing_impaired'] == "True" and desired_subtitles is not None: for i, desired_subtitle in desired_subtitles_enum: desired_subtitles[i] = desired_subtitle + ":hi" elif movie_subtitles[ 'forced'] == "True" and desired_subtitles is not None: for i, desired_subtitle in desired_subtitles_enum: desired_subtitles[i] = desired_subtitle + ":forced" elif movie_subtitles[ 'forced'] == "Both" and desired_subtitles is not None: for desired_subtitle in desired_subtitles: desired_subtitles_temp.append(desired_subtitle) desired_subtitles_temp.append(desired_subtitle + ":forced") desired_subtitles = desired_subtitles_temp actual_subtitles_list = [] if desired_subtitles is None: missing_subtitles_global.append( tuple(['[]', movie_subtitles['radarrId']])) else: for item in actual_subtitles: if item[0] == "pt-BR": actual_subtitles_list.append("pb") elif item[0] == "pt-BR:forced": actual_subtitles_list.append("pb:forced") else: actual_subtitles_list.append(item[0]) missing_subtitles = list( set(desired_subtitles) - set(actual_subtitles_list)) hi_subs_to_remove = [] for item in missing_subtitles: if item + ':hi' in actual_subtitles_list: hi_subs_to_remove.append(item) missing_subtitles = list( set(missing_subtitles) - set(hi_subs_to_remove)) missing_subtitles_global.append( tuple([str(missing_subtitles), movie_subtitles['radarrId']])) for missing_subtitles_item in missing_subtitles_global: database.execute( "UPDATE table_movies SET missing_subtitles=? WHERE radarrId=?", (missing_subtitles_item[0], missing_subtitles_item[1])) if send_event: event_stream(type='movie', action='update', movie=missing_subtitles_item[1]) event_stream(type='badges_movies')
def patch(self): # Download radarrId = request.args.get('radarrid') movieInfo = TableMovies.select(TableMovies.title, TableMovies.path, TableMovies.sceneName, TableMovies.audio_language)\ .where(TableMovies.radarrId == radarrId)\ .dicts()\ .get_or_none() if not movieInfo: return 'Movie not found', 500 moviePath = path_mappings.path_replace_movie(movieInfo['path']) sceneName = movieInfo['sceneName'] or 'None' title = movieInfo['title'] audio_language = movieInfo['audio_language'] language = request.form.get('language') hi = request.form.get('hi').capitalize() forced = request.form.get('forced').capitalize() audio_language_list = get_audio_profile_languages(movie_id=radarrId) if len(audio_language_list) > 0: audio_language = audio_language_list[0]['name'] else: audio_language = None try: result = list( generate_subtitles( moviePath, [(language, hi, forced)], audio_language, sceneName, title, 'movie', profile_id=get_profile_id(movie_id=radarrId))) if result: result = result[0] message = result[0] path = result[1] forced = result[5] if result[8]: language_code = result[2] + ":hi" elif forced: language_code = result[2] + ":forced" else: language_code = result[2] provider = result[3] score = result[4] subs_id = result[6] subs_path = result[7] history_log_movie(1, radarrId, message, path, language_code, provider, score, subs_id, subs_path) send_notifications_movie(radarrId, message) store_subtitles_movie(path, moviePath) else: event_stream(type='movie', payload=radarrId) except OSError: pass return '', 204
def blacklist_delete_all(): TableBlacklist.delete().execute() event_stream(type='episode-blacklist', action='delete')
def save_settings(settings_items): from database import database configure_debug = False configure_captcha = False update_schedule = False update_path_map = False configure_proxy = False exclusion_updated = False for key, value in settings_items: # Intercept database stored settings if key == 'enabled_languages': database.execute("UPDATE table_settings_languages SET enabled=0") for item in value: database.execute("UPDATE table_settings_languages SET enabled=1 WHERE code2=?", (item,)) continue # Make sure that text based form values aren't pass as list unless they are language list if isinstance(value, list) and len(value) == 1 and key not in ['settings-general-serie_default_language', 'settings-general-movie_default_language']: value = value[0] # Make sure empty language list are stored correctly due to bug in bootstrap-select if key in ['settings-general-serie_default_language', 'settings-general-movie_default_language'] and value == ['null']: value = [] settings_keys = key.split('-') if value == 'true': value = 'True' elif value == 'false': value = 'False' if key == 'settings-auth-password': if value != settings.auth.password: value = hashlib.md5(value.encode('utf-8')).hexdigest() if key == 'settings-general-debug': configure_debug = True if key in ['settings-general-anti_captcha_provider', 'settings-anticaptcha-anti_captcha_key', 'settings-deathbycaptcha-username', 'settings-deathbycaptcha-password']: configure_captcha = True if key in ['update_schedule', 'settings-general-use_sonarr', 'settings-general-use_radarr', 'settings-general-auto_update', 'settings-general-upgrade_subs']: update_schedule = True if key in ['settings-general-path_mappings', 'settings-general-path_mappings_movie']: update_path_map = True if key in ['settings-proxy-type', 'settings-proxy-url', 'settings-proxy-port', 'settings-proxy-username', 'settings-proxy-password']: configure_proxy = True if key in ['settings-sonarr-excluded_tags', 'settings-sonarr-only_monitored', 'settings-sonarr-excluded_series_types', 'settings.radarr.excluded_tags', 'settings-radarr-only_monitored']: exclusion_updated = True if key == 'settings-addic7ed-username': if key != settings.addic7ed.username: region.delete('addic7ed_data') if key == 'settings-legendasdivx-username': if key != settings.legendasdivx.username: region.delete('legendasdivx_cookies2') if key == 'settings-opensubtitles-username': if key != settings.opensubtitles.username: region.delete('os_token') if key == 'settings-opensubtitlescom-username': if key != settings.opensubtitlescom.username: region.delete('oscom_token') if key == 'settings-subscene-username': if key != settings.subscene.username: region.delete('subscene_cookies2') if key == 'settings-titlovi-username': if key != settings.titlovi.username: region.delete('titlovi_token') if settings_keys[0] == 'settings': settings[settings_keys[1]][settings_keys[2]] = str(value) with open(os.path.join(args.config_dir, 'config', 'config.ini'), 'w+') as handle: settings.write(handle) # Reconfigure Bazarr to reflect changes if configure_debug: from logger import configure_logging configure_logging(settings.general.getboolean('debug') or args.debug) if configure_captcha: configure_captcha_func() if update_schedule: from api import scheduler scheduler.update_configurable_tasks() if update_path_map: from helper import path_mappings path_mappings.update() if configure_proxy: configure_proxy_func() if exclusion_updated: from event_handler import event_stream event_stream(type='badges_series') event_stream(type='badges_movies')
def blacklist_delete_movie(provider, subs_id): database.execute("DELETE FROM table_blacklist_movie WHERE provider=? AND subs_id=?", (provider, subs_id)) event_stream(type='movieBlacklist')
def blacklist_delete_all_movie(): database.execute("DELETE FROM table_blacklist_movie") event_stream(type='movieBlacklist')
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 blacklist_log_movie(radarr_id, provider, subs_id, language): database.execute("INSERT INTO table_blacklist_movie (radarr_id, timestamp, provider, subs_id, language) " "VALUES (?,?,?,?,?)", (radarr_id, time.time(), provider, subs_id, language)) event_stream(type='movieBlacklist')
def update_series(): apikey_sonarr = settings.sonarr.apikey if apikey_sonarr is None: return sonarr_version = get_sonarr_version() 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() # Get shows data from Sonarr url_sonarr_api_series = url_sonarr( ) + "/api/series?apikey=" + apikey_sonarr try: r = requests.get(url_sonarr_api_series, timeout=60, verify=False) r.raise_for_status() except requests.exceptions.HTTPError: logging.exception( "BAZARR Error trying to get series from Sonarr. Http error.") return except requests.exceptions.ConnectionError: logging.exception( "BAZARR Error trying to get series from Sonarr. Connection Error.") return except requests.exceptions.Timeout: logging.exception( "BAZARR Error trying to get series from Sonarr. Timeout Error.") return except requests.exceptions.RequestException: logging.exception("BAZARR Error trying to get series from Sonarr.") return # Get current shows in DB current_shows_db = database.execute( "SELECT sonarrSeriesId FROM table_shows") current_shows_db_list = [x['sonarrSeriesId'] for x in current_shows_db] current_shows_sonarr = [] series_to_update = [] series_to_add = [] series_list_length = len(r.json()) for i, show in enumerate(r.json(), 1): overview = show['overview'] if 'overview' in show else '' poster = '' fanart = '' for image in show['images']: if image['coverType'] == 'poster': poster_big = image['url'].split('?')[0] poster = os.path.splitext( poster_big)[0] + '-250' + os.path.splitext(poster_big)[1] if image['coverType'] == 'fanart': fanart = image['url'].split('?')[0] alternate_titles = None if show['alternateTitles'] is not None: alternate_titles = str( [item['title'] for item in show['alternateTitles']]) audio_language = [] if sonarr_version.startswith('2'): audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles) else: audio_language = profile_id_to_language(show['languageProfileId'], audio_profiles) tags = [d['label'] for d in tagsDict if d['id'] in show['tags']] imdbId = show['imdbId'] if 'imdbId' in show else None # Add shows in Sonarr to current shows list current_shows_sonarr.append(show['id']) if show['id'] in current_shows_db_list: series_to_update.append({ 'title': show["title"], 'path': show["path"], 'tvdbId': int(show["tvdbId"]), 'sonarrSeriesId': int(show["id"]), 'overview': overview, 'poster': poster, 'fanart': fanart, 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternateTitles': alternate_titles, 'tags': str(tags), 'seriesType': show['seriesType'], 'imdbId': imdbId }) else: series_to_add.append({ 'title': show["title"], 'path': show["path"], 'tvdbId': show["tvdbId"], 'sonarrSeriesId': show["id"], 'overview': overview, 'poster': poster, 'fanart': fanart, 'audio_language': str(audio_language), 'sortTitle': show['sortTitle'], 'year': str(show['year']), 'alternateTitles': alternate_titles, 'tags': str(tags), 'seriesType': show['seriesType'], 'imdbId': imdbId, 'profileId': serie_default_profile }) # Remove old series from DB removed_series = list( set(current_shows_db_list) - set(current_shows_sonarr)) for series in removed_series: database.execute("DELETE FROM table_shows WHERE sonarrSeriesId=?", (series, )) event_stream(type='series', action='delete', series=series) # Update existing series in DB series_in_db_list = [] series_in_db = database.execute( "SELECT title, path, tvdbId, sonarrSeriesId, overview, poster, fanart, " "audio_language, sortTitle, year, alternateTitles, tags, seriesType, imdbId FROM table_shows" ) for item in series_in_db: series_in_db_list.append(item) series_to_update_list = [ i for i in series_to_update if i not in series_in_db_list ] for updated_series in series_to_update_list: query = dict_converter.convert(updated_series) database.execute( '''UPDATE table_shows SET ''' + query.keys_update + ''' WHERE sonarrSeriesId = ?''', query.values + (updated_series['sonarrSeriesId'], )) event_stream(type='series', action='update', series=updated_series['sonarrSeriesId']) # Insert new series in DB for added_series in series_to_add: query = dict_converter.convert(added_series) result = database.execute( '''INSERT OR IGNORE INTO table_shows(''' + query.keys_insert + ''') VALUES(''' + query.question_marks + ''')''', query.values) if result: list_missing_subtitles(no=added_series['sonarrSeriesId']) else: logging.debug( 'BAZARR unable to insert this series into the database:', path_mappings.path_replace(added_series['path'])) event_stream(type='series', action='insert', series=added_series['sonarrSeriesId']) logging.debug( 'BAZARR All series synced from Sonarr into database.')
def task_listener_add(event): if event.job_id not in self.__running_tasks: self.__running_tasks.append(event.job_id) event_stream(type='task', task=event.job_id)
def manual_upload_subtitle(path, language, forced, hi, title, scene_name, media_type, subtitle, audio_language): logging.debug('BAZARR Manually uploading subtitles for this file: ' + path) single = settings.general.getboolean('single_language') use_postprocessing = settings.general.getboolean('use_postprocessing') postprocessing_cmd = settings.general.postprocessing_cmd chmod = int(settings.general.chmod, 8) if not sys.platform.startswith( 'win') and settings.general.getboolean('chmod_enabled') else None language = alpha3_from_alpha2(language) custom = CustomLanguage.from_value(language, "alpha3") if custom is None: lang_obj = Language(language) else: lang_obj = custom.subzero_language() if forced: lang_obj = Language.rebuild(lang_obj, forced=True) sub = Subtitle( lang_obj, mods=get_array_from(settings.general.subzero_mods) ) sub.content = subtitle.read() if not sub.is_valid(): logging.exception('BAZARR Invalid subtitle file: ' + subtitle.filename) sub.mods = None if settings.general.getboolean('utf8_encode'): sub.set_encoding("utf-8") saved_subtitles = [] try: saved_subtitles = save_subtitles(path, [sub], single=single, tags=None, # fixme directory=get_target_folder(path), chmod=chmod, # formats=("srt", "vtt") path_decoder=force_unicode) except Exception: logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path) return if len(saved_subtitles) < 1: logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path) return subtitle_path = saved_subtitles[0].storage_path if hi: modifier_string = " HI" elif forced: modifier_string = " forced" else: modifier_string = "" message = language_from_alpha3(language) + modifier_string + " Subtitles manually uploaded." if hi: modifier_code = ":hi" elif forced: modifier_code = ":forced" else: modifier_code = "" uploaded_language_code3 = language + modifier_code uploaded_language = language_from_alpha3(language) + modifier_string uploaded_language_code2 = alpha2_from_alpha3(language) + modifier_code audio_language_code2 = alpha2_from_language(audio_language) audio_language_code3 = alpha3_from_language(audio_language) if media_type == 'series': episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId) \ .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \ .dicts() \ .get_or_none() if not episode_metadata: return series_id = episode_metadata['sonarrSeriesId'] episode_id = episode_metadata['sonarrEpisodeId'] sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type, percent_score=100, sonarr_series_id=episode_metadata['sonarrSeriesId'], forced=forced, sonarr_episode_id=episode_metadata['sonarrEpisodeId']) else: movie_metadata = TableMovies.select(TableMovies.radarrId) \ .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \ .dicts() \ .get_or_none() if not movie_metadata: return series_id = "" episode_id = movie_metadata['radarrId'] sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type, percent_score=100, radarr_id=movie_metadata['radarrId'], forced=forced) if use_postprocessing: command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language, uploaded_language_code2, uploaded_language_code3, audio_language, audio_language_code2, audio_language_code3, forced, 100, "1", "manual", series_id, episode_id, hi=hi) postprocessing(command, path) if media_type == 'series': reversed_path = path_mappings.path_replace_reverse(path) reversed_subtitles_path = path_mappings.path_replace_reverse(subtitle_path) notify_sonarr(episode_metadata['sonarrSeriesId']) event_stream(type='series', action='update', payload=episode_metadata['sonarrSeriesId']) event_stream(type='episode-wanted', action='delete', payload=episode_metadata['sonarrEpisodeId']) else: reversed_path = path_mappings.path_replace_reverse_movie(path) reversed_subtitles_path = path_mappings.path_replace_reverse_movie(subtitle_path) notify_radarr(movie_metadata['radarrId']) event_stream(type='movie', action='update', payload=movie_metadata['radarrId']) event_stream(type='movie-wanted', action='delete', payload=movie_metadata['radarrId']) return message, reversed_path, reversed_subtitles_path
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 update_series(send_event=True): check_sonarr_rootfolder() apikey_sonarr = settings.sonarr.apikey if apikey_sonarr is None: 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() # Get shows data from Sonarr series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr) if not series: return else: # Get current shows in DB current_shows_db = TableShows.select(TableShows.sonarrSeriesId).dicts() current_shows_db_list = [x['sonarrSeriesId'] for x in current_shows_db] current_shows_sonarr = [] series_to_update = [] series_to_add = [] series_count = len(series) for i, show in enumerate(series): if send_event: show_progress(id='series_progress', header='Syncing series...', name=show['title'], value=i, count=series_count) # Add shows in Sonarr to current shows list current_shows_sonarr.append(show['id']) if show['id'] in current_shows_db_list: series_to_update.append(seriesParser(show, action='update', tags_dict=tagsDict, serie_default_profile=serie_default_profile, audio_profiles=audio_profiles)) else: series_to_add.append(seriesParser(show, action='insert', tags_dict=tagsDict, serie_default_profile=serie_default_profile, audio_profiles=audio_profiles)) if send_event: hide_progress(id='series_progress') # Remove old series from DB removed_series = list(set(current_shows_db_list) - set(current_shows_sonarr)) for series in removed_series: try: TableShows.delete().where(TableShows.sonarrSeriesId == series).execute() except Exception as e: logging.error(f"BAZARR cannot delete series with sonarrSeriesId {series} because of {e}") continue else: if send_event: event_stream(type='series', action='delete', payload=series) # Update existing series in DB series_in_db_list = [] series_in_db = TableShows.select(TableShows.title, TableShows.path, TableShows.tvdbId, TableShows.sonarrSeriesId, TableShows.overview, TableShows.poster, TableShows.fanart, TableShows.audio_language, TableShows.sortTitle, TableShows.year, TableShows.alternateTitles, TableShows.tags, TableShows.seriesType, TableShows.imdbId).dicts() for item in series_in_db: series_in_db_list.append(item) series_to_update_list = [i for i in series_to_update if i not in series_in_db_list] for updated_series in series_to_update_list: try: TableShows.update(updated_series).where(TableShows.sonarrSeriesId == updated_series['sonarrSeriesId']).execute() except IntegrityError as e: logging.error(f"BAZARR cannot update series {updated_series['path']} because of {e}") continue else: if send_event: event_stream(type='series', payload=updated_series['sonarrSeriesId']) # Insert new series in DB for added_series in series_to_add: try: result = TableShows.insert(added_series).on_conflict(action='IGNORE').execute() except IntegrityError as e: logging.error(f"BAZARR cannot insert series {added_series['path']} because of {e}") continue else: if result: list_missing_subtitles(no=added_series['sonarrSeriesId']) else: logging.debug('BAZARR unable to insert this series into the database:', path_mappings.path_replace(added_series['path'])) if send_event: event_stream(type='series', action='update', payload=added_series['sonarrSeriesId']) logging.debug('BAZARR All series synced from Sonarr into database.')
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 list_missing_subtitles(no=None, epno=None, send_event=True): if no is not None: episodes_subtitles_clause = " WHERE table_episodes.sonarrSeriesId=" + str( no) elif epno is not None: episodes_subtitles_clause = " WHERE table_episodes.sonarrEpisodeId=" + str( epno) else: episodes_subtitles_clause = "" episodes_subtitles = database.execute( "SELECT table_shows.sonarrSeriesId, table_episodes.sonarrEpisodeId, " "table_episodes.subtitles, table_shows.languages, table_shows.forced " "FROM table_episodes LEFT JOIN table_shows " "on table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId" + episodes_subtitles_clause) if isinstance(episodes_subtitles, str): logging.error( "BAZARR list missing subtitles query to DB returned this instead of rows: " + episodes_subtitles) return missing_subtitles_global = [] use_embedded_subs = settings.general.getboolean('use_embedded_subs') for episode_subtitles in episodes_subtitles: actual_subtitles_temp = [] desired_subtitles_temp = [] actual_subtitles = [] desired_subtitles = [] missing_subtitles = [] if episode_subtitles['subtitles'] is not None: if use_embedded_subs: actual_subtitles = ast.literal_eval( episode_subtitles['subtitles']) else: actual_subtitles_temp = ast.literal_eval( episode_subtitles['subtitles']) for subtitle in actual_subtitles_temp: if subtitle[1] is not None: actual_subtitles.append(subtitle) if episode_subtitles['languages'] is not None: desired_subtitles = ast.literal_eval( episode_subtitles['languages']) if episode_subtitles[ 'forced'] == "True" and desired_subtitles is not None: for i, desired_subtitle in enumerate(desired_subtitles): desired_subtitles[i] = desired_subtitle + ":forced" elif episode_subtitles[ 'forced'] == "Both" and desired_subtitles is not None: for desired_subtitle in desired_subtitles: desired_subtitles_temp.append(desired_subtitle) desired_subtitles_temp.append(desired_subtitle + ":forced") desired_subtitles = desired_subtitles_temp actual_subtitles_list = [] if desired_subtitles is None: missing_subtitles_global.append( tuple([ '[]', episode_subtitles['sonarrEpisodeId'], episode_subtitles['sonarrSeriesId'] ])) else: for item in actual_subtitles: if item[0] == "pt-BR": actual_subtitles_list.append("pb") elif item[0] == "pt-BR:forced": actual_subtitles_list.append("pb:forced") else: actual_subtitles_list.append(item[0]) missing_subtitles = list( set(desired_subtitles) - set(actual_subtitles_list)) missing_subtitles_global.append( tuple([ str(missing_subtitles), episode_subtitles['sonarrEpisodeId'], episode_subtitles['sonarrSeriesId'] ])) for missing_subtitles_item in missing_subtitles_global: database.execute( "UPDATE table_episodes SET missing_subtitles=? WHERE sonarrEpisodeId=?", (missing_subtitles_item[0], missing_subtitles_item[1])) if send_event: event_stream(type='episode', action='update', series=missing_subtitles_item[2], episode=missing_subtitles_item[1]) event_stream(type='badges_series')
def process_subtitle(subtitle, media_type, audio_language, path, max_score, is_upgrade=False, is_manual=False): use_postprocessing = settings.general.getboolean('use_postprocessing') postprocessing_cmd = settings.general.postprocessing_cmd downloaded_provider = subtitle.provider_name downloaded_language_code3 = _get_download_code3(subtitle) downloaded_language = language_from_alpha3(downloaded_language_code3) downloaded_language_code2 = alpha2_from_alpha3(downloaded_language_code3) audio_language_code2 = alpha2_from_language(audio_language) audio_language_code3 = alpha3_from_language(audio_language) downloaded_path = subtitle.storage_path subtitle_id = subtitle.id if subtitle.language.hi: modifier_string = " HI" elif subtitle.language.forced: modifier_string = " forced" else: modifier_string = "" logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path) if is_upgrade: action = "upgraded" elif is_manual: action = "manually downloaded" else: action = "downloaded" percent_score = round(subtitle.score * 100 / max_score, 2) message = downloaded_language + modifier_string + " subtitles " + action + " from " + \ downloaded_provider + " with a score of " + str(percent_score) + "%." if media_type == 'series': episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId) \ .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \ .dicts() \ .get_or_none() if not episode_metadata: return series_id = episode_metadata['sonarrSeriesId'] episode_id = episode_metadata['sonarrEpisodeId'] sync_subtitles(video_path=path, srt_path=downloaded_path, forced=subtitle.language.forced, srt_lang=downloaded_language_code2, media_type=media_type, percent_score=percent_score, sonarr_series_id=episode_metadata['sonarrSeriesId'], sonarr_episode_id=episode_metadata['sonarrEpisodeId']) else: movie_metadata = TableMovies.select(TableMovies.radarrId) \ .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \ .dicts() \ .get_or_none() if not movie_metadata: return series_id = "" episode_id = movie_metadata['radarrId'] sync_subtitles(video_path=path, srt_path=downloaded_path, forced=subtitle.language.forced, srt_lang=downloaded_language_code2, media_type=media_type, percent_score=percent_score, radarr_id=movie_metadata['radarrId']) if use_postprocessing is True: command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3, audio_language, audio_language_code2, audio_language_code3, subtitle.language.forced, percent_score, subtitle_id, downloaded_provider, series_id, episode_id, subtitle.language.hi) if media_type == 'series': use_pp_threshold = settings.general.getboolean( 'use_postprocessing_threshold') pp_threshold = int(settings.general.postprocessing_threshold) else: use_pp_threshold = settings.general.getboolean( 'use_postprocessing_threshold_movie') pp_threshold = int(settings.general.postprocessing_threshold_movie) if not use_pp_threshold or (use_pp_threshold and percent_score < pp_threshold): logging.debug( "BAZARR Using post-processing command: {}".format(command)) postprocessing(command, path) else: logging.debug( "BAZARR post-processing skipped because subtitles score isn't below this " "threshold value: " + str(pp_threshold) + "%") if media_type == 'series': reversed_path = path_mappings.path_replace_reverse(path) reversed_subtitles_path = path_mappings.path_replace_reverse( downloaded_path) notify_sonarr(episode_metadata['sonarrSeriesId']) event_stream(type='series', action='update', payload=episode_metadata['sonarrSeriesId']) event_stream(type='episode-wanted', action='delete', payload=episode_metadata['sonarrEpisodeId']) else: reversed_path = path_mappings.path_replace_reverse_movie(path) reversed_subtitles_path = path_mappings.path_replace_reverse_movie( downloaded_path) notify_radarr(movie_metadata['radarrId']) event_stream(type='movie-wanted', action='delete', payload=movie_metadata['radarrId']) track_event(category=downloaded_provider, action=action, label=downloaded_language) return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, \ subtitle.language.forced, subtitle.id, reversed_subtitles_path, subtitle.language.hi
def list_missing_subtitles_movies(no=None, epno=None, send_event=True): if no is not None: movies_subtitles_clause = " WHERE radarrId=" + str(no) else: movies_subtitles_clause = "" movies_subtitles = database.execute( "SELECT radarrId, subtitles, profileId, audio_language FROM table_movies" + movies_subtitles_clause) if isinstance(movies_subtitles, str): logging.error( "BAZARR list missing subtitles query to DB returned this instead of rows: " + movies_subtitles) return use_embedded_subs = settings.general.getboolean('use_embedded_subs') for movie_subtitles in movies_subtitles: missing_subtitles_text = '[]' if movie_subtitles['profileId']: # get desired subtitles desired_subtitles_temp = get_profiles_list( profile_id=movie_subtitles['profileId']) desired_subtitles_list = [] if desired_subtitles_temp: for language in ast.literal_eval( desired_subtitles_temp['items']): if language['audio_exclude'] == "True": cutoff_lang_temp = get_profile_cutoff( profile_id=movie_subtitles['profileId']) if cutoff_lang_temp: if language_from_alpha2( cutoff_lang_temp[0] ['language']) in ast.literal_eval( movie_subtitles['audio_language']): desired_subtitles_list = [] break if language_from_alpha2( language['language']) in ast.literal_eval( movie_subtitles['audio_language']): continue desired_subtitles_list.append([ language['language'], language['forced'], language['hi'] ]) # get existing subtitles actual_subtitles_list = [] if movie_subtitles['subtitles'] is not None: if use_embedded_subs: actual_subtitles_temp = ast.literal_eval( movie_subtitles['subtitles']) else: actual_subtitles_temp = [ x for x in ast.literal_eval(movie_subtitles['subtitles']) if x[1] ] for subtitles in actual_subtitles_temp: subtitles = subtitles[0].split(':') lang = subtitles[0] forced = False hi = False if len(subtitles) > 1: if subtitles[1] == 'forced': forced = True hi = False elif subtitles[1] == 'hi': forced = False hi = True actual_subtitles_list.append([lang, str(forced), str(hi)]) # check if cutoff is reached and skip any further check cutoff_met = False cutoff_temp_list = get_profile_cutoff( profile_id=movie_subtitles['profileId']) if cutoff_temp_list: for cutoff_temp in cutoff_temp_list: cutoff_language = [ cutoff_temp['language'], cutoff_temp['forced'], cutoff_temp['hi'] ] if cutoff_language in actual_subtitles_list: cutoff_met = True missing_subtitles_text = str([]) elif cutoff_language and [ cutoff_language[0], 'True', 'False' ] in actual_subtitles_list: cutoff_met = True missing_subtitles_text = str([]) elif cutoff_language and [ cutoff_language[0], 'False', 'True' ] in actual_subtitles_list: cutoff_met = True missing_subtitles_text = str([]) if not cutoff_met: # get difference between desired and existing subtitles missing_subtitles_list = [] for item in desired_subtitles_list: if item not in actual_subtitles_list: missing_subtitles_list.append(item) # remove missing that have forced or hi subtitles for this language in existing for item in actual_subtitles_list: if item[1] == 'True' or item[2] == 'True': try: missing_subtitles_list.remove( [item[0], 'False', 'False']) except ValueError: pass # make the missing languages list looks like expected missing_subtitles_output_list = [] for item in missing_subtitles_list: lang = item[0] if item[1] == 'True': lang += ':forced' elif item[2] == 'True': lang += ':hi' missing_subtitles_output_list.append(lang) missing_subtitles_text = str(missing_subtitles_output_list) database.execute( "UPDATE table_movies SET missing_subtitles=? WHERE radarrId=?", (missing_subtitles_text, movie_subtitles['radarrId'])) if send_event: event_stream(type='movie', action='update', movie=movie_subtitles['radarrId']) event_stream(type='badges_movies')
def sync_episodes(): logging.debug('BAZARR Starting episodes sync from Sonarr.') apikey_sonarr = settings.sonarr.apikey # Get current episodes id in DB current_episodes_db = database.execute("SELECT sonarrEpisodeId, path, sonarrSeriesId FROM table_episodes") 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 = database.execute("SELECT sonarrSeriesId, title FROM table_shows") for i, seriesId in enumerate(seriesIdList): # Get episodes data for a series from Sonarr url_sonarr_api_episode = url_sonarr() + "/api/episode?seriesId=" + str(seriesId['sonarrSeriesId']) + "&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 audio_language = None if 'language' in episode['episodeFile'] and len(episode['episodeFile']['language']): item = episode['episodeFile']['language'] if isinstance(item, dict): if 'name' in item: audio_language = item['name'] else: audio_language = database.execute("SELECT audio_language FROM table_shows WHERE " "sonarrSeriesId=?", (episode['seriesId'],), only_one=True)['audio_language'] # 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({'sonarrSeriesId': episode['seriesId'], 'sonarrEpisodeId': 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'], 'audio_language': audio_language}) else: episodes_to_add.append({'sonarrSeriesId': episode['seriesId'], 'sonarrEpisodeId': 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'], 'audio_language': audio_language}) # 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 = database.execute("SELECT sonarrSeriesId, sonarrEpisodeId FROM table_episodes WHERE " "sonarrEpisodeId=?", (removed_episode,), only_one=True) database.execute("DELETE FROM table_episodes WHERE sonarrEpisodeId=?", (removed_episode,)) event_stream(type='episode', action='delete', series=episode_to_delete['sonarrSeriesId'], episode=episode_to_delete['sonarrEpisodeId']) # Update existing episodes in DB episode_in_db_list = [] episodes_in_db = database.execute("SELECT sonarrSeriesId, sonarrEpisodeId, title, path, season, episode, " "scene_name, monitored, format, resolution, video_codec, audio_codec, " "episode_file_id, audio_language FROM table_episodes") 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: query = dict_converter.convert(updated_episode) database.execute('''UPDATE table_episodes SET ''' + query.keys_update + ''' WHERE sonarrEpisodeId = ?''', query.values + (updated_episode['sonarrEpisodeId'],)) altered_episodes.append([updated_episode['sonarrEpisodeId'], updated_episode['path'], updated_episode['sonarrSeriesId']]) # Insert new episodes in DB for added_episode in episodes_to_add: query = dict_converter.convert(added_episode) result = database.execute( '''INSERT OR IGNORE INTO table_episodes(''' + query.keys_insert + ''') VALUES(''' + query.question_marks + ''')''', query.values) if result > 0: altered_episodes.append([added_episode['sonarrEpisodeId'], added_episode['path'], added_episode['monitored']]) event_stream(type='episode', action='insert', series=added_episode['sonarrSeriesId'], episode=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.') # 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: data = database.execute("SELECT table_episodes.sonarrEpisodeId, table_episodes.monitored, table_shows.tags," " table_shows.seriesType FROM table_episodes LEFT JOIN table_shows on " "table_episodes.sonarrSeriesId = table_shows.sonarrSeriesId WHERE " "sonarrEpisodeId = ?" + get_exclusion_clause('series'), (altered_episode[0],), only_one=True) if data: episode_download_subtitles(data['sonarrEpisodeId']) else: logging.debug("BAZARR skipping download for this episode as it is excluded.") else: logging.debug("BAZARR More than 5 episodes were added during this sync then we wont search for subtitles right now.")
def blacklist_log(sonarr_series_id, sonarr_episode_id, provider, subs_id, language): database.execute("INSERT INTO table_blacklist (sonarr_series_id, sonarr_episode_id, timestamp, provider, " "subs_id, language) VALUES (?,?,?,?,?,?)", (sonarr_series_id, sonarr_episode_id, time.time(), provider, subs_id, language)) event_stream(type='episodeBlacklist')
def task_listener_remove(event): if event.job_id in self.__running_tasks: self.__running_tasks.remove(event.job_id) event_stream(type='task', task=event.job_id)
def blacklist_delete_all(): database.execute("DELETE FROM table_blacklist") event_stream(type='episodeBlacklist')