notestockカラムの微調整。
This commit is contained in:
parent
1916fe0d8e
commit
17f11fd196
@ -1139,6 +1139,17 @@ class ActMain : AsyncActivity(), Column.Callback, View.OnClickListener,
|
|||||||
text
|
text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActText.RESULT_SEARCH_NOTESTOCK -> {
|
||||||
|
val text = data?.getStringExtra(Intent.EXTRA_TEXT) ?: ""
|
||||||
|
addColumn(
|
||||||
|
false,
|
||||||
|
defaultInsertPosition,
|
||||||
|
SavedAccount.na,
|
||||||
|
ColumnType.SEARCH_NOTESTOCK,
|
||||||
|
text
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class ActText : AppCompatActivity(), View.OnClickListener {
|
|||||||
|
|
||||||
internal const val RESULT_SEARCH_MSP = RESULT_FIRST_USER + 1
|
internal const val RESULT_SEARCH_MSP = RESULT_FIRST_USER + 1
|
||||||
internal const val RESULT_SEARCH_TS = RESULT_FIRST_USER + 2
|
internal const val RESULT_SEARCH_TS = RESULT_FIRST_USER + 2
|
||||||
internal const val RESULT_SEARCH_NOTESTOCK = RESULT_FIRST_USER + 2
|
internal const val RESULT_SEARCH_NOTESTOCK = RESULT_FIRST_USER + 3
|
||||||
|
|
||||||
internal const val EXTRA_TEXT = "text"
|
internal const val EXTRA_TEXT = "text"
|
||||||
internal const val EXTRA_CONTENT_START = "content_start"
|
internal const val EXTRA_CONTENT_START = "content_start"
|
||||||
|
@ -643,7 +643,7 @@ class Column(
|
|||||||
val isSearchColumn: Boolean
|
val isSearchColumn: Boolean
|
||||||
get() {
|
get() {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
ColumnType.SEARCH, ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS -> true
|
ColumnType.SEARCH, ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS ,ColumnType.SEARCH_NOTESTOCK-> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -694,7 +694,7 @@ class Column(
|
|||||||
search_resolve = getParamAt(params, 1)
|
search_resolve = getParamAt(params, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS ->
|
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS,ColumnType.SEARCH_NOTESTOCK ->
|
||||||
search_query = getParamString(params, 0)
|
search_query = getParamString(params, 0)
|
||||||
|
|
||||||
ColumnType.INSTANCE_INFORMATION ->
|
ColumnType.INSTANCE_INFORMATION ->
|
||||||
@ -808,7 +808,7 @@ class Column(
|
|||||||
search_resolve = src.optBoolean(KEY_SEARCH_RESOLVE, false)
|
search_resolve = src.optBoolean(KEY_SEARCH_RESOLVE, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS -> search_query =
|
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS ,ColumnType.SEARCH_NOTESTOCK-> search_query =
|
||||||
src.optString(KEY_SEARCH_QUERY)
|
src.optString(KEY_SEARCH_QUERY)
|
||||||
|
|
||||||
ColumnType.INSTANCE_INFORMATION -> instance_uri = src.optString(KEY_INSTANCE_URI)
|
ColumnType.INSTANCE_INFORMATION -> instance_uri = src.optString(KEY_INSTANCE_URI)
|
||||||
@ -927,7 +927,7 @@ class Column(
|
|||||||
dst[KEY_SEARCH_RESOLVE] = search_resolve
|
dst[KEY_SEARCH_RESOLVE] = search_resolve
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS -> {
|
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS,ColumnType.SEARCH_NOTESTOCK -> {
|
||||||
dst[KEY_SEARCH_QUERY] = search_query
|
dst[KEY_SEARCH_QUERY] = search_query
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -998,7 +998,7 @@ class Column(
|
|||||||
getParamString(params, 0) == search_query &&
|
getParamString(params, 0) == search_query &&
|
||||||
getParamAtNullable<Boolean>(params, 1) == search_resolve
|
getParamAtNullable<Boolean>(params, 1) == search_resolve
|
||||||
|
|
||||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS ->
|
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS,ColumnType.SEARCH_NOTESTOCK ->
|
||||||
getParamString(params, 0) == search_query
|
getParamString(params, 0) == search_query
|
||||||
|
|
||||||
ColumnType.INSTANCE_INFORMATION -> getParamString(params, 0) == instance_uri
|
ColumnType.INSTANCE_INFORMATION -> getParamString(params, 0) == instance_uri
|
||||||
@ -2235,6 +2235,10 @@ class Column(
|
|||||||
R.raw.search_desc_ts_en,
|
R.raw.search_desc_ts_en,
|
||||||
R.raw.search_desc_ts_ja
|
R.raw.search_desc_ts_ja
|
||||||
)
|
)
|
||||||
|
ColumnType.SEARCH_NOTESTOCK -> loadSearchDesc(
|
||||||
|
R.raw.search_desc_notestock_en,
|
||||||
|
R.raw.search_desc_notestock_ja
|
||||||
|
)
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
cacheHeaderDesc = cache
|
cacheHeaderDesc = cache
|
||||||
@ -2302,7 +2306,7 @@ class Column(
|
|||||||
if (getFilterContext() != TootFilter.CONTEXT_NONE) return true
|
if (getFilterContext() != TootFilter.CONTEXT_NONE) return true
|
||||||
|
|
||||||
return when (type) {
|
return when (type) {
|
||||||
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS -> true
|
ColumnType.SEARCH_MSP, ColumnType.SEARCH_TS,ColumnType.SEARCH_NOTESTOCK -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2424,6 +2428,7 @@ class Column(
|
|||||||
ColumnType.SEARCH,
|
ColumnType.SEARCH,
|
||||||
ColumnType.SEARCH_MSP,
|
ColumnType.SEARCH_MSP,
|
||||||
ColumnType.SEARCH_TS,
|
ColumnType.SEARCH_TS,
|
||||||
|
ColumnType.SEARCH_NOTESTOCK,
|
||||||
ColumnType.CONVERSATION,
|
ColumnType.CONVERSATION,
|
||||||
ColumnType.LIST_LIST,
|
ColumnType.LIST_LIST,
|
||||||
ColumnType.TREND_TAG,
|
ColumnType.TREND_TAG,
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package jp.juggler.subwaytooter
|
package jp.juggler.subwaytooter
|
||||||
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import jp.juggler.subwaytooter.api.TootApiCallback
|
import jp.juggler.subwaytooter.api.*
|
||||||
import jp.juggler.subwaytooter.api.TootApiClient
|
|
||||||
import jp.juggler.subwaytooter.api.TootApiResult
|
|
||||||
import jp.juggler.subwaytooter.api.TootParser
|
|
||||||
import jp.juggler.subwaytooter.api.entity.*
|
import jp.juggler.subwaytooter.api.entity.*
|
||||||
import jp.juggler.subwaytooter.util.ScrollPosition
|
import jp.juggler.subwaytooter.util.ScrollPosition
|
||||||
import jp.juggler.util.*
|
import jp.juggler.util.*
|
||||||
@ -1230,7 +1227,7 @@ class ColumnTask_Refresh(
|
|||||||
if(jsonArray != null) {
|
if(jsonArray != null) {
|
||||||
// max_id の更新
|
// max_id の更新
|
||||||
column.idOld = EntityId.mayNull(
|
column.idOld = EntityId.mayNull(
|
||||||
TootApiClient.getMspMaxId(
|
getMspMaxId(
|
||||||
jsonArray,
|
jsonArray,
|
||||||
column.idOld?.toString()
|
column.idOld?.toString()
|
||||||
)
|
)
|
||||||
@ -1257,7 +1254,7 @@ class ColumnTask_Refresh(
|
|||||||
if(jsonObject != null) {
|
if(jsonObject != null) {
|
||||||
// max_id の更新
|
// max_id の更新
|
||||||
column.idOld = EntityId.mayNull(
|
column.idOld = EntityId.mayNull(
|
||||||
TootApiClient.getTootsearchMaxId(
|
getTootsearchMaxId(
|
||||||
jsonObject,
|
jsonObject,
|
||||||
old
|
old
|
||||||
)?.toString()
|
)?.toString()
|
||||||
@ -1284,7 +1281,7 @@ class ColumnTask_Refresh(
|
|||||||
if(jsonObject != null) {
|
if(jsonObject != null) {
|
||||||
// max_id の更新
|
// max_id の更新
|
||||||
column.idOld = EntityId.mayNull(
|
column.idOld = EntityId.mayNull(
|
||||||
TootApiClient.getNotestockMaxDt(
|
getNotestockMaxDt(
|
||||||
jsonObject
|
jsonObject
|
||||||
)?.toString()
|
)?.toString()
|
||||||
)
|
)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1929,7 +1929,8 @@ internal class ItemViewHolder(
|
|||||||
s != null -> Action_Toot.conversation(activity, pos, access_info, s)
|
s != null -> Action_Toot.conversation(activity, pos, access_info, s)
|
||||||
|
|
||||||
// tootsearchは返信元のIDを取得するのにひと手間必要
|
// tootsearchは返信元のIDを取得するのにひと手間必要
|
||||||
column.type == ColumnType.SEARCH_TS ->
|
column.type == ColumnType.SEARCH_TS ||
|
||||||
|
column.type == ColumnType.SEARCH_NOTESTOCK ->
|
||||||
Action_Toot.showReplyTootsearch(activity, pos, status_showing)
|
Action_Toot.showReplyTootsearch(activity, pos, status_showing)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
@ -2165,7 +2166,8 @@ internal class ItemViewHolder(
|
|||||||
// それ以外はコンテキストメニューではなく会話を開く
|
// それ以外はコンテキストメニューではなく会話を開く
|
||||||
|
|
||||||
// tootsearchは返信元のIDを取得するのにひと手間必要
|
// tootsearchは返信元のIDを取得するのにひと手間必要
|
||||||
column.type == ColumnType.SEARCH_TS ->
|
column.type == ColumnType.SEARCH_TS ||
|
||||||
|
column.type == ColumnType.SEARCH_NOTESTOCK ->
|
||||||
Action_Toot.showReplyTootsearch(
|
Action_Toot.showReplyTootsearch(
|
||||||
activity,
|
activity,
|
||||||
activity.nextPosition(column),
|
activity.nextPosition(column),
|
||||||
|
100
app/src/main/java/jp/juggler/subwaytooter/api/MspHelper.kt
Normal file
100
app/src/main/java/jp/juggler/subwaytooter/api/MspHelper.kt
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package jp.juggler.subwaytooter.api
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.Pref
|
||||||
|
import jp.juggler.subwaytooter.put
|
||||||
|
import jp.juggler.util.*
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
|
||||||
|
private const val mspTokenUrl = "http://mastodonsearch.jp/api/v1.0.1/utoken"
|
||||||
|
private const val mspSearchUrl = "http://mastodonsearch.jp/api/v1.0.1/cross"
|
||||||
|
private const val mspApiKey = "e53de7f66130208f62d1808672bf6320523dcd0873dc69bc"
|
||||||
|
|
||||||
|
fun getMspMaxId(array: JsonArray, old: String?): String? {
|
||||||
|
// max_id の更新
|
||||||
|
val size = array.size
|
||||||
|
if (size > 0) {
|
||||||
|
val sv = array[size - 1].cast<JsonObject>()?.string("msp_id")?.notEmpty()
|
||||||
|
if (sv != null) return sv
|
||||||
|
}
|
||||||
|
// MSPでは終端は分からず、何度もリトライする
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun TootApiClient.searchMsp(query: String, max_id: String?): TootApiResult? {
|
||||||
|
|
||||||
|
// ユーザトークンを読む
|
||||||
|
var user_token: String? = Pref.spMspUserToken(pref)
|
||||||
|
|
||||||
|
for (nTry in 0 until 3) {
|
||||||
|
if (callback.isApiCancelled) return null
|
||||||
|
|
||||||
|
// ユーザトークンがなければ取得する
|
||||||
|
if (user_token == null || user_token.isEmpty()) {
|
||||||
|
|
||||||
|
callback.publishApiProgress("get MSP user token...")
|
||||||
|
|
||||||
|
val result: TootApiResult = TootApiResult.makeWithCaption("Mastodon Search Portal")
|
||||||
|
if (result.error != null) return result
|
||||||
|
|
||||||
|
if (!sendRequest(result) {
|
||||||
|
Request.Builder()
|
||||||
|
.url(mspTokenUrl + "?apikey=" + mspApiKey.encodePercent())
|
||||||
|
.build()
|
||||||
|
}) return result
|
||||||
|
|
||||||
|
val r2 = parseJson(result) { json ->
|
||||||
|
val error = json.string("error")
|
||||||
|
if (error == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val type = json.string("type")
|
||||||
|
"error: $type $error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val jsonObject = r2?.jsonObject ?: return r2
|
||||||
|
user_token = jsonObject.jsonObject("result")?.string("token")
|
||||||
|
if (user_token?.isEmpty() != false) {
|
||||||
|
return result.setError("Can't get MSP user token. response=${result.bodyString}")
|
||||||
|
} else {
|
||||||
|
pref.edit().put(Pref.spMspUserToken, user_token).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ユーザトークンを使って検索APIを呼び出す
|
||||||
|
val result: TootApiResult = TootApiResult.makeWithCaption("Mastodon Search Portal")
|
||||||
|
if (result.error != null) return result
|
||||||
|
|
||||||
|
if (!sendRequest(result) {
|
||||||
|
val url = StringBuilder()
|
||||||
|
.append(mspSearchUrl)
|
||||||
|
.append("?apikey=").append(mspApiKey.encodePercent())
|
||||||
|
.append("&utoken=").append(user_token.encodePercent())
|
||||||
|
.append("&q=").append(query.encodePercent())
|
||||||
|
.append("&max=").append(max_id?.encodePercent() ?: "")
|
||||||
|
|
||||||
|
Request.Builder().url(url.toString()).build()
|
||||||
|
}) return result
|
||||||
|
|
||||||
|
var isUserTokenError = false
|
||||||
|
val r2 = parseJson(result) { json ->
|
||||||
|
val error = json.string("error")
|
||||||
|
if (error == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
// ユーザトークンがダメなら生成しなおす
|
||||||
|
val detail = json.string("detail")
|
||||||
|
if ("utoken" == detail) {
|
||||||
|
isUserTokenError = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val type = json.string("type")
|
||||||
|
"API returns error: $type $error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r2 == null || !isUserTokenError) return r2
|
||||||
|
}
|
||||||
|
return TootApiResult("MSP user token retry exceeded.")
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package jp.juggler.subwaytooter.api
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.api.entity.TootStatus
|
||||||
|
import jp.juggler.util.JsonArray
|
||||||
|
import jp.juggler.util.JsonObject
|
||||||
|
import jp.juggler.util.cast
|
||||||
|
import jp.juggler.util.encodePercent
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
fun getNotestockStatuses(root: JsonObject): JsonArray? =
|
||||||
|
root["statuses"].cast()
|
||||||
|
|
||||||
|
// notestock の検索結果からmax_dtを抽出します。
|
||||||
|
// 次ページがない場合はnullを返します。
|
||||||
|
fun getNotestockMaxDt(root: JsonObject)=
|
||||||
|
root.jsonArray("statuses")
|
||||||
|
?.mapNotNull{ it.cast<JsonObject>()?.string("published")}
|
||||||
|
?.map{ Pair(it, TootStatus.parseTime(it))}
|
||||||
|
?.filter { it.second != 0L }
|
||||||
|
?.minByOrNull { it.second }
|
||||||
|
?.first
|
||||||
|
|
||||||
|
fun TootApiClient.searchNotestock(
|
||||||
|
query: String,
|
||||||
|
max_dt: String?
|
||||||
|
): TootApiResult? {
|
||||||
|
|
||||||
|
val result = TootApiResult.makeWithCaption("Notestock")
|
||||||
|
if (result.error != null) return result
|
||||||
|
|
||||||
|
if (!sendRequest(result) {
|
||||||
|
val url = StringBuilder().apply {
|
||||||
|
append("https://notestock.osa-p.net/api/v1/search.json?q=")
|
||||||
|
append(query.encodePercent())
|
||||||
|
if (max_dt != null) append("&max_dt=").append(max_dt.encodePercent())
|
||||||
|
}.toString()
|
||||||
|
|
||||||
|
Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
}) return result
|
||||||
|
|
||||||
|
return parseJson(result)
|
||||||
|
}
|
||||||
|
|
@ -70,48 +70,6 @@ class TootApiClient(
|
|||||||
private val reStartJsonObject = """\A\s*\{""".asciiPattern()
|
private val reStartJsonObject = """\A\s*\{""".asciiPattern()
|
||||||
private val reWhiteSpace = """\s+""".asciiPattern()
|
private val reWhiteSpace = """\s+""".asciiPattern()
|
||||||
|
|
||||||
private const val mspTokenUrl = "http://mastodonsearch.jp/api/v1.0.1/utoken"
|
|
||||||
private const val mspSearchUrl = "http://mastodonsearch.jp/api/v1.0.1/cross"
|
|
||||||
private const val mspApiKey = "e53de7f66130208f62d1808672bf6320523dcd0873dc69bc"
|
|
||||||
|
|
||||||
fun getMspMaxId(array: JsonArray, old: String?): String? {
|
|
||||||
// max_id の更新
|
|
||||||
val size = array.size
|
|
||||||
if (size > 0) {
|
|
||||||
val sv = array[size - 1].cast<JsonObject>()?.string("msp_id")?.notEmpty()
|
|
||||||
if (sv != null) return sv
|
|
||||||
}
|
|
||||||
// MSPでは終端は分からず、何度もリトライする
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTootsearchHits(root: JsonObject): JsonArray? {
|
|
||||||
return root["hits"].cast<JsonObject>()?.get("hits")?.cast()
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the number for "from" parameter of next page.
|
|
||||||
// returns null if no more next page.
|
|
||||||
fun getTootsearchMaxId(root: JsonObject, old: Long?): Long? {
|
|
||||||
val size = getTootsearchHits(root)?.size ?: 0
|
|
||||||
return when {
|
|
||||||
size <= 0 -> null
|
|
||||||
else -> (old ?: 0L) + size.toLong()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getNotestockStatuses(root: JsonObject): JsonArray? {
|
|
||||||
return root["statuses"].cast()
|
|
||||||
}
|
|
||||||
|
|
||||||
// notestock の検索結果からmax_dtを抽出します。
|
|
||||||
// 次ページがない場合はnullを返します。
|
|
||||||
fun getNotestockMaxDt(root: JsonObject)=
|
|
||||||
root.jsonArray("statuses")
|
|
||||||
?.mapNotNull{ it.cast<JsonObject>()?.string("published")}
|
|
||||||
?.map{ Pair(it,TootStatus.parseTime(it))}
|
|
||||||
?.filter { it.second != 0L }
|
|
||||||
?.minByOrNull { it.second }
|
|
||||||
?.first
|
|
||||||
|
|
||||||
val DEFAULT_JSON_ERROR_PARSER =
|
val DEFAULT_JSON_ERROR_PARSER =
|
||||||
{ json: JsonObject -> json["error"]?.toString() }
|
{ json: JsonObject -> json["error"]?.toString() }
|
||||||
@ -1204,132 +1162,6 @@ class TootApiClient(
|
|||||||
return parseJson(result)
|
return parseJson(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun searchMsp(query: String, max_id: String?): TootApiResult? {
|
|
||||||
|
|
||||||
// ユーザトークンを読む
|
|
||||||
var user_token: String? = Pref.spMspUserToken(pref)
|
|
||||||
|
|
||||||
for (nTry in 0 until 3) {
|
|
||||||
if (callback.isApiCancelled) return null
|
|
||||||
|
|
||||||
// ユーザトークンがなければ取得する
|
|
||||||
if (user_token == null || user_token.isEmpty()) {
|
|
||||||
|
|
||||||
callback.publishApiProgress("get MSP user token...")
|
|
||||||
|
|
||||||
val result: TootApiResult = TootApiResult.makeWithCaption("Mastodon Search Portal")
|
|
||||||
if (result.error != null) return result
|
|
||||||
|
|
||||||
if (!sendRequest(result) {
|
|
||||||
Request.Builder()
|
|
||||||
.url(mspTokenUrl + "?apikey=" + mspApiKey.encodePercent())
|
|
||||||
.build()
|
|
||||||
}) return result
|
|
||||||
|
|
||||||
val r2 = parseJson(result) { json ->
|
|
||||||
val error = json.string("error")
|
|
||||||
if (error == null) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
val type = json.string("type")
|
|
||||||
"error: $type $error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val jsonObject = r2?.jsonObject ?: return r2
|
|
||||||
user_token = jsonObject.jsonObject("result")?.string("token")
|
|
||||||
if (user_token?.isEmpty() != false) {
|
|
||||||
return result.setError("Can't get MSP user token. response=${result.bodyString}")
|
|
||||||
} else {
|
|
||||||
pref.edit().put(Pref.spMspUserToken, user_token).apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ユーザトークンを使って検索APIを呼び出す
|
|
||||||
val result: TootApiResult = TootApiResult.makeWithCaption("Mastodon Search Portal")
|
|
||||||
if (result.error != null) return result
|
|
||||||
|
|
||||||
if (!sendRequest(result) {
|
|
||||||
val url = StringBuilder()
|
|
||||||
.append(mspSearchUrl)
|
|
||||||
.append("?apikey=").append(mspApiKey.encodePercent())
|
|
||||||
.append("&utoken=").append(user_token.encodePercent())
|
|
||||||
.append("&q=").append(query.encodePercent())
|
|
||||||
.append("&max=").append(max_id?.encodePercent() ?: "")
|
|
||||||
|
|
||||||
Request.Builder().url(url.toString()).build()
|
|
||||||
}) return result
|
|
||||||
|
|
||||||
var isUserTokenError = false
|
|
||||||
val r2 = parseJson(result) { json ->
|
|
||||||
val error = json.string("error")
|
|
||||||
if (error == null) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
// ユーザトークンがダメなら生成しなおす
|
|
||||||
val detail = json.string("detail")
|
|
||||||
if ("utoken" == detail) {
|
|
||||||
isUserTokenError = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val type = json.string("type")
|
|
||||||
"API returns error: $type $error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r2 == null || !isUserTokenError) return r2
|
|
||||||
}
|
|
||||||
return TootApiResult("MSP user token retry exceeded.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun searchTootsearch(
|
|
||||||
query: String,
|
|
||||||
from: Long?
|
|
||||||
): TootApiResult? {
|
|
||||||
|
|
||||||
val result = TootApiResult.makeWithCaption("Tootsearch")
|
|
||||||
if (result.error != null) return result
|
|
||||||
|
|
||||||
if (!sendRequest(result) {
|
|
||||||
val sb = StringBuilder()
|
|
||||||
.append("https://tootsearch.chotto.moe/api/v1/search?sort=")
|
|
||||||
.append("created_at:desc".encodePercent())
|
|
||||||
.append("&q=").append(query.encodePercent())
|
|
||||||
if (from != null) {
|
|
||||||
sb.append("&from=").append(from.toString().encodePercent())
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.Builder()
|
|
||||||
.url(sb.toString())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
}) return result
|
|
||||||
|
|
||||||
return parseJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun searchNotestock(
|
|
||||||
query: String,
|
|
||||||
max_dt: String?
|
|
||||||
): TootApiResult? {
|
|
||||||
|
|
||||||
val result = TootApiResult.makeWithCaption("Notestock")
|
|
||||||
if (result.error != null) return result
|
|
||||||
|
|
||||||
if (!sendRequest(result) {
|
|
||||||
val url = StringBuilder().apply {
|
|
||||||
append("https://notestock.osa-p.net/api/v1/search.json?q=")
|
|
||||||
append(query.encodePercent())
|
|
||||||
if (max_dt != null) append("&max_dt=").append(max_dt.encodePercent())
|
|
||||||
}.toString()
|
|
||||||
|
|
||||||
Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
}) return result
|
|
||||||
|
|
||||||
return parseJson(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// JSONデータ以外を扱うリクエスト
|
// JSONデータ以外を扱うリクエスト
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package jp.juggler.subwaytooter.api
|
||||||
|
|
||||||
|
import jp.juggler.util.JsonArray
|
||||||
|
import jp.juggler.util.JsonObject
|
||||||
|
import jp.juggler.util.cast
|
||||||
|
import jp.juggler.util.encodePercent
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
|
||||||
|
fun getTootsearchHits(root: JsonObject): JsonArray? {
|
||||||
|
return root["hits"].cast<JsonObject>()?.get("hits")?.cast()
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the number for "from" parameter of next page.
|
||||||
|
// returns null if no more next page.
|
||||||
|
fun getTootsearchMaxId(root: JsonObject, old: Long?): Long? {
|
||||||
|
val size = getTootsearchHits(root)?.size ?: 0
|
||||||
|
return when {
|
||||||
|
size <= 0 -> null
|
||||||
|
else -> (old ?: 0L) + size.toLong()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TootApiClient.searchTootsearch(
|
||||||
|
query: String,
|
||||||
|
from: Long?
|
||||||
|
): TootApiResult? {
|
||||||
|
|
||||||
|
val result = TootApiResult.makeWithCaption("Tootsearch")
|
||||||
|
if (result.error != null) return result
|
||||||
|
|
||||||
|
if (!sendRequest(result) {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
.append("https://tootsearch.chotto.moe/api/v1/search?sort=")
|
||||||
|
.append("created_at:desc".encodePercent())
|
||||||
|
.append("&q=").append(query.encodePercent())
|
||||||
|
if (from != null) {
|
||||||
|
sb.append("&from=").append(from.toString().encodePercent())
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.Builder()
|
||||||
|
.url(sb.toString())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
}) return result
|
||||||
|
|
||||||
|
return parseJson(result)
|
||||||
|
}
|
@ -238,7 +238,7 @@ class TootPolls (
|
|||||||
this.expired_at =
|
this.expired_at =
|
||||||
TootStatus.parseTime(src.string("endTime")).notZero() ?: Long.MAX_VALUE
|
TootStatus.parseTime(src.string("endTime")).notZero() ?: Long.MAX_VALUE
|
||||||
this.expired = expired_at >= System.currentTimeMillis()
|
this.expired = expired_at >= System.currentTimeMillis()
|
||||||
this.multiple = false // TODO
|
this.multiple = src.containsKey("anyOf")
|
||||||
this.votes_count = items?.sumBy{ it.votes?: 0 }?.notZero()
|
this.votes_count = items?.sumBy{ it.votes?: 0 }?.notZero()
|
||||||
|
|
||||||
this.ownVoted = false
|
this.ownVoted = false
|
||||||
|
@ -8,9 +8,7 @@ import android.text.SpannableString
|
|||||||
import jp.juggler.subwaytooter.App1
|
import jp.juggler.subwaytooter.App1
|
||||||
import jp.juggler.subwaytooter.Pref
|
import jp.juggler.subwaytooter.Pref
|
||||||
import jp.juggler.subwaytooter.R
|
import jp.juggler.subwaytooter.R
|
||||||
import jp.juggler.subwaytooter.api.TootAccountMap
|
import jp.juggler.subwaytooter.api.*
|
||||||
import jp.juggler.subwaytooter.api.TootApiClient
|
|
||||||
import jp.juggler.subwaytooter.api.TootParser
|
|
||||||
import jp.juggler.subwaytooter.table.HighlightWord
|
import jp.juggler.subwaytooter.table.HighlightWord
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount
|
import jp.juggler.subwaytooter.table.SavedAccount
|
||||||
import jp.juggler.subwaytooter.util.*
|
import jp.juggler.subwaytooter.util.*
|
||||||
@ -543,7 +541,7 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
|||||||
if (this.highlightSpeech == null) this.highlightSpeech = options.highlightSpeech
|
if (this.highlightSpeech == null) this.highlightSpeech = options.highlightSpeech
|
||||||
if (this.highlightAny == null) this.highlightAny = options.highlightAny
|
if (this.highlightAny == null) this.highlightAny = options.highlightAny
|
||||||
|
|
||||||
this.enquete = src.jsonArray("oneOf")?.let {
|
this.enquete = (src.jsonArray("oneOf")?: src.jsonArray("anyOf")) ?.let {
|
||||||
try {
|
try {
|
||||||
TootPolls(
|
TootPolls(
|
||||||
parser,
|
parser,
|
||||||
@ -1119,7 +1117,7 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
|||||||
parser.serviceType = ServiceType.TOOTSEARCH
|
parser.serviceType = ServiceType.TOOTSEARCH
|
||||||
|
|
||||||
val result = ArrayList<TootStatus>()
|
val result = ArrayList<TootStatus>()
|
||||||
val array = TootApiClient.getTootsearchHits(root)
|
val array = getTootsearchHits(root)
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
val array_size = array.size
|
val array_size = array.size
|
||||||
result.ensureCapacity(array_size)
|
result.ensureCapacity(array_size)
|
||||||
@ -1143,7 +1141,7 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
|||||||
parser.serviceType = ServiceType.NOTESTOCK // TODO
|
parser.serviceType = ServiceType.NOTESTOCK // TODO
|
||||||
|
|
||||||
val result = ArrayList<TootStatus>()
|
val result = ArrayList<TootStatus>()
|
||||||
val array = TootApiClient.getNotestockStatuses(root)
|
val array = getNotestockStatuses(root)
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
val array_size = array.size
|
val array_size = array.size
|
||||||
result.ensureCapacity(array_size)
|
result.ensureCapacity(array_size)
|
||||||
@ -1161,7 +1159,7 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
|||||||
|
|
||||||
private val tz_utc = TimeZone.getTimeZone("UTC")
|
private val tz_utc = TimeZone.getTimeZone("UTC")
|
||||||
|
|
||||||
private val reTime = """\A(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)"""
|
private val reTime = """\A(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)(?:\D+(\d+))?"""
|
||||||
.asciiPattern()
|
.asciiPattern()
|
||||||
|
|
||||||
private val reMSPTime = """\A(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)"""
|
private val reMSPTime = """\A(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)"""
|
||||||
@ -1190,7 +1188,6 @@ class TootStatus(parser: TootParser, src: JsonObject) : TimelineItem() {
|
|||||||
log.trace(ex)
|
log.trace(ex)
|
||||||
log.e(ex, "TootStatus.parseTime failed. src=%s", strTime)
|
log.e(ex, "TootStatus.parseTime failed. src=%s", strTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0L
|
return 0L
|
||||||
}
|
}
|
||||||
|
1
app/src/main/res/raw/search_desc_notestock_en.txt
Normal file
1
app/src/main/res/raw/search_desc_notestock_en.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Powered by <a href="https://notestock.osa-p.net/">notestock</a>, it indexes toots of users registered to that site.
|
1
app/src/main/res/raw/search_desc_notestock_ja.txt
Normal file
1
app/src/main/res/raw/search_desc_notestock_ja.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Powered by <a href="https://notestock.osa-p.net/">notestock</a>.
|
Loading…
x
Reference in New Issue
Block a user