Compare commits

...
9 Commits
Author SHA1 Message Date
death-claw d960b13a9f version bump 2024-04-21 10:25:27 +01:00
death-clawandGitHub b26f78a576 fixes #187 (#188) 2024-04-21 10:24:55 +01:00
death-claw 733f5c926e version bump 2024-04-20 22:34:47 +01:00
death-clawandGitHub 0012e3b8ca fixes #185 (#186) 2024-04-20 22:24:40 +01:00
death-claw 564033eb03 version bump 2024-04-19 21:38:26 +01:00
death-claw 776f996673 fixes #176
fixes #179
fixes #180
fixes #181
fixes #182
2024-04-19 21:38:06 +01:00
death-clawandGitHub 06942c70c8 Update README.md 2024-03-17 18:07:09 +01:00
death-clawandGitHub 0d95b97aee Update README.md 2024-03-17 18:03:28 +01:00
death-clawandGitHub e3598769cd screenshot 2024-03-17 18:02:32 +01:00
28 changed files with 511 additions and 351 deletions
+2 -2
View File
@@ -3,7 +3,7 @@
This is my spin for a cross-platform gallery ripper for [vipergirls.to](https://vipergirls.to).
![1Jw0oq8h_o](https://github.com/UncleRoger33/vripper-project/assets/66418211/80b44389-7620-4e05-8696-4b62fa626b1b)
![GitHub Image](/image.png)
## Requirements
@@ -13,7 +13,7 @@ Direct access to vipergirls.to (or one of its [alternative domains](https://vipe
<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 | <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/death-claw/vripper-project/releases/download/5.4.0/vripper-windows-installer-5.4.0.exe) <br /> [Installer (MSI)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-windows-installer-5.4.0.msi) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-windows-portable-5.4.0.zip) | [Installer (DMG)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-macos-5.4.0.dmg) <br /> [Installer (PKG)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-macos-5.4.0.pkg) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-macos-portable-5.4.0.zip) | [Linux (amd64) (DEB)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-linux-5.4.0_amd64.deb) <br /> [Linux (x86_64) (RPM)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-linux-5.4.0.x86_64.rpm) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-linux-portable-5.4.0.zip) | [Java GUI (noarch)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-noarch-gui-5.4.0.jar) <br /> [Java Web (noarch)](https://github.com/death-claw/vripper-project/releases/download/5.4.0/vripper-noarch-web-5.4.0.jar)
[Installer (EXE)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-windows-installer-5.5.0.exe) <br /> [Installer (MSI)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-windows-installer-5.5.0.msi) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-windows-portable-5.5.0.zip) | [Installer (DMG)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-macos-5.5.0.dmg) <br /> [Installer (PKG)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-macos-5.5.0.pkg) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-macos-portable-5.5.0.zip) | [Linux (amd64) (DEB)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-linux-5.5.0_amd64.deb) <br /> [Linux (x86_64) (RPM)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-linux-5.5.0.x86_64.rpm) <br /> [Portable (ZIP)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-linux-portable-5.5.0.zip) | [Java GUI (noarch)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-noarch-gui-5.5.0.jar) <br /> [Java Web (noarch)](https://github.com/death-claw/vripper-project/releases/download/5.5.0/vripper-noarch-web-5.5.0.jar)
Source code and previous versions are available on the [Releases page](https://github.com/death-claw/vripper-project/releases).
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

+206 -206
View File
@@ -1,209 +1,209 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.vripper</groupId>
<artifactId>vripper-project</artifactId>
<packaging>pom</packaging>
<version>${revision}</version>
<properties>
<java.version>21</java.version>
<maven.deploy.skip>false</maven.deploy.skip>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<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>5.5.0</revision>
<kotlin.version>1.9.22</kotlin.version>
<slf4j.version>2.0.12</slf4j.version>
<logback.version>1.5.0</logback.version>
<kotlinx-coroutines.version>1.8.0</kotlinx-coroutines.version>
<exposed.version>0.47.0</exposed.version>
<snakeyaml.version>2.0</snakeyaml.version>
<koin.version>3.5.3</koin.version>
<h2.version>2.2.224</h2.version>
<htmlcleaner.version>2.29</htmlcleaner.version>
<failsafe.version>2.4.4</failsafe.version>
<caffeine.version>3.1.8</caffeine.version>
<jna-platform.version>5.14.0</jna-platform.version>
<kotlinx-serialization-json.version>1.6.2</kotlinx-serialization-json.version>
<httpclient5.version>5.3.1</httpclient5.version>
<commons-codec.version>1.16.1</commons-codec.version>
<liquibase-core.version>4.26.0</liquibase-core.version>
<liquibase-slf4j.version>5.0.0</liquibase-slf4j.version>
<grpc.kotlin.version>1.4.1</grpc.kotlin.version>
<java.grpc.version>1.62.2</java.grpc.version>
<protobuf.version>3.25.3</protobuf.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<modules>
<module>vripper-core</module>
<module>vripper-web-ui</module>
<module>vripper-web</module>
<module>vripper-gui</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
<version>${logback.version}</version>
</dependency>
<dependency>
<artifactId>logback-core</artifactId>
<groupId>ch.qos.logback</groupId>
<version>${logback.version}</version>
</dependency>
<dependency>
<artifactId>kotlin-stdlib</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core-jvm</artifactId>
<version>${kotlinx-coroutines.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-javafx</artifactId>
<version>${kotlinx-coroutines.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>exposed-jdbc</artifactId>
<version>${exposed.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>exposed-java-time</artifactId>
<version>${exposed.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<dependency>
<groupId>io.insert-koin</groupId>
<artifactId>koin-core-jvm</artifactId>
<version>${koin.version}</version>
</dependency>
<dependency>
<artifactId>h2</artifactId>
<groupId>com.h2database</groupId>
<version>${h2.version}</version>
</dependency>
<dependency>
<artifactId>htmlcleaner</artifactId>
<groupId>net.sourceforge.htmlcleaner</groupId>
<version>${htmlcleaner.version}</version>
</dependency>
<dependency>
<artifactId>failsafe</artifactId>
<groupId>net.jodah</groupId>
<version>${failsafe.version}</version>
</dependency>
<dependency>
<artifactId>caffeine</artifactId>
<groupId>com.github.ben-manes.caffeine</groupId>
<version>${caffeine.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>${jna-platform.version}</version>
</dependency>
<dependency>
<artifactId>kotlin-reflect</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json</artifactId>
<version>${kotlinx-serialization-json.version}</version>
</dependency>
<dependency>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<artifactId>httpclient5</artifactId>
<groupId>org.apache.httpcomponents.client5</groupId>
<version>${httpclient5.version}</version>
</dependency>
<dependency>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<artifactId>liquibase-core</artifactId>
<groupId>org.liquibase</groupId>
<version>${liquibase-core.version}</version>
</dependency>
<dependency>
<artifactId>liquibase-slf4j</artifactId>
<groupId>com.mattbertolini</groupId>
<version>${liquibase-slf4j.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-kotlin-stub</artifactId>
<version>${grpc.kotlin.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${java.grpc.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-kotlin</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>${java.grpc.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.vripper</groupId>
<artifactId>vripper-project</artifactId>
<packaging>pom</packaging>
<version>${revision}</version>
<properties>
<java.version>21</java.version>
<maven.deploy.skip>false</maven.deploy.skip>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<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>5.8.0</revision>
<kotlin.version>1.9.22</kotlin.version>
<slf4j.version>2.0.12</slf4j.version>
<logback.version>1.5.0</logback.version>
<kotlinx-coroutines.version>1.8.0</kotlinx-coroutines.version>
<exposed.version>0.47.0</exposed.version>
<snakeyaml.version>2.0</snakeyaml.version>
<koin.version>3.5.3</koin.version>
<h2.version>2.2.224</h2.version>
<htmlcleaner.version>2.29</htmlcleaner.version>
<failsafe.version>2.4.4</failsafe.version>
<caffeine.version>3.1.8</caffeine.version>
<jna-platform.version>5.14.0</jna-platform.version>
<kotlinx-serialization-json.version>1.6.2</kotlinx-serialization-json.version>
<httpclient5.version>5.3.1</httpclient5.version>
<commons-codec.version>1.16.1</commons-codec.version>
<liquibase-core.version>4.26.0</liquibase-core.version>
<liquibase-slf4j.version>5.0.0</liquibase-slf4j.version>
<grpc.kotlin.version>1.4.1</grpc.kotlin.version>
<java.grpc.version>1.62.2</java.grpc.version>
<protobuf.version>3.25.3</protobuf.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<modules>
<module>vripper-core</module>
<module>vripper-web-ui</module>
<module>vripper-web</module>
<module>vripper-gui</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
<version>${logback.version}</version>
</dependency>
<dependency>
<artifactId>logback-core</artifactId>
<groupId>ch.qos.logback</groupId>
<version>${logback.version}</version>
</dependency>
<dependency>
<artifactId>kotlin-stdlib</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core-jvm</artifactId>
<version>${kotlinx-coroutines.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-javafx</artifactId>
<version>${kotlinx-coroutines.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>exposed-jdbc</artifactId>
<version>${exposed.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>exposed-java-time</artifactId>
<version>${exposed.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<dependency>
<groupId>io.insert-koin</groupId>
<artifactId>koin-core-jvm</artifactId>
<version>${koin.version}</version>
</dependency>
<dependency>
<artifactId>h2</artifactId>
<groupId>com.h2database</groupId>
<version>${h2.version}</version>
</dependency>
<dependency>
<artifactId>htmlcleaner</artifactId>
<groupId>net.sourceforge.htmlcleaner</groupId>
<version>${htmlcleaner.version}</version>
</dependency>
<dependency>
<artifactId>failsafe</artifactId>
<groupId>net.jodah</groupId>
<version>${failsafe.version}</version>
</dependency>
<dependency>
<artifactId>caffeine</artifactId>
<groupId>com.github.ben-manes.caffeine</groupId>
<version>${caffeine.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>${jna-platform.version}</version>
</dependency>
<dependency>
<artifactId>kotlin-reflect</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-json</artifactId>
<version>${kotlinx-serialization-json.version}</version>
</dependency>
<dependency>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<artifactId>httpclient5</artifactId>
<groupId>org.apache.httpcomponents.client5</groupId>
<version>${httpclient5.version}</version>
</dependency>
<dependency>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<artifactId>liquibase-core</artifactId>
<groupId>org.liquibase</groupId>
<version>${liquibase-core.version}</version>
</dependency>
<dependency>
<artifactId>liquibase-slf4j</artifactId>
<groupId>com.mattbertolini</groupId>
<version>${liquibase-slf4j.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-kotlin-stub</artifactId>
<version>${grpc.kotlin.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${java.grpc.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-kotlin</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>${java.grpc.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
@@ -105,7 +105,6 @@ class DownloadService(
continue
}
if (isPending(post.postId)) {
log.warn("Cannot restart, jobs are currently running for post id $posts")
continue
}
toProcess[post] = images
@@ -118,10 +118,7 @@ class ImageDownloadRunnable(
} finally {
try {
Files.delete(downloadedImage.path)
} catch (e: IOException) {
log.warn(
"Failed to delete temporary file ${downloadedImage.path}"
)
} catch (_: IOException) {
}
}
}
@@ -24,7 +24,7 @@ class PostLookupAPIParser(private val threadId: Long, private val postId: Long)
private val dataTransaction: DataTransaction by inject()
@Throws(PostParseException::class)
fun parse(): PostItem {
fun parse(): ThreadItem? {
log.debug("Parsing post $postId")
val httpGet =
HttpGet(URIBuilder("${settingsService.settings.viperSettings.host}/vr.php").also {
@@ -58,7 +58,7 @@ class PostLookupAPIParser(private val threadId: Long, private val postId: Long)
}
factory.newSAXParser()
.parse(response.entity.content, threadLookupAPIResponseHandler)
threadLookupAPIResponseHandler.result.postItemList.first()
threadLookupAPIResponseHandler.result
}
})
} catch (e: Exception) {
@@ -5,5 +5,6 @@ data class ThreadItem(
val title: String,
val securityToken: String,
val forum: String,
val postItemList: List<PostItem>
val postItemList: List<PostItem>,
val error: String
)
@@ -8,7 +8,6 @@ import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
class ThreadLookupAPIResponseHandler : KoinComponent, DefaultHandler() {
private val log by me.vripper.delegate.LoggerDelegate()
private val supportedHosts: List<Host> = getKoin().getAll()
private val settingsService: SettingsService by inject()
private var error: String = ""
@@ -17,13 +16,13 @@ class ThreadLookupAPIResponseHandler : KoinComponent, DefaultHandler() {
private val imageItemList: MutableList<ImageItem> = mutableListOf()
private lateinit var threadItem: ThreadItem
private var threadId: Long = -1
private lateinit var threadTitle: String
private lateinit var forum: String
private lateinit var securityToken: String
private var threadTitle: String = ""
private var forum: String = ""
private var securityToken: String = ""
private var postId: Long = -1
private lateinit var postTitle: String
private var postCounter: Int = 0
private var postTitle: String = ""
private var postCounter: Int = 0
val result: ThreadItem
get() = threadItem
@@ -89,6 +88,6 @@ class ThreadLookupAPIResponseHandler : KoinComponent, DefaultHandler() {
}
override fun endDocument() {
threadItem = ThreadItem(threadId, threadTitle, securityToken, forum, postItemList.toList())
threadItem = ThreadItem(threadId, threadTitle, securityToken, forum, postItemList.toList(), error)
}
}
@@ -1,8 +1,6 @@
package me.vripper.services
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.time.sample
import me.vripper.download.DownloadService
import me.vripper.entities.LogEntryEntity
@@ -17,9 +15,12 @@ import me.vripper.utilities.GLOBAL_EXECUTOR
import me.vripper.utilities.PathUtils
import java.time.Duration
import java.util.concurrent.CompletableFuture
import java.util.concurrent.locks.ReentrantLock
import java.util.regex.Pattern
import kotlin.concurrent.withLock
import kotlin.io.path.Path
import kotlin.io.path.exists
import kotlin.jvm.optionals.getOrNull
class AppEndpointService(
private val downloadService: DownloadService,
@@ -30,12 +31,11 @@ class AppEndpointService(
) : IAppEndpointService {
private val log by me.vripper.delegate.LoggerDelegate()
private val semaphore = Semaphore(1)
private val lock = ReentrantLock()
override suspend fun scanLinks(postLinks: String) {
semaphore.withPermit {
lock.withLock {
if (postLinks.isBlank()) {
log.warn("Nothing to scan")
return
}
val urlList = postLinks.split(Pattern.compile("\\r?\\n")).dropLastWhile { it.isEmpty() }.map { it.trim() }
@@ -82,13 +82,12 @@ class AppEndpointService(
}
override suspend fun restartAll(posIds: List<Long>) {
semaphore.withPermit {
lock.withLock {
downloadService.restartAll(posIds.map { dataTransaction.findPostByPostId(it) }.filter { it.isPresent }
.map { it.get() })
}
}
override suspend fun download(posts: List<ThreadPostId>) {
CompletableFuture.runAsync(
AddPostRunnable(posts), GLOBAL_EXECUTOR
@@ -96,26 +95,26 @@ class AppEndpointService(
}
override suspend fun stopAll(postIdList: List<Long>) {
semaphore.withPermit {
lock.withLock {
downloadService.stop(postIdList)
}
}
override suspend fun remove(postIdList: List<Long>) {
semaphore.withPermit {
lock.withLock {
downloadService.stop(postIdList)
dataTransaction.removeAll(postIdList)
}
}
override suspend fun clearCompleted(): List<Long> {
semaphore.withPermit {
lock.withLock {
return dataTransaction.clearCompleted()
}
}
override suspend fun grab(threadId: Long): List<PostSelection> {
semaphore.withPermit {
lock.withLock {
return try {
val thread = dataTransaction.findThreadByThreadId(threadId).orElseThrow {
PostParseException(
@@ -160,7 +159,7 @@ class AppEndpointService(
}
override suspend fun threadRemove(threadIdList: List<Long>) {
semaphore.withPermit {
lock.withLock {
threadIdList.forEach {
dataTransaction.removeThread(it)
}
@@ -168,13 +167,25 @@ class AppEndpointService(
}
override suspend fun threadClear() {
semaphore.withPermit {
lock.withLock {
dataTransaction.clearQueueLinks()
}
}
override suspend fun logClear() {
dataTransaction.deleteAllLogs()
lock.withLock {
dataTransaction.deleteAllLogs()
}
}
override suspend fun renameToFirst(postIds: List<Long>) {
postIds.forEach { postId ->
dataTransaction
.findMetadataByPostId(postId)
.map { it.data.resolvedNames }
.filter { it.isNotEmpty() }
.getOrNull()?.let { rename(postId, it.first()) }
}
}
override suspend fun rename(postId: Long, newName: String) {
@@ -44,4 +44,5 @@ interface IAppEndpointService {
fun onUpdateSettings(): Flow<Settings>
suspend fun loggedInUser(): String
suspend fun getVersion(): String
suspend fun renameToFirst(postIds: List<Long>)
}
@@ -4,12 +4,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import me.vripper.entities.MetadataEntity
import me.vripper.exception.DownloadException
import me.vripper.exception.VripperException
import me.vripper.utilities.HtmlUtils
import me.vripper.utilities.RequestLimit
import me.vripper.utilities.Tasks
import me.vripper.utilities.XpathUtils
import org.apache.hc.client5.http.classic.methods.HttpGet
import org.apache.hc.core5.net.URIBuilder
@@ -17,7 +18,6 @@ import org.w3c.dom.Node
import java.util.concurrent.atomic.AtomicBoolean
import java.util.stream.Collectors
class MetadataService(
private val httpService: HTTPService,
private val settingsService: SettingsService,
@@ -26,51 +26,55 @@ class MetadataService(
) {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val requestSemaphore = Semaphore(6)
private val dictionary: List<String> =
mutableListOf("download", "link", "rapidgator", "filefactory", "filefox")
private val dictionary: List<String> = mutableListOf("download", "link", "rapidgator", "filefactory", "filefox")
fun init() {
dataTransaction.findAllPosts()
.filter { dataTransaction.findMetadataByPostId(it.postId).isEmpty }.map { it.postId }
.forEach(::fetchMetadata)
dataTransaction.findAllPosts().filter { dataTransaction.findMetadataByPostId(it.postId).isEmpty }
.map { it.postId }.forEach(::fetchMetadata)
}
fun fetchMetadata(postId: Long) {
Tasks.increment()
coroutineScope.launch {
requestSemaphore.withPermit {
val httpGet =
HttpGet(URIBuilder(settingsService.settings.viperSettings.host + "/threads/").also {
RequestLimit.semaphore.withPermit {
try {
val httpGet = HttpGet(URIBuilder(settingsService.settings.viperSettings.host + "/threads/").also {
it.setParameter(
"p", postId.toString()
)
}.build())
val metadataEntity = httpService.client.execute(httpGet, vgAuthService.context) {
if (it.code / 100 != 2) {
throw DownloadException("Unexpected response code '${it.code}' for $httpGet")
val metadataEntity = httpService.client.execute(httpGet, vgAuthService.context) {
if (it.code / 100 != 2) {
throw DownloadException("Unexpected response code '${it.code}' for $httpGet")
}
val document = HtmlUtils.clean(it.entity.content)
val postNode: Node = XpathUtils.getAsNode(
document,
"//li[@id='post_$postId']/div[contains(@class, 'postdetails')]",
) ?: throw VripperException("Unable to find post #'$postId'")
val postedBy: String = XpathUtils.getAsNode(
postNode, "./div[contains(@class, 'userinfo')]//a[contains(@class, 'username')]//font"
)?.textContent?.trim()
?: throw VripperException("Unable to find the poster for post #'$postId'")
val node: Node = XpathUtils.getAsNode(
document, java.lang.String.format("//div[@id='post_message_%s']", postId)
) ?: throw VripperException("Unable to locate post content")
val titles = findTitleInContent(node)
MetadataEntity(postId, MetadataEntity.Data(postedBy, titles))
}
val document = HtmlUtils.clean(it.entity.content)
val postNode: Node = XpathUtils.getAsNode(
document,
"//li[@id='post_$postId']/div[contains(@class, 'postdetails')]",
) ?: throw VripperException("Unable to find post #'$postId'")
val postedBy: String = XpathUtils.getAsNode(
postNode,
"./div[contains(@class, 'userinfo')]//a[contains(@class, 'username')]//font"
)?.textContent?.trim()
?: throw VripperException("Unable to find the poster for post #'$postId'")
val node: Node = XpathUtils.getAsNode(
document, java.lang.String.format("//div[@id='post_message_%s']", postId)
) ?: throw VripperException("Unable to locate post content")
val titles = findTitleInContent(node)
MetadataEntity(postId, MetadataEntity.Data(postedBy, titles))
try {
dataTransaction.saveMetadata(metadataEntity)
} catch (e: Exception) {
e.printStackTrace()
}
} finally {
Tasks.decrement()
}
dataTransaction.saveMetadata(metadataEntity)
}
}
}
@@ -57,6 +57,7 @@ class SettingsService(private val eventBus: EventBus) {
customProxiesPath.readText()
)
} catch (e: Exception) {
e.printStackTrace()
emptyList()
}
} else {
@@ -2,15 +2,14 @@ package me.vripper.services
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.LoadingCache
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withPermit
import me.vripper.event.EventBus
import me.vripper.event.SettingsUpdateEvent
import me.vripper.parser.ThreadItem
import me.vripper.parser.ThreadLookupAPIParser
import me.vripper.utilities.RequestLimit
import java.util.*
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
@@ -29,12 +28,16 @@ class ThreadCacheService(val eventBus: EventBus) {
private val cache: LoadingCache<Long, ThreadItem> =
Caffeine.newBuilder().expireAfterWrite(20, TimeUnit.MINUTES).build { threadId ->
ThreadLookupAPIParser(threadId).parse()
runBlocking {
RequestLimit.semaphore.withPermit {
ThreadLookupAPIParser(threadId).parse()
}
}
}
@Throws(ExecutionException::class)
operator fun get(threadId: Long): ThreadItem {
return cache[threadId] ?: throw NoSuchElementException("$threadId does not exist")
return cache[threadId]
}
fun getIfPresent(threadId: Long): ThreadItem? {
@@ -115,7 +115,6 @@ class VGAuthService(
}
authenticated = true
loggedUser = username
log.info(String.format("Authenticated: %s", username))
coroutineScope.launch {
eventBus.publishEvent(VGUserLoginEvent(loggedUser))
@@ -1,6 +1,9 @@
package me.vripper.tasks
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.withPermit
import me.vripper.download.DownloadService
import me.vripper.entities.LogEntryEntity
import me.vripper.model.ThreadPostId
import me.vripper.parser.PostItem
import me.vripper.parser.PostLookupAPIParser
@@ -8,6 +11,7 @@ import me.vripper.services.DataTransaction
import me.vripper.services.MetadataService
import me.vripper.services.SettingsService
import me.vripper.services.ThreadCacheService
import me.vripper.utilities.RequestLimit
import me.vripper.utilities.Tasks
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -26,25 +30,76 @@ class AddPostRunnable(private val items: List<ThreadPostId>) : KoinComponent, Ru
val toProcess = mutableListOf<PostItem>()
for ((threadId, postId) in items) {
if (dataTransaction.exists(postId)) {
log.warn(String.format("skipping %s, already loaded", postId))
continue
}
val threadItem = threadCacheService.getIfPresent(threadId)
val postItem: PostItem =
threadItem?.postItemList?.find { it.postId == postId } ?: PostLookupAPIParser(
threadId,
postId
).parse()
val link =
"https://${settingsService.settings.viperSettings.host}/threads/$threadId?p=$postId&viewfull=1#post$postId"
val cachedThread = threadCacheService.getIfPresent(threadId)
val threadItem = cachedThread ?: runBlocking {
RequestLimit.semaphore.withPermit {
PostLookupAPIParser(
threadId, postId
).parse()
}
}
if (threadItem == null) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.POST,
status = LogEntryEntity.Status.ERROR,
message = "Failed to load $link"
)
)
continue
} else {
if (threadItem.error.isNotBlank()) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.POST,
status = LogEntryEntity.Status.ERROR,
message = "Error loading $link: ${threadItem.error}"
)
)
continue
} else if (threadItem.postItemList.isEmpty()) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.POST,
status = LogEntryEntity.Status.ERROR,
message = "Nothing found for $link"
)
)
continue
}
}
val postItem = threadItem.postItemList.firstOrNull { it.postId == postId }
if (postItem == null) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.POST,
status = LogEntryEntity.Status.ERROR,
message = "Unable to load $link"
)
)
continue
}
toProcess.add(postItem)
}
val posts = dataTransaction.newPosts(toProcess.toList())
val posts = try {
dataTransaction.newPosts(toProcess.toList())
} catch (e: Exception) {
e.printStackTrace()
emptyList()
}
posts.forEach {
metadataService.fetchMetadata(it.postId)
}
if (settingsService.settings.downloadSettings.autoStart) {
log.debug("Auto start downloads option is enabled")
downloadService.restartAll(posts)
}
} catch (e: Exception) {
@@ -1,13 +1,10 @@
package me.vripper.tasks
import kotlinx.coroutines.runBlocking
import me.vripper.entities.LogEntryEntity
import me.vripper.entities.LogEntryEntity.Status.ERROR
import me.vripper.entities.ThreadEntity
import me.vripper.model.Settings
import me.vripper.model.ThreadPostId
import me.vripper.parser.ThreadItem
import me.vripper.services.AppEndpointService
import me.vripper.services.DataTransaction
import me.vripper.services.SettingsService
import me.vripper.services.ThreadCacheService
@@ -18,13 +15,11 @@ import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.util.concurrent.CompletableFuture
class ThreadLookupRunnable(private val threadId: Long, private val settings: Settings) :
KoinComponent, Runnable {
class ThreadLookupRunnable(private val threadId: Long, private val settings: Settings) : KoinComponent, Runnable {
private val log by me.vripper.delegate.LoggerDelegate()
private val dataTransaction by inject<DataTransaction>()
private val settingsService by inject<SettingsService>()
private val threadCacheService by inject<ThreadCacheService>()
private val appEndpointService by inject<AppEndpointService>()
private val link: String = "${settingsService.settings.viperSettings.host}/threads/$threadId"
override fun run() {
@@ -32,28 +27,47 @@ class ThreadLookupRunnable(private val threadId: Long, private val settings: Set
Tasks.increment()
if (dataTransaction.findThreadByThreadId(threadId).isEmpty) {
val threadLookupResult = threadCacheService[threadId]
if (threadLookupResult.postItemList.isEmpty()) {
val message = "Nothing found for $link"
if (threadLookupResult.error.isNotBlank()) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.THREAD,
status = ERROR,
message = message
status = LogEntryEntity.Status.ERROR,
message = "Error loading $link: ${threadLookupResult.error}"
)
)
return
}
dataTransaction.save(
ThreadEntity(
title = threadLookupResult.title,
link = link,
threadId = threadId,
total = threadLookupResult.postItemList.size
if (threadLookupResult.postItemList.isEmpty()) {
dataTransaction.saveLog(
LogEntryEntity(
type = LogEntryEntity.Type.THREAD,
status = LogEntryEntity.Status.ERROR,
message = "Nothing found for $link"
)
)
)
autostart(threadLookupResult)
} else {
log.info("Link $link is already loaded")
return
}
if (threadLookupResult.postItemList.size <= settings.downloadSettings.autoQueueThreshold) {
CompletableFuture.runAsync(AddPostRunnable(threadLookupResult.postItemList.map {
ThreadPostId(
it.threadId, it.postId
)
}), GLOBAL_EXECUTOR)
} else {
try {
dataTransaction.save(
ThreadEntity(
title = threadLookupResult.title,
link = link,
threadId = threadId,
total = threadLookupResult.postItemList.size
)
)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
} catch (e: Exception) {
val error = "Error when processing $link"
@@ -70,18 +84,4 @@ class ThreadLookupRunnable(private val threadId: Long, private val settings: Set
Tasks.decrement()
}
}
private fun autostart(lookupResult: ThreadItem) {
if (lookupResult.postItemList.size <= settings.downloadSettings.autoQueueThreshold) {
runBlocking {
appEndpointService.threadRemove(listOf(lookupResult.threadId))
}
CompletableFuture.runAsync(
AddPostRunnable(
lookupResult.postItemList.map { ThreadPostId(it.threadId, it.postId) }
),
GLOBAL_EXECUTOR
)
}
}
}
@@ -53,7 +53,8 @@ object PathUtils {
if (currentDownloadDirectory.listDirectoryEntries().isEmpty()) {
try {
Files.delete(currentDownloadDirectory)
} catch (ignored: Exception) {
} catch (e: Exception) {
e.printStackTrace()
}
}
} catch (e: IOException) {
@@ -0,0 +1,7 @@
package me.vripper.utilities
import kotlinx.coroutines.sync.Semaphore
object RequestLimit {
val semaphore: Semaphore = Semaphore(6)
}
@@ -42,6 +42,9 @@ message Rename {
int64 postId = 1;
string name = 2;
}
message RenameToFirst {
repeated int64 postIds = 1;
}
message PostSelection {
int64 threadId = 1;
string threadTitle = 2;
@@ -94,6 +97,7 @@ service EndpointService {
rpc remove (IdList) returns (EmptyResponse) {}
rpc clearCompleted (EmptyRequest) returns (IdList) {}
rpc rename (Rename) returns (EmptyResponse) {}
rpc renameToFirst (RenameToFirst) returns (EmptyResponse) {}
rpc onStopped (EmptyRequest) returns (stream Id) {}
rpc logClear (EmptyRequest) returns (EmptyResponse) {}
rpc findAllLogs (EmptyRequest) returns (Logs) {}
@@ -165,4 +165,8 @@
<column name="FILENAME" type="VARCHAR(260)" afterColumn="STATUS" defaultValue=""/>
</addColumn>
</changeSet>
<changeSet id="0009" author="vripper">
<addUniqueConstraint tableName="POST" columnNames="POST_ID" constraintName="POST__POST_ID_UQ"/>
<addUniqueConstraint tableName="THREAD" columnNames="THREAD_ID" constraintName="THREAD__THREAD_ID_UQ"/>
</changeSet>
</databaseChangeLog>
+25 -23
View File
@@ -1,28 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUT">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender class="ch.qos.logback.core.ConsoleAppender" name="STDOUT">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender class="ch.qos.logback.core.rolling.RollingFileAppender"
name="FILE">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</encoder>
<file>${VRIPPER_DIR}/vripper.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${VRIPPER_DIR}/vripper.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<appender class="ch.qos.logback.core.rolling.RollingFileAppender"
name="FILE">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</encoder>
<file>${VRIPPER_DIR}/vripper.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${VRIPPER_DIR}/vripper.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
<logger name="Exposed" level="OFF"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
@@ -131,6 +131,19 @@ class ActionBarView : View() {
postsTableView.renameSelected()
}
}
button("Bulk rename", FontIcon.of(Feather.EDIT_3)) {
contentDisplay = ContentDisplay.GRAPHIC_ONLY
tooltip("Bulk rename selected [Ctrl+Shift+R]")
shortcut(KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN))
enableWhen(
postsTableView.tableView.selectionModel.selectedItems.sizeProperty.greaterThan(
0
)
)
action {
postsTableView.bulkRenameSelected()
}
}
button("Delete", FontIcon.of(Feather.TRASH)) {
contentDisplay = ContentDisplay.GRAPHIC_ONLY
tooltip("Delete selected posts [Del]")
@@ -1,8 +1,10 @@
package me.vripper.gui.components.views
import javafx.collections.FXCollections
import javafx.scene.control.TabPane
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import me.vripper.delegate.LoggerDelegate
import me.vripper.gui.controller.PostController
@@ -110,7 +112,16 @@ class PostInfoView : View() {
return
}
coroutineScope.launch {
val model = async { postController.find(postId) }.await()
val model: PostModel? = async {
try {
postController.find(postId)
} catch (e: Exception) {
null
}
}.await()
if (model == null) {
return@launch
}
runLater {
postModel.apply {
this.postId = model.postId
@@ -136,6 +147,8 @@ class PostInfoView : View() {
postController.onUpdatePosts().catch {
logger.error("gRPC error", it)
currentCoroutineContext().cancel(null)
}.filter {
it.postId == postModel.postId
}.collect { post ->
runLater {
postModel.status = post.status.stringValue.lowercase().replaceFirstChar { it.uppercase() }
@@ -152,5 +165,19 @@ class PostInfoView : View() {
}
}
}.also { jobs.add(it) }
coroutineScope.launch {
postController.onUpdateMetadata().catch {
logger.error("gRPC error", it)
currentCoroutineContext().cancel(null)
}.filter {
it.postId == postModel.postId
}.collect {
runLater {
postModel.altTitles = FXCollections.observableArrayList(it.data.resolvedNames)
postModel.postedBy = it.data.postedBy
}
}
}.also { jobs.add(it) }
}
}
@@ -98,6 +98,13 @@ class PostsTableView : View() {
graphic = FontIcon.of(Feather.EDIT)
}
val bulkRenameItem = MenuItem("Bulk rename").apply {
setOnAction {
bulkRenameSelected()
}
graphic = FontIcon.of(Feather.EDIT_3)
}
val deleteItem = MenuItem("Delete").apply {
setOnAction {
deleteSelected()
@@ -122,7 +129,14 @@ class PostsTableView : View() {
val contextMenu = ContextMenu()
contextMenu.items.addAll(
startItem, stopItem, renameItem, deleteItem, SeparatorMenuItem(), locationItem, urlItem
startItem,
stopItem,
renameItem,
bulkRenameItem,
deleteItem,
SeparatorMenuItem(),
locationItem,
urlItem
)
tableRow.contextMenuProperty()
.bind(tableRow.emptyProperty().map { empty -> if (empty) null else contextMenu })
@@ -430,6 +444,13 @@ class PostsTableView : View() {
}
}
fun bulkRenameSelected() {
val selectedItems = tableView.selectionModel.selectedItems
coroutineScope.launch {
postController.renameToFirst(selectedItems.map { it.postId })
}
}
fun deleteSelected() {
val postIdList = tableView.selectionModel.selectedItems.map { it.postId }
confirm(
@@ -88,6 +88,10 @@ class PostController : Controller() {
appEndpointService.rename(postId, value)
}
suspend fun renameToFirst(postIds: List<Long>) {
appEndpointService.renameToFirst(postIds)
}
fun onNewPosts() =
appEndpointService.onNewPosts().catch {
logger.error("gRPC error", it)
@@ -58,6 +58,10 @@ class GrpcEndpointService : IAppEndpointService {
)
}
override suspend fun renameToFirst(postIds: List<Long>) {
endpointServiceCoroutineStub!!.renameToFirst(RenameToFirst.newBuilder().addAllPostIds(postIds).build())
}
override fun onNewPosts(): Flow<Post> =
endpointServiceCoroutineStub!!.onNewPosts(EmptyRequest.getDefaultInstance()).map { mapper(it) }
@@ -153,7 +157,6 @@ class GrpcEndpointService : IAppEndpointService {
override fun onDownloadSpeed(): Flow<Long> =
endpointServiceCoroutineStub!!.onDownloadSpeed(EmptyRequest.getDefaultInstance()).map { it.speed }
override fun onVGUserUpdate(): Flow<String> =
endpointServiceCoroutineStub!!.onVGUserUpdate(EmptyRequest.getDefaultInstance()).map { it.user }
@@ -170,7 +173,6 @@ class GrpcEndpointService : IAppEndpointService {
override suspend fun getSettings(): Settings =
mapper(endpointServiceCoroutineStub!!.getSettings(EmptyRequest.getDefaultInstance()))
override suspend fun saveSettings(settings: Settings) {
val viperSettings = with(SettingsOuterClass.ViperSettings.newBuilder()) {
login = settings.viperSettings.login
@@ -89,7 +89,7 @@ class Preview(owner: Stage, private val images: List<String>, private val cacheP
}
}
} catch (e: Exception) {
log.warn("Failed to load preview $url")
e.printStackTrace()
null
}
}
@@ -95,11 +95,16 @@ class GrpcServerAppEndpointService : EndpointServiceGrpcKt.EndpointServiceCorout
return IdList.newBuilder().addAllIds(appEndpointService.clearCompleted()).build()
}
override suspend fun rename(request: EndpointServiceOuterClass.Rename): EmptyResponse {
override suspend fun rename(request: Rename): EmptyResponse {
appEndpointService.rename(request.postId, request.name)
return EmptyResponse.getDefaultInstance()
}
override suspend fun renameToFirst(request: RenameToFirst): EmptyResponse {
appEndpointService.renameToFirst(request.postIdsList)
return EmptyResponse.getDefaultInstance()
}
override fun onStopped(request: EmptyRequest): Flow<Id> {
return appEndpointService.onStopped().map { Id.newBuilder().setId(it).build() }
}