mirror of
https://github.com/dev-claw/vripper-project.git
synced 2026-08-19 08:35:41 +02:00
@@ -1,11 +1,11 @@
|
||||
package me.mnlr.vripper.model
|
||||
|
||||
class Settings {
|
||||
var desktopClipboard: Boolean = false
|
||||
var maxEventLog: Int = 1_000
|
||||
var connectionSettings: ConnectionSettings = ConnectionSettings()
|
||||
var downloadSettings: DownloadSettings = DownloadSettings()
|
||||
var viperSettings: ViperSettings = ViperSettings()
|
||||
var connectionSettings = ConnectionSettings()
|
||||
var downloadSettings = DownloadSettings()
|
||||
var viperSettings = ViperSettings()
|
||||
var clipboardSettings = ClipboardSettings()
|
||||
}
|
||||
|
||||
data class ViperSettings(
|
||||
@@ -32,4 +32,6 @@ data class ConnectionSettings(
|
||||
var maxTotalThreads: Int = 0,
|
||||
var timeout: Int = 30,
|
||||
var maxAttempts: Int = 3,
|
||||
)
|
||||
)
|
||||
|
||||
data class ClipboardSettings(var enable: Boolean = false, var pollingRate: Int = 500)
|
||||
@@ -7,16 +7,16 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.core.io.Resource
|
||||
import org.springframework.stereotype.Service
|
||||
import me.mnlr.vripper.SpringContext
|
||||
import me.mnlr.vripper.delegate.LoggerDelegate
|
||||
import me.mnlr.vripper.event.Event
|
||||
import me.mnlr.vripper.event.EventBus
|
||||
import me.mnlr.vripper.exception.ValidationException
|
||||
import me.mnlr.vripper.model.Settings
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.core.io.Resource
|
||||
import org.springframework.stereotype.Service
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
import java.nio.file.*
|
||||
@@ -92,7 +92,8 @@ class SettingsService(
|
||||
fun newSettings(settings: Settings) {
|
||||
if (settings.viperSettings.login) {
|
||||
if (this.settings.viperSettings.password != settings.viperSettings.password) {
|
||||
settings.viperSettings.password = DigestUtils.md5Hex(settings.viperSettings.password)
|
||||
settings.viperSettings.password =
|
||||
DigestUtils.md5Hex(settings.viperSettings.password)
|
||||
}
|
||||
} else {
|
||||
settings.viperSettings.username = ""
|
||||
@@ -156,55 +157,54 @@ class SettingsService(
|
||||
val path: Path = try {
|
||||
Paths.get(settings.downloadSettings.downloadPath)
|
||||
} catch (e: InvalidPathException) {
|
||||
throw ValidationException(String.format("%s is invalid", settings.downloadSettings.downloadPath))
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"%s is invalid", settings.downloadSettings.downloadPath
|
||||
)
|
||||
)
|
||||
}
|
||||
if (!Files.exists(path)) {
|
||||
throw ValidationException(String.format("%s does not exist", settings.downloadSettings.downloadPath))
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"%s does not exist", settings.downloadSettings.downloadPath
|
||||
)
|
||||
)
|
||||
} else if (!Files.isDirectory(path)) {
|
||||
throw ValidationException(String.format("%s is not a directory", settings.downloadSettings.downloadPath))
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"%s is not a directory", settings.downloadSettings.downloadPath
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if(settings.downloadSettings.autoQueueThreshold < 0) {
|
||||
if (settings.downloadSettings.autoQueueThreshold < 0) {
|
||||
throw ValidationException("Invalid auto queue settings, value must be a positive integer")
|
||||
}
|
||||
|
||||
if (settings.connectionSettings.maxTotalThreads < 0 || settings.connectionSettings.maxTotalThreads > 12) {
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"Invalid max global concurrent download settings, values must be in [%d,%d]",
|
||||
0,
|
||||
12
|
||||
)
|
||||
"Invalid max global concurrent download settings, values must be in [0,12]"
|
||||
)
|
||||
}
|
||||
if (settings.connectionSettings.maxThreads < 1 || settings.connectionSettings.maxThreads > 4) {
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"Invalid max concurrent download settings, values must be in [%d,%d]", 1, 4
|
||||
)
|
||||
)
|
||||
throw ValidationException("Invalid max concurrent download settings, values must be in [1,4]")
|
||||
}
|
||||
if (settings.connectionSettings.timeout < 1 || settings.connectionSettings.timeout > 300) {
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"Invalid connection timeout settings, values must be in [%d,%d]", 1, 300
|
||||
)
|
||||
"Invalid connection timeout settings, values must be in [1,300]"
|
||||
)
|
||||
}
|
||||
if (settings.connectionSettings.maxAttempts < 1 || settings.connectionSettings.maxAttempts > 10) {
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"Invalid maximum attempts settings, values must be in [%d,%d]", 1, 10
|
||||
)
|
||||
)
|
||||
throw ValidationException("Invalid maximum attempts settings, values must be in [1,10]")
|
||||
}
|
||||
if (settings.maxEventLog < 100 || settings.maxEventLog > 10000) {
|
||||
throw ValidationException(
|
||||
String.format(
|
||||
"Invalid maximum event log record settings, values must be in [%d,%d]",
|
||||
100,
|
||||
10000
|
||||
)
|
||||
"Invalid maximum event log record settings, values must be in [100,10000]"
|
||||
)
|
||||
}
|
||||
if (settings.clipboardSettings.pollingRate < 500) {
|
||||
throw ValidationException(
|
||||
"Invalid clipboard monitoring polling rate settings, values must be >= 500"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,78 @@
|
||||
package me.mnlr.vripper.clipboard
|
||||
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import javafx.scene.input.Clipboard
|
||||
import me.mnlr.vripper.AppEndpointService
|
||||
import org.springframework.scheduling.annotation.Scheduled
|
||||
import me.mnlr.vripper.event.Event
|
||||
import me.mnlr.vripper.event.EventBus
|
||||
import me.mnlr.vripper.services.SettingsService
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Sinks
|
||||
import reactor.core.scheduler.Schedulers
|
||||
import tornadofx.*
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Service
|
||||
class ClipboardService(private val appEndpointService: AppEndpointService) {
|
||||
|
||||
class ClipboardService(
|
||||
private val appEndpointService: AppEndpointService,
|
||||
private val settingsService: SettingsService,
|
||||
eventBus: EventBus
|
||||
) {
|
||||
private val eventBusDisposable: Disposable
|
||||
private val sink = Sinks.many().unicast().onBackpressureBuffer<String>()
|
||||
private val scheduler = Executors.newSingleThreadScheduledExecutor()
|
||||
private var current: String? = null
|
||||
private var scheduledFuture: ScheduledFuture<*>? = null
|
||||
|
||||
@PostConstruct
|
||||
fun init() {
|
||||
init {
|
||||
runLater {
|
||||
this.current = if (Clipboard.getSystemClipboard()
|
||||
.hasString()
|
||||
) Clipboard.getSystemClipboard().string else null
|
||||
}
|
||||
eventBusDisposable = eventBus
|
||||
.flux()
|
||||
.filter { it.kind == Event.Kind.SETTINGS_UPDATE }
|
||||
.subscribe { init() }
|
||||
sink.asFlux().subscribeOn(Schedulers.single()).subscribe {
|
||||
this.appEndpointService.scanLinks(it)
|
||||
}
|
||||
runLater {
|
||||
this.current = if(Clipboard.getSystemClipboard().hasString()) Clipboard.getSystemClipboard().string else null
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
fun init() {
|
||||
scheduledFuture?.cancel(true)
|
||||
if(settingsService.settings.clipboardSettings.enable) {
|
||||
scheduledFuture = scheduler.scheduleWithFixedDelay({
|
||||
poll()
|
||||
}, 500, settingsService.settings.clipboardSettings.pollingRate.toLong(), TimeUnit.MILLISECONDS)
|
||||
} else {
|
||||
current = null
|
||||
}
|
||||
}
|
||||
@Scheduled(fixedDelay = 500)
|
||||
|
||||
fun poll() {
|
||||
runLater {
|
||||
val clipboard = Clipboard.getSystemClipboard()
|
||||
if(clipboard.hasString()) {
|
||||
if (clipboard.hasString()) {
|
||||
val value: String? = clipboard.string
|
||||
if(!value.isNullOrBlank() && value != this.current) {
|
||||
if (!value.isNullOrBlank() && value != this.current) {
|
||||
this.current = value
|
||||
sink.emitNext(value) { _,_ ->
|
||||
sink.emitNext(value) { _, _ ->
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
fun destroy() {
|
||||
scheduledFuture?.cancel(true)
|
||||
scheduler.shutdown()
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,12 @@
|
||||
package me.mnlr.vripper.controller
|
||||
|
||||
import javafx.scene.control.Alert
|
||||
import me.mnlr.vripper.exception.ValidationException
|
||||
import me.mnlr.vripper.model.ConnectionSettings
|
||||
import me.mnlr.vripper.model.DownloadSettings
|
||||
import me.mnlr.vripper.model.settings.DownloadSettingsModel
|
||||
import me.mnlr.vripper.model.Settings
|
||||
import me.mnlr.vripper.model.ViperSettings
|
||||
import me.mnlr.vripper.model.*
|
||||
import me.mnlr.vripper.model.settings.ClipboardSettingsModel
|
||||
import me.mnlr.vripper.model.settings.ConnectionSettingsModel
|
||||
import me.mnlr.vripper.model.settings.DownloadSettingsModel
|
||||
import me.mnlr.vripper.model.settings.ViperSettingsModel
|
||||
import me.mnlr.vripper.services.SettingsService
|
||||
import tornadofx.Controller
|
||||
import tornadofx.alert
|
||||
import tornadofx.warning
|
||||
import tornadofx.*
|
||||
|
||||
class SettingsController : Controller() {
|
||||
|
||||
@@ -30,36 +24,46 @@ class SettingsController : Controller() {
|
||||
return settingsService.settings.viperSettings
|
||||
}
|
||||
|
||||
fun findClipboardSettings(): ClipboardSettings {
|
||||
return settingsService.settings.clipboardSettings
|
||||
}
|
||||
|
||||
fun saveNewSettings(
|
||||
downloadSettingsModel: DownloadSettingsModel,
|
||||
connectionSettingsModel: ConnectionSettingsModel,
|
||||
viperSettingsModel: ViperSettingsModel
|
||||
viperSettingsModel: ViperSettingsModel,
|
||||
clipboardSettingsModel: ClipboardSettingsModel
|
||||
) {
|
||||
settingsService.newSettings(Settings().apply {
|
||||
downloadSettings = DownloadSettings(
|
||||
downloadSettingsModel.downloadPath,
|
||||
downloadSettingsModel.autoStart,
|
||||
downloadSettingsModel.autoQueueThreshold,
|
||||
downloadSettingsModel.forceOrder,
|
||||
downloadSettingsModel.forumSubfolder,
|
||||
downloadSettingsModel.threadSubLocation,
|
||||
downloadSettingsModel.clearCompleted,
|
||||
downloadSettingsModel.appendPostId
|
||||
settingsService.newSettings(Settings().apply {
|
||||
downloadSettings = DownloadSettings(
|
||||
downloadSettingsModel.downloadPath,
|
||||
downloadSettingsModel.autoStart,
|
||||
downloadSettingsModel.autoQueueThreshold,
|
||||
downloadSettingsModel.forceOrder,
|
||||
downloadSettingsModel.forumSubfolder,
|
||||
downloadSettingsModel.threadSubLocation,
|
||||
downloadSettingsModel.clearCompleted,
|
||||
downloadSettingsModel.appendPostId
|
||||
)
|
||||
connectionSettings = ConnectionSettings(
|
||||
connectionSettingsModel.maxThreads,
|
||||
connectionSettingsModel.maxTotalThreads,
|
||||
connectionSettingsModel.timeout,
|
||||
connectionSettingsModel.maxAttempts,
|
||||
)
|
||||
viperSettings = ViperSettings(
|
||||
viperSettingsModel.login,
|
||||
viperSettingsModel.username,
|
||||
viperSettingsModel.password,
|
||||
viperSettingsModel.thanks,
|
||||
viperSettingsModel.host,
|
||||
)
|
||||
clipboardSettings =
|
||||
ClipboardSettings(
|
||||
clipboardSettingsModel.enable,
|
||||
if (clipboardSettingsModel.pollingRate.isBlank()) 500 else clipboardSettingsModel.pollingRate.toInt()
|
||||
)
|
||||
connectionSettings = ConnectionSettings(
|
||||
connectionSettingsModel.maxThreads,
|
||||
connectionSettingsModel.maxTotalThreads,
|
||||
connectionSettingsModel.timeout,
|
||||
connectionSettingsModel.maxAttempts,
|
||||
)
|
||||
viperSettings = ViperSettings(
|
||||
viperSettingsModel.login,
|
||||
viperSettingsModel.username,
|
||||
viperSettingsModel.password,
|
||||
viperSettingsModel.thanks,
|
||||
viperSettingsModel.host,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package me.mnlr.vripper.model.settings
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import tornadofx.*
|
||||
|
||||
class ClipboardSettingsModel {
|
||||
val enableProperty = SimpleBooleanProperty()
|
||||
var enable: Boolean by enableProperty
|
||||
|
||||
val pollingRateProperty = SimpleStringProperty()
|
||||
var pollingRate: String by pollingRateProperty
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.mnlr.vripper.view.settings
|
||||
|
||||
import me.mnlr.vripper.controller.SettingsController
|
||||
import me.mnlr.vripper.model.settings.ClipboardSettingsModel
|
||||
import tornadofx.*
|
||||
|
||||
class ClipboardSettingsView : View("Clipboard Settings") {
|
||||
private val settingsController: SettingsController by inject()
|
||||
val clipboardSettingsModel = ClipboardSettingsModel()
|
||||
|
||||
override fun onDock() {
|
||||
val clipboardSettings = settingsController.findClipboardSettings()
|
||||
clipboardSettingsModel.enable = clipboardSettings.enable
|
||||
clipboardSettingsModel.pollingRate = clipboardSettings.pollingRate.toString()
|
||||
}
|
||||
|
||||
override val root = vbox {
|
||||
form {
|
||||
fieldset {
|
||||
field("Enable") {
|
||||
checkbox {
|
||||
bind(clipboardSettingsModel.enableProperty)
|
||||
}
|
||||
}
|
||||
fieldset {
|
||||
visibleWhen(clipboardSettingsModel.enableProperty)
|
||||
field("Polling rate (ms)") {
|
||||
textfield(clipboardSettingsModel.pollingRateProperty) {
|
||||
filterInput {
|
||||
it.controlNewText.isInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ class ConnectionSettingsView : View("Connection settings") {
|
||||
filterInput { it.controlNewText.isInt() }
|
||||
}
|
||||
}
|
||||
field("Connection timeout") {
|
||||
field("Connection timeout (s)") {
|
||||
textfield(connectionSettingsModel.timeoutProperty) {
|
||||
filterInput { it.controlNewText.isInt() }
|
||||
}
|
||||
|
||||
@@ -18,25 +18,32 @@ class SettingsView : Fragment("Settings") {
|
||||
private val downloadSettingsView: DownloadSettingsView by inject()
|
||||
private val connectionSettingsView: ConnectionSettingsView by inject()
|
||||
private val viperSettingsView: ViperSettingsView by inject()
|
||||
private val clipboardSettingsView: ClipboardSettingsView by inject()
|
||||
|
||||
override val root = vbox(alignment = Pos.CENTER_RIGHT) {
|
||||
spacing = 5.0
|
||||
tabpane {
|
||||
tabClosingPolicy = TabPane.TabClosingPolicy.UNAVAILABLE
|
||||
VBox.setVgrow(this, Priority.ALWAYS)
|
||||
tab<DownloadSettingsView>() {
|
||||
tab<DownloadSettingsView> {
|
||||
val imageView = ImageView("downloads-folder.png")
|
||||
imageView.fitWidth = 18.0
|
||||
imageView.fitHeight = 18.0
|
||||
graphic = imageView
|
||||
}
|
||||
tab<ConnectionSettingsView>() {
|
||||
tab<ConnectionSettingsView> {
|
||||
val imageView = ImageView("data-transfer.png")
|
||||
imageView.fitWidth = 18.0
|
||||
imageView.fitHeight = 18.0
|
||||
graphic = imageView
|
||||
}
|
||||
tab<ViperSettingsView>() {
|
||||
tab<ClipboardSettingsView> {
|
||||
val imageView = ImageView("clipboard.png")
|
||||
imageView.fitWidth = 18.0
|
||||
imageView.fitHeight = 18.0
|
||||
graphic = imageView
|
||||
}
|
||||
tab<ViperSettingsView> {
|
||||
val imageView = ImageView("icons/32x32.png")
|
||||
imageView.fitWidth = 18.0
|
||||
imageView.fitHeight = 18.0
|
||||
@@ -56,7 +63,8 @@ class SettingsView : Fragment("Settings") {
|
||||
settingsController.saveNewSettings(
|
||||
downloadSettingsView.downloadSettingsModel,
|
||||
connectionSettingsView.connectionSettingsModel,
|
||||
viperSettingsView.viperSettingsModel
|
||||
viperSettingsView.viperSettingsModel,
|
||||
clipboardSettingsView.clipboardSettingsModel
|
||||
)
|
||||
close()
|
||||
} catch (e: ValidationException) {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 511 B |
Reference in New Issue
Block a user