Skip to content

Commit

Permalink
[Radarr/Sonarr] Implement NoOp classes to disable these services via …
Browse files Browse the repository at this point in the history
…config
  • Loading branch information
Schaka committed Mar 7, 2024
1 parent 89cf016 commit c88cc09
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 56 deletions.
9 changes: 7 additions & 2 deletions src/main/kotlin/com/github/schaka/janitorr/CleanupSchedule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import com.github.schaka.janitorr.mediaserver.jellyfin.library.LibraryType.TV_SH
import com.github.schaka.janitorr.jellyseerr.JellyseerrService
import com.github.schaka.janitorr.mediaserver.MediaServerService
import com.github.schaka.janitorr.servarr.LibraryItem
import com.github.schaka.janitorr.servarr.ServarrService
import com.github.schaka.janitorr.servarr.radarr.Radarr
import com.github.schaka.janitorr.servarr.radarr.RadarrService
import com.github.schaka.janitorr.servarr.sonarr.Sonarr
import com.github.schaka.janitorr.servarr.sonarr.SonarrService
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service
Expand All @@ -16,8 +19,10 @@ class CleanupSchedule(
val mediaServerService: MediaServerService,
val jellyseerrService: JellyseerrService,
val applicationProperties: ApplicationProperties,
val sonarrService: SonarrService,
val radarrService: RadarrService,
@Sonarr
val sonarrService: ServarrService,
@Radarr
val radarrService: ServarrService,
) {

// run every hour
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.github.schaka.janitorr.mediaserver.jellyfin
import com.github.schaka.janitorr.ApplicationProperties
import com.github.schaka.janitorr.FileSystemProperties
import com.github.schaka.janitorr.mediaserver.MediaServerService
import com.github.schaka.janitorr.mediaserver.jellyfin.filesystem.PathStructure
import com.github.schaka.janitorr.mediaserver.jellyfin.library.AddLibraryRequest
import com.github.schaka.janitorr.mediaserver.jellyfin.library.LibraryContent
import com.github.schaka.janitorr.mediaserver.jellyfin.library.LibraryType
Expand All @@ -16,17 +15,16 @@ import org.springframework.stereotype.Service
import org.springframework.util.FileSystemUtils
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.*

@Service
@ConditionalOnProperty("clients.jellyfin.enabled", havingValue = "true", matchIfMissing = false)
class JellyfinRestService(

val jellyfinClient: JellyfinClient,
val jellyfinUserClient: JellyfinUserClient,
val jellyfinProperties: JellyfinProperties,
val applicationProperties: ApplicationProperties,
val fileSystemProperties: FileSystemProperties
val jellyfinClient: JellyfinClient,
val jellyfinUserClient: JellyfinUserClient,
val jellyfinProperties: JellyfinProperties,
val applicationProperties: ApplicationProperties,
val fileSystemProperties: FileSystemProperties

) : MediaServerService() {

Expand All @@ -47,14 +45,14 @@ class JellyfinRestService(

for (show: LibraryItem in items) {
jellyfinShows.firstOrNull { tvShowMatches(show, it) }
?.let { jellyfinContent ->
if (!applicationProperties.dryRun) {
jellyfinUserClient.deleteItemAndFiles(jellyfinContent.Id)
log.info("Deleting {} {} from Jellyfin", jellyfinContent.SeriesName, jellyfinContent.Name)
} else {
log.info("Found {} {} on Jellyfin", jellyfinContent.SeriesName, jellyfinContent.Name)
}
?.let { jellyfinContent ->
if (!applicationProperties.dryRun) {
jellyfinUserClient.deleteItemAndFiles(jellyfinContent.Id)
log.info("Deleting {} {} from Jellyfin", jellyfinContent.SeriesName, jellyfinContent.Name)
} else {
log.info("Found {} {} on Jellyfin", jellyfinContent.SeriesName, jellyfinContent.Name)
}
}
}

// TODO: Remove TV shows if all seasons gone
Expand All @@ -69,19 +67,22 @@ class JellyfinRestService(

for (movie: LibraryItem in items) {
jellyfinMovies.firstOrNull { mediaMatches(MOVIES, movie, it) }
?.let { jellyfinContent ->
if (!applicationProperties.dryRun) {
jellyfinUserClient.deleteItemAndFiles(jellyfinContent.Id)
log.info("Deleting {} from Jellyfin", jellyfinContent.Name)
} else {
log.info("Found {} on Jellyfin", jellyfinContent.Name)
}
?.let { jellyfinContent ->
if (!applicationProperties.dryRun) {
jellyfinUserClient.deleteItemAndFiles(jellyfinContent.Id)
log.info("Deleting {} from Jellyfin", jellyfinContent.Name)
} else {
log.info("Found {} on Jellyfin", jellyfinContent.Name)
}
}
}
}

private fun tvShowMatches(item: LibraryItem, candidate: LibraryContent, matchSeason: Boolean = true): Boolean {
val seasonMatches = candidate.Type == "Season" && candidate.Name.contains("Season") && item.season == seasonPattern.find(candidate.Name)?.groups?.get("season")?.value?.toInt()
val seasonMatches = candidate.Type == "Season"
&& candidate.Name.contains("Season")
&& item.season == seasonPattern.find(candidate.Name)?.groups?.get("season")?.value?.toInt()

return mediaMatches(TV_SHOWS, item, candidate) && if (matchSeason) seasonMatches else true
}

Expand Down Expand Up @@ -121,21 +122,14 @@ class JellyfinRestService(

// Collections are created via the Collection API, but it just puts them into a BoxSet library called collections
// They're also a lot harder (imho) to manage - so we just create a media library that consists only
var goneSoonCollection =
result.firstOrNull { it.CollectionType == collectionFilter && it.Name == "${type.collectionName} (Deleted Soon)" }
var goneSoonCollection = result.firstOrNull { it.CollectionType == collectionFilter && it.Name == "${type.collectionName} (Deleted Soon)" }
if (goneSoonCollection == null) {
Files.createDirectories(path)
val pathString = path.toUri().path
// Windows paths may have a trailing trash - Windows Jellyfin can't deal with that, this is a bit hacky but makes development easier
val pathforJellyfin = if (pathString.startsWith("/C:")) pathString.replaceFirst("/", "") else pathString
jellyfinClient.createLibrary(
"${type.collectionName} (Deleted Soon)",
type.collectionType,
AddLibraryRequest(),
listOf(pathforJellyfin)
)
goneSoonCollection = jellyfinClient.listLibraries()
.firstOrNull { it.CollectionType == collectionFilter && it.Name == "${type.collectionName} (Deleted Soon)" }
jellyfinClient.createLibrary("${type.collectionName} (Deleted Soon)", type.collectionType, AddLibraryRequest(), listOf(pathforJellyfin))
goneSoonCollection = jellyfinClient.listLibraries().firstOrNull { it.CollectionType == collectionFilter && it.Name == "${type.collectionName} (Deleted Soon)" }
}

// Clean up entire directory and rebuild from scratch - this can help with clearing orphaned data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import feign.Feign
import feign.jackson.JacksonDecoder
import feign.jackson.JacksonEncoder
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
Expand All @@ -27,25 +28,8 @@ class ServarrClientConfig {
private val log = LoggerFactory.getLogger(this::class.java.enclosingClass)
}

@Radarr
@Bean
fun radarrRestTemplate(builder: RestTemplateBuilder, properties: RadarrProperties): RestTemplate {
return builder
.rootUri("${properties.url}/api/v3")
.defaultHeader("X-Api-Key", properties.apiKey)
.build()
}

@Sonarr
@Bean
fun sonarrRestTemplate(builder: RestTemplateBuilder, properties: SonarrProperties): RestTemplate {
return builder
.rootUri("${properties.url}/api/v3")
.defaultHeader("X-Api-Key", properties.apiKey)
.build()
}

@Bean
@ConditionalOnProperty("clients.radarr.enabled", havingValue = "true", matchIfMissing = false)
fun radarrClient(properties: RadarrProperties, mapper: ObjectMapper): RadarrClient {
return Feign.builder()
.decoder(JacksonDecoder(mapper))
Expand All @@ -58,6 +42,7 @@ class ServarrClientConfig {
}

@Bean
@ConditionalOnProperty("clients.sonarr.enabled", havingValue = "true", matchIfMissing = false)
fun sonarrClient(properties: SonarrProperties, mapper: ObjectMapper): SonarrClient {
return Feign.builder()
.decoder(JacksonDecoder(mapper))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.github.schaka.janitorr.servarr

import java.time.LocalDateTime

interface ServarrService {

fun getEntries(): List<LibraryItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.schaka.janitorr.servarr.radarr

import com.github.schaka.janitorr.servarr.LibraryItem
import com.github.schaka.janitorr.servarr.ServarrService
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service

@Radarr
@Service
@ConditionalOnProperty("clients.radarr.enabled", havingValue = "false", matchIfMissing = false)
class RadarrNoOpService : ServarrService {

companion object {
private val log = LoggerFactory.getLogger(this::class.java.enclosingClass)
}

override fun getEntries(): List<LibraryItem> {
log.info("Radarr is disabled, not getting any movies")
return listOf()
}

override fun removeEntries(items: List<LibraryItem>) {
log.info("Radarr is disabled, not deleting any movies")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import com.github.schaka.janitorr.servarr.data_structures.Tag
import com.github.schaka.janitorr.servarr.sonarr.SonarrService
import jakarta.annotation.PostConstruct
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import java.nio.file.Path
import java.time.LocalDateTime
import kotlin.io.path.exists

@Radarr
@Service
@ConditionalOnProperty("clients.radarr.enabled", havingValue = "true", matchIfMissing = true)
class RadarrService(

val radarrClient: RadarrClient,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.schaka.janitorr.servarr.sonarr

import com.github.schaka.janitorr.servarr.LibraryItem
import com.github.schaka.janitorr.servarr.ServarrService
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service

@Sonarr
@Service
@ConditionalOnProperty("clients.sonarr.enabled", havingValue = "false", matchIfMissing = false)
class SonarrNoOpService : ServarrService {

companion object {
private val log = LoggerFactory.getLogger(this::class.java.enclosingClass)
}

override fun getEntries(): List<LibraryItem> {
log.info("Sonarr is disabled, not getting any shows")
return listOf()
}

override fun removeEntries(items: List<LibraryItem>) {
log.info("Sonarr is disabled, not deleting any shows")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import com.github.schaka.janitorr.servarr.radarr.RadarrService
import com.github.schaka.janitorr.servarr.sonarr.series.SeriesPayload
import jakarta.annotation.PostConstruct
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import java.nio.file.Path
import java.time.LocalDateTime
import kotlin.io.path.exists

@Sonarr
@Service
@ConditionalOnProperty("clients.sonarr.enabled", havingValue = "true", matchIfMissing = true)
class SonarrService(

val sonarrClient: SonarrClient,
Expand Down Expand Up @@ -44,8 +47,8 @@ class SonarrService(
val history = sonarrClient.getAllSeries()
.filter { !it.tags.contains(keepTag.id) }
.flatMap { series ->
series.seasons.map { season ->
sonarrClient.getHistory(series.id, season.seasonNumber)
series.seasons.map { season ->
sonarrClient.getHistory(series.id, season.seasonNumber)
.filter { it.eventType == "downloadFolderImported" && it.data.droppedPath != null }
.map {
LibraryItem(
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ application:

clients:
sonarr:
enabled: true
url: "http://localhost:8989"
api-key: "4ed7f4d0e8584d65aa2d47d944077ff6"
radarr:
enabled: true
url: "http://localhost:7878"
api-key: "cd0912f129d348c9b69bb20d49fcbe44"
## You can only choose one out of Jellyfin or Emby. Emby is not yet fully supported
Expand Down

0 comments on commit c88cc09

Please sign in to comment.