「アプリ設定/投稿/添付メディア(Pixelfed)の最大バイト数」を追加。インスタンス情報キャッシュのリファクタ。

This commit is contained in:
tateisu 2019-10-01 05:31:55 +09:00
parent 0313b5d264
commit de8a4b7575
13 changed files with 260 additions and 170 deletions

View File

@ -15,6 +15,7 @@
<w>basi</w> <w>basi</w>
<w>blockee</w> <w>blockee</w>
<w>blurhash</w> <w>blurhash</w>
<w>bpixelfed</w>
<w>buggie</w> <w>buggie</w>
<w>bumptech</w> <w>bumptech</w>
<w>codepoint</w> <w>codepoint</w>

View File

@ -239,6 +239,7 @@ class ActAppSettingChild : AppCompatActivity()
private var etCardDescriptionLength : EditText? = null private var etCardDescriptionLength : EditText? = null
private var etMediaSizeMax : EditText? = null private var etMediaSizeMax : EditText? = null
private var etMovieSizeMax : EditText? = null private var etMovieSizeMax : EditText? = null
private var etMediaSizeMaxPixelfed : EditText? = null
private var etRoundRatio : EditText? = null private var etRoundRatio : EditText? = null
private var etBoostAlpha : EditText? = null private var etBoostAlpha : EditText? = null
private var etMediaReadTimeout : EditText? = null private var etMediaReadTimeout : EditText? = null
@ -565,6 +566,9 @@ class ActAppSettingChild : AppCompatActivity()
etMovieSizeMax = findViewById(R.id.etMovieSizeMax) etMovieSizeMax = findViewById(R.id.etMovieSizeMax)
etMovieSizeMax?.addTextChangedListener(this) etMovieSizeMax?.addTextChangedListener(this)
etMediaSizeMaxPixelfed= findViewById(R.id.etMediaSizeMaxPixelfed)
etMediaSizeMaxPixelfed?.addTextChangedListener(this)
etRoundRatio = findViewById(R.id.etRoundRatio) etRoundRatio = findViewById(R.id.etRoundRatio)
etRoundRatio?.addTextChangedListener(this) etRoundRatio?.addTextChangedListener(this)
@ -732,6 +736,7 @@ class ActAppSettingChild : AppCompatActivity()
etMediaSizeMax?.setText(Pref.spMediaSizeMax(pref)) etMediaSizeMax?.setText(Pref.spMediaSizeMax(pref))
etMovieSizeMax?.setText(Pref.spMovieSizeMax(pref)) etMovieSizeMax?.setText(Pref.spMovieSizeMax(pref))
etMediaSizeMaxPixelfed?.setText(Pref.spMediaSizeMaxPixelfed(pref))
etRoundRatio?.setText(Pref.spRoundRatio(pref)) etRoundRatio?.setText(Pref.spRoundRatio(pref))
etBoostAlpha?.setText(Pref.spBoostAlpha(pref)) etBoostAlpha?.setText(Pref.spBoostAlpha(pref))
@ -828,6 +833,7 @@ class ActAppSettingChild : AppCompatActivity()
putText(Pref.spPullNotificationCheckInterval, etPullNotificationCheckInterval) putText(Pref.spPullNotificationCheckInterval, etPullNotificationCheckInterval)
putText(Pref.spMediaSizeMax, etMediaSizeMax) putText(Pref.spMediaSizeMax, etMediaSizeMax)
putText(Pref.spMovieSizeMax, etMovieSizeMax) putText(Pref.spMovieSizeMax, etMovieSizeMax)
putText(Pref.spMediaSizeMaxPixelfed, etMediaSizeMaxPixelfed)
putText(Pref.spRoundRatio, etRoundRatio) putText(Pref.spRoundRatio, etRoundRatio)
putText(Pref.spBoostAlpha, etBoostAlpha) putText(Pref.spBoostAlpha, etBoostAlpha)
putText(Pref.spMediaReadTimeout, etMediaReadTimeout) putText(Pref.spMediaReadTimeout, etMediaReadTimeout)

View File

@ -972,9 +972,7 @@ class ActPost : AppCompatActivity(),
} }
} }
visibility = visibility visibility = visibility ?: account?.visibility ?: TootVisibility.Public
?: account?.visibility
?: TootVisibility.Public
// 2017/9/13 VISIBILITY_WEB_SETTING から VISIBILITY_PUBLICに変更した // 2017/9/13 VISIBILITY_WEB_SETTING から VISIBILITY_PUBLICに変更した
// VISIBILITY_WEB_SETTING だと 1.5未満のタンスでトラブルになるので… // VISIBILITY_WEB_SETTING だと 1.5未満のタンスでトラブルになるので…
@ -1271,42 +1269,30 @@ class ActPost : AppCompatActivity(),
else -> { else -> {
// インスタンス情報を確認する // インスタンス情報を確認する
val info = account.instance val info = TootInstance.getCached(account.host)
if(info == null || System.currentTimeMillis() - info.time_parse >= 300000L) { if(info == null || info.isExpire ) {
// 情報がないか古いなら再取得 // 情報がないか古いなら再取得
// 同時に実行するタスクは1つまで // 同時に実行するタスクは1つまで
var lastTask = lastInstanceTask if(lastInstanceTask?.isActive != true) {
if(lastTask?.isActive != true) { lastInstanceTask = TootTaskRunner(this, TootTaskRunner.PROGRESS_NONE)
lastTask = TootTaskRunner(this, TootTaskRunner.PROGRESS_NONE) .run(account, object : TootTask {
lastInstanceTask = lastTask var newInfo : TootInstance? = null
lastTask.run(account, object : TootTask {
var newInfo : TootInstance? = null override fun background(client : TootApiClient) : TootApiResult? {
val (result, ti) = TootInstance.get(client, account)
override fun background(client : TootApiClient) : TootApiResult? { newInfo = ti
val result = if(account.isMisskey) { return result
client.request(
"/api/meta",
account.putMisskeyApiToken().toPostRequestBuilder()
)
} else {
client.request("/api/v1/instance")
} }
newInfo =
TootParser(this@ActPost, account).instance(result?.jsonObject) override fun handleResult(result : TootApiResult?) {
return result if(isFinishing || isDestroyed) return
} if(newInfo != null) updateTextCount()
override fun handleResult(result : TootApiResult?) {
if(isFinishing || isDestroyed) return
if(newInfo != null) {
account.instance = newInfo
updateTextCount()
} }
} })
})
// fall thru // fall thru
} }
// fall thru
} }
val max = info?.max_toot_chars val max = info?.max_toot_chars
@ -2094,9 +2080,17 @@ class ActPost : AppCompatActivity(),
client.account = account client.account = account
val (tiResult, ti) = TootInstance.get(client, account)
if(ti == null) return tiResult
val opener = createOpener(uri, mimeType) val opener = createOpener(uri, mimeType)
val media_size_max = when { val media_size_max = when {
ti.instanceType == TootInstance.InstanceType.Pixelfed -> {
1000000 * max(1, Pref.spMediaSizeMaxPixelfed.toInt(pref))
}
mimeType.startsWith("video") || mimeType.startsWith("audio") -> { mimeType.startsWith("video") || mimeType.startsWith("audio") -> {
1000000 * max(1, Pref.spMovieSizeMax.toInt(pref)) 1000000 * max(1, Pref.spMovieSizeMax.toInt(pref))
} }

View File

@ -122,7 +122,6 @@ class Column(
internal const val PATH_STATUSES = "/api/v1/statuses/%s" // 1:status_id internal const val PATH_STATUSES = "/api/v1/statuses/%s" // 1:status_id
internal const val PATH_STATUSES_CONTEXT = "/api/v1/statuses/%s/context" // 1:status_id internal const val PATH_STATUSES_CONTEXT = "/api/v1/statuses/%s/context" // 1:status_id
// search args 1: query(urlencoded) , also, append "&resolve=1" if resolve non-local accounts // search args 1: query(urlencoded) , also, append "&resolve=1" if resolve non-local accounts
// internal const val PATH_INSTANCE = "/api/v1/instance"
internal const val PATH_LIST_INFO = "/api/v1/lists/%s" internal const val PATH_LIST_INFO = "/api/v1/lists/%s"
const val PATH_FILTERS = "/api/v1/filters" const val PATH_FILTERS = "/api/v1/filters"

View File

@ -18,8 +18,6 @@ class ColumnTask_Loading(
internal val log = LogCategory("CT_Loading") internal val log = LogCategory("CT_Loading")
} }
internal var instance_tmp : TootInstance? = null
internal var list_pinned : ArrayList<TimelineItem>? = null internal var list_pinned : ArrayList<TimelineItem>? = null
override fun doInBackground(vararg unused : Void) : TootApiResult? { override fun doInBackground(vararg unused : Void) : TootApiResult? {
@ -88,8 +86,8 @@ class ColumnTask_Loading(
val list_new = column.duplicate_map.filterDuplicate(list_pinned) val list_new = column.duplicate_map.filterDuplicate(list_pinned)
column.list_data.addAll(list_new) column.list_data.addAll(list_new)
} }
val list_new = when(column.type){ val list_new = when(column.type) {
// 検索カラムはIDによる重複排除が不可能 // 検索カラムはIDによる重複排除が不可能
ColumnType.SEARCH -> list_tmp ColumnType.SEARCH -> list_tmp
@ -97,7 +95,7 @@ class ColumnTask_Loading(
// 他のカラムは重複排除してから追加 // 他のカラムは重複排除してから追加
else -> column.duplicate_map.filterDuplicate(list_tmp) else -> column.duplicate_map.filterDuplicate(list_tmp)
} }
column.list_data.addAll(list_new) column.list_data.addAll(list_new)
} }
@ -114,23 +112,7 @@ class ColumnTask_Loading(
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// functions that called from ColumnTask.loading lambda. // functions that called from ColumnTask.loading lambda.
internal fun getInstanceInformation(
client : TootApiClient,
instance_name : String?
) : TootApiResult? {
when {
// 「インスタンス情報」カラムをNAアカウントで開く場合
instance_name != null -> client.instance = instance_name
// カラムに紐付けられたアカウントのタンスのインスタンス情報を取得する
else -> {
}
}
val (result, ti) = client.parseInstanceInformation(client.getInstanceInformation())
instance_tmp = ti
return result
}
internal fun getStatusesPinned(client : TootApiClient, path_base : String) { internal fun getStatusesPinned(client : TootApiClient, path_base : String) {
val result = client.request(path_base) val result = client.request(path_base)
val jsonArray = result?.jsonArray val jsonArray = result?.jsonArray
@ -700,14 +682,8 @@ class ColumnTask_Loading(
) : TootApiResult? { ) : TootApiResult? {
// (Mastodonのみ対応) // (Mastodonのみ対応)
var instance = access_info.instance val (instanceResult, instance) = TootInstance.get(client, access_info)
if(instance == null) { if(instance == null) return instanceResult
getInstanceInformation(client, null)
if(instance_tmp != null) {
instance = instance_tmp
access_info.instance = instance
}
}
// ステータスIDに該当するトゥート // ステータスIDに該当するトゥート
// タンスをまたいだりすると存在しないかもしれないが、エラーは出さない // タンスをまたいだりすると存在しないかもしれないが、エラーは出さない
@ -722,7 +698,7 @@ class ColumnTask_Loading(
column.idRecent = null column.idRecent = null
var bInstanceTooOld = false var bInstanceTooOld = false
if(instance?.versionGE(TootInstance.VERSION_2_6_0) == true) { if(instance.versionGE(TootInstance.VERSION_2_6_0)) {
// 指定より新しいトゥート // 指定より新しいトゥート
result = getStatusList(client, url, aroundMin = true) result = getStatusList(client, url, aroundMin = true)
if(result == null || result.error != null) return result if(result == null || result.error != null) return result
@ -750,14 +726,8 @@ class ColumnTask_Loading(
internal fun getAccountAroundStatuses(client : TootApiClient) : TootApiResult? { internal fun getAccountAroundStatuses(client : TootApiClient) : TootApiResult? {
// (Mastodonのみ対応) // (Mastodonのみ対応)
var instance = access_info.instance val (instanceResult, instance) = TootInstance.get(client, access_info)
if(instance == null) { if(instance == null) return instanceResult
getInstanceInformation(client, null)
if(instance_tmp != null) {
instance = instance_tmp
access_info.instance = instance
}
}
// ステータスIDに該当するトゥート // ステータスIDに該当するトゥート
// タンスをまたいだりすると存在しないかもしれない // タンスをまたいだりすると存在しないかもしれない
@ -774,7 +744,7 @@ class ColumnTask_Loading(
column.idRecent = null column.idRecent = null
var bInstanceTooOld = false var bInstanceTooOld = false
if(instance?.versionGE(TootInstance.VERSION_2_6_0) == true) { if(instance.versionGE(TootInstance.VERSION_2_6_0)) {
// 指定より新しいトゥート // 指定より新しいトゥート
result = getStatusList(client, path, aroundMin = true) result = getStatusList(client, path, aroundMin = true)
if(result == null || result.error != null) return result if(result == null || result.error != null) return result
@ -1007,31 +977,25 @@ class ColumnTask_Loading(
return TootApiResult(context.getString(R.string.search_is_not_available_on_pseudo_account)) return TootApiResult(context.getString(R.string.search_is_not_available_on_pseudo_account))
} }
var instance = access_info.instance val(instanceResult,instance) = TootInstance.get(client,access_info)
if(instance == null) { if( instance==null) return instanceResult
getInstanceInformation(client, null)
if(instance_tmp != null) {
instance = instance_tmp
access_info.instance = instance
}
}
var query="q=${column.search_query.encodePercent()}" var query = "q=${column.search_query.encodePercent()}"
if(column.search_resolve) query += "&resolve=1" if(column.search_resolve) query += "&resolve=1"
val(apiResult,searchResult)= client.requestMastodonSearch(parser,query) val (apiResult, searchResult) = client.requestMastodonSearch(parser, query)
if( searchResult != null){ if(searchResult != null) {
list_tmp = java.util.ArrayList() list_tmp = java.util.ArrayList()
addAll(list_tmp, searchResult.hashtags) addAll(list_tmp, searchResult.hashtags)
if(searchResult.searchApiVersion>=2 && searchResult.hashtags.isNotEmpty()) { if(searchResult.searchApiVersion >= 2 && searchResult.hashtags.isNotEmpty()) {
addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Hashtag)) addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Hashtag))
} }
addAll(list_tmp, searchResult.accounts) addAll(list_tmp, searchResult.accounts)
if(searchResult.searchApiVersion>=2 && searchResult.accounts.isNotEmpty()) { if(searchResult.searchApiVersion >= 2 && searchResult.accounts.isNotEmpty()) {
addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Account)) addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Account))
} }
addAll(list_tmp, searchResult.statuses) addAll(list_tmp, searchResult.statuses)
if( searchResult.searchApiVersion>=2 && searchResult.statuses.isNotEmpty()) { if(searchResult.searchApiVersion >= 2 && searchResult.statuses.isNotEmpty()) {
addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Status)) addOne(list_tmp, TootSearchGap(TootSearchGap.SearchType.Status))
} }
} }

View File

@ -57,28 +57,21 @@ enum class ColumnType(
ProfileStatusMastodon( ProfileStatusMastodon(
loading = { client -> loading = { client ->
var instance = access_info.instance val(instanceResult,instance) = TootInstance.get(client,access_info)
if(instance==null){
// まだ取得してない instanceResult
// 疑似アカウントの場合は過去のデータが別タンスかもしれない? }else {
if(instance == null || access_info.isPseudo) { val path = column.makeProfileStatusesUrl(column.profile_id)
getInstanceInformation(client, null)
if(instance_tmp != null) { if(instance.versionGE(TootInstance.VERSION_1_6)
instance = instance_tmp // 将来的に正しく判定できる見込みがないので、Pleroma条件でのフィルタは行わない
access_info.instance = instance // && instance.instanceType != TootInstance.InstanceType.Pleroma
) {
getStatusesPinned(client, "$path&pinned=true")
} }
getStatusList(client, path)
} }
val path = column.makeProfileStatusesUrl(column.profile_id)
if(instance?.versionGE(TootInstance.VERSION_1_6) == true
// 将来的に正しく判定できる見込みがないので、Pleroma条件でのフィルタは行わない
// && instance.instanceType != TootInstance.InstanceType.Pleroma
) {
getStatusesPinned(client, "$path&pinned=true")
}
getStatusList(client, path)
}, },
refresh = { client -> refresh = { client ->
@ -1102,12 +1095,26 @@ enum class ColumnType(
headerType = HeaderType.Instance, headerType = HeaderType.Instance,
loading = { client -> loading = { client ->
val result = getInstanceInformation(client, column.instance_uri) val(instanceResult,instance) = TootInstance.get(client,access_info,column.instance_uri)
if(instance_tmp != null) { if(instance!=null) {
column.instance_information = instance_tmp column.instance_information = instance
column.handshake = result?.response?.handshake column.handshake = instanceResult?.response?.handshake
} }
result instanceResult
//
// // 「インスタンス情報」カラムをNAアカウントで開く場合
// instance_name != null -> client.instance = instance_name
//
// val (result, ti) = client.parseInstanceInformation(client.getInstanceInformation())
// instance_tmp = ti
// return result
// }
//
// val result = getInstanceInformation(client, column.instance_uri)
// if(instance_tmp != null) {
//
// }
// result
} }
), ),

View File

@ -519,6 +519,7 @@ object Pref {
val spStripIconSize = StringPref("StripIconSize", "30") val spStripIconSize = StringPref("StripIconSize", "30")
val spMediaSizeMax = StringPref("max_media_size", "8") val spMediaSizeMax = StringPref("max_media_size", "8")
val spMovieSizeMax = StringPref("max_movie_size", "40") val spMovieSizeMax = StringPref("max_movie_size", "40")
val spMediaSizeMaxPixelfed = StringPref("MediaSizeMaxPixelfed", "15")
val spTimelineFont = StringPref("timeline_font", "", skipImport = true) val spTimelineFont = StringPref("timeline_font", "", skipImport = true)
val spTimelineFontBold = StringPref("timeline_font_bold", "", skipImport = true) val spTimelineFontBold = StringPref("timeline_font_bold", "", skipImport = true)
val spMspUserToken = StringPref("mastodon_search_portal_user_token", "") val spMspUserToken = StringPref("mastodon_search_portal_user_token", "")

View File

@ -1,34 +1,97 @@
package jp.juggler.subwaytooter.api.entity package jp.juggler.subwaytooter.api.entity
import android.os.SystemClock
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.TootApiResult
import jp.juggler.subwaytooter.api.TootParser import jp.juggler.subwaytooter.api.TootParser
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.* import jp.juggler.subwaytooter.util.*
import jp.juggler.util.parseInt import jp.juggler.util.*
import jp.juggler.util.parseLong
import jp.juggler.util.parseString
import jp.juggler.util.toStringArrayList
import org.json.JSONObject import org.json.JSONObject
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
class TootInstance(parser : TootParser, src : JSONObject) { class TootInstance(parser : TootParser, src : JSONObject) {
companion object { companion object {
private val rePleroma = Pattern.compile("\\bpleroma\\b", Pattern.CASE_INSENSITIVE) private val rePleroma = Pattern.compile("\\bpleroma\\b", Pattern.CASE_INSENSITIVE)
private val rePixelfed = Pattern.compile("\\bpixelfed\\b", Pattern.CASE_INSENSITIVE)
val VERSION_1_6 = VersionString("1.6") val VERSION_1_6 = VersionString("1.6")
val VERSION_2_4_0_rc1 = VersionString("2.4.0rc1") val VERSION_2_4_0_rc1 = VersionString("2.4.0rc1")
val VERSION_2_4_0_rc2 = VersionString("2.4.0rc2") val VERSION_2_4_0_rc2 = VersionString("2.4.0rc2")
// val VERSION_2_4_0 = VersionString("2.4.0") // val VERSION_2_4_0 = VersionString("2.4.0")
// val VERSION_2_4_1_rc1 = VersionString("2.4.1rc1") // val VERSION_2_4_1_rc1 = VersionString("2.4.1rc1")
val VERSION_2_4_1 = VersionString("2.4.1") val VERSION_2_4_1 = VersionString("2.4.1")
val VERSION_2_6_0 = VersionString("2.6.0") val VERSION_2_6_0 = VersionString("2.6.0")
val VERSION_2_7_0_rc1 = VersionString("2.7.0rc1") val VERSION_2_7_0_rc1 = VersionString("2.7.0rc1")
val VERSION_3_0_0_rc1 = VersionString("3.0.0rc1") val VERSION_3_0_0_rc1 = VersionString("3.0.0rc1")
val MISSKEY_VERSION_11 = VersionString("11.0") val MISSKEY_VERSION_11 = VersionString("11.0")
private const val EXPIRE = 600000L
private val cache = HashMap<String, TootInstance>()
// get from cache
// no request, no expiration check
fun getCached(host : String) : TootInstance? {
synchronized(cache) {
return cache[host.toLowerCase(Locale.JAPAN)]
}
}
fun get(
client : TootApiClient,
account : SavedAccount,
host : String? = null
) : Pair<TootApiResult?, TootInstance?> {
val tmpInstance = client.instance
val tmpAccount = client.account
try {
synchronized(cache) {
// re-use cached item.
val now = SystemClock.elapsedRealtime()
val item = cache[account.host.toLowerCase(Locale.JAPAN)]
if(item != null && now - item.time_parse <= EXPIRE)
return Pair(TootApiResult(), item)
// get new information
client.account = account
if(host != null) client.instance = host
val result = if(account.isMisskey) {
val params = JSONObject().apply {
put("dummy", 1)
}
client.request("/api/meta", params.toPostRequestBuilder())
} else {
client.request("/api/v1/instance")
}
val data = parseItem(
::TootInstance,
TootParser(client.context, account),
result?.jsonObject
)
if(data != null) {
cache[account.host.toLowerCase(Locale.JAPAN)] = data
}
return Pair(result, data)
}
} finally {
client.account = tmpAccount
client.instance = tmpInstance // must be last.
}
}
} }
// いつ取得したか(内部利用) // いつ取得したか(内部利用)
var time_parse : Long = System.currentTimeMillis() private var time_parse : Long = SystemClock.elapsedRealtime()
val isExpire : Boolean
get() = SystemClock.elapsedRealtime() - time_parse >= EXPIRE
// URI of the current instance // URI of the current instance
val uri : String? val uri : String?
@ -64,9 +127,11 @@ class TootInstance(parser : TootParser, src : JSONObject) {
// インスタンスの種別 // インスタンスの種別
enum class InstanceType { enum class InstanceType {
Mastodon, Mastodon,
Pleroma, Misskey,
Misskey Pixelfed,
Pleroma
} }
val instanceType : InstanceType val instanceType : InstanceType
@ -74,15 +139,15 @@ class TootInstance(parser : TootParser, src : JSONObject) {
// XXX: urls をパースしてない。使ってないから… // XXX: urls をパースしてない。使ってないから…
init { init {
if(parser.serviceType == ServiceType.MISSKEY){ if(parser.serviceType == ServiceType.MISSKEY) {
this.uri = parser.accessHost this.uri = parser.accessHost
this.title = parser.accessHost this.title = parser.accessHost
this.description = "(Misskey instance)" this.description = "(Misskey instance)"
val sv = src.optJSONObject("maintainer")?.parseString("url") val sv = src.optJSONObject("maintainer")?.parseString("url")
this.email = when{ this.email = when {
sv?.startsWith("mailto:") ==true-> sv.substring(7) sv?.startsWith("mailto:") == true -> sv.substring(7)
else-> sv else -> sv
} }
this.version = src.parseString("version") this.version = src.parseString("version")
@ -94,15 +159,15 @@ class TootInstance(parser : TootParser, src : JSONObject) {
this.languages = src.optJSONArray("langs")?.toStringArrayList() ?: ArrayList() this.languages = src.optJSONArray("langs")?.toStringArrayList() ?: ArrayList()
this.contact_account = null this.contact_account = null
}else { } else {
this.uri = src.parseString("uri") this.uri = src.parseString("uri")
this.title = src.parseString("title") this.title = src.parseString("title")
this.description = src.parseString("description") this.description = src.parseString("description")
val sv = src.parseString("email") val sv = src.parseString("email")
this.email = when{ this.email = when {
sv?.startsWith("mailto:") ==true-> sv.substring(7) sv?.startsWith("mailto:") == true -> sv.substring(7)
else-> sv else -> sv
} }
this.version = src.parseString("version") this.version = src.parseString("version")
@ -114,6 +179,7 @@ class TootInstance(parser : TootParser, src : JSONObject) {
this.instanceType = when { this.instanceType = when {
rePleroma.matcher(version ?: "").find() -> InstanceType.Pleroma rePleroma.matcher(version ?: "").find() -> InstanceType.Pleroma
rePixelfed.matcher(version ?: "").find() -> InstanceType.Pixelfed
else -> InstanceType.Mastodon else -> InstanceType.Mastodon
} }
@ -145,11 +211,71 @@ class TootInstance(parser : TootParser, src : JSONObject) {
val i = VersionString.compare(decoded_version, check) val i = VersionString.compare(decoded_version, check)
return i >= 0 return i >= 0
} }
val misskeyVersion :Int val misskeyVersion : Int
get()=when{ get() = when {
instanceType != InstanceType.Misskey -> 0 instanceType != InstanceType.Misskey -> 0
versionGE(MISSKEY_VERSION_11) -> 11 versionGE(MISSKEY_VERSION_11) -> 11
else->10 else -> 10
} }
} }
//
//import android.os.SystemClock
//import jp.juggler.subwaytooter.api.TootApiClient
//import jp.juggler.subwaytooter.api.TootApiResult
//import jp.juggler.subwaytooter.api.TootParser
//import jp.juggler.subwaytooter.api.entity.TootInstance
//import jp.juggler.subwaytooter.api.entity.parseItem
//import jp.juggler.subwaytooter.table.SavedAccount
//import jp.juggler.util.toPostRequestBuilder
//import org.json.JSONObject
//import java.util.*
//import kotlin.collections.HashMap
//
//object InstanceInformationCache {
//
//
// // var instance =
// // if(instance == null) {
// // val r2 = getInstanceInformation(client)
// // instance = instance_tmp ?: return r2
// // account.instance = instance
// // }
// // var instance_tmp : TootInstance? = null
// // fun getInstanceInformation(client : TootApiClient) : TootApiResult? {
// //
// // instance_tmp =
// // return result
// // }
// //
// // client.instance = host
// // val result = if(isMisskey) {
// // client.getInstanceInformation()
// // client.request(
// // "/api/meta",
// // account.putMisskeyApiToken().toPostRequestBuilder()
// // )
// // } else {
// // client.request("/api/v1/instance")
// // }
// // newInfo =
// // TootParser(this@ActPost, account).instance(result?.jsonObject)
// // return Pair(null,null)
// // }
//
// //private val refInstance = AtomicReference<TootInstance>(null)
// //
// //// DBには保存しない
// //var instance : TootInstance?
// // get() {
// // val instance = refInstance.get()
// // return when {
// // instance == null -> null
// // System.currentTimeMillis() - instance.time_parse > INSTANCE_INFORMATION_EXPIRE -> null
// // else -> instance
// // }
// // }
// // set(instance) = refInstance.set(instance)
//
//}

View File

@ -66,19 +66,7 @@ class SavedAccount(
var max_toot_chars = 0 var max_toot_chars = 0
private val refInstance = AtomicReference<TootInstance>(null)
// DBには保存しない
var instance : TootInstance?
get() {
val instance = refInstance.get()
return when {
instance == null -> null
System.currentTimeMillis() - instance.time_parse > INSTANCE_INFORMATION_EXPIRE -> null
else -> instance
}
}
set(instance) = refInstance.set(instance)
init { init {
val pos = acct.indexOf('@') val pos = acct.indexOf('@')
@ -431,7 +419,6 @@ class SavedAccount(
///////////////////////////////// /////////////////////////////////
// login information // login information
const val INVALID_DB_ID = - 1L const val INVALID_DB_ID = - 1L
private const val INSTANCE_INFORMATION_EXPIRE = 60000L * 5
// アプリデータのインポート時に呼ばれる // アプリデータのインポート時に呼ばれる
fun onDBDelete(db : SQLiteDatabase) { fun onDBDelete(db : SQLiteDatabase) {

View File

@ -250,7 +250,6 @@ class PostHelper(
var status : TootStatus? = null var status : TootStatus? = null
var instance_tmp : TootInstance? = null
var credential_tmp : TootAccount? = null var credential_tmp : TootAccount? = null
@ -258,19 +257,6 @@ class PostHelper(
var scheduledStatusSucceeded = false var scheduledStatusSucceeded = false
fun getInstanceInformation(client : TootApiClient) : TootApiResult? {
val result = if(account.isMisskey) {
val params = JSONObject().apply {
put("dummy", 1)
}
client.request("/api/meta", params.toPostRequestBuilder())
} else {
client.request("/api/v1/instance")
}
instance_tmp = parseItem(::TootInstance, parser, result?.jsonObject)
return result
}
fun getCredential(client : TootApiClient) : TootApiResult? { fun getCredential(client : TootApiClient) : TootApiResult? {
val result = client.request("/api/v1/accounts/verify_credentials") val result = client.request("/api/v1/accounts/verify_credentials")
credential_tmp = parser.account(result?.jsonObject) credential_tmp = parser.account(result?.jsonObject)
@ -311,12 +297,8 @@ class PostHelper(
var visibility_checked : TootVisibility? = visibility var visibility_checked : TootVisibility? = visibility
var instance = account.instance val(ri,instance) = TootInstance.get(client,account)
if(instance == null) { if(instance==null) return ri
val r2 = getInstanceInformation(client)
instance = instance_tmp ?: return r2
account.instance = instance
}
if(visibility == TootVisibility.WebSetting) { if(visibility == TootVisibility.WebSetting) {
visibility_checked = visibility_checked =

View File

@ -79,6 +79,25 @@
<View style="@style/setting_divider"/> <View style="@style/setting_divider"/>
<TextView
style="@style/setting_row_label"
android:labelFor="@+id/etMediaSizeMaxPixelfed"
android:text="@string/media_attachment_max_byte_size_pixelfed"
/>
<LinearLayout style="@style/setting_row_form">
<EditText
android:id="@+id/etMediaSizeMaxPixelfed"
style="@style/setting_horizontal_stretch"
android:inputType="number"
android:gravity="center"
/>
</LinearLayout>
<View style="@style/setting_divider"/>
<TextView <TextView
style="@style/setting_row_label" style="@style/setting_row_label"
android:text="@string/refresh_after_toot" android:text="@string/refresh_after_toot"

View File

@ -414,6 +414,7 @@
<string name="media_attachment_empty">添付メディアがありません</string> <string name="media_attachment_empty">添付メディアがありません</string>
<string name="media_attachment_max_byte_size">添付メディア(静止画)の最大バイト数(単位:MB。デフォルトは8)</string> <string name="media_attachment_max_byte_size">添付メディア(静止画)の最大バイト数(単位:MB。デフォルトは8)</string>
<string name="media_attachment_max_byte_size_movie">添付メディア(動画)の最大バイト数(単位:MB。デフォルトは40)</string> <string name="media_attachment_max_byte_size_movie">添付メディア(動画)の最大バイト数(単位:MB。デフォルトは40)</string>
<string name="media_attachment_max_byte_size_pixelfed">添付メディア(Pixelfed)の最大バイト数(単位:MB。デフォルトは15)</string>
<string name="media_attachment_still_uploading">添付メディアのアップロードが終わってません</string> <string name="media_attachment_still_uploading">添付メディアのアップロードが終わってません</string>
<string name="media_attachment_type_error">添付メディアの種類\"%1$s\"はこのアプリでは開けません。下の「…」にある「ブラウザで開く」を試すことができます</string> <string name="media_attachment_type_error">添付メディアの種類\"%1$s\"はこのアプリでは開けません。下の「…」にある「ブラウザで開く」を試すことができます</string>
<string name="media_description">(添付 %1$d) %2$s</string> <string name="media_description">(添付 %1$d) %2$s</string>

View File

@ -572,6 +572,9 @@
<string name="your_lists">Your lists</string> <string name="your_lists">Your lists</string>
<string name="media_attachment_max_byte_size">Media attachment (image) bytes size limit (Unit:MB. The default is 8)</string> <string name="media_attachment_max_byte_size">Media attachment (image) bytes size limit (Unit:MB. The default is 8)</string>
<string name="media_attachment_max_byte_size_movie">Media attachment (movie) bytes size limit (Unit:MB. The default is 40)</string> <string name="media_attachment_max_byte_size_movie">Media attachment (movie) bytes size limit (Unit:MB. The default is 40)</string>
<string name="media_attachment_max_byte_size_pixelfed">Media attachment (Pixelfed) bytes size limit (Unit:MB. The default is 15)</string>
<string name="tootsearch">tootsearch (JP)</string> <string name="tootsearch">tootsearch (JP)</string>
<string name="cant_handle_uri_of">Subway Tooter can\'t handle URI \"%1$s\". Please select other app.</string> <string name="cant_handle_uri_of">Subway Tooter can\'t handle URI \"%1$s\". Please select other app.</string>
<string name="use_internal_media_viewer">Use built-in media viewer</string> <string name="use_internal_media_viewer">Use built-in media viewer</string>