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. 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..56938c7 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 () }