Skip to content

Commit

Permalink
Update monitoring of files to scheduled job.
Browse files Browse the repository at this point in the history
The EAC3 and AC3 files will be automatically converted
  • Loading branch information
jsixface committed Jul 30, 2024
1 parent 64b88c3 commit 820bf0c
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 142 deletions.
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ ij_java_use_single_class_imports = true

[*.yml]
indent_size = 2

[{*.kt,*.kts}]
ij_kotlin_name_count_to_use_star_import = 99
ij_kotlin_name_count_to_use_star_import_for_members = 99
ij_kotlin_packages_to_use_import_on_demand = unset
23 changes: 18 additions & 5 deletions composeApp/src/commonMain/kotlin/ui/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.sharp.Delete
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Divider
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedCard
Expand All @@ -37,11 +37,16 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.github.jsixface.common.Settings
import kotlinx.coroutines.launch
import org.koin.compose.koinInject
import ui.model.Screen
import ui.model.ModelState
import ui.model.Screen
import ui.utils.ComboBox
import viewmodels.SettingsScreenModel
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes

object SettingsScreen : Screen {

Expand Down Expand Up @@ -73,6 +78,7 @@ object SettingsScreen : Screen {
var workspace by remember { mutableStateOf("") }
val extensions = remember { mutableStateListOf<String>() }
val locations = remember { mutableStateListOf<String>() }
var refreshDuration by remember { mutableStateOf<Duration?>(null) }

LaunchedEffect(Unit) {
scope.launch {
Expand All @@ -99,6 +105,7 @@ object SettingsScreen : Screen {
}
extensions.addAll(extsToAdd)
workspace = settings.workspaceLocation
refreshDuration = settings.watchDuration
}
}
}
Expand All @@ -119,19 +126,25 @@ object SettingsScreen : Screen {
}
Column {
ListEditor("Locations", locations, { locations.remove(it) }, { locations.add(it) })
Divider()
HorizontalDivider()
ListEditor("Extensions", extensions, { extensions.remove(it) }, { extensions.add(it) })
Divider()
HorizontalDivider()
OutlinedTextField(value = workspace,
onValueChange = { workspace = it },
modifier = padding,
label = { Text("Workspace Location") })
ComboBox(
title = "Media Scan Duration",
options = listOf(1.minutes, 5.minutes, 15.minutes, 30.minutes, 1.hours),
selected = refreshDuration
) { refreshDuration = it }

}
Row(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.weight(1f))
ElevatedButton(onClick = {
scope.launch {
settingsModel.save(locations.toList(), extensions.toList(), workspace)
settingsModel.save(Settings(locations, workspace, extensions, refreshDuration))
}
}, modifier = padding) {
Text("Save")
Expand Down
87 changes: 29 additions & 58 deletions composeApp/src/commonMain/kotlin/ui/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,32 @@ package ui.home
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Expand All @@ -23,13 +38,14 @@ import kotlinx.coroutines.launch
import org.koin.compose.koinInject
import ui.model.ModelState
import ui.model.Screen
import ui.utils.ComboBox
import viewmodels.VideoListViewModel


object HomeScreen : Screen {

private var filteredAudioCodec by mutableStateOf("")
private var filteredVideoCodec by mutableStateOf("")
private var filteredAudioCodec by mutableStateOf<String?>(null)
private var filteredVideoCodec by mutableStateOf<String?>(null)
private var filteredName by mutableStateOf("")
private var selectedVideo by mutableStateOf<VideoFile?>(null)
private var showFileDetails by mutableStateOf(false)
Expand Down Expand Up @@ -128,8 +144,8 @@ object HomeScreen : Screen {
val filteredVideos =
list.filter {
it.fileName.contains(filteredName, ignoreCase = true)
&& it.videos.any { v -> if (filteredVideoCodec != "") v.codec == filteredVideoCodec else true }
&& it.audios.any { a -> if (filteredAudioCodec != "") a.codec == filteredAudioCodec else true }
&& it.videos.any { v -> filteredVideoCodec?.let { fv -> v.codec == fv } ?: true }
&& it.audios.any { a -> filteredAudioCodec?.let { fa -> a.codec == fa } ?: true }
}
Column {
Row(modifier = bottomPad.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Expand All @@ -139,18 +155,18 @@ object HomeScreen : Screen {
label = { Text("File name") },
leadingIcon = { Icon(Icons.Rounded.Search, contentDescription = "Search") })
val videoOptions = list.asSequence().flatMap { it.videos }.map { it.codec }.toSet().toList().sorted()
FilterOptions("Video Codecs", videoOptions, filteredVideoCodec) { filteredVideoCodec = it }
ComboBox("Video Codecs", videoOptions, filteredVideoCodec) { filteredVideoCodec = it }
val audioOptions = list.asSequence().flatMap { it.audios }.map { it.codec }.toSet().toList().sorted()
FilterOptions("Audio Codecs", audioOptions, filteredAudioCodec) { filteredAudioCodec = it }
ComboBox("Audio Codecs", audioOptions, filteredAudioCodec) { filteredAudioCodec = it }
IconButton(modifier = sidePad, onClick = onRefresh) {
Icon(Icons.Rounded.Refresh, contentDescription = "Refresh")
}
// Clear filters
if (filteredName.isNotEmpty() || filteredAudioCodec.isNotEmpty() || filteredVideoCodec.isNotEmpty()) {
if (filteredName.isNotEmpty() || filteredAudioCodec != null || filteredVideoCodec != null) {
IconButton(onClick = {
filteredName = ""
filteredAudioCodec = ""
filteredVideoCodec = ""
filteredAudioCodec = null
filteredVideoCodec = null
}) {
Icon(Icons.Rounded.Close, contentDescription = "Clear filters")
}
Expand Down Expand Up @@ -185,51 +201,6 @@ object HomeScreen : Screen {
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun FilterOptions(
title: String,
options: List<String>,
selected: String,
onSelect: (String) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(expanded, onExpandedChange = { expanded = it }, modifier = sidePad) {
TextField(
modifier = sidePad.menuAnchor(),
value = selected,
onValueChange = { },
readOnly = true,
label = { Text(title) },
colors = ExposedDropdownMenuDefaults.textFieldColors(),
trailingIcon = { Icon(Icons.Rounded.ArrowDropDown, contentDescription = "Select") },
)

if (options.isNotEmpty()) {
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(
text = { Text("None") },
onClick = {
onSelect("")
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
options.forEach { codec ->
DropdownMenuItem(
text = { Text(codec) },
onClick = {
onSelect(codec)
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}

@Composable
private fun VideoRow(file: VideoFile, onClick: (VideoFile) -> Unit) {
Column {
Expand Down
69 changes: 69 additions & 0 deletions composeApp/src/commonMain/kotlin/ui/utils/ComboBox.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ui.utils

import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun <T> ComboBox(
title: String,
options: List<T>,
selected: T?,
optionName: T.() -> String = { toString() },
onSelect: (T?) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
ExposedDropdownMenuBox(
expanded,
onExpandedChange = { expanded = it },
modifier = Modifier.padding(8.dp, 0.dp, 0.dp, 0.dp)
) {
OutlinedTextField(
modifier = Modifier.menuAnchor(),
value = selected?.optionName() ?: "",
onValueChange = { },
readOnly = true,
label = { Text(title) },
trailingIcon = { Icon(Icons.Rounded.ArrowDropDown, contentDescription = "Select") },
)

if (options.isNotEmpty()) {
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
DropdownMenuItem(
text = { Text("None") },
onClick = {
onSelect(null)
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
options.forEach { option ->
DropdownMenuItem(
text = { Text(option.optionName()) },
onClick = {
onSelect(option)
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
}
}
15 changes: 4 additions & 11 deletions composeApp/src/commonMain/kotlin/viewmodels/SettingsScreenModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import io.ktor.http.contentType
import io.ktor.http.isSuccess
import kotlinx.coroutines.flow.flow
import ui.model.ModelState
import util.log
import ui.model.ModelState.Error
import ui.model.ModelState.Init
import ui.model.ModelState.Success
import util.log

class SettingsScreenModel(private val client: HttpClient) {

Expand All @@ -33,15 +33,8 @@ class SettingsScreenModel(private val client: HttpClient) {
}
}

suspend fun save(locations: List<String>, extension: List<String>, workLocation: String) {
val settings = Settings(
libraryLocations = locations,
workspaceLocation = workLocation,
videoExtensions = extension
)
client.post(Api.Settings) {
contentType(ContentType.Application.Cbor)
setBody(settings)
}
suspend fun save(settings: Settings) = client.post(Api.Settings) {
contentType(ContentType.Application.Cbor)
setBody(settings)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.github.jsixface.codexvert
import io.github.jsixface.codexvert.plugins.configureHTTP
import io.github.jsixface.codexvert.plugins.configureKoin
import io.github.jsixface.codexvert.plugins.configureRouting
import io.github.jsixface.codexvert.plugins.configureWatchers
import io.ktor.server.application.Application
import io.ktor.server.netty.EngineMain
import org.slf4j.Logger
Expand All @@ -15,7 +14,6 @@ fun Application.module() {
configureKoin()
configureRouting()
configureHTTP()
configureWatchers()
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ import io.github.jsixface.common.Conversion
import io.github.jsixface.common.MediaTrack
import io.github.jsixface.common.VideoFile
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock.System
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
Expand All @@ -15,17 +22,17 @@ import java.io.File
import java.io.InputStream
import java.io.UncheckedIOException
import java.nio.file.Files
import java.util.*
import java.util.UUID
import kotlin.io.path.Path
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

class ConversionApi(settingsApi: SettingsApi) {
class ConversionApi {
private val logger = logger()
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val jobs = mutableListOf<ConvertingJob>()
private val workspace = File(settingsApi.getSettings().workspaceLocation)
private val workspace = File(SavedData.load().settings.workspaceLocation)

init {
if (workspace.isDirectory.not()) {
Expand Down
Loading

0 comments on commit 820bf0c

Please sign in to comment.