majro update
This commit is contained in:
+4
-2
@@ -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>"
|
||||
]
|
||||
}
|
||||
}
|
||||
+32
@@ -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;
|
||||
}
|
||||
});
|
||||
+21
@@ -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>"
|
||||
]
|
||||
}
|
||||
Vendored
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../../../../../javascript/readability/dist/readability.min.js
|
||||
+2
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -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,
|
||||
|
||||
+53
@@ -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")))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+104
@@ -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)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
+36
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user