mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 03:14:40 -05:00
Browser Webview (#1486)
* WebView: Add initial controller Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com> * WebView: Prepare page * WebView: Basic HTML setup * WebView: Improve navigation * WebView: Refactor message class deserialization * WebView: Refactor event message serialization * WebView: Handle click events * WebView: Fix events after refactor * WebView: Fix normalizing of URLs * WebView: HTML remove navigation buttons * WebView: Handle more events * WebView: Handle document change in events * WebView: Refactor to send mutation events * WebView: More mouse events * WebView: Include bubbles, cancelable in event Those seem to be important * WebView: Attempt to support nested iframe * WebView: Handle long titles * WebView: Avoid setting invalid url * WebView: Send mousemove * WebView: Start switch to canvas-based render * WebView: Send on every render * WebView: Dynamic size * WebView: Keyboard events * WebView: Handle mouse events in CEF This is important because JS can't click into iFrames, meaning the previous solution doesn't work for captchas * WebView: Cleanup * WebView: Cleanup 2 * WebView: Document title * WebView: Also send title on address change * WebView: Load and flush cookies from store * WebView: remove outdated TODOs * Offline WebView: Load cookies from store * Cleanup * Add KcefCookieManager, need to figure out how to inject it * ktLintFormat * Fix a few cookie bugs * Fix Webview on Windows * Minor cleanup * WebView: Remove /tmp image write, lint * Remove custom cookie manager * Multiple cookie fixes * Minor fix * Minor cleanup and add support for MacOS meta key * Get enter working * WebView HTML: Make responsive for mobile pages * WebView: Translate touch events to mouse scroll * WebView: Overlay an actual input to allow typing on mobile Browsers will only show the keyboard if an input is focused. This also removes the `tabstop` hack. * WebView: Protect against occasional NullPointerException * WebView: Use float for clientX/Y * WebView: Fix ChromeAndroid being a pain * Simplify enter fix * NetworkHelper: Fix cache * Improve CookieStore url matching, fix another cookie conversion issue * Move distinctBy * WebView: Mouse direction toggle * Remove accidentally copied comment --------- Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This commit is contained in:
105
server/src/main/kotlin/suwayomi/tachidesk/global/impl/WebView.kt
Normal file
105
server/src/main/kotlin/suwayomi/tachidesk/global/impl/WebView.kt
Normal file
@@ -0,0 +1,105 @@
|
||||
package suwayomi.tachidesk.global.impl
|
||||
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import io.javalin.websocket.WsContext
|
||||
import io.javalin.websocket.WsMessageContext
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.eclipse.jetty.websocket.api.CloseStatus
|
||||
import suwayomi.tachidesk.manga.impl.update.Websocket
|
||||
|
||||
object WebView : Websocket<String>() {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private var driver: KcefWebView? = null
|
||||
|
||||
override fun addClient(ctx: WsContext) {
|
||||
if (clients.isNotEmpty()) {
|
||||
// TODO: allow multiple concurrent accesses?
|
||||
clients.forEach { it.value.closeSession(CloseStatus(1001, "Other client connected")) }
|
||||
clients.clear()
|
||||
}
|
||||
if (driver == null) {
|
||||
driver = KcefWebView()
|
||||
}
|
||||
super.addClient(ctx)
|
||||
ctx.enableAutomaticPings()
|
||||
}
|
||||
|
||||
override fun removeClient(ctx: WsContext) {
|
||||
super.removeClient(ctx)
|
||||
if (clients.isEmpty()) {
|
||||
driver?.destroy()
|
||||
driver = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun notifyClient(
|
||||
ctx: WsContext,
|
||||
value: String?,
|
||||
) {
|
||||
if (value != null) {
|
||||
ctx.send(value)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable public sealed class TypeObject
|
||||
|
||||
@Serializable
|
||||
@SerialName("loadUrl")
|
||||
private data class LoadUrlMessage(
|
||||
val url: String,
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
) : TypeObject()
|
||||
|
||||
@Serializable
|
||||
@SerialName("resize")
|
||||
private data class ResizeMessage(
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
) : TypeObject()
|
||||
|
||||
@Serializable
|
||||
@SerialName("event")
|
||||
public data class JsEventMessage(
|
||||
val eventType: String,
|
||||
val clickX: Float,
|
||||
val clickY: Float,
|
||||
val button: Int? = null,
|
||||
val ctrlKey: Boolean? = null,
|
||||
val shiftKey: Boolean? = null,
|
||||
val altKey: Boolean? = null,
|
||||
val metaKey: Boolean? = null,
|
||||
val key: String? = null,
|
||||
val code: String? = null,
|
||||
val clientX: Float? = null,
|
||||
val clientY: Float? = null,
|
||||
val deltaY: Float? = null,
|
||||
) : TypeObject()
|
||||
|
||||
override fun handleRequest(ctx: WsMessageContext) {
|
||||
val dr = driver ?: return
|
||||
try {
|
||||
val event = Json.decodeFromString<TypeObject>(ctx.message())
|
||||
when (event) {
|
||||
is LoadUrlMessage -> {
|
||||
val url = event.url
|
||||
dr.loadUrl(url)
|
||||
dr.resize(event.width, event.height)
|
||||
logger.info { "Loading URL $url" }
|
||||
}
|
||||
is ResizeMessage -> {
|
||||
dr.resize(event.width, event.height)
|
||||
logger.info { "Resize browser" }
|
||||
}
|
||||
is JsEventMessage -> {
|
||||
val type = event.eventType
|
||||
dr.event(event)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Failed to deserialize client request: ${ctx.message()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user