From 8ad60fa6b7b0a18ecab8d5fe1e2499c7abd675e2 Mon Sep 17 00:00:00 2001 From: Stef Tervelde Date: Wed, 29 Jan 2025 18:22:19 +0100 Subject: [PATCH] Added support for Base64 encoded extra files --- SCHEMA.md | 33 ++++++++++------ app/src/processing/app/Schema.kt | 67 ++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/SCHEMA.md b/SCHEMA.md index 53d5ba8b6..23244be7f 100644 --- a/SCHEMA.md +++ b/SCHEMA.md @@ -4,6 +4,7 @@ ``` pde:///path/to/sketch.pde ``` +Attention: The 3rd slash is import to trigger local files. ## Sketch Operations @@ -17,27 +18,37 @@ pde://sketch/new pde://sketch/base64/ ``` Optional query parameters: -- `data`: Comma-separated URLs of data files to download -- `code`: Comma-separated URLs of code files to download -- `pde`: Comma-separated URLs of Processing sketch files to download -- `mode`: Processing mode identifier +- `data`: Comma-separated {File} that should be placed in the data folder +- `code`: Comma-separated {File} that should be placed in the code folder +- `pde`: Comma-separated {File} that should be placed in the sketch folder +- `mode`: Processing mode identifier, e.g. `processing.mode.android.AndroidMode` You can find this in the sketch.properties file when switching modes on a sketch ### Load Sketch from URL + ``` -pde://sketch/url/domain.com/path/to/sketch.pde +pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/Array/Array.pde ``` +[Click to here to test](pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Arrays/Array/Array.pde) + Supports the same query parameters as base64 endpoint. Optional query parameters: - -- `data`: Comma-separated URLs of data files to download -- `code`: Comma-separated URLs of code files to download -- `pde`: Comma-separated URLs of Processing sketch files to download -- `mode`: Processing mode identifier +- `data`: Comma-separated {File} that should be placed in the data folder +- `code`: Comma-separated {File} that should be placed in the code folder +- `pde`: Comma-separated {File} that should be placed in the sketch folder +- `mode`: Processing mode identifier, e.g. `processing.mode.android.AndroidMode` You can find this in the sketch.properties file when switching modes on a sketch Example with query parameters: + ``` -pde://sketch/url/example.com/sketch.pde?data=image1.png,sound1.mp3&mode=java +pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Image/Alphamask/Alphamask.pde?data=data/moonwalk.jpg,data/mask.jpg,processing.org/img/processing-web.png ``` +[Click to here to test](pde://sketch/url/github.com/processing/processing-examples/raw/refs/heads/main/Basics/Image/Alphamask/Alphamask.pde?data=data/moonwalk.jpg,data/mask.jpg,processing.org/img/processing-web.png) + +#### A {File} +A {File} is a string that represents a file in the sketch and has a couple of options, it always starts with the filename followed by a colon, e.g. `file.pde:example.com/path/to/file.pde`. The following options are available: +- `example.com/path/to/file.pde`: A remote file that should be downloaded +- `file.pde`: A remote file that should be downloaded with a path relative to the sketch (only available in loading the sketch from url) +- a base64 encoded file: A base64 encoded file ## Preferences ``` diff --git a/app/src/processing/app/Schema.kt b/app/src/processing/app/Schema.kt index 148a8747c..8ea12e7f6 100644 --- a/app/src/processing/app/Schema.kt +++ b/app/src/processing/app/Schema.kt @@ -7,6 +7,7 @@ import java.net.URI import java.net.URL import java.net.URLDecoder import java.nio.charset.StandardCharsets +import java.util.* class Schema { @@ -44,7 +45,7 @@ class Schema { tempSketchFolder.mkdirs() val tempSketchFile = File(tempSketchFolder, "${tempSketchFolder.name}.pde") val sketchB64 = uri.path.replace("/base64/", "") - val sketch = java.util.Base64.getDecoder().decode(sketchB64) + val sketch = Base64.getDecoder().decode(sketchB64) tempSketchFile.writeBytes(sketch) handleSketchOptions(uri, tempSketchFolder) return base?.handleOpenUntitled(tempSketchFile.absolutePath) @@ -73,7 +74,6 @@ class Schema { URLDecoder.decode(it[1], StandardCharsets.UTF_8) } ?: emptyMap() - options["data"]?.let{ data -> downloadFiles(uri, data, File(sketchFolder, "data")) } @@ -89,31 +89,56 @@ class Schema { } } - private fun downloadFiles(uri: URI, urlList: String, sketchFolder: File){ + private fun downloadFiles(uri: URI, urlList: String, targetFolder: File){ Thread{ - val base = uri.path.split("/").drop(2).dropLast(1).joinToString("/") + targetFolder.mkdirs() + + val base = uri.path.split("/") + .drop(2) // drop the /sketch/base64/ or /sketch/url/ etc... + .dropLast(1) // drop the file name + .joinToString("/") + val files = urlList.split(",") - .map { - val fileUrl = URI.create(it) - if(fileUrl.host == null){ - return@map "https://$base/$it" - } - if(fileUrl.scheme == null){ - return@map "https://$it" + + files.filter { it.isNotBlank() } + .map{ it.split(":", limit = 2) } + .map{ segments -> + if(segments.size == 2){ + if(segments[0].isBlank()){ + return@map listOf(null, segments[1]) + } + return@map segments } - return@map it + return@map listOf(null, segments[0]) } - sketchFolder.mkdirs() - for(file in files){ - val url = URL(file) - val name = url.path.split("/").last() - val dataFile = File(sketchFolder, name) - URL(file).openStream().use { input -> - FileOutputStream(dataFile).use { output -> - input.copyTo(output) + .forEach { (name, content) -> + try{ + // Try to decode the content as base64 + val file = Base64.getDecoder().decode(content) + if(name == null){ + Messages.err("Base64 files needs to start with a file name followed by a colon") + return@forEach + } + File(targetFolder, name).writeBytes(file) + }catch(_: IllegalArgumentException){ + // Assume it's a URL and download it + var url = URI.create(content) + if(url.host == null){ + url = URI.create("https://$base/$content") + } + if(url.scheme == null){ + url = URI.create("https://$content") + } + + val target = File(targetFolder, name ?: url.path.split("/").last()) + url.toURL().openStream().use { input -> + target.outputStream().use { output -> + input.copyTo(output) + } + } } + } - } }.start() }