@cutls/megalodon
Version:
Mastodon, Pleroma, Misskey API client for node.js and browser
1,469 lines • 58.5 kB
JavaScript
import FormData from 'form-data';
import MisskeyAPI from './misskey/api_client.js';
import { DEFAULT_UA } from './default.js';
import MisskeyOAuth from './misskey_oauth.js';
import { NotImplementedError, ArgumentError, UnexpectedError } from './megalodon.js';
export default class Misskey {
client;
baseUrl;
constructor(baseUrl, accessToken = null, userAgent = DEFAULT_UA) {
let token = '';
if (accessToken) {
token = accessToken;
}
let agent = DEFAULT_UA;
if (userAgent) {
agent = userAgent;
}
this.client = new MisskeyAPI.Client(baseUrl, token, agent);
this.baseUrl = baseUrl;
}
baseUrlToHost(baseUrl) {
return baseUrl.replace('https://', '');
}
cancel() {
return this.client.cancel();
}
async registerApp(client_name, options = {
scopes: MisskeyAPI.DEFAULT_SCOPE,
redirect_uris: this.baseUrl
}) {
return this.createApp(client_name, options).then(async (appData) => {
return this.generateAuthUrlAndToken(appData.client_secret).then(session => {
appData.url = session.url;
appData.session_token = session.token;
return appData;
});
});
}
async createApp(client_name, options = {
scopes: MisskeyAPI.DEFAULT_SCOPE,
redirect_uris: this.baseUrl
}) {
const redirect_uris = options.redirect_uris || this.baseUrl;
const scopes = options.scopes || MisskeyAPI.DEFAULT_SCOPE;
const params = {
name: client_name,
description: '',
permission: scopes,
callbackUrl: redirect_uris
};
return this.client.post('/api/app/create', params).then((res) => {
const appData = {
id: res.data.id,
name: res.data.name,
website: null,
redirect_uri: res.data.callbackUrl,
client_id: '',
client_secret: res.data.secret
};
return MisskeyOAuth.AppData.from(appData);
});
}
async generateAuthUrlAndToken(clientSecret) {
return this.client
.post('/api/auth/session/generate', {
appSecret: clientSecret
})
.then((res) => res.data);
}
async verifyAppCredentials() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async fetchAccessToken(_client_id, client_secret, session_token, _redirect_uri) {
return this.client
.post('/api/auth/session/userkey', {
appSecret: client_secret,
token: session_token
})
.then((res) => {
const token = new MisskeyOAuth.TokenData(res.data.accessToken, 'misskey', '', 0, null, null);
return token;
});
}
async refreshToken(_client_id, _client_secret, _refresh_token) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async revokeToken(_client_id, _client_secret, _token) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async registerAccount(_username, _email, _password, _agreement, _locale, _reason) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async verifyAccountCredentials() {
return this.client.post('/api/i').then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl))
});
});
}
async updateCredentials(options) {
let params = {};
if (options) {
if (options.bot !== undefined) {
params = Object.assign(params, {
isBot: options.bot
});
}
if (options.display_name) {
params = Object.assign(params, {
name: options.display_name
});
}
if (options.note) {
params = Object.assign(params, {
description: options.note
});
}
if (options.locked !== undefined) {
params = Object.assign(params, {
isLocked: options.locked
});
}
if (options.source) {
if (options.source.language) {
params = Object.assign(params, {
lang: options.source.language
});
}
if (options.source.sensitive) {
params = Object.assign(params, {
alwaysMarkNsfw: options.source.sensitive
});
}
}
}
return this.client.post('/api/i', params).then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl))
});
});
}
async getAccount(id) {
return this.client
.post('/api/users/show', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.userDetail(res.data, this.baseUrlToHost(this.baseUrl))
});
});
}
async getAccountStatuses(id, options) {
if (options && options.pinned) {
return this.client
.post('/api/users/show', {
userId: id
})
.then(res => {
if (res.data.pinnedNotes) {
return { ...res, data: res.data.pinnedNotes.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) };
}
return { ...res, data: [] };
});
}
let params = {
userId: id
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.exclude_replies) {
params = Object.assign(params, {
includeReplies: false
});
}
if (options.exclude_reblogs) {
params = Object.assign(params, {
includeMyRenotes: false
});
}
if (options.only_media) {
params = Object.assign(params, {
withFiles: options.only_media
});
}
}
return this.client.post('/api/users/notes', params).then(res => {
const statuses = res.data.map(note => MisskeyAPI.Converter.note(note, this.baseUrlToHost(this.baseUrl)));
return Object.assign(res, {
data: statuses
});
});
}
async getAccountFavourites(_id, _options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async subscribeAccount(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unsubscribeAccount(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getAccountFollowers(id, options) {
let params = {
userId: id
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
}
return this.client.post('/api/users/followers', params).then(res => {
return Object.assign(res, {
data: res.data.map(f => MisskeyAPI.Converter.follower(f, this.baseUrlToHost(this.baseUrl)))
});
});
}
async getAccountFollowing(id, options) {
let params = {
userId: id
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
}
return this.client.post('/api/users/following', params).then(res => {
return Object.assign(res, {
data: res.data.map(f => MisskeyAPI.Converter.following(f, this.baseUrlToHost(this.baseUrl)))
});
});
}
async getAccountLists(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getIdentityProof(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async followAccount(id, _options) {
await this.client.post('/api/following/create', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async unfollowAccount(id) {
await this.client.post('/api/following/delete', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async blockAccount(id) {
await this.client.post('/api/blocking/create', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async unblockAccount(id) {
await this.client.post('/api/blocking/delete', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async muteAccount(id, _notifications) {
await this.client.post('/api/mute/create', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async unmuteAccount(id) {
await this.client.post('/api/mute/delete', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async pinAccount(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unpinAccount(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async setAccountNote(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support this method');
reject(err);
});
}
async getRelationship(id) {
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data[0])
});
});
}
async getRelationships(ids) {
return Promise.all(ids.map(id => this.getRelationship(id))).then(results => ({
...results[0],
data: results.map(r => r.data)
}));
}
async searchAccount(q, options) {
let params = {
query: q,
detail: true
};
if (options) {
params = Object.assign(params, {
localOnly: !options.resolve
});
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
}
return this.client.post('/api/users/search', params).then(res => {
return Object.assign(res, {
data: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl)))
});
});
}
async lookupAccount(acct) {
const params = {
query: acct,
detail: true
};
return this.client.post('/api/users/search', params).then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.user(res.data[0], this.baseUrlToHost(this.baseUrl))
});
});
}
async getBookmarks(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getFavourites(options) {
let params = {};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client.post('/api/i/favorites', params).then(res => {
return Object.assign(res, {
data: res.data.map(fav => MisskeyAPI.Converter.note(fav.note, this.baseUrlToHost(this.baseUrl)))
});
});
}
async getMutes(options) {
let params = {};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client.post('/api/mute/list', params).then(res => {
return Object.assign(res, {
data: res.data.map(mute => MisskeyAPI.Converter.userDetail(mute.mutee, this.baseUrlToHost(this.baseUrl)))
});
});
}
async getBlocks(options) {
let params = {};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client.post('/api/blocking/list', params).then(res => {
return Object.assign(res, {
data: res.data.map(blocking => MisskeyAPI.Converter.userDetail(blocking.blockee, this.baseUrlToHost(this.baseUrl)))
});
});
}
async getDomainBlocks(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async blockDomain(_domain) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unblockDomain(_domain) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getFilters() {
return this.client.post('/api/i', { scope: ['client', 'base'] }).then(res => {
return Object.assign(res, {
data: res.data.mutedWords.map(f => ({
id: f.join('_'),
phrase: f.join(' '),
context: ['home', 'notifications', 'public', 'thread'],
expires_at: null,
irreversible: false,
whole_word: false
}))
});
});
}
async getFilter(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async createFilter(_phrase, _context, _options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async updateFilter(_id, _phrase, _context, _options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async deleteFilter(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async report(account_id, options) {
return this.client
.post('/api/users/report-abuse', {
userId: account_id,
comment: options?.comment || ''
})
.then(res => {
return Object.assign(res, {
data: {
id: '',
action_taken: false,
comment: options?.comment || '',
account_id: account_id,
status_ids: [],
category: null,
forwarded: null,
action_taken_at: null,
rule_ids: null
}
});
});
}
async getFollowRequests(_limit) {
return this.client.post('/api/following/requests/list').then(res => {
return Object.assign(res, {
data: res.data.map(r => MisskeyAPI.Converter.user(r.follower, this.baseUrlToHost(this.baseUrl)))
});
});
}
async acceptFollowRequest(id) {
await this.client.post('/api/following/requests/accept', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async rejectFollowRequest(id) {
await this.client.post('/api/following/requests/reject', {
userId: id
});
return this.client
.post('/api/users/relation', {
userId: id
})
.then(res => {
return Object.assign(res, {
data: MisskeyAPI.Converter.relation(res.data)
});
});
}
async getEndorsements(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getFeaturedTags() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async createFeaturedTag(_name) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async deleteFeaturedTag(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getSuggestedTags() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getPreferences() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getSuggestions(limit) {
let params = {};
if (limit) {
params = Object.assign(params, {
limit: limit
});
}
return this.client
.post('/api/users/recommendation', params)
.then(res => ({ ...res, data: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl))) }));
}
async getTag(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async followTag(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unfollowTag(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async postStatus(status, options) {
let params = {
text: status
};
if (options) {
if (options.media_ids) {
params = Object.assign(params, {
fileIds: options.media_ids
});
}
if (options.poll) {
let pollParam = {
choices: options.poll.options,
expiresAt: null,
expiredAfter: options.poll.expires_in
};
if (options.poll.multiple !== undefined) {
pollParam = Object.assign(pollParam, {
multiple: options.poll.multiple
});
}
params = Object.assign(params, {
poll: pollParam
});
}
if (options.in_reply_to_id) {
params = Object.assign(params, {
replyId: options.in_reply_to_id
});
}
if (options.sensitive) {
params = Object.assign(params, {
cw: ''
});
}
if (options.spoiler_text) {
params = Object.assign(params, {
cw: options.spoiler_text
});
}
if (options.visibility) {
params = Object.assign(params, {
visibility: MisskeyAPI.Converter.encodeVisibility(options.visibility)
});
}
if (options.quoted_status_id) {
params = Object.assign(params, {
renoteId: options.quoted_status_id
});
}
}
return this.client
.post('/api/notes/create', params)
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) }));
}
async getStatus(id) {
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async getStatusSource(id) {
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({
...res,
data: {
id,
text: res.data.text || '',
spoiler_text: res.data.cw || ''
}
}));
}
async editStatus(_id, _options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async revokeQuote(_yourId, _quotingId) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async deleteStatus(id) {
return this.client.post('/api/notes/delete', {
noteId: id
});
}
async getStatusContext(id, options) {
let params = {
noteId: id
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
}
return this.client.post('/api/notes/children', params).then(res => {
const context = {
ancestors: [],
descendants: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl)))
};
return {
...res,
data: context
};
});
}
async getStatusRebloggedBy(id) {
return this.client
.post('/api/notes/renotes', {
noteId: id
})
.then(res => ({
...res,
data: res.data.map(n => MisskeyAPI.Converter.user(n.user, this.baseUrlToHost(this.baseUrl)))
}));
}
async getStatusFavouritedBy(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async favouriteStatus(id) {
await this.client.post('/api/notes/favorites/create', {
noteId: id
});
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async unfavouriteStatus(id) {
await this.client.post('/api/notes/favorites/delete', {
noteId: id
});
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async reblogStatus(id) {
return this.client
.post('/api/notes/create', {
renoteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote, this.baseUrlToHost(this.baseUrl)) }));
}
async unreblogStatus(id) {
await this.client.post('/api/notes/unrenote', {
noteId: id
});
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async bookmarkStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unbookmarkStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async muteStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async unmuteStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async pinStatus(id) {
await this.client.post('/api/i/pin', {
noteId: id
});
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async unpinStatus(id) {
await this.client.post('/api/i/unpin', {
noteId: id
});
return this.client
.post('/api/notes/show', {
noteId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl)) }));
}
async uploadMedia(file, _options) {
const formData = new FormData();
formData.append('file', file);
let headers = {};
if (typeof formData.getHeaders === 'function') {
headers = formData.getHeaders();
}
return this.client
.post('/api/drive/files/create', formData, headers)
.then(res => ({ ...res, data: MisskeyAPI.Converter.file(res.data) }));
}
async getMedia(id) {
const res = await this.client.post('/api/drive/files/show', { fileId: id });
return { ...res, data: MisskeyAPI.Converter.file(res.data) };
}
async updateMedia(id, options) {
let params = {
fileId: id
};
if (options) {
if (options.is_sensitive !== undefined) {
params = Object.assign(params, {
isSensitive: options.is_sensitive
});
}
}
return this.client
.post('/api/drive/files/update', params)
.then(res => ({ ...res, data: MisskeyAPI.Converter.file(res.data) }));
}
async getPoll(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async votePoll(_id, choices, status_id) {
if (!status_id) {
return new Promise((_, reject) => {
const err = new ArgumentError('status_id is required');
reject(err);
});
}
const params = {
noteId: status_id,
choice: choices[0]
};
await this.client.post('/api/notes/polls/vote', params);
const res = await this.client
.post('/api/notes/show', {
noteId: status_id
})
.then(res => {
const note = MisskeyAPI.Converter.note(res.data, this.baseUrlToHost(this.baseUrl));
return { ...res, data: note.poll };
});
if (!res.data) {
return new Promise((_, reject) => {
const err = new UnexpectedError('poll does not exist');
reject(err);
});
}
return { ...res, data: res.data };
}
async getScheduledStatuses(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getScheduledStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async scheduleStatus(_id, _scheduled_at) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async cancelScheduledStatus(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getPublicTimeline(options) {
let params = {};
if (options) {
if (options.only_media !== undefined) {
params = Object.assign(params, {
withFiles: options.only_media
});
}
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client
.post('/api/notes/global-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getLocalTimeline(options) {
let params = {};
if (options) {
if (options.only_media !== undefined) {
params = Object.assign(params, {
withFiles: options.only_media
});
}
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client
.post('/api/notes/local-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getTagTimeline(hashtag, options) {
let params = {
tag: hashtag
};
if (options) {
if (options.only_media !== undefined) {
params = Object.assign(params, {
withFiles: options.only_media
});
}
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client
.post('/api/notes/search-by-tag', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getIntegratedTimeline(options) {
let params = {
withFiles: false
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
const home = await this.client.post('/api/notes/timeline', params);
const local = await this.client.post('/api/notes/local-timeline', params);
const merged = [...home.data, ...local.data.map(s => ({ ...s, _integrated_isLocal: true }))].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const uniqueData = Array.from(new Map(merged.map(item => [item.id, item])).values());
return { ...home, data: uniqueData.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) };
}
async getHomeTimeline(options) {
let params = {
withFiles: false
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client
.post('/api/notes/timeline', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getListTimeline(list_id, options, isAntenna) {
let params = {
listId: isAntenna ? undefined : list_id,
antennaId: isAntenna ? list_id : undefined,
withFiles: false
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
if (isAntenna) {
return this.client
.post('/api/antennas/notes', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
return this.client
.post('/api/notes/user-list-timeline', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getConversationTimeline(options) {
let params = {
visibility: 'specified'
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
}
return this.client
.post('/api/notes/mentions', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.noteToConversation(n, this.baseUrlToHost(this.baseUrl))) }));
}
async deleteConversation(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async readConversation(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getLists(includeAntenna) {
const lists = this.client
.post('/api/users/lists/list')
.then(res => ({ ...res, data: res.data.map(l => MisskeyAPI.Converter.list(l)) }));
if (!includeAntenna)
return lists;
const antennas = this.client
.post('/api/antennas/list')
.then(res => ({ ...res, data: res.data.map(a => MisskeyAPI.Converter.antennaToList(a)) }));
const [listsRes, antennasRes] = await Promise.all([lists, antennas]);
return {
...listsRes,
data: listsRes.data.concat(antennasRes.data)
};
}
async getList(id) {
return this.client
.post('/api/users/lists/show', {
listId: id
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) }));
}
async createList(title) {
return this.client
.post('/api/users/lists/create', {
name: title
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) }));
}
async updateList(id, title) {
return this.client
.post('/api/users/lists/update', {
listId: id,
name: title
})
.then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) }));
}
async deleteList(id) {
return this.client.post('/api/users/lists/delete', {
listId: id
});
}
async getAccountsInList(id, _options) {
const res = await this.client.post('/api/users/lists/show', {
listId: id
});
const promise = res.data.userIds.map(userId => this.getAccount(userId));
const accounts = await Promise.all(promise);
return { ...res, data: accounts.map(r => r.data) };
}
async addAccountsToList(id, account_ids) {
return this.client.post('/api/users/lists/push', {
listId: id,
userId: account_ids[0]
});
}
async deleteAccountsFromList(id, account_ids) {
return this.client.post('/api/users/lists/pull', {
listId: id,
userId: account_ids[0]
});
}
async getMarkers(_timeline) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async saveMarkers(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getNotifications(options) {
let params = {};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.since_id) {
params = Object.assign(params, {
sinceId: options.since_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
if (options.exclude_type) {
params = Object.assign(params, {
excludeType: options.exclude_type.map(e => MisskeyAPI.Converter.encodeNotificationType(e))
});
}
}
return this.client
.post('/api/i/notifications', params)
.then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.notification(n, this.baseUrlToHost(this.baseUrl))) }));
}
async getNotification(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async dismissNotifications() {
return this.client.post('/api/notifications/mark-all-as-read');
}
async dismissNotification(_id) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async readNotifications(_options) {
return new Promise((_, reject) => {
const err = new NotImplementedError('mastodon does not support');
reject(err);
});
}
async subscribePushNotification(_subscription, _data) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async getPushSubscription() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async updatePushSubscription(_data) {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async deletePushSubscription() {
return new Promise((_, reject) => {
const err = new NotImplementedError('misskey does not support');
reject(err);
});
}
async search(q, options) {
switch (options?.type) {
case 'accounts': {
let params = {
query: q
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.offset) {
params = Object.assign(params, {
offset: options.offset
});
}
params = Object.assign(params, {
localOnly: !options.resolve
});
}
return this.client.post('/api/users/search', params).then(res => ({
...res,
data: {
accounts: res.data.map(u => MisskeyAPI.Converter.userDetail(u, this.baseUrlToHost(this.baseUrl))),
statuses: [],
hashtags: []
}
}));
}
case 'statuses': {
let params = {
query: q
};
if (options) {
if (options.limit) {
params = Object.assign(params, {
limit: options.limit
});
}
if (options.offset) {
params = Object.assign(params, {
offset: options.offset
});
}
if (options.max_id) {
params = Object.assign(params, {
untilId: options.max_id
});
}
if (options.min_id) {
params = Object.assign(params, {
sinceId: options.min_id
});
}
if (options.account_id) {
params = Object.assign(params, {
userId: options.account_id
});
}
}
return this.client.post('/api/notes/search', params).then(res => ({
...res,
data: {
accounts: [],
statuses: res.data.map(n => MisskeyAPI.Converter.note(n, this.baseUrlToHost(this.baseUrl))),
hashtags: []
}
}));
}
case 'hashtags': {
let params =