Compare commits

...
Author SHA1 Message Date
dev-claw 3faae98ff8 wip #247 2025-09-06 14:46:11 +01:00
dev-claw 1c39673c55 wip #247 2025-09-06 14:46:11 +01:00
dev-clawandGitHub 9283ab7837 fixes #260 (#262) 2025-09-06 14:19:34 +01:00
dev-claw ca77074ef6 version bump 2025-08-19 15:42:07 +01:00
dev-clawandGitHub 3cb251cb36 fixes #250 (#252) 2025-08-19 15:38:08 +01:00
dev-clawandGitHub 73f478c1bc fixes #248 (#249) 2025-08-18 19:46:05 +01:00
dev-claw bb1dfbfee1 version bump 2025-08-18 19:36:51 +01:00
dev-clawandGitHub a89fe8571c fixes #243 (#246) 2025-08-18 19:34:21 +01:00
dev-clawandGitHub 44c8e443f4 fixes #240 (#241) 2025-08-08 15:41:43 +01:00
36 changed files with 295 additions and 184 deletions
+12 -12
View File
@@ -57,9 +57,9 @@ jobs:
name: Package for Linux
run: |
cd jpackage
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon icon.png
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-linux.cfg" --type deb
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-linux.cfg" --type rpm
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon resources/VRipper.png
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-linux.cfg" --resource-dir resources --type deb
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-linux.cfg" --resource-dir resources --type rpm
mv dist/vripper-${{ github.event.release.tag_name }}-1.x86_64.rpm dist/vripper-linux-${{ github.event.release.tag_name }}.x86_64.rpm
mv dist/vripper_${{ github.event.release.tag_name }}-1_amd64.deb dist/vripper-linux-${{ github.event.release.tag_name }}_amd64.deb
@@ -67,9 +67,9 @@ jobs:
name: Package for Windows
run: |
cd jpackage
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon icon.ico
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-windows.cfg" --type msi
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-windows.cfg" --type exe
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon resources/VRipper.ico
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-windows.cfg" --resource-dir resources --type msi
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-windows.cfg" --resource-dir resources --type exe
cd dist
ren VRipper-${{ github.event.release.tag_name }}.msi vripper-windows-installer-${{ github.event.release.tag_name }}.msi
ren VRipper-${{ github.event.release.tag_name }}.exe vripper-windows-installer-${{ github.event.release.tag_name }}.exe
@@ -78,9 +78,9 @@ jobs:
name: Package for macOS(arm64)
run: |
cd jpackage
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon icon.icns
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --type pkg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --type dmg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon resources/VRipper.icns
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --resource-dir resources --type pkg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --resource-dir resources --type dmg
mv dist/VRipper-${{ github.event.release.tag_name }}.pkg dist/vripper-macos-${{ github.event.release.tag_name }}.arm64.pkg
mv dist/VRipper-${{ github.event.release.tag_name }}.dmg dist/vripper-macos-${{ github.event.release.tag_name }}.arm64.dmg
@@ -88,9 +88,9 @@ jobs:
name: Package for macOS(x86_64)
run: |
cd jpackage
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon icon.icns
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --type pkg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --type dmg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-app-image.cfg" --icon resources/VRipper.icns
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --resource-dir resources --type pkg
jpackage --app-version ${{ github.event.release.tag_name }} "@jpackage.cfg" "@jpackage-macos.cfg" --resource-dir resources --type dmg
mv dist/VRipper-${{ github.event.release.tag_name }}.pkg dist/vripper-macos-${{ github.event.release.tag_name }}.x86_64.pkg
mv dist/VRipper-${{ github.event.release.tag_name }}.dmg dist/vripper-macos-${{ github.event.release.tag_name }}.x86_64.dmg
+1 -1
View File
@@ -22,7 +22,7 @@ Direct access to `vipergirls.to` domain.
<img src="https://github.com/stashapp/stash/raw/develop/docs/readme_assets/windows_logo.svg" width="100%" height="75"> Windows | <img src="https://github.com/stashapp/stash/raw/develop/docs/readme_assets/mac_logo.svg" width="100%" height="75"> macOS (Intel) | <img src="https://github.com/stashapp/stash/raw/develop/docs/readme_assets/mac_logo.svg" width="100%" height="75"> macOS (Apple silicon) | <img src="https://github.com/stashapp/stash/raw/develop/docs/readme_assets/linux_logo.svg" width="100%" height="75"> Linux | <img src="https://images.vexels.com/media/users/3/166401/isolated/preview/b82aa7ac3f736dd78570dd3fa3fa9e24-java-programming-language-icon-by-vexels.png" width="100%" height="75"> Java
:---:|:---:|:---:|:---:|:---:
[Installer (EXE)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-windows-installer-6.5.4.exe) <br /> [Installer (MSI)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-windows-installer-6.5.4.msi) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-windows-portable-6.5.4.zip) | [Installer (DMG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-6.5.4.x86_64.dmg) <br /> [Installer (PKG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-6.5.4.x86_64.pkg) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-portable-6.5.4.x86_64.zip) | [Installer (DMG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-6.5.4.arm64.dmg) <br /> [Installer (PKG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-6.5.4.arm64.pkg) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-macos-portable-6.5.4.arm64.zip) | [Linux (amd64) (DEB)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-linux-6.5.3_amd64.deb) <br /> [Linux (x86_64) (RPM)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-linux-6.5.4.x86_64.rpm) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-linux-portable-6.5.4.zip) | [Java GUI (noarch)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-noarch-gui-6.5.4.jar) <br /> [Java Web (noarch)](https://github.com/dev-claw/vripper-project/releases/download/6.5.4/vripper-noarch-web-6.5.4.jar)
[Installer (EXE)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-windows-installer-6.5.6.exe) <br /> [Installer (MSI)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-windows-installer-6.5.6.msi) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-windows-portable-6.5.6.zip) | [Installer (DMG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-6.5.6.x86_64.dmg) <br /> [Installer (PKG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-6.5.6.x86_64.pkg) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-portable-6.5.6.x86_64.zip) | [Installer (DMG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-6.5.6.arm64.dmg) <br /> [Installer (PKG)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-6.5.6.arm64.pkg) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-macos-portable-6.5.6.arm64.zip) | [Linux (amd64) (DEB)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-linux-6.5.3_amd64.deb) <br /> [Linux (x86_64) (RPM)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-linux-6.5.6.x86_64.rpm) <br /> [Portable (ZIP)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-linux-portable-6.5.6.zip) | [Java GUI (noarch)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-noarch-gui-6.5.6.jar) <br /> [Java Web (noarch)](https://github.com/dev-claw/vripper-project/releases/download/6.5.6/vripper-noarch-web-6.5.6.jar)
Source code and previous versions are available on
the [Releases page](https://github.com/dev-claw/vripper-project/releases).
-1
View File
@@ -1,4 +1,3 @@
--icon icon.png
--java-options "-Dvripper.portable=false"
--linux-package-name vripper
--linux-app-release 1
-1
View File
@@ -1,4 +1,3 @@
--icon icon.icns
--java-options "-Dvripper.portable=false"
--mac-package-identifier me.mnlr.vripper.vripper-gui
--mac-package-name VRipper
-1
View File
@@ -1,4 +1,3 @@
--icon icon.ico
--java-options "-Dvripper.portable=false"
--win-dir-chooser
--win-menu
+10
View File
@@ -0,0 +1,10 @@
[Desktop Entry]
Name=VRipper
Comment=Image ripper tool for vipergirls
Exec=/opt/vripper/bin/VRipper
Icon=/opt/vripper/lib/VRipper.png
Terminal=false
Type=Application
Categories=Utility
MimeType=
StartupWMClass=me.vripper.gui.VripperGuiApplication

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 303 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

+1 -1
View File
@@ -15,7 +15,7 @@
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<revision>6.5.4</revision>
<revision>6.5.6</revision>
<kotlin.version>2.0.21</kotlin.version>
<slf4j.version>2.0.16</slf4j.version>
<logback.version>1.5.12</logback.version>
@@ -44,8 +44,9 @@ internal class AcidimgHost(
)
)
)
it.setAbsoluteRequestUri(true)
}.also { context.requests.add(it) }
log.debug(String.format("Requesting %s", httpPost.uri))
log.info("Requesting {}", httpPost)
val doc = try {
httpService.client.execute(
httpPost, context.httpContext
@@ -157,8 +157,11 @@ internal abstract class Host(
@Throws(HostException::class)
fun head(url: String, context: ImageDownloadContext): Array<Header> {
val httpHead = HttpHead(url).also { context.requests.add(it) }
log.debug(String.format("Requesting %s", url))
val httpHead = HttpHead(url).also {
it.setAbsoluteRequestUri(true)
context.requests.add(it)
}
log.info("Requesting {}", httpHead)
return httpService.client.execute(
httpHead,
context.httpContext
@@ -177,8 +180,11 @@ internal abstract class Host(
transformer: (ClassicHttpResponse) -> T
): T {
val httpGet =
HttpGet(url).also { it.addHeader("Referer", context.imageEntity.url) }.also { context.requests.add(it) }
log.debug(String.format("Requesting %s", url))
HttpGet(url).also {
it.addHeader("Referer", context.imageEntity.url)
it.setAbsoluteRequestUri(true)
}.also { context.requests.add(it) }
log.info("Requesting {}", httpGet)
return httpService.client.execute(httpGet, context.httpContext) {
if (it.code / 100 != 2) {
throw DownloadException("Server returned code ${it.code}")
@@ -23,6 +23,15 @@ internal class ImxHost : Host("imx.to", 8) {
private val log by LoggerDelegate()
private val failFastHttpClient = HttpClients.custom().apply {
setConnectionManager(BasicHttpClientConnectionManager().apply {
connectionConfig = ConnectionConfig.custom()
.setConnectTimeout(5000, TimeUnit.MILLISECONDS)
.setSocketTimeout(5000, TimeUnit.MILLISECONDS)
.build()
})
}.build()
@Throws(HostException::class)
override fun resolve(
image: ImageEntity,
@@ -31,29 +40,26 @@ internal class ImxHost : Host("imx.to", 8) {
log.debug("Resolving name and image url for ${image.url}")
val imgTitle = String.format("IMG_%04d", image.index + 1)
synchronized(image.postId.toString().intern()) {
val resolvedHost = resolvedHosts.getIfPresent(image.postId)
if (resolvedHost != null) {
val imgUrl = image.thumbUrl.replace("imx.to", resolvedHost).replace("u/t/", "i/")
.replace("t/", "i/")
val subDomain = resolvedHosts.getIfPresent(image.postId)
if (subDomain != null) {
val imgUrl = findPattern(image, subDomain)
return Pair(
imgTitle.ifEmpty { getDefaultImageName(imgUrl) }, imgUrl
)
} else {
IMX_SUBDOMAINS.forEach { subDomain ->
val imgUrl = image.thumbUrl.replace("imx.to", subDomain).replace("u/t/", "i/").replace("t/", "i/")
val imgUrl = findPattern(image, subDomain)
val result = runCatching {
RequestLimit.getPermit(1)
val httpHead = HttpHead(imgUrl).also { context.requests.add(it) }
HttpClients.custom().apply {
setConnectionManager(BasicHttpClientConnectionManager().apply {
connectionConfig = ConnectionConfig.custom()
.setConnectTimeout(5000, TimeUnit.MILLISECONDS)
.setSocketTimeout(5000, TimeUnit.MILLISECONDS)
.build()
})
}.build().execute(httpHead) { response ->
val httpHead = HttpHead(imgUrl)
.also {
it.setAbsoluteRequestUri(true)
context.requests.add(it)
}
log.info("Requesting: {}", httpHead)
failFastHttpClient.execute(httpHead) { response ->
if (response.code / 100 != 2) {
throw HostException("Invalid response")
throw HostException("Invalid response code ${response.code}")
}
}
}
@@ -68,4 +74,11 @@ internal class ImxHost : Host("imx.to", 8) {
}
throw HostException("Unable to find full size image for ${image.url}")
}
private fun findPattern(image: ImageEntity, subDomain: String): String = image.thumbUrl
.replace("http:", "https:")
.replace("imx.to", subDomain)
.replace("upload/small/", "i/")
.replace("u/t/", "i/")
.replace("t/", "i/")
}
@@ -58,8 +58,9 @@ internal class VGAuthService(
BasicNameValuePair("vb_login_md5password", password)
)
)
it.setAbsoluteRequestUri(true)
}
log.info("Authenticating: ${postAuth.uri}")
log.info("Authenticating: {}", postAuth)
try {
val context = HttpClientContext.create().apply {
cookieStore =
@@ -41,10 +41,10 @@ internal class FetchMetadataTask(
it.setParameter(
"p", postId.toString()
)
}.build())
}.build()).also { it.setAbsoluteRequestUri(true) }
RequestLimit.getPermit(1)
log.debug("Requesting {}", httpGet.uri)
log.info("Requesting {}", httpGet)
val response = httpService.client.execute(httpGet, vgAuthService.createVgContext()) {
if (it.code / 100 != 2) {
throw DownloadException("Unexpected response code '${it.code}' for $httpGet")
@@ -40,9 +40,10 @@ internal class LeaveThanksTask(
BasicNameValuePair("securitytoken", postEntity.token)
)
)
it.setAbsoluteRequestUri(true)
}
RequestLimit.getPermit(1)
log.info("Posting {}", postThanks.uri)
log.info("Posting {}", postThanks)
cm.client.execute(postThanks, context) { response ->
if (response.code / 100 != 2) {
throw VripperException("Unexpected response code '${response.code}' for $postThanks")
@@ -32,7 +32,7 @@ internal class PostLookupAPIParser(private val threadId: Long, private val postI
it.setParameter(
"p", postId.toString()
)
}.build())
}.build()).also { it.setAbsoluteRequestUri(true) }
val threadLookupAPIResponseHandler = ThreadLookupAPIResponseHandler()
Tasks.increment()
return try {
@@ -42,7 +42,7 @@ internal class PostLookupAPIParser(private val threadId: Long, private val postI
)
}.get(CheckedSupplier {
RequestLimit.getPermit(1)
log.info("Requesting {}", httpGet.uri)
log.info("Requesting {}", httpGet)
httpService.client.execute(
httpGet,
vgAuthService.createClickContext()
@@ -33,7 +33,7 @@ internal class ThreadLookupAPIParser(private val threadId: Long) : KoinComponent
"t",
threadId.toString()
)
}.build())
}.build()).also { it.setAbsoluteRequestUri(true) }
val threadLookupAPIResponseHandler = ThreadLookupAPIResponseHandler()
Tasks.increment()
return try {
@@ -44,7 +44,7 @@ internal class ThreadLookupAPIParser(private val threadId: Long) : KoinComponent
)
}.get(CheckedSupplier {
RequestLimit.getPermit(1)
log.info("Requesting {}", httpGet.uri)
log.info("Requesting {}", httpGet)
cm.client.execute(
httpGet, vgAuthService.createClickContext()
) { response ->
@@ -1,5 +1,6 @@
package me.vripper.gui
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.services.GrpcEndpointService
import me.vripper.services.IAppEndpointService
import org.koin.core.qualifier.named
@@ -10,6 +11,9 @@ val guiModule = module {
single((named("remoteAppEndpointService"))) {
GrpcEndpointService()
} bind IAppEndpointService::class
single<WidgetsController> {
WidgetsController()
}
}
val modules = module {
@@ -1,7 +1,7 @@
package me.vripper.gui
import atlantafx.base.theme.CupertinoDark
import atlantafx.base.theme.CupertinoLight
import atlantafx.base.theme.NordDark
import atlantafx.base.theme.NordLight
import javafx.application.Application
import javafx.scene.image.Image
import javafx.stage.Stage
@@ -15,22 +15,19 @@ import me.vripper.gui.utils.WidgetSettings
import me.vripper.utilities.AppLock
import me.vripper.utilities.ApplicationProperties.VRIPPER_DIR
import me.vripper.utilities.LoggerDelegate
import org.koin.core.context.GlobalContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.core.qualifier.named
import tornadofx.App
import tornadofx.DIContainer
import tornadofx.FX
import kotlin.reflect.KClass
import kotlin.system.exitProcess
class VripperGuiApplication : App(
LoadingView::class
) {
), KoinComponent {
private val log by LoggerDelegate()
private var initialized = false
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
init {
@@ -38,13 +35,14 @@ class VripperGuiApplication : App(
}
override fun start(stage: Stage) {
PRIMARY_STAGE = stage
Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler { t, e ->
log.error("Thread $t threw an exception: ${e.message}", e)
})
if (widgetsController.currentSettings.darkMode) {
setUserAgentStylesheet(CupertinoDark().userAgentStylesheet)
setUserAgentStylesheet(NordDark().userAgentStylesheet)
} else {
setUserAgentStylesheet(CupertinoLight().userAgentStylesheet)
setUserAgentStylesheet(NordLight().userAgentStylesheet)
}
with(stage) {
width = widgetsController.currentSettings.width
@@ -77,18 +75,15 @@ class VripperGuiApplication : App(
}
}
stage.addEventFilter(WindowEvent.WINDOW_SHOWN) {
startKoin {
modules(modules)
}
FX.dicontainer =
object : DIContainer {
override fun <T : Any> getInstance(type: KClass<T>): T =
GlobalContext.get().get(type)
override fun <T : Any> getInstance(type: KClass<T>, name: String): T =
GlobalContext.get().get(type, named(name))
}
// FX.dicontainer =
// object : DIContainer {
// override fun <T : Any> getInstance(type: KClass<T>): T =
// GlobalContext.get().get(type)
//
// override fun <T : Any> getInstance(type: KClass<T>, name: String): T =
// GlobalContext.get().get(type, named(name))
//
// }
coroutineScope.launch {
GuiEventBus.publishEvent(GuiEventBus.ApplicationInitialized(parameters.raw))
initialized = true
@@ -105,6 +100,7 @@ class VripperGuiApplication : App(
companion object {
lateinit var APP_INSTANCE: Application
lateinit var PRIMARY_STAGE: Stage
}
}
@@ -130,6 +126,9 @@ fun main(args: Array<String>) {
Watcher.notify(threadId)
exitProcess(0)
}
startKoin {
modules(modules)
}
Watcher.init()
Application.launch(
VripperGuiApplication::class.java,
@@ -0,0 +1,30 @@
package me.vripper.gui.components
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.Scene
import javafx.stage.Modality
import javafx.stage.Stage
import me.vripper.gui.VripperGuiApplication.Companion.PRIMARY_STAGE
abstract class Fragment(
private val title: String = "",
private val width: Double = 0.0,
private val height: Double = 0.0
) {
abstract val root: Node
fun openModal(owner: Stage = PRIMARY_STAGE): Stage {
val modalStage = Stage()
modalStage.initModality(Modality.WINDOW_MODAL)
modalStage.initOwner(owner)
modalStage.title = title
modalStage.setScene(Scene(root as Parent, width, height))
modalStage.x = owner.x + (owner.width / 2) - width / 2
modalStage.y = owner.y + (owner.height / 2) - height / 2
modalStage.show()
return modalStage
}
}
@@ -1,112 +1,140 @@
package me.vripper.gui.components.fragments
import javafx.event.EventHandler
import javafx.geometry.Insets
import javafx.scene.control.TabPane
import javafx.scene.text.FontWeight
import javafx.geometry.Pos
import javafx.scene.control.*
import javafx.scene.image.ImageView
import javafx.scene.layout.GridPane
import javafx.scene.layout.HBox
import javafx.scene.layout.Priority
import javafx.scene.layout.VBox
import javafx.scene.text.Text
import javafx.stage.DirectoryChooser
import me.vripper.gui.VripperGuiApplication
import me.vripper.gui.components.Fragment
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.utils.openLink
import me.vripper.utilities.ApplicationProperties
import tornadofx.*
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import kotlin.io.path.Path
import kotlin.io.path.pathString
class AboutFragment : Fragment("About") {
class AboutFragment(width: Double, height: Double) : Fragment("About", width, height), KoinComponent {
private val widgetsController: WidgetsController by inject()
override val root = tabpane()
override val root = TabPane()
init {
with(root) {
tab("About") {
Tab("About").apply {
tabClosingPolicy = TabPane.TabClosingPolicy.UNAVAILABLE
hbox {
HBox().apply {
padding = Insets(15.0, 15.0, 15.0, 15.0)
spacing = 15.0
imageview("icons/64x64.png")
vbox(spacing = 5.0) {
text("VRipper ${ApplicationProperties.VERSION}") {
style {
fontWeight = FontWeight.BOLD
fontSize = Dimension(18.0, Dimension.LinearUnits.px)
}
}
text("Developed by dev-claw and VRipper working group")
hbox(spacing = 5.0) {
hyperlink {
ImageView("icons/64x64.png").also { children.add(it) }
VBox(5.0).apply {
Text("VRipper ${ApplicationProperties.VERSION}").apply {
style = "-fx-font-weight: 700; -fx-font-size: 18px"
}.also { children.add(it) }
Text("Developed by dev-claw and VRipper working group").also { children.add(it) }
HBox(5.0).apply {
Hyperlink().apply {
if (widgetsController.currentSettings.darkMode) {
imageview("icons/github-mark-white.png").apply {
ImageView("icons/github-mark-white.png").apply {
isPreserveRatio = true
fitHeight = 32.0
}
}.also { graphic = it }
} else {
imageview("icons/github-mark.png").apply {
ImageView("icons/github-mark.png").apply {
isPreserveRatio = true
fitHeight = 32.0
}
}.also { graphic = it }
}
action {
onAction = EventHandler {
openLink("https://github.com/dev-claw/vripper-project")
}
}.also { children.add(it) }
}.also { children.add(it) }
Text("Donation").apply { style = "-fx-font-weight: 700; -fx-font-size: 16px" }
.also { children.add(it) }
Hyperlink().apply {
ImageView("icons/buymeacoffee-logo.png").apply {
isPreserveRatio = true
fitHeight = 32.0
}.also { graphic = it }
onAction = EventHandler {
openLink("https://buymeacoffee.com/devclaw")
}
}
form {
fieldset("Donation") {
minWidth = 400.0
field {
hyperlink {
imageview("icons/buymeacoffee-logo.png").apply {
isPreserveRatio = true
fitHeight = 32.0
}
action {
openLink("https://buymeacoffee.com/devclaw")
}
}
}
field("ETH:") {
textfield("0xDdac82B16dC5E3D742fc915ffF583D8548A301cA") {
}.also { children.add(it) }
GridPane().apply {
alignment = Pos.TOP_LEFT
hgap = 10.0
vgap = 10.0
minWidth = 400.0
Text("ETH").also { add(it, 0, 0) }
TextField("0xDdac82B16dC5E3D742fc915ffF583D8548A301cA").apply {
GridPane.setHgrow(this, Priority.ALWAYS)
isEditable = false
}.also { add(it, 1, 0) }
Text("BTC").also { add(it, 0, 1) }
TextField("bc1qcqudnkrndwyadsjwrxww42svkf8trnzx3c8vlr").apply {
GridPane.setHgrow(this, Priority.ALWAYS)
isEditable = false
}
.also { add(it, 1, 1) }
}.also { children.add(it) }
}.also { children.add(it) }
}.also { content = it }
tabs.add(this)
}
Tab("System").apply {
GridPane().apply {
padding = Insets(10.0)
alignment = Pos.TOP_LEFT
hgap = 10.0
vgap = 10.0
minWidth = 400.0
Text("Application data folder").apply { add(this, 0, 0) }
TextField(ApplicationProperties.VRIPPER_DIR.pathString).apply {
isEditable = false
add(this, 1, 0)
}
Text("Previews Path").apply { add(this, 0, 1) }
TextField().apply {
textProperty().bind(widgetsController.currentSettings.cachePathProperty)
isEditable = false
add(this, 1, 1)
}
Button("Browse").apply {
onAction = EventHandler {
isEditable = false
}
}
field("BTC:") {
textfield("bc1qcqudnkrndwyadsjwrxww42svkf8trnzx3c8vlr") {
isEditable = false
}
}
val chooser = DirectoryChooser()
chooser.title = "Select previews folder"
chooser.initialDirectory = Path(widgetsController.currentSettings.cachePath).toFile()
val directory = chooser.showDialog(VripperGuiApplication.PRIMARY_STAGE)
if (directory != null) {
widgetsController.currentSettings.cachePathProperty.set(directory.path)
}
}
add(this, 2, 1)
}
content = this
}
tabs.add(this)
}
tab("System") {
form {
fieldset {
field("Application data folder") {
textfield {
text = ApplicationProperties.VRIPPER_DIR.pathString
isEditable = false
}
}
field("Previews Path") {
textfield(widgetsController.currentSettings.cachePathProperty) {
isEditable = false
}
button("Browse") {
action {
val directory = chooseDirectory(title = "Select previews folder")
if (directory != null) {
widgetsController.currentSettings.cachePathProperty.set(directory.path)
}
}
}
}
}
}
Tab("License").apply {
TextArea(LICENSE).apply { isEditable = false }.also { content = it }
tabs.add(this)
}
tab("License") {
textarea(
"""
}
}
}
val LICENSE = """
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
@@ -781,11 +809,4 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
""".trimIndent()
).apply {
isEditable = false
}
}
}
}
}
""".trimIndent()
@@ -7,12 +7,14 @@ import me.vripper.gui.controller.SettingsController
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.model.settings.DownloadSettingsModel
import me.vripper.model.DownloadSettings
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class DownloadSettingsFragment : Fragment("Download Settings") {
class DownloadSettingsFragment : Fragment("Download Settings"), KoinComponent {
private val settingsController: SettingsController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private lateinit var downloadSettings: DownloadSettings
val downloadSettingsModel = DownloadSettingsModel()
@@ -14,11 +14,13 @@ import me.vripper.gui.event.GuiEventBus
import me.vripper.gui.services.GrpcEndpointService
import me.vripper.gui.utils.AppEndpointManager
import me.vripper.listeners.AppManager
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class SessionFragment : Fragment("Change Session") {
class SessionFragment : Fragment("Change Session"), KoinComponent {
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val grpcEndpointService: GrpcEndpointService by di("remoteAppEndpointService")
private val toggleGroup = ToggleGroup()
override val root = VBox().apply {
@@ -8,11 +8,13 @@ import me.vripper.gui.controller.SettingsController
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.model.settings.SystemSettingsModel
import me.vripper.model.SystemSettings
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class SystemSettingsFragment : Fragment("System Settings") {
class SystemSettingsFragment : Fragment("System Settings"), KoinComponent {
private val settingsController: SettingsController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private lateinit var systemSettings: SystemSettings
val systemSettingsModel = SystemSettingsModel()
@@ -19,16 +19,18 @@ import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.model.ThreadSelectionModel
import me.vripper.gui.utils.Preview
import me.vripper.gui.utils.openLink
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
import kotlin.io.path.Path
class ThreadSelectionTableFragment : Fragment("Thread") {
class ThreadSelectionTableFragment : Fragment("Thread"), KoinComponent {
private lateinit var tableView: TableView<ThreadSelectionModel>
private val threadController: ThreadController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private var items = SortedFilteredList<ThreadSelectionModel>()
private var preview: Preview? = null
private val searchInput = SimpleStringProperty()
@@ -1,18 +1,20 @@
package me.vripper.gui.components.views
import atlantafx.base.theme.CupertinoDark
import atlantafx.base.theme.CupertinoLight
import atlantafx.base.theme.NordDark
import atlantafx.base.theme.NordLight
import javafx.application.Application
import kotlinx.coroutines.runBlocking
import me.vripper.gui.controller.MainController
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.event.GuiEventBus
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.View
import tornadofx.onChange
import tornadofx.runLater
import tornadofx.vbox
class AppView : View() {
class AppView : View(), KoinComponent {
override val root = vbox { }
private val mainController: MainController by inject()
@@ -20,7 +22,7 @@ class AppView : View() {
private val mainView: MainView by inject()
private val statusBarView: StatusBarView by inject()
private val actionBarView: ActionBarView by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
init {
title = "VRipper ${mainController.version}"
with(root) {
@@ -54,9 +56,9 @@ class AppView : View() {
widgetsController.currentSettings.darkModeProperty.onChange {
if (it) {
Application.setUserAgentStylesheet(CupertinoDark().userAgentStylesheet)
Application.setUserAgentStylesheet(NordDark().userAgentStylesheet)
} else {
Application.setUserAgentStylesheet(CupertinoLight().userAgentStylesheet)
Application.setUserAgentStylesheet(NordLight().userAgentStylesheet)
}
}
@@ -22,16 +22,18 @@ import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.model.ImageModel
import me.vripper.gui.utils.Preview
import me.vripper.gui.utils.openLink
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
import kotlin.io.path.Path
class ImagesTableView : View("Photos") {
class ImagesTableView : View("Photos"), KoinComponent {
private val tableView: TableView<ImageModel>
private val imageController: ImageController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val items: ObservableList<ImageModel> = FXCollections.observableArrayList()
private var preview: Preview? = null
@@ -12,11 +12,13 @@ import me.vripper.gui.utils.ClipboardManager
import me.vripper.gui.utils.Watcher
import me.vripper.listeners.AppManager
import me.vripper.utilities.DatabaseManager
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class LoadingView : View("VRipper") {
class LoadingView : View("VRipper"), KoinComponent {
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val grpcEndpointService: GrpcEndpointService by di("remoteAppEndpointService")
private val coroutineScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
@@ -13,14 +13,16 @@ import me.vripper.gui.controller.LogController
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.event.GuiEventBus
import me.vripper.gui.model.LogModel
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
class LogTableView : View() {
class LogTableView : View(), KoinComponent {
private val logController: LogController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val tableView: TableView<LogModel>
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val items: ObservableList<LogModel> = FXCollections.observableArrayList()
@@ -18,15 +18,17 @@ import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.utils.openLink
import me.vripper.services.IAppEndpointService
import me.vripper.utilities.ApplicationProperties
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
class MenuBarView : View() {
class MenuBarView : View(), KoinComponent {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val downloadActiveProperty = SimpleBooleanProperty(false)
private val postsTableView: PostsTableView by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val postController: PostController by inject()
private val actionBarController: ActionBarController by inject()
private lateinit var appEndpointService: IAppEndpointService
@@ -190,7 +192,10 @@ class MenuBarView : View() {
item("About").apply {
graphic = FontIcon.of(Feather.INFO)
action {
find<AboutFragment>().openModal()?.apply {
AboutFragment(
width = 500.0,
height = 300.0
).openModal().apply {
this.minWidth = 100.0
this.minHeight = 100.0
}
@@ -6,14 +6,16 @@ import javafx.scene.layout.Priority
import kotlinx.coroutines.*
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.utils.WidgetSettings
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class PostsTabView : View() {
class PostsTabView : View(), KoinComponent {
override val root: SplitPane = splitpane()
private val postsTableView: PostsTableView by inject()
private val postInfoView: PostInfoView by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val coroutineScope = CoroutineScope(SupervisorJob())
init {
@@ -31,15 +31,17 @@ import me.vripper.gui.model.PostModel
import me.vripper.gui.utils.Preview
import me.vripper.gui.utils.openFileDirectory
import me.vripper.gui.utils.openLink
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
import kotlin.io.path.Path
class PostsTableView : View() {
class PostsTableView : View(), KoinComponent {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val postController: PostController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val mainView: MainView by inject()
val tableView: TableView<PostModel>
@@ -10,10 +10,12 @@ import me.vripper.gui.controller.StatusBarController
import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.event.GuiEventBus
import me.vripper.utilities.formatSI
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import tornadofx.*
class StatusBarView : View("Status bar") {
private val widgetsController: WidgetsController by inject()
class StatusBarView : View("Status bar"), KoinComponent {
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val statusBarController: StatusBarController by inject()
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val remoteText = SimpleStringProperty()
@@ -20,15 +20,17 @@ import me.vripper.gui.controller.WidgetsController
import me.vripper.gui.event.GuiEventBus
import me.vripper.gui.model.ThreadModel
import me.vripper.gui.utils.openLink
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.kordamp.ikonli.feather.Feather
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.*
class ThreadTableView : View() {
class ThreadTableView : View(), KoinComponent {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val threadController: ThreadController by inject()
private val widgetsController: WidgetsController by inject()
private val widgetsController: WidgetsController by inject<WidgetsController>()
private val mainView: MainView by inject()
private val tableView: TableView<ThreadModel>
private val items: ObservableList<ThreadModel> = FXCollections.observableArrayList()
@@ -3,10 +3,9 @@ package me.vripper.gui.controller
import me.vripper.gui.model.WidgetsViewModel
import me.vripper.gui.utils.WidgetSettings
import me.vripper.gui.utils.WidgetSettings.loadSettings
import tornadofx.Controller
import tornadofx.onChange
class WidgetsController : Controller() {
class WidgetsController {
var currentSettings: WidgetsViewModel = loadSettings().let {
WidgetsViewModel(