Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ dependencies {
implementation("io.ktor:ktor-server-status-pages-jvm")
implementation("io.ktor:ktor-server-call-logging-jvm")
implementation("io.ktor:ktor-server-rate-limit-jvm")
implementation("ch.qos.logback:logback-classic:1.5.32")
implementation("ch.qos.logback:logback-classic:1.5.34")
implementation("com.github.InfinityLoop1308.PipePipeExtractor:extractor:871ea2df92cb81d6bc59967531523b041a9bf462")
implementation("com.squareup.okhttp3:okhttp:5.3.2")
implementation("io.lettuce:lettuce-core:7.5.2.RELEASE")
implementation("io.lettuce:lettuce-core:7.6.0.RELEASE")
implementation("org.jetbrains.exposed:exposed-core:1.3.0")
implementation("org.jetbrains.exposed:exposed-jdbc:1.3.0")
implementation("com.zaxxer:HikariCP:7.0.2")
implementation("org.postgresql:postgresql:42.7.11")
implementation("org.xerial:sqlite-jdbc:3.53.1.0")
implementation("org.xerial:sqlite-jdbc:3.53.2.0")
implementation("com.password4j:password4j:1.8.4")
implementation("com.auth0:java-jwt:4.5.2")
testImplementation("org.junit.jupiter:junit-jupiter:6.1.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("io.mockk:mockk:1.14.9")
testImplementation("io.mockk:mockk:1.14.11")
testImplementation("io.ktor:ktor-server-test-host-jvm")
testImplementation("io.ktor:ktor-server-content-negotiation-jvm")
testImplementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
Expand Down
2 changes: 1 addition & 1 deletion gradle/openapi-validation.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.gradle.api.GradleException
val openApiValidator by configurations.creating

dependencies {
openApiValidator("io.swagger.parser.v3:swagger-parser-v3:2.1.42")
openApiValidator("io.swagger.parser.v3:swagger-parser-v3:2.1.43")
openApiValidator("org.slf4j:slf4j-nop:2.0.17")
}

Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/dev/typetype/server/db/DatabaseFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ object DatabaseFactory {
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS default_subtitle_language TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS default_audio_language TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS prefer_original_language BOOLEAN NOT NULL DEFAULT false")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS enable_high_quality_playback BOOLEAN NOT NULL DEFAULT false")
exec("ALTER TABLE settings ADD COLUMN IF NOT EXISTS subscription_sync_interval INTEGER NOT NULL DEFAULT 0")
exec("ALTER TABLE history ADD COLUMN IF NOT EXISTS channel_avatar TEXT NOT NULL DEFAULT ''")
exec("ALTER TABLE history ADD COLUMN IF NOT EXISTS user_id TEXT NOT NULL DEFAULT ''")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ object SettingsTable : Table("settings") {
val defaultSubtitleLanguage = text("default_subtitle_language").default("")
val defaultAudioLanguage = text("default_audio_language").default("")
val preferOriginalLanguage = bool("prefer_original_language").default(false)
val enableHighQualityPlayback = bool("enable_high_quality_playback").default(false)
override val primaryKey = PrimaryKey(userId)
}
1 change: 1 addition & 0 deletions src/main/kotlin/dev/typetype/server/models/SettingsItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ data class SettingsItem(
val defaultSubtitleLanguage: String = "",
val defaultAudioLanguage: String = "",
val preferOriginalLanguage: Boolean = false,
val enableHighQualityPlayback: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SettingsService {
defaultSubtitleLanguage = it[SettingsTable.defaultSubtitleLanguage],
defaultAudioLanguage = it[SettingsTable.defaultAudioLanguage],
preferOriginalLanguage = it[SettingsTable.preferOriginalLanguage],
enableHighQualityPlayback = it[SettingsTable.enableHighQualityPlayback],
)
} ?: SettingsItem()
}
Expand All @@ -38,6 +39,7 @@ class SettingsService {
it[defaultSubtitleLanguage] = settings.defaultSubtitleLanguage
it[defaultAudioLanguage] = settings.defaultAudioLanguage
it[preferOriginalLanguage] = settings.preferOriginalLanguage
it[enableHighQualityPlayback] = settings.enableHighQualityPlayback
}
if (updated == 0) {
SettingsTable.insert {
Expand All @@ -51,6 +53,7 @@ class SettingsService {
it[defaultSubtitleLanguage] = settings.defaultSubtitleLanguage
it[defaultAudioLanguage] = settings.defaultAudioLanguage
it[preferOriginalLanguage] = settings.preferOriginalLanguage
it[enableHighQualityPlayback] = settings.enableHighQualityPlayback
}
}
}
Expand Down
27 changes: 9 additions & 18 deletions src/test/kotlin/dev/typetype/server/SettingsRoutesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,27 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class SettingsRoutesTest {

private val service = SettingsService()
private val auth = AuthService.fixed(TEST_USER_ID)

companion object {
@BeforeAll
@JvmStatic
fun initDb() { TestDatabase.setup() }
}

@BeforeEach
fun clean() { TestDatabase.truncateAll() }

private fun withApp(block: suspend ApplicationTestBuilder.() -> Unit) = testApplication {
application {
install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true; encodeDefaults = true }) }
routing { settingsRoutes(service, auth) }
}
block()
}

private val settingsBody = """{"defaultService":0,"defaultQuality":"1080p","autoplay":true,"volume":1.0,"muted":false}"""
private fun assertContainsAll(body: String, values: List<String>) =
values.forEach { assertTrue(body.contains(it)) }
private fun assertContainsNone(body: String, values: List<String>) =
values.forEach { assertTrue(!body.contains(it)) }

@Test
fun `GET settings without token returns 401`() = withApp {
Expand Down Expand Up @@ -91,28 +90,20 @@ class SettingsRoutesTest {
@Test
fun `GET settings returns defaults for new fields when no row exists`() = withApp {
val body = client.get("/settings") { headers.append(HttpHeaders.Authorization, "Bearer test-jwt") }.bodyAsText()
assertTrue(body.contains("\"subtitlesEnabled\":false"))
assertTrue(body.contains("\"defaultSubtitleLanguage\":\"\""))
assertTrue(body.contains("\"defaultAudioLanguage\":\"\""))
assertTrue(body.contains("\"preferOriginalLanguage\":false"))
assertTrue(!body.contains("recommendationPersonalizationEnabled"))
assertTrue(!body.contains("subscriptionSyncInterval"))
assertContainsAll(body, listOf("\"subtitlesEnabled\":false", "\"defaultSubtitleLanguage\":\"\"", "\"defaultAudioLanguage\":\"\"", "\"preferOriginalLanguage\":false", "\"enableHighQualityPlayback\":false"))
assertContainsNone(body, listOf("recommendationPersonalizationEnabled", "subscriptionSyncInterval"))
}

@Test
fun `PUT settings persists new fields and GET returns them`() = withApp {
client.put("/settings") {
headers.append(HttpHeaders.Authorization, "Bearer test-jwt")
headers.append(HttpHeaders.ContentType, ContentType.Application.Json.toString())
setBody("""{"defaultService":0,"defaultQuality":"1080p","autoplay":true,"volume":1.0,"muted":false,"subtitlesEnabled":true,"defaultSubtitleLanguage":"fr","defaultAudioLanguage":"fr","preferOriginalLanguage":true,"subscriptionSyncInterval":60}""")
setBody("""{"defaultService":0,"defaultQuality":"1080p","autoplay":true,"volume":1.0,"muted":false,"subtitlesEnabled":true,"defaultSubtitleLanguage":"fr","defaultAudioLanguage":"fr","preferOriginalLanguage":true,"enableHighQualityPlayback":true,"subscriptionSyncInterval":60}""")
}
val body = client.get("/settings") { headers.append(HttpHeaders.Authorization, "Bearer test-jwt") }.bodyAsText()
assertTrue(body.contains("\"subtitlesEnabled\":true"))
assertTrue(body.contains("\"defaultSubtitleLanguage\":\"fr\""))
assertTrue(body.contains("\"defaultAudioLanguage\":\"fr\""))
assertTrue(body.contains("\"preferOriginalLanguage\":true"))
assertTrue(!body.contains("recommendationPersonalizationEnabled"))
assertTrue(!body.contains("subscriptionSyncInterval"))
assertContainsAll(body, listOf("\"subtitlesEnabled\":true", "\"defaultSubtitleLanguage\":\"fr\"", "\"defaultAudioLanguage\":\"fr\"", "\"preferOriginalLanguage\":true", "\"enableHighQualityPlayback\":true"))
assertContainsNone(body, listOf("recommendationPersonalizationEnabled", "subscriptionSyncInterval"))
}

@Test
Expand Down