diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index b772f3efd..43e4ddbf3 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -437,6 +437,7 @@ export class ApRendererService { }, _misskey_quote: quote, quoteUrl: quote, + quoteUri: quote, published: note.createdAt.toISOString(), to, cc, @@ -627,6 +628,8 @@ export class ApRendererService { sensitive: 'as:sensitive', Hashtag: 'as:Hashtag', quoteUrl: 'as:quoteUrl', + fedibird: 'http://fedibird.com/ns#', + quoteUri: 'fedibird:quoteUri', // Mastodon toot: 'http://joinmastodon.org/ns#', Emoji: 'toot:Emoji', diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index dc544a01d..261263842 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -205,12 +205,12 @@ export class ApNoteService { // 引用 let quote: MiNote | undefined | null = null; - if (note._misskey_quote ?? note.quoteUrl) { + if (note._misskey_quote ?? note.quoteUrl ?? note.quoteUri) { const tryResolveNote = async (uri: string): Promise< | { status: 'ok'; res: MiNote } | { status: 'permerror' | 'temperror' } > => { - if (!/^https?:/.test(uri)) return { status: 'permerror' }; + if (typeof uri !== 'string' || !/^https?:/.test(uri)) return { status: 'permerror' }; try { const res = await this.resolveNote(uri); if (res == null) return { status: 'permerror' }; @@ -222,7 +222,7 @@ export class ApNoteService { } }; - const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string')); + const uris = unique([note._misskey_quote, note.quoteUrl, note.quoteUri].filter((x): x is string => typeof x === 'string')); const results = await Promise.all(uris.map(tryResolveNote)); quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 16ff86e89..e819c9900 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -118,6 +118,7 @@ export interface IPost extends IObject { _misskey_quote?: string; _misskey_content?: string; quoteUrl?: string; + quoteUri?: string; } export interface IQuestion extends IObject { @@ -129,6 +130,7 @@ export interface IQuestion extends IObject { }; _misskey_quote?: string; quoteUrl?: string; + quoteUri?: string; oneOf?: IQuestionChoice[]; anyOf?: IQuestionChoice[]; endTime?: Date; diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index e08588e8e..599985439 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -217,9 +217,12 @@ const reactButton = shallowRef(); const clipButton = shallowRef(); const likeButton = shallowRef(); let appearNote = $computed(() => isRenote ? note.renote as Misskey.entities.Note : note); +const renoteUrl = appearNote.renote ? appearNote.renote.url : null; +const renoteUri = appearNote.renote ? appearNote.renote.uri : null; + const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); -const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null; +const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)).filter(u => u !== renoteUrl && u !== renoteUri) : null; const isLong = shouldCollapsed(appearNote); const collapsed = ref(appearNote.cw == null && isLong); const isDeleted = ref(false); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 8e1f69a0c..03a417c24 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -257,13 +257,16 @@ const reactButton = shallowRef(); const clipButton = shallowRef(); const likeButton = shallowRef(); let appearNote = $computed(() => isRenote ? note.renote as Misskey.entities.Note : note); +const renoteUrl = appearNote.renote ? appearNote.renote.url : null; +const renoteUri = appearNote.renote ? appearNote.renote.uri : null; + const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); const isDeleted = ref(false); const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords)); const translation = ref(null); const translating = ref(false); -const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null; +const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)).filter(u => u !== renoteUrl && u !== renoteUri) : null; const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance); const conversation = ref([]); const replies = ref([]);