Add hardcoded websearch url template strings for popular web searches that
do not implement the OpenSearch standard
This commit is contained in:
parent
75be571e53
commit
bf89134326
@ -0,0 +1,21 @@
|
|||||||
|
package de.mm20.launcher2.searchactions
|
||||||
|
|
||||||
|
import de.mm20.launcher2.searchactions.builders.WebsearchActionBuilder
|
||||||
|
|
||||||
|
fun knownWebsearchByHostname(hostname: String): WebsearchActionBuilder? {
|
||||||
|
// List of popular web search engines that do not implement the OpenSearch standard
|
||||||
|
return when(hostname) {
|
||||||
|
"google.com" -> WebsearchActionBuilder(label = "Google", urlTemplate = "https://google.com/search?q=\${1}")
|
||||||
|
"bing.com" -> WebsearchActionBuilder(label = "Google", urlTemplate = "https://bing.com/search?q=\${1}")
|
||||||
|
"amazon.com" -> WebsearchActionBuilder(label = "Amazon", urlTemplate = "https://www.amazon.com/s?k=\${1}")
|
||||||
|
"amazon.de" -> WebsearchActionBuilder(label = "Amazon DE", urlTemplate = "https://www.amazon.de/s?k=\${1}")
|
||||||
|
"amazon.co.uk" -> WebsearchActionBuilder(label = "Amazon UK", urlTemplate = "https://www.amazon.co.uk/s?k=\${1}")
|
||||||
|
"amazon.fr" -> WebsearchActionBuilder(label = "Amazon FR", urlTemplate = "https://www.amazon.fr/s?k=\${1}")
|
||||||
|
"amazon.co.jp" -> WebsearchActionBuilder(label = "Amazon JP", urlTemplate = "https://www.amazon.co.jp/s?k=\${1}")
|
||||||
|
"amazon.ca" -> WebsearchActionBuilder(label = "Amazon CA", urlTemplate = "https://www.amazon.ca/s?k=\${1}")
|
||||||
|
"amazon.cn" -> WebsearchActionBuilder(label = "Amazon CN", urlTemplate = "https://www.amazon.cn/s?k=\${1}")
|
||||||
|
"duckduckgo.com" -> WebsearchActionBuilder(label = "DuckDuckGo", urlTemplate = "https://duckduckgo.com/?q=\${1}")
|
||||||
|
"yahoo.com" -> WebsearchActionBuilder(label = "DuckDuckGo", urlTemplate = "https://search.yahoo.com/search?p=\${1}")
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -119,88 +119,18 @@ internal class SearchActionServiceImpl(
|
|||||||
.getOrNull(0)
|
.getOrNull(0)
|
||||||
?.absUrl("href")
|
?.absUrl("href")
|
||||||
?.takeIf { it.isNotEmpty() }
|
?.takeIf { it.isNotEmpty() }
|
||||||
?: return@withContext run {
|
|
||||||
Log.d("MM20", "Specified URL does not implement the OpenSearch protocol")
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val httpClient = OkHttpClient()
|
var action = openSearchHref?.let {
|
||||||
val request = Request.Builder()
|
importOpenSearch(it)
|
||||||
.url(openSearchHref)
|
|
||||||
.build()
|
|
||||||
val response = httpClient.newCall(request).execute()
|
|
||||||
val inputStream = response.body?.byteStream() ?: return@withContext null
|
|
||||||
|
|
||||||
var label: String? = null
|
|
||||||
var urlTemplate: String? = null
|
|
||||||
var icon: String? = null
|
|
||||||
var iconSize: Int = 0
|
|
||||||
var iconUrl: String? = null
|
|
||||||
|
|
||||||
inputStream.use {
|
|
||||||
val parser = Xml.newPullParser()
|
|
||||||
parser.setInput(inputStream.reader())
|
|
||||||
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (parser.eventType == XmlPullParser.START_TAG) {
|
|
||||||
when (parser.name) {
|
|
||||||
"ShortName" -> {
|
|
||||||
parser.next()
|
|
||||||
if (parser.eventType == XmlPullParser.TEXT) {
|
|
||||||
label = parser.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"LongName" -> {
|
|
||||||
parser.next()
|
|
||||||
if (parser.eventType == XmlPullParser.TEXT) {
|
|
||||||
if (label != null) label = parser.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Image" -> {
|
|
||||||
val size =
|
|
||||||
parser.getAttributeValue(null, "width")?.toIntOrNull() ?: 0
|
|
||||||
if (size > iconSize || iconUrl == null) {
|
|
||||||
parser.next()
|
|
||||||
if (parser.eventType == XmlPullParser.TEXT) {
|
|
||||||
iconUrl = parser.text
|
|
||||||
iconSize = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Url" -> {
|
|
||||||
if (parser.getAttributeValue(null, "type") == "text/html") {
|
|
||||||
val rel = parser.getAttributeValue(null, "rel")
|
|
||||||
if (rel == null || rel == "results") {
|
|
||||||
val template =
|
|
||||||
parser.getAttributeValue(null, "template")
|
|
||||||
?.takeIf { it.isNotEmpty() } ?: continue
|
|
||||||
urlTemplate = template
|
|
||||||
.replace("{searchTerms}", "\${1}")
|
|
||||||
.replace("{startPage?}", "1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val localIconUrl = iconUrl?.let {
|
|
||||||
val uri = Uri.parse(it)
|
|
||||||
createIcon(uri, iconSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
return@withContext WebsearchActionBuilder(
|
|
||||||
label = label ?: "",
|
|
||||||
icon = if (localIconUrl == null) SearchActionIcon.Search else SearchActionIcon.Custom,
|
|
||||||
customIcon = localIconUrl,
|
|
||||||
iconColor = if (localIconUrl == null) 0 else 1,
|
|
||||||
urlTemplate = urlTemplate ?: ""
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action != null) {
|
||||||
|
return@withContext action
|
||||||
|
}
|
||||||
|
|
||||||
|
val host = URL(u).host ?: return@withContext null
|
||||||
|
return@withContext knownWebsearchByHostname(host)
|
||||||
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
CrashReporter.logException(e)
|
CrashReporter.logException(e)
|
||||||
} catch (e: XmlPullParserException) {
|
} catch (e: XmlPullParserException) {
|
||||||
@ -209,6 +139,91 @@ internal class SearchActionServiceImpl(
|
|||||||
return@withContext null
|
return@withContext null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun importOpenSearch(openSearchHref: String): WebsearchActionBuilder? {
|
||||||
|
try {
|
||||||
|
val httpClient = OkHttpClient()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(openSearchHref)
|
||||||
|
.build()
|
||||||
|
val response = httpClient.newCall(request).execute()
|
||||||
|
val inputStream = response.body?.byteStream() ?: return null
|
||||||
|
|
||||||
|
var label: String? = null
|
||||||
|
var urlTemplate: String? = null
|
||||||
|
var icon: String? = null
|
||||||
|
var iconSize: Int = 0
|
||||||
|
var iconUrl: String? = null
|
||||||
|
|
||||||
|
inputStream.use {
|
||||||
|
val parser = Xml.newPullParser()
|
||||||
|
parser.setInput(inputStream.reader())
|
||||||
|
while (parser.next() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (parser.eventType == XmlPullParser.START_TAG) {
|
||||||
|
when (parser.name) {
|
||||||
|
"ShortName" -> {
|
||||||
|
parser.next()
|
||||||
|
if (parser.eventType == XmlPullParser.TEXT) {
|
||||||
|
label = parser.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"LongName" -> {
|
||||||
|
parser.next()
|
||||||
|
if (parser.eventType == XmlPullParser.TEXT) {
|
||||||
|
if (label != null) label = parser.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"Image" -> {
|
||||||
|
val size =
|
||||||
|
parser.getAttributeValue(null, "width")?.toIntOrNull() ?: 0
|
||||||
|
if (size > iconSize || iconUrl == null) {
|
||||||
|
parser.next()
|
||||||
|
if (parser.eventType == XmlPullParser.TEXT) {
|
||||||
|
iconUrl = parser.text
|
||||||
|
iconSize = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"Url" -> {
|
||||||
|
if (parser.getAttributeValue(null, "type") == "text/html") {
|
||||||
|
val rel = parser.getAttributeValue(null, "rel")
|
||||||
|
if (rel == null || rel == "results") {
|
||||||
|
val template =
|
||||||
|
parser.getAttributeValue(null, "template")
|
||||||
|
?.takeIf { it.isNotEmpty() } ?: continue
|
||||||
|
urlTemplate = template
|
||||||
|
.replace("{searchTerms}", "\${1}")
|
||||||
|
.replace("{startPage?}", "1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val localIconUrl = iconUrl?.let {
|
||||||
|
val uri = Uri.parse(it)
|
||||||
|
createIcon(uri, iconSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebsearchActionBuilder(
|
||||||
|
label = label ?: "",
|
||||||
|
icon = if (localIconUrl == null) SearchActionIcon.Search else SearchActionIcon.Custom,
|
||||||
|
customIcon = localIconUrl,
|
||||||
|
iconColor = if (localIconUrl == null) 0 else 1,
|
||||||
|
urlTemplate = urlTemplate ?: ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
|
||||||
|
} catch (e: XmlPullParserException) {}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun createIcon(uri: Uri, size: Int): String? = withContext(
|
override suspend fun createIcon(uri: Uri, size: Int): String? = withContext(
|
||||||
Dispatchers.IO
|
Dispatchers.IO
|
||||||
) {
|
) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user