mirror of https://github.com/usbharu/Hideout.git
feat: Mastodon 互換APIでカスタム絵文字を使用できるように
This commit is contained in:
parent
2d84ad073f
commit
8af489c93c
|
@ -21,5 +21,6 @@ data class Timeline(
|
||||||
val sensitive: Boolean,
|
val sensitive: Boolean,
|
||||||
val isLocal: Boolean,
|
val isLocal: Boolean,
|
||||||
val isPureRepost: Boolean = false,
|
val isPureRepost: Boolean = false,
|
||||||
val mediaIds: List<Long> = emptyList()
|
val mediaIds: List<Long> = emptyList(),
|
||||||
|
val emojiIds: List<Long> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
|
@ -37,6 +37,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
|
||||||
it[isLocal] = timeline.isLocal
|
it[isLocal] = timeline.isLocal
|
||||||
it[isPureRepost] = timeline.isPureRepost
|
it[isPureRepost] = timeline.isPureRepost
|
||||||
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
||||||
|
it[emojiIds] = timeline.emojiIds.joinToString(",")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timelines.update({ Timelines.id eq timeline.id }) {
|
Timelines.update({ Timelines.id eq timeline.id }) {
|
||||||
|
@ -52,6 +53,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
|
||||||
it[isLocal] = timeline.isLocal
|
it[isLocal] = timeline.isLocal
|
||||||
it[isPureRepost] = timeline.isPureRepost
|
it[isPureRepost] = timeline.isPureRepost
|
||||||
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
||||||
|
it[emojiIds] = timeline.emojiIds.joinToString(",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@query timeline
|
return@query timeline
|
||||||
|
@ -72,6 +74,7 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
|
||||||
this[Timelines.isLocal] = it.isLocal
|
this[Timelines.isLocal] = it.isLocal
|
||||||
this[Timelines.isPureRepost] = it.isPureRepost
|
this[Timelines.isPureRepost] = it.isPureRepost
|
||||||
this[Timelines.mediaIds] = it.mediaIds.joinToString(",")
|
this[Timelines.mediaIds] = it.mediaIds.joinToString(",")
|
||||||
|
this[Timelines.emojiIds] = it.emojiIds.joinToString(",")
|
||||||
}
|
}
|
||||||
return@query timelines
|
return@query timelines
|
||||||
}
|
}
|
||||||
|
@ -104,7 +107,8 @@ fun ResultRow.toTimeline(): Timeline {
|
||||||
sensitive = this[Timelines.sensitive],
|
sensitive = this[Timelines.sensitive],
|
||||||
isLocal = this[Timelines.isLocal],
|
isLocal = this[Timelines.isLocal],
|
||||||
isPureRepost = this[Timelines.isPureRepost],
|
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 isLocal = bool("is_local")
|
||||||
val isPureRepost = bool("is_pure_repost")
|
val isPureRepost = bool("is_pure_repost")
|
||||||
val mediaIds = varchar("media_ids", 255)
|
val mediaIds = varchar("media_ids", 255)
|
||||||
|
val emojiIds = varchar("emoji_ids", 255)
|
||||||
|
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ class ExposedGenerateTimelineService(private val statusQueryService: StatusQuery
|
||||||
it[Timelines.postId],
|
it[Timelines.postId],
|
||||||
it[Timelines.replyId],
|
it[Timelines.replyId],
|
||||||
it[Timelines.repostId],
|
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() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ class MongoGenerateTimelineService(
|
||||||
it.postId,
|
it.postId,
|
||||||
it.replyId,
|
it.replyId,
|
||||||
it.repostId,
|
it.repostId,
|
||||||
it.mediaIds
|
it.mediaIds,
|
||||||
|
it.emojiIds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -37,7 +37,8 @@ class TimelineService(
|
||||||
sensitive = post.sensitive,
|
sensitive = post.sensitive,
|
||||||
isLocal = isLocal,
|
isLocal = isLocal,
|
||||||
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
|
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
|
||||||
mediaIds = post.mediaIds
|
mediaIds = post.mediaIds,
|
||||||
|
emojiIds = post.emojiIds
|
||||||
)
|
)
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
if (post.visibility == Visibility.PUBLIC) {
|
if (post.visibility == Visibility.PUBLIC) {
|
||||||
|
@ -55,7 +56,8 @@ class TimelineService(
|
||||||
sensitive = post.sensitive,
|
sensitive = post.sensitive,
|
||||||
isLocal = isLocal,
|
isLocal = isLocal,
|
||||||
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
|
isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()),
|
||||||
mediaIds = post.mediaIds
|
mediaIds = post.mediaIds,
|
||||||
|
emojiIds = post.emojiIds
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
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.domain.model.media.toMediaAttachments
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
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.jetbrains.exposed.sql.select
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import dev.usbharu.hideout.domain.mastodon.model.generated.CustomEmoji as MastodonEmoji
|
||||||
|
|
||||||
@Suppress("IncompleteDestructuring")
|
@Suppress("IncompleteDestructuring")
|
||||||
@Repository
|
@Repository
|
||||||
|
@ -23,6 +25,10 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
postIdSet.addAll(statusQueries.flatMap { listOfNotNull(it.postId, it.replyId, it.repostId) })
|
postIdSet.addAll(statusQueries.flatMap { listOfNotNull(it.postId, it.replyId, it.repostId) })
|
||||||
val mediaIdSet = mutableSetOf<Long>()
|
val mediaIdSet = mutableSetOf<Long>()
|
||||||
mediaIdSet.addAll(statusQueries.flatMap { it.mediaIds })
|
mediaIdSet.addAll(statusQueries.flatMap { it.mediaIds })
|
||||||
|
|
||||||
|
val emojiIdSet = mutableSetOf<Long>()
|
||||||
|
emojiIdSet.addAll(statusQueries.flatMap { it.emojiIds })
|
||||||
|
|
||||||
val postMap = Posts
|
val postMap = Posts
|
||||||
.leftJoin(Actors)
|
.leftJoin(Actors)
|
||||||
.select { Posts.id inList postIdSet }
|
.select { Posts.id inList postIdSet }
|
||||||
|
@ -32,12 +38,16 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
it[Media.id] to it.toMedia().toMediaAttachments()
|
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 ->
|
return statusQueries.mapNotNull { statusQuery ->
|
||||||
postMap[statusQuery.postId]?.copy(
|
postMap[statusQuery.postId]?.copy(
|
||||||
inReplyToId = statusQuery.replyId?.toString(),
|
inReplyToId = statusQuery.replyId?.toString(),
|
||||||
inReplyToAccountId = postMap[statusQuery.replyId]?.account?.id,
|
inReplyToAccountId = postMap[statusQuery.replyId]?.account?.id,
|
||||||
reblog = postMap[statusQuery.repostId],
|
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> {
|
private suspend fun findByPostIdsWithMedia(ids: List<Long>): List<Status> {
|
||||||
val pairs = Posts
|
val pairs = Posts
|
||||||
.leftJoin(PostsMedia)
|
.leftJoin(PostsMedia)
|
||||||
|
.leftJoin(PostsEmojis)
|
||||||
|
.leftJoin(CustomEmojis)
|
||||||
.leftJoin(Actors)
|
.leftJoin(Actors)
|
||||||
.leftJoin(Media)
|
.leftJoin(Media)
|
||||||
.select { Posts.id inList ids }
|
.select { Posts.id inList ids }
|
||||||
|
@ -129,13 +141,22 @@ class StatusQueryServiceImpl : StatusQueryService {
|
||||||
toStatus(it.first()).copy(
|
toStatus(it.first()).copy(
|
||||||
mediaAttachments = it.mapNotNull { resultRow ->
|
mediaAttachments = it.mapNotNull { resultRow ->
|
||||||
resultRow.toMediaOrNull()?.toMediaAttachments()
|
resultRow.toMediaOrNull()?.toMediaAttachments()
|
||||||
}
|
},
|
||||||
|
emojis = it.mapNotNull { resultRow -> resultRow.toCustomEmoji()?.toMastodonEmoji() }
|
||||||
) to it.first()[Posts.repostId]
|
) to it.first()[Posts.repostId]
|
||||||
}
|
}
|
||||||
return resolveReplyAndRepost(pairs)
|
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(
|
private fun toStatus(it: ResultRow) = Status(
|
||||||
id = it[Posts.id].toString(),
|
id = it[Posts.id].toString(),
|
||||||
uri = it[Posts.apId],
|
uri = it[Posts.apId],
|
||||||
|
|
|
@ -4,5 +4,6 @@ data class StatusQuery(
|
||||||
val postId: Long,
|
val postId: Long,
|
||||||
val replyId: Long?,
|
val replyId: Long?,
|
||||||
val repostId: Long?,
|
val repostId: Long?,
|
||||||
val mediaIds: List<Long>
|
val mediaIds: List<Long>,
|
||||||
|
val emojiIds: List<Long>
|
||||||
)
|
)
|
||||||
|
|
|
@ -98,7 +98,7 @@ create table if not exists posts
|
||||||
reply_id bigint null,
|
reply_id bigint null,
|
||||||
"sensitive" boolean default false not null,
|
"sensitive" boolean default false not null,
|
||||||
ap_id varchar(100) not null unique,
|
ap_id varchar(100) not null unique,
|
||||||
deleted boolean default false not null
|
deleted boolean default false not null
|
||||||
);
|
);
|
||||||
alter table posts
|
alter table posts
|
||||||
add constraint fk_posts_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict;
|
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,
|
user_id bigint not null,
|
||||||
timeline_id bigint not null,
|
timeline_id bigint not null,
|
||||||
post_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,
|
created_at bigint not null,
|
||||||
reply_id bigint null,
|
reply_id bigint null,
|
||||||
repost_id bigint null,
|
repost_id bigint null,
|
||||||
|
@ -158,7 +158,8 @@ create table if not exists timelines
|
||||||
"sensitive" boolean not null,
|
"sensitive" boolean not null,
|
||||||
is_local boolean not null,
|
is_local boolean not null,
|
||||||
is_pure_repost 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
|
create table if not exists application_authorization
|
||||||
|
|
Loading…
Reference in New Issue