mirror of
https://github.com/Kurocon/projectivy-booru-wallpaper-provider.git
synced 2025-07-21 16:28:27 +02:00
Add support for Moebooru-, Gelbooru- and Zerochan-based imageboards, and Wallhaven. Restructure how board type preference is saved. Restructure README.
This commit is contained in:
parent
291307b121
commit
799151a720
6 changed files with 412 additions and 39 deletions
|
@ -13,8 +13,8 @@ android {
|
|||
applicationId = "nl.kurocon.plugin.wallpaperprovider.booru"
|
||||
minSdk = 23
|
||||
targetSdk = 35
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
versionCode = 2
|
||||
versionName = "1.1"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +1,63 @@
|
|||
package nl.kurocon.plugin.wallpaperprovider.booru
|
||||
|
||||
import android.content.Context
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.DANBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.GELBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.MOEBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.WALLHAVEN
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.ZEROCHAN
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.net.URLEncoder
|
||||
|
||||
class BooruAPI(context: Context) {
|
||||
private val client = OkHttpClient()
|
||||
private var booruPluginUserAgent = "ProjectivyBooruWallpaperPlugin"
|
||||
|
||||
init {
|
||||
PreferencesManager.init(context)
|
||||
val pluginName = context.getString(R.string.plugin_name)
|
||||
val pluginVersion = context.getString(R.string.plugin_version)
|
||||
booruPluginUserAgent = "$pluginName/$pluginVersion"
|
||||
}
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
return when (PreferencesManager.booruType) {
|
||||
"danbooru" -> getDanbooruImageUrls(limit = limit)
|
||||
DANBOORU -> getDanbooruImageUrls(limit = limit)
|
||||
GELBOORU -> getGelbooruImageUrls(limit = limit)
|
||||
MOEBOORU -> getMoebooruImageUrls(limit = limit)
|
||||
ZEROCHAN -> getZerochanImageUrls(limit = limit)
|
||||
WALLHAVEN -> getWallhavenImageUrls(limit = limit)
|
||||
else -> getDanbooruImageUrls(limit = limit)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRequestBuilder(url: String, addAuth: Boolean = false): Request.Builder {
|
||||
// Add default headers (User-Agent) and set URL
|
||||
var builder = Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("User-Agent", booruPluginUserAgent)
|
||||
if (addAuth && (PreferencesManager.booruUserId.isNotEmpty() && PreferencesManager.booruApiKey.isNotEmpty())) {
|
||||
builder = builder.addHeader(
|
||||
"Authorization",
|
||||
okhttp3.Credentials.basic(PreferencesManager.booruUserId, PreferencesManager.booruApiKey)
|
||||
)
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getDanbooruImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
val tags = PreferencesManager.booruTagSearch
|
||||
val encodedTags = URLEncoder.encode(tags, "UTF-8")
|
||||
val url = "${PreferencesManager.booruUrl}/posts.json?tags=$encodedTags&limit=$limit"
|
||||
var requestBuilder = Request.Builder()
|
||||
.url(url)
|
||||
if (PreferencesManager.booruUserId.isNotEmpty() && PreferencesManager.booruApiKey.isNotEmpty()) {
|
||||
requestBuilder = requestBuilder.addHeader("Authorization", okhttp3.Credentials.basic(PreferencesManager.booruUserId, PreferencesManager.booruApiKey))
|
||||
}
|
||||
val request = requestBuilder.build()
|
||||
val request = getRequestBuilder(url, addAuth=true).build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
|
@ -44,7 +68,7 @@ class BooruAPI(context: Context) {
|
|||
if (errorMessage.isNotEmpty()) {
|
||||
throw IOException("Error ${response.code}. $errorMessage")
|
||||
}
|
||||
throw IOException("Unexpected code ${response.code} - ${response.body}")
|
||||
throw IOException("Error ${response.code} - ${response.body}")
|
||||
}
|
||||
|
||||
val responseBody = response.body?.string() ?: throw IOException("Response body is null")
|
||||
|
@ -65,6 +89,222 @@ class BooruAPI(context: Context) {
|
|||
return images
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getMoebooruImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
val tags = PreferencesManager.booruTagSearch
|
||||
val encodedTags = URLEncoder.encode(tags, "UTF-8")
|
||||
var url = "${PreferencesManager.booruUrl}/post.json?tags=$encodedTags&limit=$limit"
|
||||
if (PreferencesManager.booruUserId.isNotEmpty() && PreferencesManager.booruApiKey.isNotEmpty()) {
|
||||
val encUsername = URLEncoder.encode(PreferencesManager.booruUserId, "UTF-8")
|
||||
val encApiKey = URLEncoder.encode(PreferencesManager.booruApiKey, "UTF-8")
|
||||
url = "$url&login=$encUsername&password_hash=$encApiKey"
|
||||
}
|
||||
val request = getRequestBuilder(url).build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// Try to parse error message from body
|
||||
val responseBody = response.body?.string() ?: throw IOException("Unexpected code ${response.code}, and response body is empty")
|
||||
val jsonBody = JSONObject(responseBody)
|
||||
val errorMessage = jsonBody.optString("message")
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
throw IOException("Error ${response.code}. $errorMessage")
|
||||
}
|
||||
throw IOException("Error ${response.code} - ${response.body}")
|
||||
}
|
||||
|
||||
val responseBody = response.body?.string() ?: throw IOException("Response body is null")
|
||||
val jsonArray = JSONArray(responseBody)
|
||||
|
||||
// Parse JSON response into BooruImage instances
|
||||
val images = mutableListOf<BooruImage>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val jsonObject = jsonArray.getJSONObject(i)
|
||||
val imageUrl = jsonObject.optString("file_url")
|
||||
val title = jsonObject.optString("tag_string")
|
||||
val author = jsonObject.optString("tag_string_artist")
|
||||
val sourceUri = jsonObject.optString("source")
|
||||
if (imageUrl.isNotEmpty()) {
|
||||
images.add(BooruImage(imageUrl, title, author, sourceUri))
|
||||
}
|
||||
}
|
||||
return images
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getGelbooruImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
val tags = PreferencesManager.booruTagSearch
|
||||
val encodedTags = URLEncoder.encode(tags, "UTF-8")
|
||||
var url = "${PreferencesManager.booruUrl}/index.php?page=dapi&s=post&q=index&tags=$encodedTags&limit=$limit&json=1"
|
||||
if (PreferencesManager.booruUserId.isNotEmpty() && PreferencesManager.booruApiKey.isNotEmpty()) {
|
||||
val encUsername = URLEncoder.encode(PreferencesManager.booruUserId, "UTF-8")
|
||||
val encApiKey = URLEncoder.encode(PreferencesManager.booruApiKey, "UTF-8")
|
||||
url = "$url&api_key=$encApiKey&user_id=$encUsername"
|
||||
}
|
||||
val request = getRequestBuilder(url).build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// Try to parse error message from body
|
||||
val responseBody = response.body?.string() ?: throw IOException("Unexpected code ${response.code}, and response body is empty")
|
||||
val jsonBody = JSONObject(responseBody)
|
||||
val errorMessage = jsonBody.optString("message")
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
throw IOException("Error ${response.code}. $errorMessage")
|
||||
}
|
||||
throw IOException("Error ${response.code} - ${response.body}")
|
||||
}
|
||||
|
||||
val responseBody = response.body?.string() ?: throw IOException("Response body is null")
|
||||
val jsonBody: JSONObject
|
||||
try {
|
||||
jsonBody = JSONObject(responseBody)
|
||||
} catch (e: Exception) {
|
||||
// gelbooru returns xml response if request was denied for some reason
|
||||
// i.e. user hit a rate limit because he didn't include api key
|
||||
throw IOException("Error. Unexpected response. You might be rate limited.")
|
||||
}
|
||||
|
||||
// Parse JSON response into BooruImage instances
|
||||
val images = mutableListOf<BooruImage>()
|
||||
val jsonArray = jsonBody.getJSONArray("post")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val jsonObject = jsonArray.getJSONObject(i)
|
||||
val imageUrl = jsonObject.optString("file_url")
|
||||
val title = jsonObject.optString("tags")
|
||||
// Gelbooru does not have an easily accessible Artist tag. Link to the source in a best-effort way.
|
||||
val author = jsonObject.optString("source")
|
||||
val sourceUri = jsonObject.optString("source")
|
||||
if (imageUrl.isNotEmpty()) {
|
||||
images.add(BooruImage(imageUrl, title, author, sourceUri))
|
||||
}
|
||||
}
|
||||
return images
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getZerochanImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
val tags = PreferencesManager.booruTagSearch
|
||||
val encodedTags = URLEncoder.encode(tags, "UTF-8")
|
||||
val url = "${PreferencesManager.booruUrl}/$encodedTags?json&l=$limit"
|
||||
var requestBuilder = getRequestBuilder(url)
|
||||
// Zerochan has no authentication, but asks to put the username in the User-Agent string.
|
||||
// This header is already added by the `getRequestBuilder`, so need to override it.
|
||||
if (PreferencesManager.booruUserId.isNotEmpty()) {
|
||||
requestBuilder = requestBuilder.header(
|
||||
"User-Agent", "$booruPluginUserAgent - ${PreferencesManager.booruUserId}"
|
||||
)
|
||||
}
|
||||
val request = requestBuilder.build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// Try to parse error message from body
|
||||
val responseBody = response.body?.string() ?: throw IOException("Unexpected code ${response.code}, and response body is empty")
|
||||
val jsonBody = JSONObject(responseBody)
|
||||
val errorMessage = jsonBody.optString("message")
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
throw IOException("Error ${response.code}. $errorMessage")
|
||||
}
|
||||
throw IOException("Error ${response.code} - ${response.body}")
|
||||
}
|
||||
|
||||
val responseBody = response.body?.string() ?: throw IOException("Response body is null")
|
||||
val jsonArray = JSONObject(responseBody).getJSONArray("items")
|
||||
|
||||
// Parse JSON response into BooruImage instances
|
||||
val images = mutableListOf<BooruImage>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val jsonObject = jsonArray.getJSONObject(i)
|
||||
val imageId = jsonObject.optInt("id")
|
||||
if (imageId != 0) {
|
||||
// Do a second request for the complete image information, because
|
||||
// zerochan does not include the full image link in the list results...
|
||||
var requestBuilder2 =
|
||||
getRequestBuilder("${PreferencesManager.booruUrl}/$imageId?json")
|
||||
if (PreferencesManager.booruUserId.isNotEmpty()) {
|
||||
requestBuilder2 = requestBuilder2.header(
|
||||
"User-Agent",
|
||||
"$booruPluginUserAgent - ${PreferencesManager.booruUserId}"
|
||||
)
|
||||
}
|
||||
val request2 = requestBuilder2.build()
|
||||
client.newCall(request2).execute().use { response2 ->
|
||||
if (response2.isSuccessful) {
|
||||
val responseBody2 = response2.body?.string()
|
||||
?: throw IOException("Response body is null")
|
||||
val jsonBody: JSONObject
|
||||
try {
|
||||
jsonBody = JSONObject(responseBody2)
|
||||
val imageUrl = jsonBody.optString("full")
|
||||
val title1 = jsonBody.optString("primary")
|
||||
val title2 = jsonBody.optJSONArray("tags")?.join(" ")
|
||||
val title = "$title1 - $title2"
|
||||
// Zerochan does not have an easily accessible Artist tag. Link to the source in a best-effort way.
|
||||
val author = jsonBody.optString("source")
|
||||
val sourceUri = jsonBody.optString("source")
|
||||
if (imageUrl.isNotEmpty()) {
|
||||
images.add(BooruImage(imageUrl, title, author, sourceUri))
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
// Invalid response, do nothing (probably rate limited, HTML output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return images
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getWallhavenImageUrls(limit: Int = 20): List<BooruImage> {
|
||||
val tags = PreferencesManager.booruTagSearch
|
||||
val encodedTags = URLEncoder.encode(tags, "UTF-8")
|
||||
var url = "${PreferencesManager.booruUrl}/api/v1/search?q=$encodedTags&sorting=random"
|
||||
val requestBuilder = getRequestBuilder(url)
|
||||
if (PreferencesManager.booruApiKey.isNotEmpty()) {
|
||||
// Users can authenticate by including their API key either in a request URL by appending
|
||||
// ?apikey=<API KEY>, or by including the X-API-Key: <API KEY> header with the request.
|
||||
// API key grants access to NSFW images (but the purity=111 flag is not set by this plugin, default is SFW, 100).
|
||||
requestBuilder.addHeader("X-API-Key", PreferencesManager.booruApiKey)
|
||||
}
|
||||
val request = requestBuilder.build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// Try to parse error message from body
|
||||
val responseBody = response.body?.string() ?: throw IOException("Unexpected code ${response.code}, and response body is empty")
|
||||
val jsonBody = JSONObject(responseBody)
|
||||
val errorMessage = jsonBody.optString("message")
|
||||
if (errorMessage.isNotEmpty()) {
|
||||
throw IOException("Error ${response.code}. $errorMessage")
|
||||
}
|
||||
throw IOException("Error ${response.code} - ${response.body}")
|
||||
}
|
||||
|
||||
val responseBody = response.body?.string() ?: throw IOException("Response body is null")
|
||||
val jsonBody = JSONObject(responseBody)
|
||||
val jsonArray = jsonBody.getJSONArray("data")
|
||||
|
||||
// Parse JSON response into BooruImage instances
|
||||
val images = mutableListOf<BooruImage>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val jsonObject = jsonArray.getJSONObject(i)
|
||||
val imageUrl = jsonObject.optString("path")
|
||||
val title = jsonObject.optString("id")
|
||||
val author = jsonObject.optString("source")
|
||||
val sourceUri = jsonObject.optString("source")
|
||||
if (imageUrl.isNotEmpty()) {
|
||||
images.add(BooruImage(imageUrl, title, author, sourceUri))
|
||||
}
|
||||
}
|
||||
return images
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BooruImage(
|
||||
|
|
|
@ -2,13 +2,40 @@ package nl.kurocon.plugin.wallpaperprovider.booru
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.annotation.IntDef
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.ToNumberPolicy
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.DANBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.MOEBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.GELBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.ZEROCHAN
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.WALLHAVEN
|
||||
|
||||
object PreferencesManager {
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@IntDef(DANBOORU, MOEBOORU, GELBOORU, ZEROCHAN, WALLHAVEN)
|
||||
annotation class BooruType {
|
||||
companion object {
|
||||
const val DANBOORU = 1
|
||||
const val MOEBOORU = 2
|
||||
const val GELBOORU = 3
|
||||
const val ZEROCHAN = 4
|
||||
const val WALLHAVEN = 5
|
||||
}
|
||||
}
|
||||
private val BOORU_TYPE_NAMES = mapOf(
|
||||
DANBOORU to "Danbooru",
|
||||
MOEBOORU to "Moebooru",
|
||||
GELBOORU to "Gelbooru",
|
||||
ZEROCHAN to "Zerochan",
|
||||
WALLHAVEN to "Wallhaven",
|
||||
)
|
||||
|
||||
private const val BOORU_URL_KEY = "booru_url_key"
|
||||
private const val BOORU_TYPE_KEY = "booru_type_key"
|
||||
private const val BOORU_TAG_SEARCH_KEY = "booru_tag_search_key"
|
||||
|
@ -27,6 +54,10 @@ object PreferencesManager {
|
|||
editor.apply()
|
||||
}
|
||||
|
||||
fun getBooruName(type: @BooruType Int): String {
|
||||
return BOORU_TYPE_NAMES[type]!!
|
||||
}
|
||||
|
||||
operator fun set(key: String, value: Any?) =
|
||||
when (value) {
|
||||
is String? -> preferences.edit { it.putString(key, value) }
|
||||
|
@ -40,21 +71,30 @@ object PreferencesManager {
|
|||
inline operator fun <reified T : Any> get(
|
||||
key: String,
|
||||
defaultValue: T? = null
|
||||
): T =
|
||||
when (T::class) {
|
||||
String::class -> preferences.getString(key, defaultValue as String? ?: "") as T
|
||||
Int::class -> preferences.getInt(key, defaultValue as? Int ?: -1) as T
|
||||
Boolean::class -> preferences.getBoolean(key, defaultValue as? Boolean ?: false) as T
|
||||
Float::class -> preferences.getFloat(key, defaultValue as? Float ?: -1f) as T
|
||||
Long::class -> preferences.getLong(key, defaultValue as? Long ?: -1) as T
|
||||
else -> throw UnsupportedOperationException("Not yet implemented")
|
||||
): T {
|
||||
try {
|
||||
when (T::class) {
|
||||
String::class -> return preferences.getString(key, defaultValue as String? ?: "") as T
|
||||
Int::class -> return preferences.getInt(key, defaultValue as? Int ?: -1) as T
|
||||
Boolean::class -> return preferences.getBoolean(
|
||||
key,
|
||||
defaultValue as? Boolean ?: false
|
||||
) as T
|
||||
|
||||
Float::class -> return preferences.getFloat(key, defaultValue as? Float ?: -1f) as T
|
||||
Long::class -> return preferences.getLong(key, defaultValue as? Long ?: -1) as T
|
||||
else -> throw UnsupportedOperationException("Not yet implemented")
|
||||
}
|
||||
} catch (e: ClassCastException) {
|
||||
return defaultValue as T
|
||||
}
|
||||
}
|
||||
|
||||
var booruUrl: String
|
||||
get () = PreferencesManager[BOORU_URL_KEY, "https://danbooru.donmai.us"]
|
||||
set(value) { PreferencesManager[BOORU_URL_KEY] = value }
|
||||
var booruType: String
|
||||
get () = PreferencesManager[BOORU_TYPE_KEY, "danbooru"]
|
||||
var booruType: @BooruType Int
|
||||
get () = PreferencesManager[BOORU_TYPE_KEY, DANBOORU]
|
||||
set(value) { PreferencesManager[BOORU_TYPE_KEY] = value }
|
||||
var booruTagSearch: String
|
||||
get () = PreferencesManager[BOORU_TAG_SEARCH_KEY, "ratio:16:9 rating:general order:random"]
|
||||
|
@ -99,4 +139,4 @@ object PreferencesManager {
|
|||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ import androidx.appcompat.content.res.AppCompatResources
|
|||
import androidx.leanback.app.GuidedStepSupportFragment
|
||||
import androidx.leanback.widget.GuidanceStylist.Guidance
|
||||
import androidx.leanback.widget.GuidedAction
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.DANBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.GELBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.MOEBOORU
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.ZEROCHAN
|
||||
import nl.kurocon.plugin.wallpaperprovider.booru.PreferencesManager.BooruType.Companion.WALLHAVEN
|
||||
import kotlin.CharSequence
|
||||
|
||||
class SettingsFragment : GuidedStepSupportFragment() {
|
||||
|
@ -32,20 +37,50 @@ class SettingsFragment : GuidedStepSupportFragment() {
|
|||
.build()
|
||||
actions.add(actionBooruUrl)
|
||||
|
||||
// Booru Type setting (choice menu with only Danbooru currently)
|
||||
val booruTypeSubActions: MutableList<GuidedAction> = mutableListOf();
|
||||
val typeDanbooruSubAction = GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_DANBOORU)
|
||||
.title(R.string.setting_booru_type_subtype_danbooru_title)
|
||||
.description(R.string.setting_booru_type_subtype_danbooru_description)
|
||||
.build()
|
||||
booruTypeSubActions.add(typeDanbooruSubAction)
|
||||
// Booru Type subaction list (choice menu)
|
||||
val booruTypeSubActions: MutableList<GuidedAction> = mutableListOf(
|
||||
// Danbooru
|
||||
GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_DANBOORU)
|
||||
.title(R.string.setting_booru_type_subtype_danbooru_title)
|
||||
.description(R.string.setting_booru_type_subtype_danbooru_description)
|
||||
.build(),
|
||||
|
||||
// Moebooru
|
||||
GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_MOEBOORU)
|
||||
.title(R.string.setting_booru_type_subtype_moebooru_title)
|
||||
.description(R.string.setting_booru_type_subtype_moebooru_description)
|
||||
.build(),
|
||||
|
||||
// Gelbooru
|
||||
GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_GELBOORU)
|
||||
.title(R.string.setting_booru_type_subtype_gelbooru_title)
|
||||
.description(R.string.setting_booru_type_subtype_gelbooru_description)
|
||||
.build(),
|
||||
|
||||
// Zerochan
|
||||
GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_ZEROCHAN)
|
||||
.title(R.string.setting_booru_type_subtype_zerochan_title)
|
||||
.description(R.string.setting_booru_type_subtype_zerochan_description)
|
||||
.build(),
|
||||
|
||||
// Wallhaven.cc
|
||||
GuidedAction.Builder(context)
|
||||
.id(SUBACTION_ID_BOORU_TYPE_WALLHAVEN)
|
||||
.title(R.string.setting_booru_type_subtype_wallhaven_title)
|
||||
.description(R.string.setting_booru_type_subtype_wallhaven_description)
|
||||
.build(),
|
||||
);
|
||||
|
||||
// Actual Booru Type choice button with subactions
|
||||
val currentBooruType = PreferencesManager.booruType
|
||||
val actionBooruType = GuidedAction.Builder(context)
|
||||
.id(ACTION_ID_BOORU_TYPE)
|
||||
.title(R.string.setting_booru_type_title)
|
||||
.description(currentBooruType)
|
||||
.description(PreferencesManager.getBooruName(currentBooruType))
|
||||
.subActions(booruTypeSubActions)
|
||||
.build()
|
||||
actions.add(actionBooruType)
|
||||
|
@ -104,10 +139,13 @@ class SettingsFragment : GuidedStepSupportFragment() {
|
|||
|
||||
override fun onSubGuidedActionClicked(action: GuidedAction): Boolean {
|
||||
when (action.id) {
|
||||
SUBACTION_ID_BOORU_TYPE_DANBOORU -> {
|
||||
findActionById(ACTION_ID_BOORU_TYPE)?.description = "danbooru"
|
||||
SUBACTION_ID_BOORU_TYPE_DANBOORU, SUBACTION_ID_BOORU_TYPE_MOEBOORU,
|
||||
SUBACTION_ID_BOORU_TYPE_GELBOORU, SUBACTION_ID_BOORU_TYPE_ZEROCHAN,
|
||||
SUBACTION_ID_BOORU_TYPE_WALLHAVEN -> {
|
||||
val bType = BOORU_TYPE_ACTION_MAP[action.id]!!
|
||||
findActionById(ACTION_ID_BOORU_TYPE)?.description = PreferencesManager.getBooruName(bType)
|
||||
notifyActionChanged(findActionPositionById(ACTION_ID_BOORU_TYPE))
|
||||
PreferencesManager.booruType = "danbooru"
|
||||
PreferencesManager.booruType = bType
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
@ -151,5 +189,17 @@ class SettingsFragment : GuidedStepSupportFragment() {
|
|||
private const val ACTION_ID_BOORU_API_KEY = 6L
|
||||
|
||||
private const val SUBACTION_ID_BOORU_TYPE_DANBOORU = 7L
|
||||
private const val SUBACTION_ID_BOORU_TYPE_MOEBOORU = 8L
|
||||
private const val SUBACTION_ID_BOORU_TYPE_GELBOORU = 9L
|
||||
private const val SUBACTION_ID_BOORU_TYPE_ZEROCHAN = 10L
|
||||
private const val SUBACTION_ID_BOORU_TYPE_WALLHAVEN = 11L
|
||||
|
||||
private val BOORU_TYPE_ACTION_MAP = mapOf(
|
||||
SUBACTION_ID_BOORU_TYPE_DANBOORU to DANBOORU,
|
||||
SUBACTION_ID_BOORU_TYPE_MOEBOORU to MOEBOORU,
|
||||
SUBACTION_ID_BOORU_TYPE_GELBOORU to GELBOORU,
|
||||
SUBACTION_ID_BOORU_TYPE_ZEROCHAN to ZEROCHAN,
|
||||
SUBACTION_ID_BOORU_TYPE_WALLHAVEN to WALLHAVEN,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<resources>
|
||||
<string name="plugin_name">Booru Wallpaper Provider</string>
|
||||
<string name="plugin_version">1.1</string>
|
||||
<string name="plugin_description">
|
||||
A wallpaper provider that can talk to Booru sites running Danbooru software.
|
||||
</string>
|
||||
|
@ -8,7 +9,7 @@
|
|||
<!-- Setting parameters -->
|
||||
<string name="settings">Settings</string>
|
||||
<string name="setting_image_url_title">Image URL</string>
|
||||
<string name="setting_booru_url_title">Booru URL - e.g. \'https://danbooru.donmai.us/\'</string>
|
||||
<string name="setting_booru_url_title">Booru URL - e.g. \'https://danbooru.donmai.us\'</string>
|
||||
<string name="setting_booru_type_title">Booru Type</string>
|
||||
<string name="setting_booru_tag_search_title">Search query - e.g. \'ratio:16:9 rating:general\'</string>
|
||||
<string name="setting_booru_user_id_title">Booru Username </string>
|
||||
|
@ -20,5 +21,13 @@
|
|||
</string>
|
||||
|
||||
<string name="setting_booru_type_subtype_danbooru_title">Danbooru</string>
|
||||
<string name="setting_booru_type_subtype_danbooru_description">Danbooru-based (danbooru.donmai.us) - Currently the only supported type</string>
|
||||
<string name="setting_booru_type_subtype_danbooru_description">Danbooru-based (danbooru.donmai.us)</string>
|
||||
<string name="setting_booru_type_subtype_moebooru_title">Moebooru (Danbooru v1)</string>
|
||||
<string name="setting_booru_type_subtype_moebooru_description">Moebooru-based (konachan.com, yande.re)</string>
|
||||
<string name="setting_booru_type_subtype_gelbooru_title">Gelbooru</string>
|
||||
<string name="setting_booru_type_subtype_gelbooru_description">Gelbooru-based (gelbooru.com)</string>
|
||||
<string name="setting_booru_type_subtype_zerochan_title">Zerochan</string>
|
||||
<string name="setting_booru_type_subtype_zerochan_description">Zerochan-based (zerochan.net, asiachan.com)</string>
|
||||
<string name="setting_booru_type_subtype_wallhaven_title">Wallhaven</string>
|
||||
<string name="setting_booru_type_subtype_wallhaven_description">Wallhaven-based (wallhaven.cc)</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue