majro update

This commit is contained in:
Fabian Freund
2025-02-28 14:30:49 +01:00
parent a8957f6cf8
commit 3c4d479bd9
181 changed files with 7090 additions and 5299 deletions
@@ -9,7 +9,9 @@
"version": "1.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"matches": [
"<all_urls>"
],
"js": [
"readability.min.js",
"content.js"
@@ -26,4 +28,4 @@
"webNavigation",
"<all_urls>"
]
}
}
@@ -0,0 +1,32 @@
const port = browser.runtime.connectNative("mozacTurndownHtml");
const parser = new DOMParser();
port.onMessage.addListener(message => {
let requestId = message["id"];
switch (message["action"]) {
case "turndown":
console.log(message.args)
// Handle array of HTML strings
if (Array.isArray(message.args)) {
const results = message.args.map(htmlString => {
const document = parser.parseFromString(htmlString, 'text/html');
return parseFullMarkdown(document);
});
port.postMessage({
"id": requestId,
"status": "success",
"result": results
});
} else {
// Handle error case for invalid input
port.postMessage({
"id": requestId,
"status": "error",
"error": "Expected args to be an array of HTML strings"
});
}
break;
}
});
@@ -0,0 +1,21 @@
{
"manifest_version": 2,
"browser_specific_settings": {
"gecko": {
"id": "turndown@movenext.me"
}
},
"name": "Converts html to markdown",
"version": "1.0",
"background": {
"scripts": [
"readability.min.js",
"background.js"
]
},
"permissions": [
"geckoViewAddons",
"nativeMessaging",
"<all_urls>"
]
}
@@ -0,0 +1 @@
../../../../../../javascript/readability/dist/readability.min.js
@@ -8,6 +8,7 @@ import android.content.Context
import eu.lensai.flutter_mozilla_components.feature.ContainerProxyFeature
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
import eu.lensai.flutter_mozilla_components.feature.PrefManagerFeature
import eu.lensai.flutter_mozilla_components.feature.TurndownFeature
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
import mozilla.components.concept.engine.DefaultSettings
@@ -52,6 +53,7 @@ object EngineProvider {
CookieManagerFeature.install(it)
PrefManagerFeature.install(it)
ContainerProxyFeature.install(it)
TurndownFeature.install(it)
}
}
@@ -18,6 +18,7 @@ import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerIm
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoSuggestionApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoTurndownApiImpl
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
@@ -38,6 +39,7 @@ import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTurndownApi
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
@@ -123,6 +125,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
))
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
GeckoDownloadsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoDownloadsApiImpl())
GeckoTurndownApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTurndownApiImpl())
ReaderViewEvents.setUp(
_flutterPluginBinding.binaryMessenger,
@@ -0,0 +1,53 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.feature.ResultConsumer
import eu.lensai.flutter_mozilla_components.feature.TurndownFeature
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTurndownApi
import org.json.JSONArray
import org.json.JSONObject
class GeckoTurndownApiImpl : GeckoTurndownApi {
private fun JSONObject.toMap(): Map<String, Any> {
val map = mutableMapOf<String, Any>()
val keys = this.keys()
while (keys.hasNext()) {
val key = keys.next()
when (val value = this.get(key)) {
is JSONObject -> map[key] = value.toMap()
is JSONArray -> map[key] = value.toList()
// JSONObject.NULL -> map[key] = null
else -> map[key] = value
}
}
return map
}
private fun JSONArray.toList(): List<Any> {
val list = mutableListOf<Any>()
for (i in 0 until this.length()) {
when (val value = this.get(i)) {
is JSONObject -> list.add(value.toMap())
is JSONArray -> list.add(value.toList())
JSONObject.NULL -> list.add(null as Any)
else -> list.add(value)
}
}
return list
}
override fun getMarkdown(htmlList: List<String>, callback: (Result<List<Any>>) -> Unit) {
TurndownFeature.scheduleRequest("turndown", htmlList, object :
ResultConsumer<JSONObject> {
override fun success(result: JSONObject) {
val resultArray = result.getJSONArray("result")
callback(Result.success(resultArray.toList()))
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
}
})
}
}
@@ -0,0 +1,104 @@
package eu.lensai.flutter_mozilla_components.feature
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import mozilla.components.concept.engine.webextension.MessageHandler
import mozilla.components.concept.engine.webextension.Port
import mozilla.components.concept.engine.webextension.WebExtensionRuntime
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.webextensions.WebExtensionController
import org.json.JSONArray
import org.json.JSONObject
object TurndownFeature {
private val logger = Logger("turndown")
private const val PREF_MANAGER_REPORTER_EXTENSION_ID = "turndown@movenext.me"
private const val PREF_MANAGER_REPORTER_EXTENSION_URL = "resource://android/assets/extensions/turndown/"
private const val PREF_MANAGER_REPORTER_MESSAGING_ID = "mozacTurndownHtml"
private var nextRequestId: Int = 0
private val requestHandlers = HashMap<Int, ResultConsumer<JSONObject>>()
private val mutex = Mutex()
@VisibleForTesting
// This is an internal var to make it mutable for unit testing purposes only
internal var extensionController = WebExtensionController(
PREF_MANAGER_REPORTER_EXTENSION_ID,
PREF_MANAGER_REPORTER_EXTENSION_URL,
PREF_MANAGER_REPORTER_MESSAGING_ID,
)
fun scheduleRequest(command: String, args: Any, callback: ResultConsumer<JSONObject>) {
val message = JSONObject()
message.put("action", command);
message.put("args", when (args) {
is List<*> -> JSONArray(args)
else -> args
})
runBlocking {
withContext(Dispatchers.Default) {
mutex.withLock {
message.put("id", nextRequestId)
requestHandlers[nextRequestId] = callback
nextRequestId += 1
extensionController.sendBackgroundMessage(message)
}
}
}
}
private class TurndownBackgroundMessageHandler() : MessageHandler {
override fun onPortMessage(message: Any, port: Port) {
runBlocking {
withContext(Dispatchers.Default) {
mutex.withLock {
val messageJSON = message as JSONObject;
val requestId = messageJSON.getInt("id")
val status = messageJSON.getString("status")
if (status == "success") {
requestHandlers[requestId]?.success(message)
} else {
requestHandlers[requestId]?.error(
"Pref Manager",
"Failed to perform operation",
message.getString("error")
)
}
}
}
}
}
}
/**
* Installs the web extension in the runtime through the WebExtensionRuntime install method
*
* @param runtime a WebExtensionRuntime.
* @param productName a custom product name used to automatically label reports. Defaults to
* "android-components".
*/
fun install(runtime: WebExtensionRuntime) {
extensionController.registerBackgroundMessageHandler(
TurndownBackgroundMessageHandler(),
)
extensionController.install(
runtime,
onSuccess = {
logger.debug("Installed Turndown webextension: ${it.id}")
},
onError = { throwable ->
logger.error("Failed to install Turndown webextension: ", throwable)
},
)
}
}
@@ -2980,6 +2980,42 @@ interface GeckoPrefApi {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoTurndownApi {
fun getMarkdown(htmlList: List<String>, callback: (Result<List<Any>>) -> Unit)
companion object {
/** The codec used by GeckoTurndownApi. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `GeckoTurndownApi` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoTurndownApi?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoTurndownApi.getMarkdown$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val htmlListArg = args[0] as List<String>
api.getMarkdown(htmlListArg) { result: Result<List<Any>> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoContainerProxyApi {
fun setProxyPort(port: Long)
fun addContainerProxy(contextId: String)