diff --git a/src/main/resources/config-template.yaml b/src/main/resources/config-template.yaml index 7224b23..4236230 100644 --- a/src/main/resources/config-template.yaml +++ b/src/main/resources/config-template.yaml @@ -2,10 +2,10 @@ ## Uncomment the lines you would like to configure, then save this file and restart Watchlistarr #interval: -## How often do you want Watchlistarr to pull the latest from Plex? In general, 10-30 seconds is okay. +## How often do you want Watchlistarr to pull the latest from Plex? In general, 60-300 seconds is okay. ## If you're running this on a slower system (e.g. Raspberry Pi), you may want to increase this ## Note: If you do not have Plex Pass, this will be overridden to ~19 minute syncs, see README -# seconds: 10 +# seconds: 120 ################################################################# diff --git a/src/main/scala/Server.scala b/src/main/scala/Server.scala index 56938c7..b381a8f 100644 --- a/src/main/scala/Server.scala +++ b/src/main/scala/Server.scala @@ -1,4 +1,5 @@ import cats.effect._ +import cats.effect.std.Random import cats.implicits.catsSyntaxTuple4Parallel import configuration.{Configuration, ConfigurationUtils, FileAndSystemPropertyReader} import http.HttpClient @@ -48,10 +49,12 @@ object Server extends IOApp { httpClient: HttpClient ): IO[Unit] = for { - config <- fetchLatestConfig(configRef) - _ <- PlexTokenSync.run(config, httpClient, runFullSync = false) - _ <- IO.sleep(config.refreshInterval) - _ <- plexRssSync(configRef, httpClient) + config <- fetchLatestConfig(configRef) + _ <- PlexTokenSync.run(config, httpClient, runFullSync = false) + // We should be considerate with the Plex servers + randomMillis <- Random.scalaUtilRandom[IO].flatMap(_.nextLongBounded(3 * config.refreshInterval.toMillis)) + _ <- IO.sleep(config.refreshInterval + randomMillis.millis) + _ <- plexRssSync(configRef, httpClient) } yield () private def plexFullSync( diff --git a/src/main/scala/configuration/ConfigurationUtils.scala b/src/main/scala/configuration/ConfigurationUtils.scala index dfff352..0a7fd3a 100644 --- a/src/main/scala/configuration/ConfigurationUtils.scala +++ b/src/main/scala/configuration/ConfigurationUtils.scala @@ -28,7 +28,7 @@ object ConfigurationUtils { def create(configReader: ConfigurationReader, client: HttpClient): IO[Configuration] = { val config = for { sonarrConfig <- getSonarrConfig(configReader, client) - refreshInterval = configReader.getConfigOption(Keys.intervalSeconds).flatMap(_.toIntOption).getOrElse(60).seconds + refreshInterval = configReader.getConfigOption(Keys.intervalSeconds).flatMap(_.toIntOption).getOrElse(120).seconds (sonarrBaseUrl, sonarrApiKey, sonarrQualityProfileId, sonarrRootFolder, sonarrLanguageProfileId, sonarrTagIds) = sonarrConfig sonarrBypassIgnored = configReader.getConfigOption(Keys.sonarrBypassIgnored).exists(_.toBoolean) diff --git a/src/main/scala/plex/PlexUtils.scala b/src/main/scala/plex/PlexUtils.scala index dc25458..81be953 100644 --- a/src/main/scala/plex/PlexUtils.scala +++ b/src/main/scala/plex/PlexUtils.scala @@ -2,6 +2,7 @@ package plex import cats.data.EitherT import cats.effect.IO +import cats.effect.implicits.parSequenceN import cats.implicits.toTraverseOps import configuration.PlexConfiguration import http.HttpClient @@ -14,6 +15,8 @@ import io.circe.syntax.EncoderOps import org.http4s.client.UnexpectedStatus import java.util.UUID +import scala.concurrent.duration.DurationInt +import scala.util.Random trait PlexUtils { @@ -23,10 +26,8 @@ trait PlexUtils { extras.Configuration.default.withDefaults protected def fetchWatchlistFromRss(client: HttpClient)(url: Uri): IO[Set[Item]] = { - val randomUUID = UUID.randomUUID().toString.take(12) val jsonFormatUrl = url .withQueryParam("format", "json") - .withQueryParam("cache_buster", randomUUID) client.httpRequest(Method.GET, jsonFormatUrl).map { case Left(UnexpectedStatus(s, _, _)) if s.code == 500 => @@ -69,7 +70,7 @@ trait PlexUtils { containerStart: Int = 0 ): EitherT[IO, Throwable, Set[Item]] = config.plexTokens .map { token => - val containerSize = 300 + val containerSize = 100 val url = Uri .unsafeFromString("https://discover.provider.plex.tv/library/sections/watchlist/all") .withQueryParam("X-Plex-Token", token) @@ -82,7 +83,12 @@ trait PlexUtils { result <- EitherT.liftF(toItems(config, client)(tokenWatchlist)) nextPage <- if (tokenWatchlist.MediaContainer.totalSize > containerStart + containerSize) - getSelfWatchlist(config, client, containerStart + containerSize) + for { + // We should be considerate with the Plex servers + randomSeconds <- EitherT.liftF(IO(Random.nextInt(11))) + _ <- EitherT.liftF(IO.sleep(3.seconds + randomSeconds.seconds)) + next <- getSelfWatchlist(config, client, containerStart + containerSize) + } yield next else EitherT.pure[IO, Throwable](Set.empty[Item]) } yield result ++ nextPage @@ -178,7 +184,12 @@ trait PlexUtils { if ( watchlist.data.user.watchlist.pageInfo.hasNextPage && watchlist.data.user.watchlist.pageInfo.endCursor.nonEmpty ) - getWatchlistIdsForUser(config, client, token)(user, watchlist.data.user.watchlist.pageInfo.endCursor) + for { + // We should be considerate with the Plex servers + randomSeconds <- EitherT.liftF(IO(Random.nextInt(11))) + _ <- EitherT.liftF(IO.sleep(3.seconds + randomSeconds.seconds)) + next <- getWatchlistIdsForUser(config, client, token)(user, watchlist.data.user.watchlist.pageInfo.endCursor) + } yield next else EitherT.pure[IO, Throwable](Set.empty[TokenWatchlistItem]) } yield watchlist.data.user.watchlist.nodes.map(_.toTokenWatchlistItem).toSet ++ extraContent