diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index 9fc03c777..a45946a05 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -10,7 +10,7 @@ import { resolvePerson, updatePerson } from './person'; import { resolveImage } from './image'; import { IRemoteUser, IUser } from '../../../models/user'; import htmlToMFM from '../../../mfm/html-to-mfm'; -import Emoji from '../../../models/emoji'; +import Emoji, { IEmoji } from '../../../models/emoji'; import { ITag } from './tag'; import { toUnicode } from 'punycode'; import { unique, concat, difference } from '../../../prelude/array'; @@ -84,6 +84,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver); + const apHashtags = await extractHashtags(note.tag); + // 添付ファイル // TODO: attachmentは必ずしもImageではない // TODO: attachmentは必ずしも配列ではない @@ -108,10 +110,13 @@ export async function createNote(value: any, resolver?: Resolver, silent = false // テキストのパース const text = note._misskey_content ? note._misskey_content : htmlToMFM(note.content); - await extractEmojis(note.tag, actor.host).catch(e => { + const emojis = await extractEmojis(note.tag, actor.host).catch(e => { console.log(`extractEmojis: ${e}`); + return [] as IEmoji[]; }); + const apEmojis = emojis.map(emoji => emoji.name); + // ユーザーの情報が古かったらついでに更新しておく if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { updatePerson(note.attributedTo); @@ -130,6 +135,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false visibility, visibleUsers, apMentions, + apHashtags, + apEmojis, uri: note.id }, silent); } @@ -199,3 +206,14 @@ async function extractMentionedUsers(actor: IRemoteUser, to: string[], cc: strin return users.filter(x => x != null); } + +function extractHashtags(tags: ITag[]) { + if (!tags) return []; + + const hashtags = tags.filter(tag => tag.type === 'Hashtag' && typeof tag.name == 'string'); + + return hashtags.map(tag => { + const m = tag.name.match(/^#(.+)/); + return m ? m[1] : null; + }).filter(x => x != null); +} diff --git a/src/services/note/create.ts b/src/services/note/create.ts index a35e4fe18..9fee12d6a 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -98,6 +98,8 @@ type Option = { visibility?: string; visibleUsers?: IUser[]; apMentions?: IUser[]; + apHashtags?: string[]; + apEmojis?: string[]; uri?: string; app?: IApp; }; @@ -153,16 +155,22 @@ export default async (user: IUser, data: Option, silent = false) => new Promise< data.text = data.text.trim(); } - // Parse MFM - const tokens = data.text ? parse(data.text) : []; - const cwTokens = data.cw ? parse(data.cw) : []; - const combinedTokens = tokens.concat(cwTokens); + let tags = data.apHashtags; + let emojis = data.apEmojis; + let mentionedUsers = data.apMentions; - const tags = extractHashtags(combinedTokens); + // Parse MFM if needed + if (!tags || !emojis || !mentionedUsers) { + const tokens = data.text ? parse(data.text) : []; + const cwTokens = data.cw ? parse(data.cw) : []; + const combinedTokens = tokens.concat(cwTokens); - const emojis = extractEmojis(combinedTokens); + tags = data.apHashtags || extractHashtags(combinedTokens); - const mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens); + emojis = data.apEmojis || extractEmojis(combinedTokens); + + mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens); + } if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) { mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));