feat: Mastodon 互換APIでカスタム絵文字を使用できるように

This commit is contained in:
usbharu 2023-12-22 14:32:11 +09:00
parent 2d84ad073f
commit 8af489c93c
8 changed files with 45 additions and 12 deletions

View File

@ -21,5 +21,6 @@ data class Timeline(
val sensitive: Boolean,
val isLocal: Boolean,
val isPureRepost: Boolean = false,
val mediaIds: List<Long> = emptyList()
val mediaIds: List<Long> = emptyList(),
val emojiIds: List<Long> = emptyList()
)

View File

@ -37,6 +37,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
it[isLocal] = timeline.isLocal
it[isPureRepost] = timeline.isPureRepost
it[mediaIds] = timeline.mediaIds.joinToString(",")
it[emojiIds] = timeline.emojiIds.joinToString(",")
}
} else {
Timelines.update({ Timelines.id eq timeline.id }) {
@ -52,6 +53,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
it[isLocal] = timeline.isLocal
it[isPureRepost] = timeline.isPureRepost
it[mediaIds] = timeline.mediaIds.joinToString(",")
it[emojiIds] = timeline.emojiIds.joinToString(",")
}
}
return@query timeline
@ -72,6 +74,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
this[Timelines.isLocal] = it.isLocal
this[Timelines.isPureRepost] = it.isPureRepost
this[Timelines.mediaIds] = it.mediaIds.joinToString(",")
this[Timelines.emojiIds] = it.emojiIds.joinToString(",")
}
return@query timelines
}
@ -104,7 +107,8 @@ fun ResultRow.toTimeline(): Timeline {
sensitive = this[Timelines.sensitive],
isLocal = this[Timelines.isLocal],
isPureRepost = this[Timelines.isPureRepost],
mediaIds = this[Timelines.mediaIds].split(",").mapNotNull { it.toLongOrNull() }
mediaIds = this[Timelines.mediaIds].split(",").mapNotNull { it.toLongOrNull() },
emojiIds = this[Timelines.emojiIds].split(",").mapNotNull { it.toLongOrNull() }
)
}
@ -122,6 +126,7 @@ object Timelines : Table("timelines") {
val isLocal = bool("is_local")
val isPureRepost = bool("is_pure_repost")
val mediaIds = varchar("media_ids", 255)
val emojiIds = varchar("emoji_ids", 255)
override val primaryKey: PrimaryKey = PrimaryKey(id)

View File

@ -45,7 +45,8 @@ class ExposedGenerateTimelineService(private val statusQueryService: StatusQuery
it[Timelines.postId],
it[Timelines.replyId],
it[Timelines.repostId],
it[Timelines.mediaIds].split(",").mapNotNull { s -> s.toLongOrNull() }
it[Timelines.mediaIds].split(",").mapNotNull { s -> s.toLongOrNull() },
it[Timelines.emojiIds].split(",").mapNotNull { s -> s.toLongOrNull() }
)
}

View File

@ -57,7 +57,8 @@ class MongoGenerateTimelineService(
it.postId,
it.replyId,
it.repostId,
it.mediaIds
it.mediaIds,
it.emojiIds
)
}
)

View File

@ -37,7 +37,8 @@ class TimelineService(
sensitive = post.sensitive,
isLocal = isLocal,
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
mediaIds = post.mediaIds
mediaIds = post.mediaIds,
emojiIds = post.emojiIds
)
}.toMutableList()
if (post.visibility == Visibility.PUBLIC) {
@ -55,7 +56,8 @@ class TimelineService(
sensitive = post.sensitive,
isLocal = isLocal,
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
mediaIds = post.mediaIds
mediaIds = post.mediaIds,
emojiIds = post.emojiIds
)
)
}

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
@ -12,6 +13,7 @@ import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.select
import org.springframework.stereotype.Repository
import java.time.Instant
import dev.usbharu.hideout.domain.mastodon.model.generated.CustomEmoji as MastodonEmoji
@Suppress("IncompleteDestructuring")
@Repository
@ -23,6 +25,10 @@ class StatusQueryServiceImpl : StatusQueryService {
postIdSet.addAll(statusQueries.flatMap { listOfNotNull(it.postId, it.replyId, it.repostId) })
val mediaIdSet = mutableSetOf<Long>()
mediaIdSet.addAll(statusQueries.flatMap { it.mediaIds })
val emojiIdSet = mutableSetOf<Long>()
emojiIdSet.addAll(statusQueries.flatMap { it.emojiIds })
val postMap = Posts
.leftJoin(Actors)
.select { Posts.id inList postIdSet }
@ -32,12 +38,16 @@ class StatusQueryServiceImpl : StatusQueryService {
it[Media.id] to it.toMedia().toMediaAttachments()
}
val emojiMap = CustomEmojis.select { CustomEmojis.id inList emojiIdSet }.associate {
it[CustomEmojis.id] to it.toCustomEmoji().toMastodonEmoji()
}
return statusQueries.mapNotNull { statusQuery ->
postMap[statusQuery.postId]?.copy(
inReplyToId = statusQuery.replyId?.toString(),
inReplyToAccountId = postMap[statusQuery.replyId]?.account?.id,
reblog = postMap[statusQuery.repostId],
mediaAttachments = statusQuery.mediaIds.mapNotNull { mediaMap[it] }
mediaAttachments = statusQuery.mediaIds.mapNotNull { mediaMap[it] },
emojis = statusQuery.emojiIds.mapNotNull { emojiMap[it] }
)
}
}
@ -120,6 +130,8 @@ class StatusQueryServiceImpl : StatusQueryService {
private suspend fun findByPostIdsWithMedia(ids: List<Long>): List<Status> {
val pairs = Posts
.leftJoin(PostsMedia)
.leftJoin(PostsEmojis)
.leftJoin(CustomEmojis)
.leftJoin(Actors)
.leftJoin(Media)
.select { Posts.id inList ids }
@ -129,13 +141,22 @@ class StatusQueryServiceImpl : StatusQueryService {
toStatus(it.first()).copy(
mediaAttachments = it.mapNotNull { resultRow ->
resultRow.toMediaOrNull()?.toMediaAttachments()
}
},
emojis = it.mapNotNull { resultRow -> resultRow.toCustomEmoji()?.toMastodonEmoji() }
) to it.first()[Posts.repostId]
}
return resolveReplyAndRepost(pairs)
}
}
private fun CustomEmoji.toMastodonEmoji(): MastodonEmoji = MastodonEmoji(
shortcode = this.name,
url = this.url,
staticUrl = this.url,
visibleInPicker = true,
category = this.category.orEmpty()
)
private fun toStatus(it: ResultRow) = Status(
id = it[Posts.id].toString(),
uri = it[Posts.apId],

View File

@ -4,5 +4,6 @@ data class StatusQuery(
val postId: Long,
val replyId: Long?,
val repostId: Long?,
val mediaIds: List<Long>
val mediaIds: List<Long>,
val emojiIds: List<Long>
)

View File

@ -98,7 +98,7 @@ create table if not exists posts
reply_id bigint null,
"sensitive" boolean default false not null,
ap_id varchar(100) not null unique,
deleted boolean default false not null
deleted boolean default false not null
);
alter table posts
add constraint fk_posts_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict;
@ -150,7 +150,7 @@ create table if not exists timelines
user_id bigint not null,
timeline_id bigint not null,
post_id bigint not null,
post_actor_id bigint not null,
post_actor_id bigint not null,
created_at bigint not null,
reply_id bigint null,
repost_id bigint null,
@ -158,7 +158,8 @@ create table if not exists timelines
"sensitive" boolean not null,
is_local boolean not null,
is_pure_repost boolean not null,
media_ids varchar(255) not null
media_ids varchar(255) not null,
emoji_ids varchar(255) not null
);
create table if not exists application_authorization