Merge pull request '[PR]: [mastodon-client] More improvements' (#10435) from e2net/calckey:masto-client-improvements into develop
Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10435
This commit is contained in:
commit
f8ed3fac13
6 changed files with 84 additions and 23 deletions
|
@ -10,7 +10,7 @@ import type { Note } from "@/models/entities/note.js";
|
||||||
import type { CacheableLocalUser, User } from "@/models/entities/user.js";
|
import type { CacheableLocalUser, User } from "@/models/entities/user.js";
|
||||||
import { isActor, isPost, getApId } from "@/remote/activitypub/type.js";
|
import { isActor, isPost, getApId } from "@/remote/activitypub/type.js";
|
||||||
import type { SchemaType } from "@/misc/schema.js";
|
import type { SchemaType } from "@/misc/schema.js";
|
||||||
import { HOUR } from "@/const.js";
|
import { MINUTE } from "@/const.js";
|
||||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||||
import { updateQuestion } from "@/remote/activitypub/models/question.js";
|
import { updateQuestion } from "@/remote/activitypub/models/question.js";
|
||||||
import { populatePoll } from "@/models/repositories/note.js";
|
import { populatePoll } from "@/models/repositories/note.js";
|
||||||
|
@ -22,8 +22,8 @@ export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
duration: HOUR,
|
duration: MINUTE,
|
||||||
max: 30,
|
max: 10,
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
|
|
@ -42,6 +42,7 @@ export function apiSearchMastodon(router: Router): void {
|
||||||
!type || type === "hashtags"
|
!type || type === "hashtags"
|
||||||
? await client.search(query.q, "hashtags", query)
|
? await client.search(query.q, "hashtags", query)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
accounts:
|
accounts:
|
||||||
acct?.data?.accounts.map((account) => convertAccount(account)) ?? [],
|
acct?.data?.accounts.map((account) => convertAccount(account)) ?? [],
|
||||||
|
|
|
@ -9,5 +9,6 @@ namespace Entity {
|
||||||
votes_count: number
|
votes_count: number
|
||||||
options: Array<PollOption>
|
options: Array<PollOption>
|
||||||
voted: boolean
|
voted: boolean
|
||||||
|
own_votes: Array<number>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -841,7 +841,7 @@ export interface MegalodonInterface {
|
||||||
* @param choices Array of own votes containing index for each option (starting from 0).
|
* @param choices Array of own votes containing index for each option (starting from 0).
|
||||||
* @return Poll
|
* @return Poll
|
||||||
*/
|
*/
|
||||||
votePoll(id: string, choices: Array<number>, status_id?: string | null): Promise<Response<Entity.Poll>>
|
votePoll(id: string, choices: Array<number>): Promise<Response<Entity.Poll>>
|
||||||
// ======================================
|
// ======================================
|
||||||
// statuses/scheduled_statuses
|
// statuses/scheduled_statuses
|
||||||
// ======================================
|
// ======================================
|
||||||
|
|
|
@ -1281,6 +1281,8 @@ export default class Misskey implements MegalodonInterface {
|
||||||
|
|
||||||
status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null);
|
status.mentions = (await this.getMentions(status.plain_content!, cache)).filter(p => p != null);
|
||||||
for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) {
|
for (const m of status.mentions.filter((value, index, array) => array.indexOf(value) === index)) {
|
||||||
|
if (m.acct == m.username)
|
||||||
|
status.content = status.content.replace(`@${m.acct}@${this.baseUrlToHost(this.baseUrl)}`, `@${m.acct}`);
|
||||||
status.content = status.content.replace(`@${m.acct}`, `<a href="${m.url}" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@${m.acct}</a>`);
|
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;
|
return status;
|
||||||
|
@ -1686,31 +1688,35 @@ export default class Misskey implements MegalodonInterface {
|
||||||
// ======================================
|
// ======================================
|
||||||
// statuses/polls
|
// statuses/polls
|
||||||
// ======================================
|
// ======================================
|
||||||
public async getPoll(_id: string): Promise<Response<Entity.Poll>> {
|
public async getPoll(id: string): Promise<Response<Entity.Poll>> {
|
||||||
return new Promise((_, reject) => {
|
const res = await this.getStatus(id);
|
||||||
const err = new NoImplementedError('misskey does not support')
|
if (res.data.poll == null)
|
||||||
reject(err)
|
throw new Error('poll not found');
|
||||||
})
|
return { ...res, data: res.data.poll }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/notes/polls/vote
|
* POST /api/notes/polls/vote
|
||||||
*/
|
*/
|
||||||
public async votePoll(_id: string, choices: Array<number>, status_id?: string | null): Promise<Response<Entity.Poll>> {
|
public async votePoll(id: string, choices: Array<number>): Promise<Response<Entity.Poll>> {
|
||||||
if (!status_id) {
|
if (!id) {
|
||||||
return new Promise((_, reject) => {
|
return new Promise((_, reject) => {
|
||||||
const err = new ArgumentError('status_id is required')
|
const err = new ArgumentError('id is required')
|
||||||
reject(err)
|
reject(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const c of choices) {
|
||||||
const params = {
|
const params = {
|
||||||
noteId: status_id,
|
noteId: id,
|
||||||
choice: choices[0]
|
choice: +c
|
||||||
}
|
}
|
||||||
await this.client.post<{}>('/api/notes/polls/vote', params)
|
await this.client.post<{}>('/api/notes/polls/vote', params)
|
||||||
|
}
|
||||||
|
|
||||||
const res = await this.client
|
const res = await this.client
|
||||||
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
|
.post<MisskeyAPI.Entity.Note>('/api/notes/show', {
|
||||||
noteId: status_id
|
noteId: id
|
||||||
})
|
})
|
||||||
.then(async res => {
|
.then(async res => {
|
||||||
const note = await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())
|
const note = await this.noteWithDetails(res.data, this.baseUrlToHost(this.baseUrl), this.getFreshAccountCache())
|
||||||
|
@ -2389,6 +2395,32 @@ export default class Misskey implements MegalodonInterface {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'accounts': {
|
case 'accounts': {
|
||||||
|
if (q.startsWith("http://") || q.startsWith("https://")) {
|
||||||
|
return this.client.post('/api/ap/show', {uri: q}).then(async res => {
|
||||||
|
if (res.status != 200 || res.data.type != 'User') {
|
||||||
|
res.status = 200;
|
||||||
|
res.statusText = "OK";
|
||||||
|
res.data = {
|
||||||
|
accounts: [],
|
||||||
|
statuses: [],
|
||||||
|
hashtags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await this.converter.userDetail(res.data.object as MisskeyAPI.Entity.UserDetail, this.baseUrlToHost(this.baseUrl));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...res,
|
||||||
|
data: {
|
||||||
|
accounts: options?.max_id && options?.max_id >= account.id ? [] : [account],
|
||||||
|
statuses: [],
|
||||||
|
hashtags: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
let params = {
|
let params = {
|
||||||
query: q
|
query: q
|
||||||
}
|
}
|
||||||
|
@ -2462,6 +2494,32 @@ export default class Misskey implements MegalodonInterface {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
case 'statuses': {
|
case 'statuses': {
|
||||||
|
if (q.startsWith("http://") || q.startsWith("https://")) {
|
||||||
|
return this.client.post('/api/ap/show', {uri: q}).then(async res => {
|
||||||
|
if (res.status != 200 || res.data.type != 'Note') {
|
||||||
|
res.status = 200;
|
||||||
|
res.statusText = "OK";
|
||||||
|
res.data = {
|
||||||
|
accounts: [],
|
||||||
|
statuses: [],
|
||||||
|
hashtags: []
|
||||||
|
};
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const post = await this.noteWithDetails(res.data.object as MisskeyAPI.Entity.Note, this.baseUrlToHost(this.baseUrl), accountCache);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...res,
|
||||||
|
data: {
|
||||||
|
accounts: [],
|
||||||
|
statuses: options?.max_id && options.max_id >= post.id ? [] : [post],
|
||||||
|
hashtags: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
let params = {
|
let params = {
|
||||||
query: q
|
query: q
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ namespace MisskeyAPI {
|
||||||
followers_count: u.followersCount,
|
followers_count: u.followersCount,
|
||||||
following_count: u.followingCount,
|
following_count: u.followingCount,
|
||||||
statuses_count: u.notesCount,
|
statuses_count: u.notesCount,
|
||||||
note: u.description,
|
note: u.description?.replace(/\n|\\n/g, '<br>') ?? '',
|
||||||
url: acctUrl,
|
url: acctUrl,
|
||||||
avatar: u.avatarUrl,
|
avatar: u.avatarUrl,
|
||||||
avatar_static: u.avatarUrl,
|
avatar_static: u.avatarUrl,
|
||||||
|
@ -275,18 +275,19 @@ namespace MisskeyAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
poll = (p: Entity.Poll): MegalodonEntity.Poll => {
|
poll = (p: Entity.Poll, id: string): MegalodonEntity.Poll => {
|
||||||
const now = dayjs()
|
const now = dayjs()
|
||||||
const expire = dayjs(p.expiresAt)
|
const expire = dayjs(p.expiresAt)
|
||||||
const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0)
|
const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0)
|
||||||
return {
|
return {
|
||||||
id: '',
|
id: id,
|
||||||
expires_at: p.expiresAt,
|
expires_at: p.expiresAt,
|
||||||
expired: now.isAfter(expire),
|
expired: now.isAfter(expire),
|
||||||
multiple: p.multiple,
|
multiple: p.multiple,
|
||||||
votes_count: count,
|
votes_count: count,
|
||||||
options: p.choices.map(c => this.choice(c)),
|
options: p.choices.map(c => this.choice(c)),
|
||||||
voted: p.choices.some(c => c.isVoted)
|
voted: p.choices.some(c => c.isVoted),
|
||||||
|
own_votes: p.choices.filter(c => c.isVoted).map(c => p.choices.indexOf(c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +319,7 @@ namespace MisskeyAPI {
|
||||||
mentions: [],
|
mentions: [],
|
||||||
tags: [],
|
tags: [],
|
||||||
card: null,
|
card: null,
|
||||||
poll: n.poll ? this.poll(n.poll) : null,
|
poll: n.poll ? this.poll(n.poll, n.id) : null,
|
||||||
application: null,
|
application: null,
|
||||||
language: null,
|
language: null,
|
||||||
pinned: null,
|
pinned: null,
|
||||||
|
|
Loading…
Reference in a new issue