Account.note中のメンションのacctに表示対象アカウントのドメイン名を補う

This commit is contained in:
tateisu 2020-09-20 20:28:14 +09:00
parent 71d16a79ca
commit 4cd5fc8365
7 changed files with 58 additions and 30 deletions

View File

@ -138,10 +138,10 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
this.apiHost = src.string("host")?.let { Host.parse(it) }
?: parser.apiHost
?: error("missing host")
?: error("missing host")
this.url = "https://${apiHost.ascii}/@$username"
this.apDomain = apiHost // FIXME apiHostとapDomainが異なる場合はMisskeyだとどうなの…
@Suppress("LeakingThis")
@ -175,7 +175,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
this.id = EntityId.mayDefault(src.string("id"))
this.followers_count = src.long("followersCount") ?: - 1L
this.following_count = src.long("followingCount") ?: - 1L
this.statuses_count = src.long("notesCount") ?: - 1L
@ -264,7 +264,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
val tmpAcct = src.stringOrThrow("acct")
val(apiHost,apDomain) = findHostFromUrl(tmpAcct, parser.linkHelper, url)
val (apiHost, apDomain) = findHostFromUrl(tmpAcct, parser.linkHelper, url)
apiHost ?: error("can't get apiHost from acct or url")
apDomain ?: error("can't get apDomain from acct or url")
this.apiHost = apiHost
@ -292,7 +292,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
val tmpAcct = src.stringOrThrow("acct")
val(apiHost,apDomain) = findHostFromUrl(tmpAcct, null, url)
val (apiHost, apDomain) = findHostFromUrl(tmpAcct, null, url)
apiHost ?: error("can't get apiHost from acct or url")
apDomain ?: error("can't get apDomain from acct or url")
this.apiHost = apiHost
@ -317,7 +317,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
this.id = EntityId.mayDefault(src.string("id"))
// MSPはLTLの情報しか持ってないのでacctは常にホスト名部分を持たない
val(apiHost,apDomain) = findHostFromUrl(null,null, url)
val (apiHost, apDomain) = findHostFromUrl(null, null, url)
apiHost ?: error("can't get apiHost from acct or url")
apDomain ?: error("can't get apDomain from acct or url")
@ -347,6 +347,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
}
class Source(src : JsonObject) {
// デフォルト公開範囲
val privacy : String?
@ -458,7 +459,8 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
decodeEmoji = true,
emojiMapProfile = profile_emojis,
emojiMapCustom = custom_emojis,
unwrapEmojiImageTag = true
unwrapEmojiImageTag = true,
mentionDefaultDomain = apDomain,
).decodeHTML(note)
.replaceAllEx(reNoteLineFeed, " ")
.trimEx()
@ -486,6 +488,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
}
companion object {
private val log = LogCategory("TootAccount")
internal val reWhitespace = "[\\s\\t\\x0d\\x0a]+".asciiPattern()
@ -544,7 +547,7 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
// MisskeyのMFMはIDNをサポートしていない
private val reMisskeyMentionBase = """@(\w+(?:[\w-]*\w)?)(?:@($reMisskeyHost))?"""
.asciiPattern()
// MFMパース時に使う
internal val reMisskeyMentionMFM = """\A$reMisskeyMentionBase"""
.asciiPattern()
@ -597,34 +600,37 @@ open class TootAccount(parser : TootParser, src : JsonObject) {
}
}
private fun findApDomain(acctArg : String?, linkHelper : LinkHelper?):Host?{
private fun findApDomain(acctArg : String?, linkHelper : LinkHelper?) : Host? {
// acctから調べる
if(acctArg != null) {
val acct = Acct.parse(acctArg)
if(acct.host != null) return acct.host
}
// Acctはnullか、hostを含まない
if(linkHelper != null) return linkHelper.apDomain
return null
}
private fun findApiHost( url:String?):Host?{
private fun findApiHost(url : String?) : Host? {
// URLから調べる
// たぶんどんなURLでもauthorityの部分にホスト名が来るだろう(慢心)
url.mayUri()?.authority?.notEmpty()?.let { return Host.parse(it) }
log.e("findApiHost: can't parse host from URL $url")
return null
}
// Tootsearch用。URLやUriを使ってアカウントのインスタンス名を調べる
fun findHostFromUrl(acctArg : String?, linkHelper : LinkHelper?, url : String?) : Pair<Host?,Host?> {
val apDomain = findApDomain(acctArg,linkHelper)
fun findHostFromUrl(
acctArg : String?,
linkHelper : LinkHelper?,
url : String?
) : Pair<Host?, Host?> {
val apDomain = findApDomain(acctArg, linkHelper)
val apiHost = findApiHost(url)
return Pair( apiHost?: apDomain, apDomain ?: apiHost )
return Pair(apiHost ?: apDomain, apDomain ?: apiHost)
}
fun parseFields(src : JsonArray?) : ArrayList<Field>? {

View File

@ -26,7 +26,8 @@ class TootAccountRef(parser: TootParser, account:TootAccount) : TimelineItem() {
decodeEmoji = true,
emojiMapProfile = account.profile_emojis,
emojiMapCustom = account.custom_emojis,
unwrapEmojiImageTag = true
unwrapEmojiImageTag = true,
mentionDefaultDomain = account.apDomain,
).decodeHTML(account.note)
}

View File

@ -4,10 +4,7 @@ import android.content.Context
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ReplacementSpan
import jp.juggler.subwaytooter.api.entity.CustomEmoji
import jp.juggler.subwaytooter.api.entity.NicoProfileEmoji
import jp.juggler.subwaytooter.api.entity.TootAttachmentLike
import jp.juggler.subwaytooter.api.entity.TootMention
import jp.juggler.subwaytooter.api.entity.*
import jp.juggler.subwaytooter.table.HighlightWord
import jp.juggler.util.WordTrieTree
import java.util.*
@ -27,7 +24,9 @@ class DecodeOptions(
var enlargeEmoji : Float = 1f,
var forceHtml : Boolean = false, // force use HTML instead of Misskey Markdown
var mentionFullAcct : Boolean = false,
var mentions : ArrayList<TootMention>? = null
var mentions : ArrayList<TootMention>? = null,
// Account.note などmentionsがない状況でメンションリンクをfull acct化するにはアカウント等からapDomainを補う必要がある
var mentionDefaultDomain : Host? = null,
) {
internal fun isMediaAttachment(url : String?) : Boolean {

View File

@ -607,8 +607,15 @@ object HTMLDecoder {
// Account.note does not have mentions metadata.
// fallback to resolve acct by mention URL.
val rawAcct = mention?.acct ?: Acct.parse(originalCaption.toString().substring(1))
val fullAcct = getFullAcctOrNull(options.linkHelper, rawAcct, href)
val rawAcct = mention?.acct
?: Acct.parse(originalCaption.toString().substring(1))
val fullAcct = getFullAcctOrNull(
options.linkHelper,
rawAcct,
href,
mentionDefaultDomain = options.mentionDefaultDomain
)
if(fullAcct != null) {

View File

@ -3,8 +3,10 @@ package jp.juggler.subwaytooter.util
import jp.juggler.subwaytooter.api.entity.Acct
import jp.juggler.subwaytooter.api.entity.Host
import jp.juggler.subwaytooter.api.entity.TootAccount
import jp.juggler.subwaytooter.api.entity.TootMention
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.util.groupEx
import java.util.ArrayList
interface LinkHelper {
@ -104,16 +106,21 @@ fun getFullAcctOrNull(
fun getFullAcctOrNull(
linkHelper : LinkHelper?,
src : Acct,
url : String
url : String,
mentionDefaultDomain: Host? = null
) : Acct? {
// 既にFull Acctだった
if(src.host != null) return src
val apDomain = linkHelper?.apDomain
// Account.noteなどメンション情報が含まれない場合、デフォルトのドメインは投稿者のドメインである
if(mentionDefaultDomain!=null){
return src.followHost( mentionDefaultDomain)
}
// トゥート検索等でないならアクセス元ホストを補って良いはず
if(linkHelper is SavedAccount && ! linkHelper.isNA && apDomain != null) {
val apDomain = linkHelper?.apDomain
if(apDomain != null && linkHelper is SavedAccount && ! linkHelper.isNA ) {
return Acct.parse(src.username, apDomain)
}

View File

@ -831,6 +831,7 @@ object MisskeyMarkdownDecoder {
) {
// ユーザが記述したacct
val rawAcct = Acct.parse(username, strHost)
.followHost(options.mentionDefaultDomain)
val linkHelper = linkHelper
if(linkHelper == null) {

View File

@ -11,6 +11,7 @@ import jp.juggler.subwaytooter.table.SavedAccount
import java.util.*
object TootTextEncoder {
private fun StringBuilder.addAfterLine(text : CharSequence) {
if(isNotEmpty() && this[length - 1] != '\n') {
append('\n')
@ -268,7 +269,13 @@ object TootTextEncoder {
sb.addAfterLine("\n")
sb.append(DecodeOptions(context, access_info).decodeHTML(who.note))
sb.append(
DecodeOptions(
context,
access_info,
mentionDefaultDomain = who.apDomain
).decodeHTML(who.note)
)
sb.addAfterLine("\n")
@ -294,7 +301,7 @@ object TootTextEncoder {
addHeader(context, sb, R.string.send_header_account_created_at, who.created_at)
addHeader(context, sb, R.string.send_header_account_statuses_count, who.statuses_count)
if(! Pref.bpHideFollowCount( App1.getAppState(context).pref)) {
if(! Pref.bpHideFollowCount(App1.getAppState(context).pref)) {
addHeader(
context,
sb,