From 7c79a1c4a569ea4b4abdaf68ca0a071c74cf0e11 Mon Sep 17 00:00:00 2001 From: Nihal Mirpuri Date: Mon, 24 Jun 2024 20:11:33 +0100 Subject: [PATCH 1/3] run a full sync every 19 minutes --- src/main/scala/PlexTokenSync.scala | 12 +++++------ src/main/scala/Server.scala | 29 ++++++++++++++++++-------- src/test/scala/PlexTokenSyncSpec.scala | 2 +- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/scala/PlexTokenSync.scala b/src/main/scala/PlexTokenSync.scala index 6efb58f..eeca074 100644 --- a/src/main/scala/PlexTokenSync.scala +++ b/src/main/scala/PlexTokenSync.scala @@ -13,19 +13,17 @@ object PlexTokenSync extends PlexUtils with SonarrUtils with RadarrUtils { private val logger = LoggerFactory.getLogger(getClass) - def run(config: Configuration, client: HttpClient, firstRun: Boolean): IO[Unit] = { - val runTokenSync = firstRun || !config.plexConfiguration.hasPlexPass - + def run(config: Configuration, client: HttpClient, runFullSync: Boolean): IO[Unit] = { val result = for { selfWatchlist <- - if (runTokenSync) + if (runFullSync) getSelfWatchlist(config.plexConfiguration, client) else EitherT.pure[IO, Throwable](Set.empty[Item]) - _ = if (runTokenSync) + _ = if (runFullSync) logger.info(s"Found ${selfWatchlist.size} items on user's watchlist using the plex token") othersWatchlist <- - if (config.plexConfiguration.skipFriendSync || !runTokenSync) + if (config.plexConfiguration.skipFriendSync || !runFullSync) EitherT.pure[IO, Throwable](Set.empty[Item]) else getOthersWatchlist(config.plexConfiguration, client) @@ -33,7 +31,7 @@ object PlexTokenSync extends PlexUtils with SonarrUtils with RadarrUtils { config.plexConfiguration.plexWatchlistUrls.map(fetchWatchlistFromRss(client)).toList.sequence.map(Right(_)) ) watchlistData = watchlistDatas.flatten.toSet - _ = if (runTokenSync) + _ = if (runFullSync) logger.info(s"Found ${othersWatchlist.size} items on other available watchlists using the plex token") movies <- fetchMovies(client)( config.radarrConfiguration.radarrApiKey, diff --git a/src/main/scala/Server.scala b/src/main/scala/Server.scala index 5191445..a84cc5d 100644 --- a/src/main/scala/Server.scala +++ b/src/main/scala/Server.scala @@ -1,6 +1,6 @@ import cats.effect._ -import cats.implicits.catsSyntaxTuple3Parallel -import configuration.{Configuration, ConfigurationUtils, FileAndSystemPropertyReader, SystemPropertyReader} +import cats.implicits.catsSyntaxTuple4Parallel +import configuration.{Configuration, ConfigurationUtils, FileAndSystemPropertyReader} import http.HttpClient import org.slf4j.LoggerFactory @@ -25,8 +25,9 @@ object Server extends IOApp { configRef <- Ref.of[IO, Configuration](initialConfig) result <- ( pingTokenSync(configRef, httpClient), - plexTokenSync(configRef, httpClient), - plexTokenDeleteSync(configRef, httpClient) + plexRssSync(configRef, httpClient), + plexTokenDeleteSync(configRef, httpClient), + plexFullSync(configRef, httpClient) ).parTupled.as(ExitCode.Success) } yield result } @@ -42,16 +43,26 @@ object Server extends IOApp { _ <- pingTokenSync(configRef, httpClient) } yield () - private def plexTokenSync( + private def plexRssSync( configRef: Ref[IO, Configuration], - httpClient: HttpClient, - firstRun: Boolean = true + httpClient: HttpClient ): IO[Unit] = for { config <- fetchLatestConfig(configRef) - _ <- PlexTokenSync.run(config, httpClient, firstRun) + _ <- PlexTokenSync.run(config, httpClient, runFullSync = false) _ <- IO.sleep(config.refreshInterval) - _ <- plexTokenSync(configRef, httpClient, firstRun = false) + _ <- plexRssSync(configRef, httpClient) + } yield () + + private def plexFullSync( + configRef: Ref[IO, Configuration], + httpClient: HttpClient + ): IO[Unit] = + for { + config <- fetchLatestConfig(configRef) + _ <- PlexTokenSync.run(config, httpClient, runFullSync = true) + _ <- IO.sleep(19.minutes) + _ <- plexFullSync(configRef, httpClient) } yield () private def plexTokenDeleteSync(configRef: Ref[IO, Configuration], httpClient: HttpClient): IO[Unit] = diff --git a/src/test/scala/PlexTokenSyncSpec.scala b/src/test/scala/PlexTokenSyncSpec.scala index 6701e94..29b8e93 100644 --- a/src/test/scala/PlexTokenSyncSpec.scala +++ b/src/test/scala/PlexTokenSyncSpec.scala @@ -23,7 +23,7 @@ class PlexTokenSyncSpec extends AnyFlatSpec with Matchers with MockFactory { defaultRadarrMock(mockHttpClient) defaultSonarrMock(mockHttpClient) - val sync: Unit = PlexTokenSync.run(config, mockHttpClient, firstRun = true).unsafeRunSync() + val sync: Unit = PlexTokenSync.run(config, mockHttpClient, runFullSync = true).unsafeRunSync() sync shouldBe () } From 20d6549c82bd28273054b076d8bdbba490afaa94 Mon Sep 17 00:00:00 2001 From: Nihal Mirpuri Date: Mon, 24 Jun 2024 20:13:49 +0100 Subject: [PATCH 2/3] update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9d08459..d96c15a 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ Sync plex watchlists in realtime with Sonarr and Radarr. There are several ways of fetching watchlist information from Plex -| Method | Pros | Cons | Supported by Watchlistarr | Supported by Overseer/Ombi | Supported by Sonarr/Radarr | -|-----------------------------------------|-------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|---------------------------|------------------------------|----------------------------------------| -| Plex Watchlist RSS Feeds | Fast and instantly updated, can create one for self and one for friends | Will only show the most recent 50 movies/shows | Yes | X | Only for self, refreshes every 6 hours | +| Method | Pros | Cons | Supported by Watchlistarr | Supported by Overseer/Ombi | Supported by Sonarr/Radarr | +|-----------------------------------------|-------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|---------------------------|------------------------------|----------------------------------------| +| Plex Watchlist RSS Feeds | Fast and instantly updated, can create one for self and one for friends | Will only show the most recent 50 movies/shows, currently broken | Yes | X | Only for self, refreshes every 6 hours | | Plex Watchlist Metadata | Can fetch the full watchlist for the user | Need a plex token for each user who wants to have their watchlist synced, Plex token expires after a few months | Yes | Yes, up to ~20 min intervals | X | -| Plex Watchlist GraphQL Call | Can fetch the full watchlist for every friend of the main user | Slow, relies on main user providing a plex token | Yes | X | X | -| Plex Watchlist Metadata for other users | Can fetch the full watchlist for every user who provides a token | Difficult to ask every user to generate a Plex token, or log into a service | Yes | Yes, up to ~20 min intervals | X | +| Plex Watchlist GraphQL Call | Can fetch the full watchlist for every friend of the main user | Slow, relies on main user providing a plex token | Yes | X | X | +| Plex Watchlist Metadata for other users | Can fetch the full watchlist for every user who provides a token | Difficult to ask every user to generate a Plex token, or log into a service | Yes | Yes, up to ~20 min intervals | X | In order to fully integrate with Plex Watchlists, Watchlistarr uses a combination of multiple methods to ensure that it does a comprehensive, yet fast real-time sync. From 916a5d253f9af06a8be58486d72e1d03f6db4695 Mon Sep 17 00:00:00 2001 From: Nihal Mirpuri Date: Mon, 24 Jun 2024 20:14:55 +0100 Subject: [PATCH 3/3] scalafmt --- src/main/scala/Server.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/Server.scala b/src/main/scala/Server.scala index a84cc5d..56938c7 100644 --- a/src/main/scala/Server.scala +++ b/src/main/scala/Server.scala @@ -55,9 +55,9 @@ object Server extends IOApp { } yield () private def plexFullSync( - configRef: Ref[IO, Configuration], - httpClient: HttpClient - ): IO[Unit] = + configRef: Ref[IO, Configuration], + httpClient: HttpClient + ): IO[Unit] = for { config <- fetchLatestConfig(configRef) _ <- PlexTokenSync.run(config, httpClient, runFullSync = true)