Merge pull request '[PR]: Next batch of masto-client improvements' (#10440) from e2net/calckey:masto-client-improvements into develop
Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10440
This commit is contained in:
commit
80b60af9f4
6 changed files with 62 additions and 127 deletions
|
@ -33,7 +33,7 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
if (ps.key !== "reactions") return;
|
if (ps.key !== "reactions" && ps.key !== "defaultNoteVisibility") return;
|
||||||
const query = RegistryItems.createQueryBuilder("item")
|
const query = RegistryItems.createQueryBuilder("item")
|
||||||
.where("item.domain IS NULL")
|
.where("item.domain IS NULL")
|
||||||
.andWhere("item.userId = :userId", { userId: user.id })
|
.andWhere("item.userId = :userId", { userId: user.id })
|
||||||
|
|
|
@ -112,7 +112,7 @@ mastoFileRouter.post("/v2/media", upload.single("file"), async (ctx) => {
|
||||||
ctx.status = 401;
|
ctx.status = 401;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = await client.uploadMedia(multipartData);
|
const data = await client.uploadMedia(multipartData, ctx.request.body);
|
||||||
ctx.body = convertAttachment(data.data as Entity.Attachment);
|
ctx.body = convertAttachment(data.data as Entity.Attachment);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
|
@ -48,7 +48,7 @@ export function apiAccountMastodon(router: Router): void {
|
||||||
acct.source = {
|
acct.source = {
|
||||||
note: acct.note,
|
note: acct.note,
|
||||||
fields: acct.fields,
|
fields: acct.fields,
|
||||||
privacy: "public",
|
privacy: await client.getDefaultPostPrivacy(),
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
language: "",
|
language: "",
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,27 +123,7 @@ export function apiStatusMastodon(router: Router): void {
|
||||||
id,
|
id,
|
||||||
convertTimelinesArgsId(limitToInt(ctx.query as any)),
|
convertTimelinesArgsId(limitToInt(ctx.query as any)),
|
||||||
);
|
);
|
||||||
const status = await client.getStatus(id);
|
|
||||||
let reqInstance = axios.create({
|
|
||||||
headers: {
|
|
||||||
Authorization: ctx.headers.authorization,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const reactionsAxios = await reqInstance.get(
|
|
||||||
`${BASE_URL}/api/notes/reactions?noteId=${id}`,
|
|
||||||
);
|
|
||||||
const reactions: IReaction[] = reactionsAxios.data;
|
|
||||||
const text = reactions
|
|
||||||
.map((r) => `${r.type.replace("@.", "")} ${r.user.username}`)
|
|
||||||
.join("<br />");
|
|
||||||
data.data.descendants.unshift(
|
|
||||||
statusModel(
|
|
||||||
status.data.id,
|
|
||||||
status.data.account.id,
|
|
||||||
status.data.emojis,
|
|
||||||
text,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
data.data.ancestors = data.data.ancestors.map((status) =>
|
data.data.ancestors = data.data.ancestors.map((status) =>
|
||||||
convertStatus(status),
|
convertStatus(status),
|
||||||
);
|
);
|
||||||
|
@ -456,65 +436,3 @@ async function getFirstReaction(
|
||||||
return react;
|
return react;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function statusModel(
|
|
||||||
id: string | null,
|
|
||||||
acctId: string | null,
|
|
||||||
emojis: MastodonEntity.Emoji[],
|
|
||||||
content: string,
|
|
||||||
) {
|
|
||||||
const now = new Date().toISOString();
|
|
||||||
return {
|
|
||||||
id: "9atm5frjhb",
|
|
||||||
uri: "/static-assets/transparent.png", // ""
|
|
||||||
url: "/static-assets/transparent.png", // "",
|
|
||||||
account: {
|
|
||||||
id: "9arzuvv0sw",
|
|
||||||
username: "Reactions",
|
|
||||||
acct: "Reactions",
|
|
||||||
display_name: "Reactions to this post",
|
|
||||||
locked: false,
|
|
||||||
created_at: now,
|
|
||||||
followers_count: 0,
|
|
||||||
following_count: 0,
|
|
||||||
statuses_count: 0,
|
|
||||||
note: "",
|
|
||||||
url: "/static-assets/transparent.png",
|
|
||||||
avatar: "/static-assets/badges/info.png",
|
|
||||||
avatar_static: "/static-assets/badges/info.png",
|
|
||||||
header: "/static-assets/transparent.png", // ""
|
|
||||||
header_static: "/static-assets/transparent.png", // ""
|
|
||||||
emojis: [],
|
|
||||||
fields: [],
|
|
||||||
moved: null,
|
|
||||||
bot: false,
|
|
||||||
},
|
|
||||||
in_reply_to_id: id,
|
|
||||||
in_reply_to_account_id: acctId,
|
|
||||||
reblog: null,
|
|
||||||
content: `<p>${content}</p>`,
|
|
||||||
plain_content: null,
|
|
||||||
created_at: now,
|
|
||||||
emojis: emojis,
|
|
||||||
replies_count: 0,
|
|
||||||
reblogs_count: 0,
|
|
||||||
favourites_count: 0,
|
|
||||||
favourited: false,
|
|
||||||
reblogged: false,
|
|
||||||
muted: false,
|
|
||||||
sensitive: false,
|
|
||||||
spoiler_text: "",
|
|
||||||
visibility: "public" as const,
|
|
||||||
media_attachments: [],
|
|
||||||
mentions: [],
|
|
||||||
tags: [],
|
|
||||||
card: null,
|
|
||||||
poll: null,
|
|
||||||
application: null,
|
|
||||||
language: null,
|
|
||||||
pinned: false,
|
|
||||||
emoji_reactions: [],
|
|
||||||
bookmarked: false,
|
|
||||||
quote: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -460,7 +460,7 @@ export default class Misskey implements MegalodonInterface {
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.limit) {
|
if (options.limit) {
|
||||||
params = Object.assign(params, {
|
params = Object.assign(params, {
|
||||||
limit: options.limit
|
limit: options.limit <= 100 ? options.limit : 100
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -474,9 +474,9 @@ export default class Misskey implements MegalodonInterface {
|
||||||
limit: 40
|
limit: 40
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return this.client.post<Array<MisskeyAPI.Entity.Follower>>('/api/users/followers', params).then(res => {
|
return this.client.post<Array<MisskeyAPI.Entity.Follower>>('/api/users/followers', params).then(async res => {
|
||||||
return Object.assign(res, {
|
return Object.assign(res, {
|
||||||
data: res.data.map(f => this.converter.follower(f))
|
data: (await Promise.all(res.data.map(async f => (this.getAccount(f.followerId)).then(p => p.data))))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -498,13 +498,13 @@ export default class Misskey implements MegalodonInterface {
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.limit) {
|
if (options.limit) {
|
||||||
params = Object.assign(params, {
|
params = Object.assign(params, {
|
||||||
limit: options.limit
|
limit: options.limit <= 100 ? options.limit : 100
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.client.post<Array<MisskeyAPI.Entity.Following>>('/api/users/following', params).then(res => {
|
return this.client.post<Array<MisskeyAPI.Entity.Following>>('/api/users/following', params).then(async res => {
|
||||||
return Object.assign(res, {
|
return Object.assign(res, {
|
||||||
data: res.data.map(f => this.converter.following(f))
|
data: (await Promise.all(res.data.map(async f => (this.getAccount(f.followeeId)).then(p => p.data))))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1079,21 +1079,9 @@ export default class Misskey implements MegalodonInterface {
|
||||||
// accounts/preferences
|
// accounts/preferences
|
||||||
// ======================================
|
// ======================================
|
||||||
public async getPreferences(): Promise<Response<Entity.Preferences>> {
|
public async getPreferences(): Promise<Response<Entity.Preferences>> {
|
||||||
return this.client.post<MisskeyAPI.Entity.UserDetailMe>('/api/i').then(res => {
|
return this.client.post<MisskeyAPI.Entity.UserDetailMe>('/api/i').then(async res => {
|
||||||
/*
|
|
||||||
return this.client.post<MisskeyAPI.Entity.GetAll>('/api/i/registry/get-all', {
|
|
||||||
scope: ['client', 'base'],
|
|
||||||
}).then(ga => {
|
|
||||||
return Object.assign(res, {
|
return Object.assign(res, {
|
||||||
data: this.converter.userPreferences(res.data, ga.data)
|
data: this.converter.userPreferences(res.data, await this.getDefaultPostPrivacy())
|
||||||
})
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// FIXME: get this from api
|
|
||||||
return Object.assign(res, {
|
|
||||||
data: this.converter.userPreferences(res.data, {defaultNoteVisibility: "followers", tutorial: -1})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1529,6 +1517,23 @@ export default class Misskey implements MegalodonInterface {
|
||||||
.then(res => res.data[0] ?? '⭐');
|
.then(res => res.data[0] ?? '⭐');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getDefaultPostPrivacy(): Promise<'public' | 'unlisted' | 'private' | 'direct'> {
|
||||||
|
// NOTE: get-unsecure is calckey's extension.
|
||||||
|
// Misskey doesn't have this endpoint and regular `/i/registry/get` won't work
|
||||||
|
// unless you have a 'nativeToken', which is reserved for the frontend webapp.
|
||||||
|
|
||||||
|
return this.client
|
||||||
|
.post<string>('/api/i/registry/get-unsecure', {
|
||||||
|
key: 'defaultNoteVisibility',
|
||||||
|
scope: ['client', 'base'],
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (!res.data || (res.data != 'public' && res.data != 'home' && res.data != 'followers' && res.data != 'specified'))
|
||||||
|
return 'public';
|
||||||
|
return this.converter.visibility(res.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async unfavouriteStatus(id: string): Promise<Response<Entity.Status>> {
|
public async unfavouriteStatus(id: string): Promise<Response<Entity.Status>> {
|
||||||
// NOTE: Misskey allows only one reaction per status, so we don't need to care what that emoji was.
|
// NOTE: Misskey allows only one reaction per status, so we don't need to care what that emoji was.
|
||||||
return this.deleteEmojiReaction(id, '');
|
return this.deleteEmojiReaction(id, '');
|
||||||
|
@ -1638,12 +1643,18 @@ export default class Misskey implements MegalodonInterface {
|
||||||
/**
|
/**
|
||||||
* POST /api/drive/files/create
|
* POST /api/drive/files/create
|
||||||
*/
|
*/
|
||||||
public async uploadMedia(file: any, _options?: { description?: string; focus?: string }): Promise<Response<Entity.Attachment>> {
|
public async uploadMedia(file: any, options?: { description?: string; focus?: string }): Promise<Response<Entity.Attachment>> {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', fs.createReadStream(file.path), {
|
formData.append('file', fs.createReadStream(file.path), {
|
||||||
contentType: file.mimetype,
|
contentType: file.mimetype
|
||||||
filename: file.originalname,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (file.originalname != null && file.originalname !== 'file')
|
||||||
|
formData.append('name', file.originalname);
|
||||||
|
|
||||||
|
if (options?.description != null)
|
||||||
|
formData.append('comment', options.description);
|
||||||
|
|
||||||
let headers: { [key: string]: string } = {}
|
let headers: { [key: string]: string } = {}
|
||||||
if (typeof formData.getHeaders === 'function') {
|
if (typeof formData.getHeaders === 'function') {
|
||||||
headers = formData.getHeaders()
|
headers = formData.getHeaders()
|
||||||
|
@ -1679,6 +1690,12 @@ export default class Misskey implements MegalodonInterface {
|
||||||
isSensitive: options.is_sensitive
|
isSensitive: options.is_sensitive
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.description !== undefined) {
|
||||||
|
params = Object.assign(params, {
|
||||||
|
comment: options.description
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.client
|
return this.client
|
||||||
.post<MisskeyAPI.Entity.File>('/api/drive/files/update', params)
|
.post<MisskeyAPI.Entity.File>('/api/drive/files/update', params)
|
||||||
|
|
|
@ -134,8 +134,8 @@ namespace MisskeyAPI {
|
||||||
url: acctUrl,
|
url: acctUrl,
|
||||||
avatar: u.avatarUrl,
|
avatar: u.avatarUrl,
|
||||||
avatar_static: u.avatarUrl,
|
avatar_static: u.avatarUrl,
|
||||||
header: this.plcUrl, // FIXME
|
header: this.plcUrl,
|
||||||
header_static: this.plcUrl, // FIXME
|
header_static: this.plcUrl,
|
||||||
emojis: u.emojis.map(e => this.emoji(e)),
|
emojis: u.emojis.map(e => this.emoji(e)),
|
||||||
moved: null,
|
moved: null,
|
||||||
fields: [],
|
fields: [],
|
||||||
|
@ -174,13 +174,13 @@ namespace MisskeyAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userPreferences = (u: MisskeyAPI.Entity.UserDetailMe, g: MisskeyAPI.Entity.GetAll): MegalodonEntity.Preferences => {
|
userPreferences = (u: MisskeyAPI.Entity.UserDetailMe, v: 'public' | 'unlisted' | 'private' | 'direct'): MegalodonEntity.Preferences => {
|
||||||
return {
|
return {
|
||||||
"reading:expand:media": "default",
|
"reading:expand:media": "default",
|
||||||
"reading:expand:spoilers": false,
|
"reading:expand:spoilers": false,
|
||||||
"posting:default:language": u.lang,
|
"posting:default:language": u.lang,
|
||||||
"posting:default:sensitive": u.alwaysMarkNsfw,
|
"posting:default:sensitive": u.alwaysMarkNsfw,
|
||||||
"posting:default:visibility": this.visibility(g.defaultNoteVisibility)
|
"posting:default:visibility": v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +308,7 @@ namespace MisskeyAPI {
|
||||||
emojis: n.emojis.map(e => this.emoji(e)),
|
emojis: n.emojis.map(e => this.emoji(e)),
|
||||||
replies_count: n.repliesCount,
|
replies_count: n.repliesCount,
|
||||||
reblogs_count: n.renoteCount,
|
reblogs_count: n.renoteCount,
|
||||||
favourites_count: this.getTotalReactions(n.reactions), // FIXME: instead get # of default reaction emoji reactions
|
favourites_count: this.getTotalReactions(n.reactions),
|
||||||
reblogged: false,
|
reblogged: false,
|
||||||
favourited: !!n.myReaction,
|
favourited: !!n.myReaction,
|
||||||
muted: false,
|
muted: false,
|
||||||
|
|
Loading…
Reference in a new issue