Improve Playwright handling (#479)

* Improve playwright

* Move DriverJar.java and Chromium.kt
This commit is contained in:
Mitchell Syer
2023-01-07 16:47:53 -05:00
committed by GitHub
parent ee8ec460a1
commit 4cf7512ee0
5 changed files with 98 additions and 25 deletions

View File

@@ -10,6 +10,7 @@ dex2jar = "v56"
rhino = "1.7.14" rhino = "1.7.14"
settings = "1.0.0-RC" settings = "1.0.0-RC"
twelvemonkeys = "3.9.4" twelvemonkeys = "3.9.4"
playwright = "1.28.0"
[libraries] [libraries]
# Kotlin # Kotlin
@@ -98,7 +99,7 @@ zip4j = "net.lingala.zip4j:zip4j:2.11.2"
junrar = "com.github.junrar:junrar:7.5.3" junrar = "com.github.junrar:junrar:7.5.3"
# CloudflareInterceptor # CloudflareInterceptor
playwright = "com.microsoft.playwright:playwright:1.28.0" playwright = { module = "com.microsoft.playwright:playwright", version.ref = "playwright" }
# AES/CBC/PKCS7Padding Cypher provider # AES/CBC/PKCS7Padding Cypher provider
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.72" bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.72"

View File

@@ -26,6 +26,8 @@ main() {
set -- "${POSITIONAL_ARGS[@]}" set -- "${POSITIONAL_ARGS[@]}"
OS="$1" OS="$1"
PLAYWRIGHT_VERSION="$(cat gradle/libs.versions.toml | grep -oP "playwright = \"\K([0-9\.]*)(?=\")")"
PLAYWRIGHT_REVISION="$(curl --silent "https://raw.githubusercontent.com/microsoft/playwright/v$PLAYWRIGHT_VERSION/packages/playwright-core/browsers.json" 2>&1 | grep -ozP "\"name\": \"chromium\",\n *\"revision\": \"\K[0-9]*")"
JAR="$(ls server/build/*.jar | tail -n1)" JAR="$(ls server/build/*.jar | tail -n1)"
RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS" RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS"
RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)" RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)"
@@ -57,6 +59,9 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="linux"
setup_playwright
RELEASE="$RELEASE_NAME.tar.gz" RELEASE="$RELEASE_NAME.tar.gz"
make_linux_bundle make_linux_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -70,6 +75,9 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_macos_bundle make_macos_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -83,6 +91,9 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="mac-arm64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_macos_bundle make_macos_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -96,6 +107,9 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_windows_bundle make_windows_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -113,6 +127,9 @@ main() {
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON" ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron download_jre_and_electron
PLAYWRIGHT_PLATFORM="win64"
setup_playwright
RELEASE="$RELEASE_NAME.zip" RELEASE="$RELEASE_NAME.zip"
make_windows_bundle make_windows_bundle
move_release_to_output_dir move_release_to_output_dir
@@ -268,6 +285,11 @@ make_windows_package() {
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" -o "$RELEASE" "$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" -o "$RELEASE"
} }
setup_playwright() {
mkdir "$RELEASE_NAME/bin"
curl -L "https://playwright.azureedge.net/builds/chromium/$PLAYWRIGHT_REVISION/chromium-$PLAYWRIGHT_PLATFORM.zip" -o "$RELEASE_NAME/bin/chromium.zip"
}
# Error handler # Error handler
# set -u: Treat unset variables as an error when substituting. # set -u: Treat unset variables as an error when substituting.
# set -o pipefail: Prevents errors in pipeline from being masked. # set -o pipefail: Prevents errors in pipeline from being masked.

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package eu.kanade.tachiyomi.network.interceptor; package suwayomi.tachidesk.server.util;
import com.microsoft.playwright.impl.driver.Driver; import com.microsoft.playwright.impl.driver.Driver;
@@ -26,22 +26,9 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/* /**
exact copy of https://github.com/microsoft/playwright-java/blob/4d278c391e3c50738ddea6c3e324a4bbbf719d86/driver-bundle/src/main/java/com/microsoft/playwright/impl/driver/jar/DriverJar.java * Copy of <a href="https://github.com/microsoft/playwright-java/blob/8c0231b0f739656e8a86bc58fca9ee778ddc571b/driver-bundle/src/main/java/com/microsoft/playwright/impl/driver/jar/DriverJar.java">DriverJar</a>
with diff: * with support for pre-installing chromium and only supports chromium playwright
108a109,116
>
> private FileSystem initFileSystem(URI uri) throws IOException {
> try {
> return FileSystems.newFileSystem(uri, Collections.emptyMap());
> } catch (FileSystemAlreadyExistsException e) {
> return null;
> }
> }
116c124
< try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? FileSystems.newFileSystem(uri, Collections.emptyMap()) : null) {
---
> try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
*/ */
public class DriverJar extends Driver { public class DriverJar extends Driver {
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD"; private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
@@ -99,12 +86,14 @@ public class DriverJar extends Driver {
logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set"); logMessage("Skipping browsers download because `SELENIUM_REMOTE_URL` env variable is set");
return; return;
} }
Chromium.preinstall(platformDir());
Path driver = driverPath(); Path driver = driverPath();
if (!Files.exists(driver)) { if (!Files.exists(driver)) {
throw new RuntimeException("Failed to find driver: " + driver); throw new RuntimeException("Failed to find driver: " + driver);
} }
ProcessBuilder pb = createProcessBuilder(); ProcessBuilder pb = createProcessBuilder();
pb.command().add("install"); pb.command().add("install");
pb.command().add("chromium");
pb.redirectError(ProcessBuilder.Redirect.INHERIT); pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = pb.start(); Process p = pb.start();
@@ -123,7 +112,6 @@ public class DriverJar extends Driver {
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains("."); return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
} }
private FileSystem initFileSystem(URI uri) throws IOException { private FileSystem initFileSystem(URI uri) throws IOException {
try { try {
return FileSystems.newFileSystem(uri, Collections.emptyMap()); return FileSystems.newFileSystem(uri, Collections.emptyMap());
@@ -131,10 +119,14 @@ public class DriverJar extends Driver {
return null; return null;
} }
} }
void extractDriverToTempDir() throws URISyntaxException, IOException {
public static URI getDriverResourceURI() throws URISyntaxException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader(); ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URI originalUri = classloader.getResource( return classloader.getResource("driver/" + platformDir()).toURI();
"driver/" + platformDir()).toURI(); }
void extractDriverToTempDir() throws URISyntaxException, IOException {
URI originalUri = getDriverResourceURI();
URI uri = maybeExtractNestedJar(originalUri); URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar. // Create zip filesystem if loading from jar.

View File

@@ -72,7 +72,7 @@ object CFClearance {
init { init {
// Fix the default DriverJar issue by providing our own implementation // Fix the default DriverJar issue by providing our own implementation
// ref: https://github.com/microsoft/playwright-java/issues/1138 // ref: https://github.com/microsoft/playwright-java/issues/1138
System.setProperty("playwright.driver.impl", "eu.kanade.tachiyomi.network.interceptor.DriverJar") System.setProperty("playwright.driver.impl", "suwayomi.tachidesk.server.util.DriverJar")
} }
fun resolveWithWebView(originalRequest: Request): Request { fun resolveWithWebView(originalRequest: Request): Request {

View File

@@ -0,0 +1,58 @@
package suwayomi.tachidesk.server.util
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import net.harawata.appdirs.AppDirsFactory
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import kotlin.io.path.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import kotlin.io.path.notExists
import kotlin.streams.asSequence
object Chromium {
@OptIn(ExperimentalSerializationApi::class)
@JvmStatic
fun preinstall(platformDir: String) {
val loader = Thread.currentThread().contextClassLoader
val resource = loader.getResource("driver/$platformDir/package/browsers.json") ?: return
val json = resource.openStream().use {
Json.decodeFromStream<JsonObject>(it)
}
val revision = json["browsers"]?.jsonArray
?.find { it.jsonObject["name"]?.jsonPrimitive?.contentOrNull == "chromium" }
?.jsonObject
?.get("revision")
?.jsonPrimitive
?.contentOrNull
?: return
val playwrightDir = AppDirsFactory.getInstance().getUserDataDir("ms-playwright", null, null)
val chromiumZip = Path(".").resolve("bin/chromium.zip")
val chromePath = Path(playwrightDir).resolve("chromium-$revision")
if (chromePath.exists() || chromiumZip.notExists()) return
chromePath.createDirectories()
FileSystems.newFileSystem(chromiumZip, null).use {
val src = it.getPath("/")
Files.walk(src)
.asSequence()
.forEach { source ->
Files.copy(
source,
chromePath.resolve(source.absolutePathString().removePrefix("/")),
StandardCopyOption.REPLACE_EXISTING
)
}
}
}
}