diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b186a110..7a8cea71 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -192,7 +192,8 @@ aboutLibraries { openApiGenerate { generatorName.set("kotlin") - inputSpec.set("$projectDir/src/main/seerr-api.yml") + inputSpec.set("$projectDir/src/main/seerr/seerr-api.yml") + templateDir.set("$projectDir/src/main/seerr/templates") outputDir.set("$buildDir/generated/seerr_api") apiPackage.set("com.github.damontecres.wholphin.api.seerr") modelPackage.set("com.github.damontecres.wholphin.api.seerr.model") diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt index 685cd5d0..aeaaefe9 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/DiscoverMovieViewModel.kt @@ -165,7 +165,7 @@ class DiscoverMovieViewModel seerrService.api.requestApi.requestPost( RequestPostRequest( is4k = false, - mediaid = id, + mediaId = id, mediaType = RequestPostRequest.MediaType.MOVIE, ), ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt index 5269aa00..b41188ab 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/discover/ExpandableDiscoverButtons.kt @@ -42,7 +42,7 @@ fun ExpandableDiscoverButtons( .focusRestorer(firstFocus), ) { if (availability == SeerrAvailability.UNKNOWN) { - item("request") { + item("first") { ExpandableFaButton( title = R.string.request, iconStringRes = R.string.fa_download, @@ -54,7 +54,7 @@ fun ExpandableDiscoverButtons( ) } } else if (availability == SeerrAvailability.PENDING || availability == SeerrAvailability.PROCESSING) { - item("pending") { + item("first") { ExpandableFaButton( title = R.string.pending, iconStringRes = R.string.fa_clock, @@ -75,12 +75,11 @@ fun ExpandableDiscoverButtons( resume = Duration.ZERO, modifier = Modifier - .focusRequester(firstFocus) .onFocusChanged(buttonOnFocusChanged), ) } } else if (availability == SeerrAvailability.PARTIALLY_AVAILABLE || availability == SeerrAvailability.AVAILABLE) { - item("goto") { + item("first") { ExpandablePlayButton( title = R.string.go_to, icon = Icons.Default.PlayArrow, diff --git a/app/src/main/seerr-api.yml b/app/src/main/seerr/seerr-api.yml similarity index 99% rename from app/src/main/seerr-api.yml rename to app/src/main/seerr/seerr-api.yml index 66dc53ca..6636d77c 100644 --- a/app/src/main/seerr-api.yml +++ b/app/src/main/seerr/seerr-api.yml @@ -6117,20 +6117,24 @@ paths: type: string enum: [movie, tv] example: movie - mediaid: + mediaId: type: integer example: 123 tvdbid: type: integer example: 123 seasons: - oneOf: - - type: array - items: - type: integer - minimum: 0 - - type: string - enum: [all] + # oneOf: + # - type: array + # items: + # type: integer + # minimum: 0 + # - type: string + # enum: [all] + # TODO + type: string + enum: [all] + nullable: true is4k: type: boolean example: false @@ -6140,6 +6144,7 @@ paths: type: integer rootFolder: type: string + nullable: true languageProfileid: type: integer userid: diff --git a/app/src/main/seerr/templates/jvm-common/infrastructure/Serializer.kt.mustache b/app/src/main/seerr/templates/jvm-common/infrastructure/Serializer.kt.mustache new file mode 100644 index 00000000..33cec807 --- /dev/null +++ b/app/src/main/seerr/templates/jvm-common/infrastructure/Serializer.kt.mustache @@ -0,0 +1,191 @@ +package {{packageName}}.infrastructure + +{{#moshi}} +import com.squareup.moshi.Moshi +{{#enumUnknownDefaultCase}} +import com.squareup.moshi.adapters.EnumJsonAdapter +{{/enumUnknownDefaultCase}} +{{^moshiCodeGen}} +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +{{/moshiCodeGen}} +{{/moshi}} +{{#gson}} +import com.google.gson.Gson +import com.google.gson.GsonBuilder +{{^threetenbp}} +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.OffsetDateTime +{{/threetenbp}} +{{#threetenbp}} +import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime +import org.threeten.bp.OffsetDateTime +{{/threetenbp}} +{{#kotlinx-datetime}} +import kotlin.time.Instant +import kotlinx.datetime.LocalDate +import kotlinx.datetime.LocalTime +{{/kotlinx-datetime}} +import java.util.UUID +{{/gson}} +{{#jackson}} +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +{{/jackson}} +{{#kotlinx_serialization}} +import java.math.BigDecimal +import java.math.BigInteger +{{^threetenbp}} +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.OffsetDateTime +{{/threetenbp}} +{{#threetenbp}} +import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime +import org.threeten.bp.OffsetDateTime +{{/threetenbp}} +import java.util.UUID +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonBuilder +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.SerializersModuleBuilder +import java.net.URI +import java.net.URL +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic.AtomicLong +{{/kotlinx_serialization}} + +{{#nonPublicApi}}internal {{/nonPublicApi}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}object Serializer { +{{#moshi}} + @JvmStatic + {{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}val moshiBuilder: Moshi.Builder = Moshi.Builder() + .add(OffsetDateTimeAdapter()) + {{#kotlinx-datetime}} + .add(InstantAdapter()) + .add(LocalDateAdapter()) + .add(LocalTimeAdapter()) + {{/kotlinx-datetime}} + .add(LocalDateTimeAdapter()) + .add(LocalDateAdapter()) + .add(UUIDAdapter()) + .add(ByteArrayAdapter()) + .add(URIAdapter()) + {{^moshiCodeGen}} + .add(KotlinJsonAdapterFactory()) + {{/moshiCodeGen}} + .add(BigDecimalAdapter()) + .add(BigIntegerAdapter()) + + @JvmStatic + {{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}val moshi: Moshi by lazy { +{{#enumUnknownDefaultCase}} + SerializerHelper.addEnumUnknownDefaultCase(moshiBuilder) +{{/enumUnknownDefaultCase}} + moshiBuilder.build() + } +{{/moshi}} +{{#gson}} + @JvmStatic + val gsonBuilder: GsonBuilder = GsonBuilder() + .registerTypeAdapter(OffsetDateTime::class.java, OffsetDateTimeAdapter()) + {{#kotlinx-datetime}} + .registerTypeAdapter(Instant::class.java, InstantAdapter()) + .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) + .registerTypeAdapter(LocalTime::class.java, LocalTimeAdapter()) + {{/kotlinx-datetime}} + .registerTypeAdapter(LocalDateTime::class.java, LocalDateTimeAdapter()) + .registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()) + .registerTypeAdapter(ByteArray::class.java, ByteArrayAdapter()) + {{#generateOneOfAnyOfWrappers}} + {{#models}} + {{#model}} + {{^isEnum}} + {{^hasChildren}} + .registerTypeAdapterFactory({{modelPackage}}.{{{classname}}}.CustomTypeAdapterFactory()) + {{/hasChildren}} + {{/isEnum}} + {{/model}} + {{/models}} + {{/generateOneOfAnyOfWrappers}} + + @JvmStatic + val gson: Gson by lazy { + gsonBuilder.create() + } +{{/gson}} +{{#jackson}} + @JvmStatic + val jacksonObjectMapper: ObjectMapper = jacksonObjectMapper() + .findAndRegisterModules() + .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) + {{#enumUnknownDefaultCase}} + .configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true) + {{/enumUnknownDefaultCase}} + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, {{failOnUnknownProperties}}) +{{/jackson}} +{{#kotlinx_serialization}} + private var isAdaptersInitialized = false + + @JvmStatic + val kotlinxSerializationAdapters: SerializersModule by lazy { + isAdaptersInitialized = true + SerializersModule { + contextual(BigDecimal::class, BigDecimalAdapter) + contextual(BigInteger::class, BigIntegerAdapter) + {{^kotlinx-datetime}} + contextual(LocalDate::class, LocalDateAdapter) + contextual(LocalDateTime::class, LocalDateTimeAdapter) + contextual(OffsetDateTime::class, OffsetDateTimeAdapter) + {{/kotlinx-datetime}} + contextual(UUID::class, UUIDAdapter) + contextual(AtomicInteger::class, AtomicIntegerAdapter) + contextual(AtomicLong::class, AtomicLongAdapter) + contextual(AtomicBoolean::class, AtomicBooleanAdapter) + contextual(URI::class, URIAdapter) + contextual(URL::class, URLAdapter) + contextual(StringBuilder::class, StringBuilderAdapter) + + apply(kotlinxSerializationAdaptersConfiguration) + } + } + + var kotlinxSerializationAdaptersConfiguration: SerializersModuleBuilder.() -> Unit = {} + set(value) { + check(!isAdaptersInitialized) { + "Cannot configure kotlinxSerializationAdaptersConfiguration after kotlinxSerializationAdapters has been initialized." + } + field = value + } + + private var isJsonInitialized = false + + @JvmStatic + val kotlinxSerializationJson: Json by lazy { + isJsonInitialized = true + Json { + serializersModule = kotlinxSerializationAdapters + encodeDefaults = true + ignoreUnknownKeys = true + isLenient = true + explicitNulls = false + + apply(kotlinxSerializationJsonConfiguration) + } + } + + var kotlinxSerializationJsonConfiguration: JsonBuilder.() -> Unit = {} + set(value) { + check(!isJsonInitialized) { + "Cannot configure kotlinxSerializationJsonConfiguration after kotlinxSerializationJson has been initialized." + } + field = value + } +{{/kotlinx_serialization}} +}