diff --git a/bazarr/api/badges/badges.py b/bazarr/api/badges/badges.py index d0656016d..7d65f586f 100644 --- a/bazarr/api/badges/badges.py +++ b/bazarr/api/badges/badges.py @@ -7,6 +7,7 @@ from flask_restx import Resource, Namespace, fields from app.database import get_exclusion_clause, TableEpisodes, TableShows, TableMovies from app.get_providers import get_throttled_providers +from app.signalr_client import sonarr_signalr_client, radarr_signalr_client from utilities.health import get_health_issues from ..utils import authenticate @@ -22,6 +23,8 @@ class Badges(Resource): 'movies': fields.Integer(), 'providers': fields.Integer(), 'status': fields.Integer(), + 'sonarr_signalr': fields.String(), + 'radarr_signalr': fields.String(), }) @authenticate @@ -56,6 +59,8 @@ class Badges(Resource): "episodes": missing_episodes, "movies": missing_movies, "providers": throttled_providers, - "status": health_issues + "status": health_issues, + 'sonarr_signalr': "LIVE" if sonarr_signalr_client.connected else "", + 'radarr_signalr': "LIVE" if radarr_signalr_client.connected else "", } return result diff --git a/bazarr/app/signalr_client.py b/bazarr/app/signalr_client.py index 3fd5c4e29..0aa85633f 100644 --- a/bazarr/app/signalr_client.py +++ b/bazarr/app/signalr_client.py @@ -20,6 +20,7 @@ from radarr.sync.movies import update_movies, update_one_movie from sonarr.info import get_sonarr_info, url_sonarr from radarr.info import url_radarr from .database import TableShows +from .event_handler import event_stream from .config import settings from .scheduler import scheduler @@ -41,12 +42,15 @@ class SonarrSignalrClientLegacy: self.session.verify = False self.session.headers = headers self.connection = None + self.connected = False def start(self): if get_sonarr_info.is_legacy(): logging.warning('BAZARR can only sync from Sonarr v3 SignalR feed to get real-time update. You should ' 'consider upgrading your version({}).'.format(get_sonarr_info.version())) else: + self.connected = False + event_stream(type='badges') logging.info('BAZARR trying to connect to Sonarr SignalR feed...') self.configure() while not self.connection.started: @@ -63,6 +67,8 @@ class SonarrSignalrClientLegacy: "user, you should make sure you properly defined PUID/PGID environment variables. " "Otherwise, please contact Sonarr support.") else: + self.connected = True + event_stream(type='badges') logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.') finally: if not args.dev: @@ -86,6 +92,8 @@ class SonarrSignalrClientLegacy: def exception_handler(self): sonarr_queue.clear() + self.connected = False + event_stream(type='badges') logging.error('BAZARR connection to Sonarr SignalR feed has been lost.') self.restart() @@ -107,6 +115,7 @@ class SonarrSignalrClient: super(SonarrSignalrClient, self).__init__() self.apikey_sonarr = None self.connection = None + self.connected = False def start(self): self.configure() @@ -130,16 +139,24 @@ class SonarrSignalrClient: def exception_handler(self): sonarr_queue.clear() + self.connected = False + event_stream(type='badges') logging.error("BAZARR connection to Sonarr SignalR feed has failed. We'll try to reconnect.") self.restart() - @staticmethod - def on_connect_handler(): + def on_connect_handler(self): + self.connected = True + event_stream(type='badges') logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.') if not args.dev: scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1) scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1) + def on_reconnect_handler(self): + self.connected = False + event_stream(type='badges') + logging.error('BAZARR SignalR client for Sonarr connection as been lost. Trying to reconnect...') + def configure(self): self.apikey_sonarr = settings.sonarr.apikey self.connection = HubConnectionBuilder() \ @@ -155,8 +172,7 @@ class SonarrSignalrClient: "max_attempts": None }).build() self.connection.on_open(self.on_connect_handler) - self.connection.on_reconnect(lambda: logging.error('BAZARR SignalR client for Sonarr connection as been lost. ' - 'Trying to reconnect...')) + self.connection.on_reconnect(self.on_reconnect_handler) self.connection.on_close(lambda: logging.debug('BAZARR SignalR client for Sonarr is disconnected.')) self.connection.on_error(self.exception_handler) self.connection.on("receiveMessage", feed_queue) @@ -167,6 +183,7 @@ class RadarrSignalrClient: super(RadarrSignalrClient, self).__init__() self.apikey_radarr = None self.connection = None + self.connected = False def start(self): self.configure() @@ -190,15 +207,23 @@ class RadarrSignalrClient: def exception_handler(self): radarr_queue.clear() + self.connected = False + event_stream(type='badges') logging.error("BAZARR connection to Radarr SignalR feed has failed. We'll try to reconnect.") self.restart() - @staticmethod - def on_connect_handler(): + def on_connect_handler(self): + self.connected = True + event_stream(type='badges') logging.info('BAZARR SignalR client for Radarr is connected and waiting for events.') if not args.dev: scheduler.add_job(update_movies, kwargs={'send_event': True}, max_instances=1) + def on_reconnect_handler(self): + self.connected = False + event_stream(type='badges') + logging.error('BAZARR SignalR client for Radarr connection as been lost. Trying to reconnect...') + def configure(self): self.apikey_radarr = settings.radarr.apikey self.connection = HubConnectionBuilder() \ @@ -214,8 +239,7 @@ class RadarrSignalrClient: "max_attempts": None }).build() self.connection.on_open(self.on_connect_handler) - self.connection.on_reconnect(lambda: logging.error('BAZARR SignalR client for Radarr connection as been lost. ' - 'Trying to reconnect...')) + self.connection.on_reconnect(self.on_reconnect_handler) self.connection.on_close(lambda: logging.debug('BAZARR SignalR client for Radarr is disconnected.')) self.connection.on_error(self.exception_handler) self.connection.on("receiveMessage", feed_queue) diff --git a/frontend/src/Router/index.tsx b/frontend/src/Router/index.tsx index 41de5fec2..3c3ab8a4a 100644 --- a/frontend/src/Router/index.tsx +++ b/frontend/src/Router/index.tsx @@ -73,6 +73,7 @@ function useRoutes(): CustomRouteObject[] { icon: faPlay, name: "Series", path: "series", + badge: data?.sonarr_signalr, hidden: !sonarr, children: [ { @@ -94,6 +95,7 @@ function useRoutes(): CustomRouteObject[] { icon: faFilm, name: "Movies", path: "movies", + badge: data?.radarr_signalr, hidden: !radarr, children: [ { @@ -291,7 +293,15 @@ function useRoutes(): CustomRouteObject[] { element: , }, ], - [data?.episodes, data?.movies, data?.providers, radarr, sonarr] + [ + data?.episodes, + data?.movies, + data?.providers, + data?.sonarr_signalr, + data?.radarr_signalr, + radarr, + sonarr, + ] ); } diff --git a/frontend/src/types/api.d.ts b/frontend/src/types/api.d.ts index 933d2c408..ffd931d43 100644 --- a/frontend/src/types/api.d.ts +++ b/frontend/src/types/api.d.ts @@ -3,6 +3,8 @@ interface Badge { movies: number; providers: number; status: number; + sonarr_signalr: string; + radarr_signalr: string; } declare namespace Language {