Skip to content

Commit

Permalink
volumes
Browse files Browse the repository at this point in the history
  • Loading branch information
nylonee committed Feb 16, 2024
1 parent 8394741 commit 4d3c205
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ target/

### Environment file for local variables
.env
config/

*.txt

Expand Down
2 changes: 2 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ val scalamockVersion = "5.2.0"
val scalatestVersion = "3.2.17"
val shapelessVersion = "2.3.10"
val slf4jVersion = "2.0.9"
val snakeYamlVersion = "2.0"
val vaultVersion = "3.5.0"

libraryDependencies ++= Seq(
Expand All @@ -40,6 +41,7 @@ libraryDependencies ++= Seq(
"org.typelevel" %% "vault" % vaultVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-generic-extras" % circeGenericExtrasVersion,
"org.yaml" % "snakeyaml" % snakeYamlVersion,
"io.circe" %% "circe-parser" % circeVersion % Test,
"org.scalamock" %% "scalamock" % scalamockVersion % Test,
"org.scalatest" %% "scalatest" % scalatestVersion % Test
Expand Down
6 changes: 2 additions & 4 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ FROM hseeberger/scala-sbt:eclipse-temurin-11.0.14.1_1.6.2_2.13.8 as build

WORKDIR /app

COPY / /
RUN sbt update
COPY . .

COPY .. .
RUN sbt compile stage
RUN sbt update compile stage

FROM openjdk:11-jre-slim

Expand Down
40 changes: 40 additions & 0 deletions src/main/resources/config-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## Watchlistarr Configuration
## If you want to specify your own configuration, copy this file, and rename it to 'config.yaml'

## How often do you want Watchlistarr to pull the latest from Plex?
## In general, 10 seconds is okay.
## If you're running this on a slower system (e.g. Raspberry Pi), you may want to increase this to 60 seconds.
interval:
seconds: 60

## Sonarr Configuration
sonarr:
#baseUrl: "127.0.0.1:8989"
#apikey: "YOUR-API-KEY"
#qualityProfile: "Your Desired Sonarr Quality Profile"
#rootFolder: "/root/folder/location"
bypassIgnored: false
seasonMonitoring: all # Possible values under 'MonitorTypes' in sonarr.tv/docs/api
tags:
- watchlistarr

## Radarr Configuration
radarr:
#baseUrl: "127.0.0.1:7878"
#apikey: "YOUR-API-KEY"
#qualityProfile: "Your Desired Radarr Quality Profile"
#rootFolder: "/root/folder/location"
bypassIgnored: false
tags:
- watchlistarr

## Plex Configuration
plex:
#token: "YOUR-PLEX-TOKEN"
skipfriendsync: false # Don't sync friends watchlists, only your own

delete:
movie: false
endedShow: false
continuingShow: false
interval.days: 7
34 changes: 19 additions & 15 deletions src/main/scala/Server.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import cats.effect._
import cats.implicits.catsSyntaxTuple3Parallel
import configuration.{Configuration, ConfigurationUtils, SystemPropertyReader}
import configuration.{Configuration, ConfigurationUtils, FileAndSystemPropertyReader, SystemPropertyReader}
import http.HttpClient
import org.slf4j.LoggerFactory

Expand All @@ -18,40 +18,44 @@ object Server extends IOApp {
}

def run(args: List[String]): IO[ExitCode] = {
val configReader = SystemPropertyReader
val configReader = FileAndSystemPropertyReader
val httpClient = new HttpClient

for {
memoizedConfigIo <- ConfigurationUtils.create(configReader, httpClient).memoize
initialConfig <- ConfigurationUtils.create(configReader, httpClient)
configRef <- Ref.of[IO, Configuration](initialConfig)
result <- (
pingTokenSync(memoizedConfigIo, httpClient),
plexTokenSync(memoizedConfigIo, httpClient),
plexTokenDeleteSync(memoizedConfigIo, httpClient)
pingTokenSync(configRef, httpClient),
plexTokenSync(configRef, httpClient),
plexTokenDeleteSync(configRef, httpClient)
).parTupled.as(ExitCode.Success)
} yield result
}

private def pingTokenSync(configIO: IO[Configuration], httpClient: HttpClient): IO[Unit] =
private def fetchLatestConfig(configRef: Ref[IO, Configuration]): IO[Configuration] =
configRef.get

private def pingTokenSync(configRef: Ref[IO, Configuration], httpClient: HttpClient): IO[Unit] =
for {
config <- configIO
config <- fetchLatestConfig(configRef)
_ <- PingTokenSync.run(config, httpClient)
_ <- IO.sleep(24.hours)
_ <- pingTokenSync(configIO, httpClient)
_ <- pingTokenSync(configRef, httpClient)
} yield ()

private def plexTokenSync(configIO: IO[Configuration], httpClient: HttpClient, firstRun: Boolean = true): IO[Unit] =
private def plexTokenSync(configRef: Ref[IO, Configuration], httpClient: HttpClient, firstRun: Boolean = true): IO[Unit] =
for {
config <- configIO
config <- fetchLatestConfig(configRef)
_ <- PlexTokenSync.run(config, httpClient, firstRun)
_ <- IO.sleep(config.refreshInterval)
_ <- plexTokenSync(configIO, httpClient, firstRun = false)
_ <- plexTokenSync(configRef, httpClient, firstRun = false)
} yield ()

private def plexTokenDeleteSync(configIO: IO[Configuration], httpClient: HttpClient): IO[Unit] =
private def plexTokenDeleteSync(configRef: Ref[IO, Configuration], httpClient: HttpClient): IO[Unit] =
for {
config <- configIO
config <- fetchLatestConfig(configRef)
_ <- PlexTokenDeleteSync.run(config, httpClient)
_ <- IO.sleep(config.deleteConfiguration.deleteInterval)
_ <- plexTokenDeleteSync(configIO, httpClient)
_ <- plexTokenDeleteSync(configRef, httpClient)
} yield ()
}
83 changes: 83 additions & 0 deletions src/main/scala/configuration/FileAndSystemPropertyReader.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package configuration

import org.slf4j.LoggerFactory
import org.yaml.snakeyaml.Yaml

import java.io.{File, FileInputStream}
import java.nio.file.{Files, Paths, StandardCopyOption}
import java.util
import scala.jdk.CollectionConverters.{ListHasAsScala, MapHasAsScala}

object FileAndSystemPropertyReader extends ConfigurationReader {

private val logger = LoggerFactory.getLogger(getClass)

private lazy val data: Map[String, String] = {
val yaml = new Yaml()
val configDirPath = "config"
val configFile = new File(s"$configDirPath/config.yaml")

try {
// Ensure parent config folder exists
val parentDir = configFile.getParentFile
if (!parentDir.exists()) parentDir.mkdirs()

if (!configFile.exists()) {
val resourceStream = getClass.getClassLoader.getResourceAsStream("config-template.yaml")
if (resourceStream != null) {
try {
Files.copy(resourceStream, Paths.get(configFile.toURI), StandardCopyOption.REPLACE_EXISTING)
logger.info(s"Created config file in ${configFile.getPath}")
} finally {
resourceStream.close()
}
} else {
logger.debug("config-template.yaml resource not found")
}
}

if (configFile.exists()) {
val inputStream = new FileInputStream(configFile)
val result = yaml.load[util.Map[String, Object]](inputStream).asScala
inputStream.close()
flattenYaml(Map.from(result))
} else {
Map.empty[String, String]
}
} catch {
case e: Exception =>
logger.debug(s"Failed to read from config.yaml: ${e.getMessage}")
Map.empty[String, String]
}
}

override def getConfigOption(key: String): Option[String] =
if (data.contains(key))
data.get(key)
else
SystemPropertyReader.getConfigOption(key)

private def flattenYaml(yaml: Map[String, _]): Map[String, String] = yaml.flatMap {
case (k, v: util.ArrayList[_]) =>
List((k, v.asScala.mkString(",")))

case (k, v: String) =>
List((k, v))

case (k, v: Integer) =>
List((k, v.toString))

case (k, v: java.lang.Boolean) =>
List((k, v.toString))

case (k, v: util.LinkedHashMap[String, _]) =>
val flattenedInner = flattenYaml(Map.from(v.asScala))
flattenedInner.map { case (innerK, innerV) =>
(s"$k.$innerK", innerV)
}.toList

case (k, v) =>
logger.warn(s"Unhandled config pair of type: ${k.getClass} -> ${v.getClass}")
List((k, v.toString))
}
}
2 changes: 1 addition & 1 deletion src/main/scala/configuration/SystemPropertyReader.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package configuration

object SystemPropertyReader extends ConfigurationReader {
def getConfigOption(key: String): Option[String] = Option(System.getProperty(key))
override def getConfigOption(key: String): Option[String] = Option(System.getProperty(key))
}

0 comments on commit 4d3c205

Please sign in to comment.