diff options
| author | MeiMei <30769358+mei23@users.noreply.github.com> | 2018-11-02 08:59:40 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2018-11-02 08:59:40 +0900 |
| commit | 80b5fda292efd70cc749910e3672d50c9a70a72e (patch) | |
| tree | a8f287c9c60a532112801d084fcb7d5b8c4e3650 /src/remote | |
| parent | Fix bug (diff) | |
| download | sharkey-80b5fda292efd70cc749910e3672d50c9a70a72e.tar.gz sharkey-80b5fda292efd70cc749910e3672d50c9a70a72e.tar.bz2 sharkey-80b5fda292efd70cc749910e3672d50c9a70a72e.zip | |
Remote custom emojis (#3074)
* Remote custom emojis
* んほおおおおお
Diffstat (limited to 'src/remote')
| -rw-r--r-- | src/remote/activitypub/misc/get-emoji-names.ts | 6 | ||||
| -rw-r--r-- | src/remote/activitypub/models/icon.ts | 5 | ||||
| -rw-r--r-- | src/remote/activitypub/models/note.ts | 39 | ||||
| -rw-r--r-- | src/remote/activitypub/models/tag.ts | 12 | ||||
| -rw-r--r-- | src/remote/activitypub/renderer/emoji.ts | 14 | ||||
| -rw-r--r-- | src/remote/activitypub/renderer/note.ts | 37 |
6 files changed, 108 insertions, 5 deletions
diff --git a/src/remote/activitypub/misc/get-emoji-names.ts b/src/remote/activitypub/misc/get-emoji-names.ts new file mode 100644 index 0000000000..f744d02fed --- /dev/null +++ b/src/remote/activitypub/misc/get-emoji-names.ts @@ -0,0 +1,6 @@ +import parse from '../../../mfm/parse'; + +export default function(text: string) { + if (!text) return []; + return parse(text).filter(t => t.type === 'emoji').map(t => (t as any).emoji); +} diff --git a/src/remote/activitypub/models/icon.ts b/src/remote/activitypub/models/icon.ts new file mode 100644 index 0000000000..50794a937d --- /dev/null +++ b/src/remote/activitypub/models/icon.ts @@ -0,0 +1,5 @@ +export type IIcon = { + type: string; + mediaType?: string; + url?: string; +}; diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index d49cf53079..be6c1bcd18 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -10,6 +10,9 @@ 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 { ITag } from './tag'; +import { toUnicode } from 'punycode'; const log = debug('misskey:activitypub'); @@ -93,6 +96,10 @@ 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 => { + console.log(`extractEmojis: ${e}`); + }); + // ユーザーの情報が古かったらついでに更新しておく if (actor.updatedAt == null || Date.now() - actor.updatedAt.getTime() > 1000 * 60 * 60 * 24) { updatePerson(note.attributedTo); @@ -135,3 +142,35 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver): // 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。 return await createNote(uri, resolver); } + +async function extractEmojis(tags: ITag[], host_: string) { + const host = toUnicode(host_.toLowerCase()); + + if (!tags) return []; + + const eomjiTags = tags.filter(tag => tag.type === 'Emoji' && tag.icon && tag.icon.url); + + return await Promise.all( + eomjiTags.map(async tag => { + const name = tag.name.replace(/^:/, '').replace(/:$/, ''); + + const exists = await Emoji.findOne({ + host, + name + }); + + if (exists) { + return exists; + } + + log(`register emoji host=${host}, name=${name}`); + + return await Emoji.insert({ + host, + name, + url: tag.icon.url, + aliases: [], + }); + }) + ); +} diff --git a/src/remote/activitypub/models/tag.ts b/src/remote/activitypub/models/tag.ts new file mode 100644 index 0000000000..5cdbfa43b1 --- /dev/null +++ b/src/remote/activitypub/models/tag.ts @@ -0,0 +1,12 @@ +import { IIcon } from "./icon"; + +/*** + * tag (ActivityPub) + */ +export type ITag = { + id: string; + type: string; + name?: string; + updated?: Date; + icon?: IIcon; +}; diff --git a/src/remote/activitypub/renderer/emoji.ts b/src/remote/activitypub/renderer/emoji.ts new file mode 100644 index 0000000000..b18337d274 --- /dev/null +++ b/src/remote/activitypub/renderer/emoji.ts @@ -0,0 +1,14 @@ +import { IEmoji } from '../../../models/emoji'; +import config from '../../../config'; + +export default (emoji: IEmoji) => ({ + id: `${config.url}/emojis/${emoji.name}`, + type: 'Emoji', + name: `:${emoji.name}:`, + updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString, + icon: { + type: 'Image', + mediaType: 'image/png', //Mei-TODO + url: emoji.url + } +}); diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts index b3ce1c03e4..a2c591de2e 100644 --- a/src/remote/activitypub/renderer/note.ts +++ b/src/remote/activitypub/renderer/note.ts @@ -1,12 +1,16 @@ import renderDocument from './document'; import renderHashtag from './hashtag'; import renderMention from './mention'; +import renderEmoji from './emoji'; import config from '../../../config'; import DriveFile, { IDriveFile } from '../../../models/drive-file'; import Note, { INote } from '../../../models/note'; import User from '../../../models/user'; import toHtml from '../misc/get-note-html'; import parseMfm from '../../../mfm/parse'; +import getEmojiNames from '../misc/get-emoji-names'; +import Emoji, { IEmoji } from '../../../models/emoji'; +import { unique } from '../../../prelude/array'; export default async function renderNote(note: INote, dive = true): Promise<any> { const promisedFiles: Promise<IDriveFile[]> = note.fileIds @@ -75,10 +79,6 @@ export default async function renderNote(note: INote, dive = true): Promise<any> const hashtagTags = (note.tags || []).map(tag => renderHashtag(tag)); const mentionTags = mentionedUsers.map(u => renderMention(u)); - const tag = [ - ...hashtagTags, - ...mentionTags, - ]; const files = await promisedFiles; @@ -108,12 +108,24 @@ export default async function renderNote(note: INote, dive = true): Promise<any> }).join(''); } + const content = toHtml(Object.assign({}, note, { text })); + + const emojiNames = unique(getEmojiNames(content)); + const emojis = await getEmojis(emojiNames); + const apemojis = emojis.map(emoji => renderEmoji(emoji)); + + const tag = [ + ...hashtagTags, + ...mentionTags, + ...apemojis, + ]; + return { id: `${config.url}/notes/${note._id}`, type: 'Note', attributedTo, summary: note.cw, - content: toHtml(Object.assign({}, note, { text })), + content, _misskey_content: text, published: note.createdAt.toISOString(), to, @@ -124,3 +136,18 @@ export default async function renderNote(note: INote, dive = true): Promise<any> tag }; } + +async function getEmojis(names: string[]): Promise<IEmoji[]> { + if (names == null || names.length < 1) return []; + + const emojis = await Promise.all( + names.map(async name => { + return await Emoji.findOne({ + name, + host: null + }); + }) + ); + + return emojis.filter(emoji => emoji != null); +} |