UNPKG

@cutls/megalodon

Version:

Mastodon, Pleroma, Misskey API client for node.js and browser

1,680 lines (1,679 loc) 43.4 kB
import { OAuth2Client } from '@badgateway/oauth2-client' import FormData from 'form-data' import dayjs from 'dayjs' import { parseLinkHeader } from './parse_link_header.js' import GotosocialAPI from './gotosocial/api_client.js' import { NotImplementedError } from './megalodon.js' import { NO_REDIRECT, DEFAULT_SCOPE, DEFAULT_UA } from './default.js' import * as GotosocialOAuth from './gotosocial/oauth.js' import { UnknownNotificationTypeError } from './notification.js' export default class Gotosocial { 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 GotosocialAPI.Client(baseUrl, token, agent) this.baseUrl = baseUrl } cancel() { return this.client.cancel() } async registerApp(client_name, options) { const scopes = options.scopes || DEFAULT_SCOPE return this.createApp(client_name, options).then(async (appData) => { return this.generateAuthUrl(appData.client_id, appData.client_secret, { scope: scopes, redirect_uri: appData.redirect_uri }).then((url) => { appData.url = url return appData }) }) } async createApp(client_name, options) { const scopes = options.scopes || DEFAULT_SCOPE const redirect_uris = options.redirect_uris || NO_REDIRECT const params = { client_name: client_name, redirect_uris: redirect_uris, scopes: scopes.join(' ') } if (options.website) params.website = options.website return this.client.post('/api/v1/apps', params).then((res) => GotosocialOAuth.toAppData(res.data)) } generateAuthUrl(clientId, clientSecret, options) { const scope = options.scope || DEFAULT_SCOPE const redirect_uri = options.redirect_uri || NO_REDIRECT return new Promise((resolve) => { const oauthClient = new OAuth2Client({ server: this.baseUrl, clientId: clientId, clientSecret: clientSecret, tokenEndpoint: '/oauth/token', authorizationEndpoint: '/oauth/authorize' }) const url = oauthClient.authorizationCode.getAuthorizeUri({ redirectUri: redirect_uri, scope: scope }) resolve(url) }) } verifyAppCredentials() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async fetchAccessToken(client_id, client_secret, code, redirect_uri = NO_REDIRECT) { if (!client_id) { throw new Error('client_id is required') } return this.client .post('/oauth/token', { client_id, client_secret, code, redirect_uri, grant_type: 'authorization_code' }) .then((res) => GotosocialOAuth.toTokenData(res.data)) } async refreshToken(client_id, client_secret, refresh_token) { return this.client .post('/oauth/token', { client_id, client_secret, refresh_token, grant_type: 'refresh_token' }) .then((res) => GotosocialOAuth.toTokenData(res.data)) } async revokeToken(client_id, client_secret, token) { return this.client.post('/oauth/revoke', { client_id, client_secret, token }) } async registerAccount(username, email, password, agreement, locale, reason) { let params = { username: username, email: email, password: password, agreement: agreement, locale: locale } if (reason) { params = Object.assign(params, { reason: reason }) } return this.client.post('/api/v1/accounts', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.token(res.data) }) }) } async verifyAccountCredentials() { return this.client.get('/api/v1/accounts/verify_credentials').then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.account(res.data) }) }) } async updateCredentials(options) { let params = {} if (options) { if (options.discoverable !== undefined) { params = Object.assign(params, { discoverable: options.discoverable }) } if (options.bot !== undefined) { params = Object.assign(params, { bot: options.bot }) } if (options.display_name) { params = Object.assign(params, { display_name: options.display_name }) } if (options.note) { params = Object.assign(params, { note: options.note }) } if (options.avatar) { params = Object.assign(params, { avatar: options.avatar }) } if (options.header) { params = Object.assign(params, { header: options.header }) } if (options.locked !== undefined) { params = Object.assign(params, { locked: options.locked }) } if (options.source) { params = Object.assign(params, { source: options.source }) } if (options.fields_attributes) { params = Object.assign(params, { fields_attributes: options.fields_attributes }) } } return this.client.patch('/api/v1/accounts/update_credentials', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.account(res.data) }) }) } async getAccount(id) { return this.client.get(`/api/v1/accounts/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.account(res.data) }) }) } async getAccountStatuses(id, options) { let params = {} if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.pinned) { params = Object.assign(params, { pinned: options.pinned }) } if (options.exclude_replies) { params = Object.assign(params, { exclude_replies: options.exclude_replies }) } if (options.exclude_reblogs) { params = Object.assign(params, { exclude_reblogs: options.exclude_reblogs }) } if (options.only_media) { params = Object.assign(params, { only_media: options.only_media }) } if (options.only_public) { params = Object.assign(params, { only_public: options.only_public }) } } return this.client.get(`/api/v1/accounts/${id}/statuses`, params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } getAccountFavourites(_id, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async subscribeAccount(id) { const params = { notify: true } return this.client.post(`/api/v1/accounts/${id}/follow`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async unsubscribeAccount(id) { const params = { notify: false } return this.client.post(`/api/v1/accounts/${id}/follow`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async getAccountFollowers(id, options) { let params = {} if (options) { if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.urlToAccounts(`/api/v1/accounts/${id}/followers`, params, options?.get_all || false, options?.sleep_ms || 0) } async getAccountFollowing(id, options) { let params = {} if (options) { if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.urlToAccounts(`/api/v1/accounts/${id}/following`, params, options?.get_all || false, options?.sleep_ms || 0) } async urlToAccounts(url, params, get_all, sleep_ms) { const res = await this.client.get(url, params) let converted = Object.assign({}, res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) if (get_all && converted.headers.link) { let parsed = parseLinkHeader(converted.headers.link) while (parsed['next']) { const nextRes = await this.client.get(parsed['next'], undefined, undefined, true) converted = Object.assign({}, converted, { data: [...converted.data, ...nextRes.data.map((a) => GotosocialAPI.Converter.account(a))] }) if (nextRes.headers.link === undefined) { break } parsed = parseLinkHeader(nextRes.headers.link) if (sleep_ms) { await new Promise((converted) => setTimeout(converted, sleep_ms)) } } } return converted } async getAccountLists(id) { return this.client.get(`/api/v1/accounts/${id}/lists`).then((res) => { return Object.assign(res, { data: res.data.map((l) => GotosocialAPI.Converter.list(l)) }) }) } async getIdentityProof(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async followAccount(id, options) { let params = {} if (options) { if (options.reblog !== undefined) { params = Object.assign(params, { reblog: options.reblog }) } } return this.client.post(`/api/v1/accounts/${id}/follow`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async unfollowAccount(id) { return this.client.post(`/api/v1/accounts/${id}/unfollow`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async blockAccount(id) { return this.client.post(`/api/v1/accounts/${id}/block`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async unblockAccount(id) { return this.client.post(`/api/v1/accounts/${id}/unblock`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async muteAccount(_id, _notifications = true) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async unmuteAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async pinAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async unpinAccount(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async setAccountNote(id, note) { let params = {} if (note) { params = Object.assign(params, { comment: note }) } return this.client.post(`/api/v1/accounts/${id}/note`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async getRelationship(id) { return this.client .get('/api/v1/accounts/relationships', { id: [id] }) .then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data[0]) }) }) } async getRelationships(ids) { return this.client .get('/api/v1/accounts/relationships', { id: ids }) .then((res) => { return Object.assign(res, { data: res.data.map((r) => GotosocialAPI.Converter.relationship(r)) }) }) } async searchAccount(_q) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async lookupAccount(acct) { return this.client.get(`/api/v1/accounts/lookup?acct=${acct}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.account(res.data) }) }) } async getBookmarks(options) { let params = {} if (options) { if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } } return this.client.get('/api/v1/bookmarks', params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getFavourites(options) { let params = {} if (options) { if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/favourites', params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getMutes(options) { let params = {} if (options) { if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/mutes', params).then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } async getBlocks(options) { let params = {} if (options) { if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/blocks', params).then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } async getDomainBlocks() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } blockDomain(_domain) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } unblockDomain(_domain) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getFilters() { return this.client.get('/api/v1/filters').then((res) => { return Object.assign(res, { data: res.data.map((f) => GotosocialAPI.Converter.filter(f)) }) }) } async getFilter(id) { return this.client.get(`/api/v1/filters/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.filter(res.data) }) }) } async createFilter(phrase, context, options) { let params = { phrase: phrase, context: context } if (options) { if (options.irreversible !== undefined) { params = Object.assign(params, { irreversible: options.irreversible }) } if (options.whole_word !== undefined) { params = Object.assign(params, { whole_word: options.whole_word }) } if (options.expires_in) { params = Object.assign(params, { expires_in: options.expires_in }) } } return this.client.post('/api/v1/filters', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.filter(res.data) }) }) } async updateFilter(id, phrase, context, options) { let params = { phrase: phrase, context: context } if (options) { if (options.irreversible !== undefined) { params = Object.assign(params, { irreversible: options.irreversible }) } if (options.whole_word !== undefined) { params = Object.assign(params, { whole_word: options.whole_word }) } if (options.expires_in) { params = Object.assign(params, { expires_in: options.expires_in }) } } return this.client.put(`/api/v1/filters/${id}`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.filter(res.data) }) }) } async deleteFilter(id) { return this.client.del(`/api/v1/filters/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.filter(res.data) }) }) } async report(account_id, options) { let params = { account_id: account_id } if (options) { if (options.status_ids) { params = Object.assign(params, { status_ids: options.status_ids }) } if (options.comment) { params = Object.assign(params, { comment: options.comment }) } if (options.forward !== undefined) { params = Object.assign(params, { forward: options.forward }) } if (options.category) { params = Object.assign(params, { category: options.category }) } if (options.rule_ids) { params = Object.assign(params, { rule_ids: options.rule_ids }) } } return this.client.post('/api/v1/reports', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.report(res.data) }) }) } async getFollowRequests(limit) { if (limit) { return this.client .get('/api/v1/follow_requests', { limit: limit }) .then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } else { return this.client.get('/api/v1/follow_requests').then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } } async acceptFollowRequest(id) { return this.client.post(`/api/v1/follow_requests/${id}/authorize`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async rejectFollowRequest(id) { return this.client.post(`/api/v1/follow_requests/${id}/reject`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.relationship(res.data) }) }) } async getEndorsements() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getFeaturedTags() { return new Promise((resolve) => { resolve({ data: [], status: 200, statusText: '200', headers: {} }) }) } async createFeaturedTag(_name) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } deleteFeaturedTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getSuggestedTags() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getPreferences() { return this.client.get('/api/v1/preferences').then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.preferences(res.data) }) }) } async getFollowedTags() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getSuggestions() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async followTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async unfollowTag(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async postStatus(status, options) { let params = { status: status } let scheduled = false if (options) { if (options.media_ids) { params = Object.assign(params, { media_ids: options.media_ids }) } if (options.poll) { let pollParam = { options: options.poll.options, expires_in: options.poll.expires_in } if (options.poll.multiple !== undefined) { pollParam = Object.assign(pollParam, { multiple: options.poll.multiple }) } if (options.poll.hide_totals !== undefined) { pollParam = Object.assign(pollParam, { hide_totals: options.poll.hide_totals }) } params = Object.assign(params, { poll: pollParam }) } if (options.in_reply_to_id) { params = Object.assign(params, { in_reply_to_id: options.in_reply_to_id }) } if (options.sensitive !== undefined) { params = Object.assign(params, { sensitive: options.sensitive }) } if (options.spoiler_text) { params = Object.assign(params, { spoiler_text: options.spoiler_text }) } if (options.visibility) { params = Object.assign(params, { visibility: GotosocialAPI.Converter.encodeVisibility(options.visibility) }) } if (options.scheduled_at && dayjs(options.scheduled_at).diff(dayjs(), 'seconds') > 300) { scheduled = true params = Object.assign(params, { scheduled_at: options.scheduled_at }) } if (options.language) { params = Object.assign(params, { language: options.language }) } } if (scheduled) { return this.client.post('/api/v1/statuses', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.scheduled_status(res.data) }) }) } return this.client.post('/api/v1/statuses', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async getStatus(id) { return this.client.get(`/api/v1/statuses/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async editStatus(_id, _options) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async deleteStatus(id) { return this.client.del(`/api/v1/statuses/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async getStatusContext(id, options) { let params = {} if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } } return this.client.get(`/api/v1/statuses/${id}/context`, params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.context(res.data) }) }) } async getStatusSource(id) { return this.client.get(`/api/v1/statuses/${id}/source`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status_source(res.data) }) }) } async getStatusRebloggedBy(id) { return this.client.get(`/api/v1/statuses/${id}/reblogged_by`).then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } async getStatusFavouritedBy(id) { return this.client.get(`/api/v1/statuses/${id}/favourited_by`).then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } async favouriteStatus(id) { return this.client.post(`/api/v1/statuses/${id}/favourite`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async unfavouriteStatus(id) { return this.client.post(`/api/v1/statuses/${id}/unfavourite`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async reblogStatus(id) { return this.client.post(`/api/v1/statuses/${id}/reblog`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async unreblogStatus(id) { return this.client.post(`/api/v1/statuses/${id}/unreblog`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async bookmarkStatus(id) { return this.client.post(`/api/v1/statuses/${id}/bookmark`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async unbookmarkStatus(id) { return this.client.post(`/api/v1/statuses/${id}/unbookmark`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async muteStatus(id) { return this.client.post(`/api/v1/statuses/${id}/mute`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async unmuteStatus(id) { return this.client.post(`/api/v1/statuses/${id}/unmute`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async pinStatus(id) { return this.client.post(`/api/v1/statuses/${id}/pin`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async unpinStatus(id) { return this.client.post(`/api/v1/statuses/${id}/unpin`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.status(res.data) }) }) } async uploadMedia(file, options) { const formData = new FormData() formData.append('file', file) if (options) { if (options.description) { formData.append('description', options.description) } if (options.focus) { formData.append('focus', options.focus) } } return this.client.postForm('/api/v2/media', formData).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.async_attachment(res.data) }) }) } async getMedia(id) { const res = await this.client.get(`/api/v1/media/${id}`) return Object.assign(res, { data: GotosocialAPI.Converter.attachment(res.data) }) } async updateMedia(id, options) { const formData = new FormData() if (options) { if (options.file) { formData.append('file', options.file) } if (options.description) { formData.append('description', options.description) } if (options.focus) { formData.append('focus', options.focus) } } return this.client.putForm(`/api/v1/media/${id}`, formData).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.attachment(res.data) }) }) } async getPoll(id) { return this.client.get(`/api/v1/polls/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.poll(res.data) }) }) } async votePoll(id, choices) { return this.client .post(`/api/v1/polls/${id}/votes`, { choices: choices }) .then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.poll(res.data) }) }) } async getScheduledStatuses() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getScheduledStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async scheduleStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } cancelScheduledStatus(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getPublicTimeline(options) { let params = { local: false } if (options) { if (options.only_media !== undefined) { params = Object.assign(params, { only_media: options.only_media }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/timelines/public', params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getLocalTimeline(options) { let params = { local: true } if (options) { if (options.only_media !== undefined) { params = Object.assign(params, { only_media: options.only_media }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/timelines/public', params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getTagTimeline(hashtag, options) { let params = {} if (options) { if (options.local !== undefined) { params = Object.assign(params, { local: options.local }) } if (options.only_media !== undefined) { params = Object.assign(params, { only_media: options.only_media }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get(`/api/v1/timelines/tag/${hashtag}`, params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getHomeTimeline(options) { let params = {} if (options) { if (options.local !== undefined) { params = Object.assign(params, { local: options.local }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get('/api/v1/timelines/home', params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getListTimeline(list_id, options) { let params = {} if (options) { if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } } return this.client.get(`/api/v1/timelines/list/${list_id}`, params).then((res) => { return Object.assign(res, { data: res.data.map((s) => GotosocialAPI.Converter.status(s)) }) }) } async getConversationTimeline() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } deleteConversation(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async readConversation(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getLists() { return this.client.get('/api/v1/lists').then((res) => { return Object.assign(res, { data: res.data.map((l) => GotosocialAPI.Converter.list(l)) }) }) } async getList(id) { return this.client.get(`/api/v1/lists/${id}`).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.list(res.data) }) }) } async createList(title) { return this.client .post('/api/v1/lists', { title: title }) .then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.list(res.data) }) }) } async updateList(id, title) { return this.client .put(`/api/v1/lists/${id}`, { title: title }) .then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.list(res.data) }) }) } deleteList(id) { return this.client.del(`/api/v1/lists/${id}`) } async getAccountsInList(id, options) { let params = {} if (options) { if (options.limit) { params = Object.assign(params, { limit: options.limit }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } } return this.client.get(`/api/v1/lists/${id}/accounts`, params).then((res) => { return Object.assign(res, { data: res.data.map((a) => GotosocialAPI.Converter.account(a)) }) }) } addAccountsToList(id, account_ids) { return this.client.post(`/api/v1/lists/${id}/accounts`, { account_ids: account_ids }) } deleteAccountsFromList(id, account_ids) { return this.client.del(`/api/v1/lists/${id}/accounts`, { account_ids: account_ids }) } async getMarkers(timeline) { return this.client .get('/api/v1/markers', { timeline: timeline }) .then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.marker(res.data) }) }) } async saveMarkers(options) { let params = {} if (options) { if (options.home) { params = Object.assign(params, { home: options.home }) } if (options.notifications) { params = Object.assign(params, { notifications: options.notifications }) } } return this.client.post('/api/v1/markers', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.marker(res.data) }) }) } 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, { max_id: options.max_id }) } if (options.since_id) { params = Object.assign(params, { since_id: options.since_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.exclude_types) { params = Object.assign(params, { exclude_types: options.exclude_types.map((e) => GotosocialAPI.Converter.encodeNotificationType(e)) }) } if (options.account_id) { params = Object.assign(params, { account_id: options.account_id }) } } return this.client.get('/api/v1/notifications', params).then((res) => { return Object.assign(res, { data: res.data.flatMap((n) => { const notify = GotosocialAPI.Converter.notification(n) if (notify instanceof UnknownNotificationTypeError) return [] return notify }) }) }) } async getNotification(id) { const res = await this.client.get(`/api/v1/notifications/${id}`) const notify = GotosocialAPI.Converter.notification(res.data) if (notify instanceof UnknownNotificationTypeError) { throw new UnknownNotificationTypeError() } return { ...res, data: notify } } dismissNotifications() { return this.client.post('/api/v1/notifications/clear') } dismissNotification(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } readNotifications(_options) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async subscribePushNotification(_subscription) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getPushSubscription() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async updatePushSubscription() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } deletePushSubscription() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async search(q, options) { let params = { q } if (options) { if (options.type) { params = Object.assign(params, { type: options.type }) } if (options.limit) { params = Object.assign(params, { limit: options.limit }) } if (options.max_id) { params = Object.assign(params, { max_id: options.max_id }) } if (options.min_id) { params = Object.assign(params, { min_id: options.min_id }) } if (options.resolve !== undefined) { params = Object.assign(params, { resolve: options.resolve }) } if (options.offset) { params = Object.assign(params, { offset: options.offset }) } if (options.following !== undefined) { params = Object.assign(params, { following: options.following }) } if (options.account_id) { params = Object.assign(params, { account_id: options.account_id }) } if (options.exclude_unreviewed) { params = Object.assign(params, { exclude_unreviewed: options.exclude_unreviewed }) } } return this.client.get('/api/v2/search', params).then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.results(res.data) }) }) } async getInstance() { return this.client.get('/api/v1/instance').then((res) => { return Object.assign(res, { data: GotosocialAPI.Converter.instance(res.data) }) }) } getInstancePeers() { return this.client.get('/api/v1/instance/peers') } async getInstanceActivity() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getInstanceTrends() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getInstanceDirectory() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getInstanceCustomEmojis() { return this.client.get('/api/v1/custom_emojis').then((res) => { return Object.assign(res, { data: res.data.map((e) => GotosocialAPI.Converter.emoji(e)) }) }) } async getInstanceAnnouncements() { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async dismissInstanceAnnouncement(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async addReactionToAnnouncement(_id, _name) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async removeReactionFromAnnouncement(_id, _name) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async createEmojiReaction(_id, _emoji) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async deleteEmojiReaction(_id, _emoji) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getEmojiReactions(_id) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async getEmojiReaction(_id, _emoji) { return new Promise((_, reject) => { const err = new NotImplementedError('Gotosocial does not support this method') reject(err) }) } async streamingURL() { const instance = await this.getInstance() if (instance.data.urls) { return instance.data.urls.streaming_api } return this.baseUrl } async userStreaming() { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'user') } async publicStreaming() { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'public') } async localStreaming() { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'public:local') } async tagStreaming(tag) { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'hashtag', `tag=${tag}`) } async listStreaming(list_id) { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'list', `list=${list_id}`) } async directStreaming() { const url = await this.streamingURL() return this.client.socket(`${url}/api/v1/streaming`, 'direct') } async userStreamingSubscription() { return this.userStreaming() } async publicStreamingSubscription(_socket) { return this.publicStreaming() } async localStreamingSubscription(_socket) { return this.localStreaming() } async tagStreamingSubscription(_socket, tag) { return this.tagStreaming(tag) } async listStreamingSubscription(_socket, list_id) { return this.listStreaming(list_id) } async directStreamingSubscription(_socket) { return this.directStreaming() } }