Make mentions work

This commit is contained in:
Laura Hausmann 2023-07-02 21:30:00 +02:00
parent 332371c481
commit b069d8201f
Signed by: zotan
GPG key ID: D044E84C5BE01605
2 changed files with 106 additions and 31 deletions

View file

@ -7,6 +7,7 @@ import OAuth from './oauth'
import Response from './response'
import Entity from './entity'
import { MegalodonInterface, WebSocketInterface, NoImplementedError, ArgumentError, UnexpectedError } from './megalodon'
import MegalodonEntity from "@/entity";
export default class Misskey implements MegalodonInterface {
public client: MisskeyAPI.Interface
@ -285,6 +286,19 @@ export default class Misskey implements MegalodonInterface {
})
}
public async getAccountByName(user: string, host: string | null): Promise<Response<Entity.Account>> {
return this.client
.post<MisskeyAPI.Entity.UserDetail>('/api/users/show', {
username: user,
host: host ?? null
})
.then(res => {
return Object.assign(res, {
data: this.converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl))
})
})
}
/**
* POST /api/users/notes
*/
@ -305,11 +319,14 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.UserDetail>('/api/users/show', {
userId: id
})
.then(res => {
.then(async res => {
if (res.data.pinnedNotes) {
return { ...res, data: res.data.pinnedNotes.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }
return {
...res,
data: await Promise.all(res.data.pinnedNotes.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl))))
}
}
return { ...res, data: [] }
return {...res, data: []}
})
}
@ -348,8 +365,8 @@ export default class Misskey implements MegalodonInterface {
})
}
}
return this.client.post<Array<MisskeyAPI.Entity.Note>>('/api/users/notes', params).then(res => {
const statuses: Array<Entity.Status> = res.data.map(note => this.converter.note(note, this.baseUrlToHost(this.baseUrl)))
return this.client.post<Array<MisskeyAPI.Entity.Note>>('/api/users/notes', params).then(async res => {
const statuses: Array<Entity.Status> = await Promise.all(res.data.map(note => this.noteWithMentions(note, this.baseUrlToHost(this.baseUrl))))
return Object.assign(res, {
data: statuses
})
@ -384,9 +401,9 @@ export default class Misskey implements MegalodonInterface {
})
}
}
return this.client.post<Array<MisskeyAPI.Entity.Favorite>>('/api/users/reactions', params).then(res => {
return this.client.post<Array<MisskeyAPI.Entity.Favorite>>('/api/users/reactions', params).then(async res => {
return Object.assign(res, {
data: res.data.map(fav => this.converter.note(fav.note, this.baseUrlToHost(this.baseUrl)))
data: await Promise.all(res.data.map(fav => this.noteWithMentions(fav.note, this.baseUrlToHost(this.baseUrl))))
})
})
}
@ -692,9 +709,9 @@ export default class Misskey implements MegalodonInterface {
})
}
}
return this.client.post<Array<MisskeyAPI.Entity.Favorite>>('/api/i/favorites', params).then(res => {
return this.client.post<Array<MisskeyAPI.Entity.Favorite>>('/api/i/favorites', params).then(async res => {
return Object.assign(res, {
data: res.data.map(s => this.converter.note(s.note, this.baseUrlToHost(this.baseUrl)))
data: await Promise.all(res.data.map(s => this.noteWithMentions(s.note, this.baseUrlToHost(this.baseUrl))))
})
})
}
@ -1120,7 +1137,10 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<MisskeyAPI.Entity.CreatedNote>('/api/notes/create', params)
.then(res => ({ ...res, data: this.converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({
...res,
data: await this.noteWithMentions(res.data.createdNote, this.baseUrlToHost(this.baseUrl))
}))
}
/**
@ -1131,7 +1151,46 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({ ...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}));
}
public async noteWithMentions(n: MisskeyAPI.Entity.Note, host: string): Promise<MegalodonEntity.Status> {
const status = await this.converter.note(n, host);
return status.mentions.length === 0 ? this.addMentionsToStatus(status) : status;
}
public async addMentionsToStatus(status: Entity.Status) : Promise<Entity.Status> {
status.mentions = (await this.getMentions(status.plain_content!)).filter(p => p != null);
for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) {
status.content = status.content.replace(`@${m.acct}`, `<a href="${m.url}" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@${m.acct}</a>`);
}
return status;
}
public async getMentions(text: string): Promise<Entity.Mention[]> {
const mentions :Entity.Mention[] = [];
const mentionMatch = text.matchAll(/(?<=^|\s)@(?<user>.*?)(?:@(?<host>.*?)|)(?=\s|$)/g);
for (const m of mentionMatch) {
console.log(`regex match:`);
console.log(JSON.stringify(m, null, 2));
if (m.groups == null)
continue;
const account = await this.getAccountByName(m.groups.user, m.groups?.host ?? null);
if (!account)
continue;
mentions.push({
id: account.data.id,
url: account.data.url,
username: account.data.username,
acct: account.data.acct
});
}
return mentions;
}
public async editStatus(
@ -1217,7 +1276,7 @@ export default class Misskey implements MegalodonInterface {
const context: Entity.Context = {
ancestors: parents.reverse(),
descendants: this.dfs(res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))))
descendants: this.dfs(await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl)))))
}
return {
...res,
@ -1321,7 +1380,10 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.CreatedNote>('/api/notes/create', {
renoteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({
...res,
data: await this.noteWithMentions(res.data.createdNote, this.baseUrlToHost(this.baseUrl))
}))
}
/**
@ -1335,7 +1397,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
/**
@ -1349,7 +1411,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
/**
@ -1363,7 +1425,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
public async muteStatus(_id: string): Promise<Response<Entity.Status>> {
@ -1391,7 +1453,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
/**
@ -1405,7 +1467,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
// ======================================
@ -1490,9 +1552,9 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: status_id
})
.then(res => {
const note = this.converter.note(res.data, this.baseUrlToHost(this.baseUrl))
return { ...res, data: note.poll }
.then(async res => {
const note = await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))
return {...res, data: note.poll}
})
if (!res.data) {
return new Promise((_, reject) => {
@ -1582,7 +1644,10 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/global-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }))
.then(async res => ({
...res,
data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl))))
}))
}
/**
@ -1625,7 +1690,10 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/local-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }))
.then(async res => ({
...res,
data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl))))
}))
}
/**
@ -1674,7 +1742,10 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/search-by-tag', params)
.then(res => ({ ...res, data: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }))
.then(async res => ({
...res,
data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl))))
}))
}
/**
@ -1714,7 +1785,10 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/timeline', params)
.then(res => ({ ...res, data: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }))
.then(async res => ({
...res,
data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl))))
}))
}
/**
@ -1757,7 +1831,7 @@ export default class Misskey implements MegalodonInterface {
}
return this.client
.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/user-list-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))) }))
.then(async res => ({ ...res, data: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl)))) }))
}
// ======================================
@ -2126,11 +2200,11 @@ export default class Misskey implements MegalodonInterface {
})
}
}
return this.client.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/search', params).then(res => ({
return this.client.post<Array<MisskeyAPI.Entity.Note>>('/api/notes/search', params).then(async res => ({
...res,
data: {
accounts: [],
statuses: res.data.map(n => this.converter.note(n, this.baseUrlToHost(this.baseUrl))),
statuses: await Promise.all(res.data.map(n => this.noteWithMentions(n, this.baseUrlToHost(this.baseUrl)))),
hashtags: []
}
}))
@ -2268,7 +2342,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
/**
@ -2282,7 +2356,7 @@ export default class Misskey implements MegalodonInterface {
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: this.converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }))
.then(async res => ({...res, data: await this.noteWithMentions(res.data, this.baseUrlToHost(this.baseUrl))}))
}
public async getEmojiReactions(id: string): Promise<Response<Array<Entity.Reaction>>> {

View file

@ -162,7 +162,7 @@ namespace MisskeyAPI {
following_count: u.followingCount,
statuses_count: u.notesCount,
note: u.description,
url: acct,
url: acctUrl,
avatar: u.avatarUrl,
avatar_static: u.avatarUrl,
header: u.bannerUrl ?? this.plcUrl,
@ -292,6 +292,7 @@ namespace MisskeyAPI {
note = (n: Entity.Note, host: string): MegalodonEntity.Status => {
host = host.replace('https://', '')
return {
id: n.id,
uri: n.uri ? n.uri : `https://${host}/notes/${n.id}`,