def post(self): sonarr_series_id = int(request.args.get('seriesid')) sonarr_episode_id = int(request.args.get('episodeid')) provider = request.form.get('provider') subs_id = request.form.get('subs_id') language = request.form.get('language') episodeInfo = TableEpisodes.select(TableEpisodes.path)\ .where(TableEpisodes.sonarrEpisodeId == sonarr_episode_id)\ .dicts()\ .get() media_path = episodeInfo['path'] subtitles_path = request.form.get('subtitles_path') blacklist_log(sonarr_series_id=sonarr_series_id, sonarr_episode_id=sonarr_episode_id, provider=provider, subs_id=subs_id, language=language) delete_subtitles(media_type='series', language=language, forced=False, hi=False, media_path=path_mappings.path_replace(media_path), subtitles_path=subtitles_path, sonarr_series_id=sonarr_series_id, sonarr_episode_id=sonarr_episode_id) episode_download_subtitles(sonarr_episode_id) event_stream(type='episode-history') return '', 200
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 = 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") seriesIdListLength = len(seriesIdList) 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['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 # 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'] }) 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'] }) # Remove old episodes from DB removed_episodes = list( set(current_episodes_db_list) - set(current_episodes_sonarr)) for removed_episode in removed_episodes: database.execute("DELETE FROM table_episodes WHERE sonarrEpisodeId=?", (removed_episode, )) # 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 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']]) else: logging.debug( 'BAZARR unable to insert this episode into the database:', path_replace(added_episode['path'])) # 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(altered_episode[1], 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: 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." )
def post(self): json_webhook = request.form.get('payload') parsed_json_webhook = json.loads(json_webhook) event = parsed_json_webhook['event'] if event not in ['media.play']: return '', 204 media_type = parsed_json_webhook['Metadata']['type'] if media_type == 'episode': season = parsed_json_webhook['Metadata']['parentIndex'] episode = parsed_json_webhook['Metadata']['index'] else: season = episode = None ids = [] for item in parsed_json_webhook['Metadata']['Guid']: splitted_id = item['id'].split('://') if len(splitted_id) == 2: ids.append({splitted_id[0]: splitted_id[1]}) if not ids: return '', 404 if media_type == 'episode': try: episode_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0] r = requests.get( 'https://imdb.com/title/{}'.format(episode_imdb_id), headers={"User-Agent": os.environ["SZ_USER_AGENT"]}) soup = bso(r.content, "html.parser") series_imdb_id = soup.find( 'a', {'class': re.compile(r'SeriesParentLink__ParentTextLink') })['href'].split('/')[2] except: return '', 404 else: sonarrEpisodeId = TableEpisodes.select(TableEpisodes.sonarrEpisodeId) \ .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId)) \ .where(TableShows.imdbId == series_imdb_id, TableEpisodes.season == season, TableEpisodes.episode == episode) \ .dicts() \ .get() if sonarrEpisodeId: episode_download_subtitles( no=sonarrEpisodeId['sonarrEpisodeId'], send_progress=True) else: try: movie_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0] except: return '', 404 else: radarrId = TableMovies.select(TableMovies.radarrId)\ .where(TableMovies.imdbId == movie_imdb_id)\ .dicts()\ .get() if radarrId: movies_download_subtitles(no=radarrId['radarrId']) return '', 200
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(): notifications.write(msg='Episodes sync from Sonarr started...', queue='get_episodes') logging.debug('BAZARR Starting episodes sync from Sonarr.') apikey_sonarr = settings.sonarr.apikey # Open database connection db = sqlite3.connect(os.path.join(args.config_dir, 'db', 'bazarr.db'), timeout=30) c = db.cursor() # Get current episodes id in DB current_episodes_db = c.execute('SELECT sonarrEpisodeId, path, sonarrSeriesId FROM table_episodes').fetchall() current_episodes_db_list = [x[0] for x in current_episodes_db] current_episodes_sonarr = [] episodes_to_update = [] episodes_to_add = [] # Get sonarrId for each series from database seriesIdList = c.execute("SELECT sonarrSeriesId, title FROM table_shows").fetchall() # Close database connection c.close() seriesIdListLength = len(seriesIdList) 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[0]) + "&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.") except requests.exceptions.ConnectionError as errc: logging.exception("BAZARR Error trying to get episodes from Sonarr. Connection Error.") except requests.exceptions.Timeout as errt: logging.exception("BAZARR Error trying to get episodes from Sonarr. Timeout Error.") except requests.exceptions.RequestException as err: logging.exception("BAZARR Error trying to get episodes from Sonarr.") 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((episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'], sceneName, str(bool(episode['monitored'])), format, resolution, videoCodec, audioCodec, episode['id'])) else: episodes_to_add.append((episode['seriesId'], episode['id'], episode['title'], episode['episodeFile']['path'], episode['seasonNumber'], episode['episodeNumber'], sceneName, str(bool(episode['monitored'])), format, resolution, videoCodec, audioCodec)) removed_episodes = list(set(current_episodes_db_list) - set(current_episodes_sonarr)) # Update or insert movies in DB db = sqlite3.connect(os.path.join(args.config_dir, 'db', 'bazarr.db'), timeout=30) c = db.cursor() updated_result = c.executemany( '''UPDATE table_episodes SET title = ?, path = ?, season = ?, episode = ?, scene_name = ?, monitored = ?, format = ?, resolution = ?, video_codec = ?, audio_codec = ? WHERE sonarrEpisodeId = ?''', episodes_to_update) db.commit() added_result = c.executemany( '''INSERT OR IGNORE INTO table_episodes(sonarrSeriesId, sonarrEpisodeId, title, path, season, episode, scene_name, monitored, format, resolution, video_codec, audio_codec) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', episodes_to_add) db.commit() for removed_episode in removed_episodes: c.execute('DELETE FROM table_episodes WHERE sonarrEpisodeId = ?', (removed_episode,)) db.commit() # Get episodes list after INSERT and UPDATE episodes_now_in_db = c.execute('SELECT sonarrEpisodeId, path, sonarrSeriesId FROM table_episodes').fetchall() # Close database connection c.close() # Get only episodes added or modified and store subtitles for them altered_episodes = set(episodes_now_in_db).difference(set(current_episodes_db)) for altered_episode in 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.")
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." )