173 lines
5.6 KiB
Kotlin
173 lines
5.6 KiB
Kotlin
import java.io.OutputStreamWriter
|
|
import java.net.URL
|
|
import java.net.HttpURLConnection
|
|
import java.time.LocalDate
|
|
|
|
// We can't import libraries here for some reason, so we must use what is provided
|
|
// by gradle, which isn't much. The groovy JSON library is meant for use by groovy code,
|
|
// so we need some creativity to use it in Kotlin.
|
|
import org.apache.groovy.json.internal.LazyMap
|
|
import groovy.json.JsonOutput
|
|
import groovy.json.JsonSlurper
|
|
|
|
// Run this as `./gradlew app:updateInstances`
|
|
tasks.register<UpdateInstancesTask>("updateInstances") {
|
|
description = "Fetches a list of popular Lemmy instances and writes it to the DefaultInstances.kt file"
|
|
|
|
// All lemmy instances with at least this amount of monthly active users will be included.
|
|
minimumMAU.set(50)
|
|
|
|
endpointUrl.set("https://api.fediverse.observer/")
|
|
instancesFile.set(file("src/main/java/com/jerboa/DefaultInstances.kt"))
|
|
manifestFile.set(file("src/main/AndroidManifest.xml"))
|
|
nsfwList.set(listOf("lemmynsfw.com"))
|
|
}
|
|
|
|
@UntrackedTask(because = "Output depends on api response")
|
|
abstract class UpdateInstancesTask: DefaultTask() {
|
|
private companion object {
|
|
const val START_TAG = "<!--#AUTO_GEN_INSTANCE_LIST_DO_NOT_TOUCH#-->"
|
|
const val END_TAG = "<!--#INSTANCE_LIST_END#-->"
|
|
const val INDENT = 14
|
|
}
|
|
|
|
@get:Input
|
|
abstract val minimumMAU: Property<Int>
|
|
@get:Input
|
|
abstract val endpointUrl: Property<String>
|
|
@get:Input
|
|
abstract val nsfwList: ListProperty<String>
|
|
|
|
@get:OutputFile
|
|
abstract val instancesFile: RegularFileProperty
|
|
@get:OutputFile
|
|
abstract val manifestFile: RegularFileProperty
|
|
|
|
// Some extension methods to make the JsonSlurper output easier to process
|
|
fun LazyMap.getMap(key: String): LazyMap {
|
|
return this[key] as LazyMap
|
|
}
|
|
|
|
fun LazyMap.getArray(key: String): ArrayList<*> {
|
|
return this[key] as ArrayList<*>
|
|
}
|
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
fun <T> LazyMap.getAs(key: String): T {
|
|
return this[key] as T
|
|
}
|
|
|
|
@TaskAction
|
|
fun action() {
|
|
// Get sorted list of nodes
|
|
val nodes = getData()
|
|
.getMap("data")
|
|
.getArray("nodes")
|
|
.map {
|
|
val name = (it as LazyMap)["domain"] as String
|
|
val users = it["active_users_monthly"] as Int?
|
|
|
|
Pair(name, users ?: 0)
|
|
}
|
|
.filter {
|
|
it.second >= minimumMAU.get() && !nsfwList.get().contains(it.first)
|
|
}
|
|
.sortedBy {
|
|
it.second
|
|
}
|
|
.reversed()
|
|
|
|
updateInstanceList(nodes)
|
|
updateManifest(nodes.map { it.first })
|
|
}
|
|
|
|
|
|
private fun getData(): LazyMap {
|
|
val url = URL(endpointUrl.get())
|
|
val query = """
|
|
{
|
|
nodes(softwarename: "lemmy") {
|
|
domain
|
|
active_users_monthly
|
|
}
|
|
}""".trimIndent()
|
|
|
|
// Format JSON request body
|
|
val body = JsonOutput.toJson(mapOf("query" to query))
|
|
|
|
// Create POST request
|
|
val req = url.openConnection() as HttpURLConnection
|
|
req.requestMethod = "POST"
|
|
req.doOutput = true
|
|
req.setRequestProperty("Content-Type", "application/json")
|
|
|
|
// Write body to request
|
|
OutputStreamWriter(req.outputStream, "UTF-8").use {
|
|
it.write(body)
|
|
}
|
|
|
|
// Get response and JSON parse it
|
|
return JsonSlurper().parse(req.inputStream.reader()) as LazyMap
|
|
}
|
|
|
|
fun updateInstanceList(nodes: List<Pair<String, Int>>) {
|
|
// Create output file and write header
|
|
val outFile = instancesFile.get().asFile
|
|
outFile.writeText("""
|
|
/***********************************************
|
|
* WARNING: AUTO-GENERATED FILE *
|
|
***********************************************/
|
|
|
|
// The following file is automatically generated by the script "update_instance_gradle.kts".
|
|
// Caution: Manual modifications to this file may be overwritten without notice.
|
|
// It is recommended to make changes to the code section responsible for the generation.
|
|
|
|
// Date of Auto-generation: ${LocalDate.now()}
|
|
|
|
package com.jerboa
|
|
|
|
val DEFAULT_LEMMY_INSTANCES = setOf(
|
|
|
|
""".trimIndent()
|
|
)
|
|
|
|
// Write each node's name, one per line
|
|
for (n in nodes) {
|
|
outFile.appendText(" \"${n.first}\", // ${n.second} monthly users\n")
|
|
}
|
|
|
|
outFile.appendText(")\n")
|
|
}
|
|
|
|
|
|
fun updateManifest(list: List<String>) {
|
|
val manifest = manifestFile.get().asFile
|
|
val lines = manifest.readLines()
|
|
manifest.writeText("")
|
|
|
|
var skip = false
|
|
|
|
for (line in lines) {
|
|
if (line.trim() == START_TAG) {
|
|
skip = true
|
|
manifest.appendText(" ".repeat(INDENT) + START_TAG)
|
|
manifest.appendText(genManifestHosts(list))
|
|
manifest.appendText(" ".repeat(INDENT) + END_TAG + System.lineSeparator())
|
|
} else if (line.trim() == END_TAG) {
|
|
skip = false
|
|
} else if (!skip) {
|
|
manifest.appendText(line + System.lineSeparator())
|
|
}
|
|
}
|
|
}
|
|
|
|
fun genManifestHosts(list: List<String>): String {
|
|
return list.joinToString(
|
|
separator = System.lineSeparator(),
|
|
prefix = System.lineSeparator(),
|
|
postfix = System.lineSeparator(),
|
|
) { " ".repeat(INDENT) + "<data android:host=\"$it\" />" }
|
|
}
|
|
}
|
|
|