From ab1245a1c20f7cf680d68026e7b2cd23fb0b86be Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 22 Sep 2023 01:15:35 +0900 Subject: [PATCH 1/4] Remove Misskey examples --- example/typescript/src/misskey/account.ts | 18 ------- .../typescript/src/misskey/authorization.ts | 48 ------------------- example/typescript/src/misskey/cancel.ts | 17 ------- .../typescript/src/misskey/emoji_reactions.ts | 26 ---------- example/typescript/src/misskey/emojis.ts | 18 ------- example/typescript/src/misskey/favourite.ts | 18 ------- example/typescript/src/misskey/instance.ts | 12 ----- example/typescript/src/misskey/media.ts | 14 ------ example/typescript/src/misskey/note.ts | 18 ------- .../typescript/src/misskey/notification.ts | 15 ------ example/typescript/src/misskey/poll.ts | 37 -------------- .../typescript/src/misskey/proxy_detector.ts | 21 -------- .../typescript/src/misskey/proxy_instance.ts | 26 ---------- .../typescript/src/misskey/relationships.ts | 17 ------- example/typescript/src/misskey/timeline.ts | 20 -------- example/typescript/src/misskey/toot.ts | 29 ----------- example/typescript/src/misskey/web_socket.ts | 46 ------------------ 17 files changed, 400 deletions(-) delete mode 100644 example/typescript/src/misskey/account.ts delete mode 100644 example/typescript/src/misskey/authorization.ts delete mode 100644 example/typescript/src/misskey/cancel.ts delete mode 100644 example/typescript/src/misskey/emoji_reactions.ts delete mode 100644 example/typescript/src/misskey/emojis.ts delete mode 100644 example/typescript/src/misskey/favourite.ts delete mode 100644 example/typescript/src/misskey/instance.ts delete mode 100644 example/typescript/src/misskey/media.ts delete mode 100644 example/typescript/src/misskey/note.ts delete mode 100644 example/typescript/src/misskey/notification.ts delete mode 100644 example/typescript/src/misskey/poll.ts delete mode 100644 example/typescript/src/misskey/proxy_detector.ts delete mode 100644 example/typescript/src/misskey/proxy_instance.ts delete mode 100644 example/typescript/src/misskey/relationships.ts delete mode 100644 example/typescript/src/misskey/timeline.ts delete mode 100644 example/typescript/src/misskey/toot.ts delete mode 100644 example/typescript/src/misskey/web_socket.ts diff --git a/example/typescript/src/misskey/account.ts b/example/typescript/src/misskey/account.ts deleted file mode 100644 index 5308759c4..000000000 --- a/example/typescript/src/misskey/account.ts +++ /dev/null @@ -1,18 +0,0 @@ -import generator, { MegalodonInterface } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client: MegalodonInterface = generator('misskey', BASE_URL, access_token) - -client - .verifyAccountCredentials() - .then(res => console.log(res.data)) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/authorization.ts b/example/typescript/src/misskey/authorization.ts deleted file mode 100644 index 4a66236c6..000000000 --- a/example/typescript/src/misskey/authorization.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as readline from 'readline' -import { OAuth, Misskey } from 'megalodon' - -const rl: readline.ReadLine = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) - -const BASE_URL: string = 'https://misskey.io' - -let clientId: string -let clientSecret: string - -const client = new Misskey(BASE_URL) - -client - .registerApp('Test App') - .then(appData => { - clientId = appData.clientId - clientSecret = appData.clientSecret - console.log('\napp_secret_key:') - console.log(clientSecret) - console.log('Authorization URL is generated.') - console.log(appData.url) - console.log() - return new Promise(resolve => { - rl.question('Enter any keys after you authorize to misskey: ', _code => { - resolve(appData.session_token) - rl.close() - }) - }) - }) - .then((session_token: string | null) => { - if (!session_token) { - throw new Error('Could not get session token') - } - return client.fetchAccessToken(clientId, clientSecret, session_token) - }) - .then((tokenData: OAuth.TokenData) => { - console.log('\naccess_token:') - console.log(tokenData.accessToken) - console.log('\nrefresh_token:') - console.log(tokenData.refreshToken) - console.log() - }) - .catch((err: any) => { - console.error(err) - }) diff --git a/example/typescript/src/misskey/cancel.ts b/example/typescript/src/misskey/cancel.ts deleted file mode 100644 index 155bfd112..000000000 --- a/example/typescript/src/misskey/cancel.ts +++ /dev/null @@ -1,17 +0,0 @@ -import generator, { isCancel } from 'megalodon' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN! -const client = generator('misskey', 'https://misskey.io', access_token) - -client - .search('h3poteto', { type: 'accounts' }) - .then(res => console.log(res.data)) - .catch(err => { - if (isCancel(err)) { - console.log('Request was canceled') - } - }) - -setTimeout(() => { - client.cancel() -}, 1000) diff --git a/example/typescript/src/misskey/emoji_reactions.ts b/example/typescript/src/misskey/emoji_reactions.ts deleted file mode 100644 index 6827e0c18..000000000 --- a/example/typescript/src/misskey/emoji_reactions.ts +++ /dev/null @@ -1,26 +0,0 @@ -import * as readline from 'readline' -import generator, { Entity, Response } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } - stdin: any - stdout: any -} - -const rl: readline.ReadLine = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) - -const BASE_URL = 'https://misskey.io' -const access_token = process.env.MISSKEY_ACCESS_TOKEN -const client = generator('misskey', BASE_URL, access_token) - -rl.question(`Enter status id of ${BASE_URL}: `, id => { - client.createEmojiReaction(id, '😄').then((res: Response) => { - console.log(res.data) - rl.close() - }) -}) diff --git a/example/typescript/src/misskey/emojis.ts b/example/typescript/src/misskey/emojis.ts deleted file mode 100644 index 1e8687591..000000000 --- a/example/typescript/src/misskey/emojis.ts +++ /dev/null @@ -1,18 +0,0 @@ -import generator, { MegalodonInterface } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client: MegalodonInterface = generator('misskey', BASE_URL, access_token) - -client - .getInstanceCustomEmojis() - .then(res => console.log(res.data)) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/favourite.ts b/example/typescript/src/misskey/favourite.ts deleted file mode 100644 index 048247c10..000000000 --- a/example/typescript/src/misskey/favourite.ts +++ /dev/null @@ -1,18 +0,0 @@ -import generator, { Entity, Response } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL = 'https://misskey.io' -const access_token = process.env.MISSKEY_ACCESS_TOKEN -const client = generator('misskey', BASE_URL, access_token) -client - .getNotifications() - .then((res: Response>) => { - console.log(res.headers) - console.log(res.data) - }) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/instance.ts b/example/typescript/src/misskey/instance.ts deleted file mode 100644 index 9e71b0b76..000000000 --- a/example/typescript/src/misskey/instance.ts +++ /dev/null @@ -1,12 +0,0 @@ -import generator, { Entity, Response } from 'megalodon' - -const BASE_URL = 'https://misskey.io' - -const client = generator('misskey', BASE_URL) - -client - .getInstance() - .then((res: Response) => { - console.log(res.data) - }) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/media.ts b/example/typescript/src/misskey/media.ts deleted file mode 100644 index db28eda73..000000000 --- a/example/typescript/src/misskey/media.ts +++ /dev/null @@ -1,14 +0,0 @@ -import generator, { Entity, Response } from 'megalodon' -import * as fs from 'fs' - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN as string - -const client = generator('misskey', BASE_URL, access_token) - -const image = fs.createReadStream('test.png') - -client.uploadMedia(image).then((resp: Response) => { - console.log(resp.data) -}) diff --git a/example/typescript/src/misskey/note.ts b/example/typescript/src/misskey/note.ts deleted file mode 100644 index 1cbe34b8c..000000000 --- a/example/typescript/src/misskey/note.ts +++ /dev/null @@ -1,18 +0,0 @@ -import generator, { MegalodonInterface } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client: MegalodonInterface = generator('misskey', BASE_URL, access_token) - -client - .getStatus('9fjp2aknrm') - .then(res => console.log(res.data)) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/notification.ts b/example/typescript/src/misskey/notification.ts deleted file mode 100644 index b35e42ef2..000000000 --- a/example/typescript/src/misskey/notification.ts +++ /dev/null @@ -1,15 +0,0 @@ -import generator, { NotificationType } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client = generator('misskey', BASE_URL, access_token) - -client.getNotifications({ exclude_types: [NotificationType.Favourite, NotificationType.Reblog] }).then(res => console.log(res.data)) diff --git a/example/typescript/src/misskey/poll.ts b/example/typescript/src/misskey/poll.ts deleted file mode 100644 index a200d4f8c..000000000 --- a/example/typescript/src/misskey/poll.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as readline from 'readline' -import generator, { Entity, Response } from 'megalodon' - -const rl: readline.ReadLine = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN as string - -const client = generator('misskey', BASE_URL, access_token) - -const options = { - poll: { - options: ['hoge', 'fuga'], - expires_in: 86400, - multiple: false - } -} - -new Promise(resolve => { - rl.question('Toot: ', status => { - client - .postStatus(status, options) - .then((res: Response) => { - console.log(res) - rl.close() - resolve(res) - }) - .catch(err => { - console.error(err) - rl.close() - }) - }) -}) diff --git a/example/typescript/src/misskey/proxy_detector.ts b/example/typescript/src/misskey/proxy_detector.ts deleted file mode 100644 index 9db675fc8..000000000 --- a/example/typescript/src/misskey/proxy_detector.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { detector, ProxyConfig } from 'megalodon' - -declare var process: { - env: { - PROXY_HOST: string - PROXY_PORT: number - PROXY_PROTOCOL: 'http' | 'https' | 'socks4' | 'socks4a' | 'socks5' | 'socks5h' | 'socks' - } -} - -const BASE_URL: string = 'https://misskey.io' - -const proxy: ProxyConfig = { - host: process.env.PROXY_HOST, - port: process.env.PROXY_PORT, - protocol: process.env.PROXY_PROTOCOL -} - -detector(BASE_URL, proxy).then(res => { - console.log(res) -}) diff --git a/example/typescript/src/misskey/proxy_instance.ts b/example/typescript/src/misskey/proxy_instance.ts deleted file mode 100644 index 73c60540c..000000000 --- a/example/typescript/src/misskey/proxy_instance.ts +++ /dev/null @@ -1,26 +0,0 @@ -import generator, { Entity, ProxyConfig, Response } from 'megalodon' - -declare var process: { - env: { - PROXY_HOST: string - PROXY_PORT: number - PROXY_PROTOCOL: 'http' | 'https' | 'socks4' | 'socks4a' | 'socks5' | 'socks5h' | 'socks' - } -} - -const BASE_URL: string = 'https://misskey.io' - -const proxy: ProxyConfig = { - host: process.env.PROXY_HOST, - port: process.env.PROXY_PORT, - protocol: process.env.PROXY_PROTOCOL -} - -const client = generator('misskey', BASE_URL, '', null, proxy) - -client - .getInstance() - .then((res: Response) => { - console.log(res) - }) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/relationships.ts b/example/typescript/src/misskey/relationships.ts deleted file mode 100644 index 8ca61d9c4..000000000 --- a/example/typescript/src/misskey/relationships.ts +++ /dev/null @@ -1,17 +0,0 @@ -import generator from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client = generator('misskey', BASE_URL, access_token) - -client.getRelationships(['7rl99pkppb', '7rkr4nmz19']).then(res => { - console.log(res.data) -}) diff --git a/example/typescript/src/misskey/timeline.ts b/example/typescript/src/misskey/timeline.ts deleted file mode 100644 index d5473bf24..000000000 --- a/example/typescript/src/misskey/timeline.ts +++ /dev/null @@ -1,20 +0,0 @@ -import generator, { MegalodonInterface, Entity, Response } from 'megalodon' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client: MegalodonInterface = generator('misskey', BASE_URL, access_token) - -client - .getLocalTimeline() - .then((resp: Response>) => { - console.log(resp.data) - }) - .catch(err => console.error(err)) diff --git a/example/typescript/src/misskey/toot.ts b/example/typescript/src/misskey/toot.ts deleted file mode 100644 index f11c604e8..000000000 --- a/example/typescript/src/misskey/toot.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as readline from 'readline' -import generator, { Entity, Response } from 'megalodon' - -const rl: readline.ReadLine = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) - -const BASE_URL: string = 'https://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN as string - -const client = generator('misskey', BASE_URL, access_token) - -new Promise(resolve => { - rl.question('Toot: ', status => { - client - .postStatus(status) - .then((res: Response) => { - console.log(res) - rl.close() - resolve(res) - }) - .catch(err => { - console.error(err) - rl.close() - }) - }) -}) diff --git a/example/typescript/src/misskey/web_socket.ts b/example/typescript/src/misskey/web_socket.ts deleted file mode 100644 index 6c8ac0206..000000000 --- a/example/typescript/src/misskey/web_socket.ts +++ /dev/null @@ -1,46 +0,0 @@ -import generator, { Entity, WebSocketInterface } from 'megalodon' -import log4js from 'log4js' - -declare var process: { - env: { - MISSKEY_ACCESS_TOKEN: string - } -} - -const BASE_URL: string = 'wss://misskey.io' - -const access_token: string = process.env.MISSKEY_ACCESS_TOKEN - -const client = generator('misskey', BASE_URL, access_token) - -const stream: WebSocketInterface = client.userSocket() - -const logger = log4js.getLogger() -logger.level = 'debug' -stream.on('connect', () => { - logger.debug('connect') -}) - -stream.on('pong', () => { - logger.debug('pong') -}) - -stream.on('update', (status: Entity.Status) => { - logger.debug(status) -}) - -stream.on('notification', (notification: Entity.Notification) => { - logger.debug(notification) -}) - -stream.on('error', (err: Error) => { - console.error(err) -}) - -stream.on('close', () => { - logger.debug('close') -}) - -stream.on('parser-error', (err: Error) => { - console.error(err) -}) From e6a6f3e41ada3c964f9973b1bcbf6f5bddcc0e16 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 22 Sep 2023 01:18:04 +0900 Subject: [PATCH 2/4] Drop Misskey support --- megalodon/src/detector.ts | 8 +- megalodon/src/index.ts | 2 - megalodon/src/megalodon.ts | 7 +- megalodon/src/misskey.ts | 2245 ----------------- megalodon/src/misskey/api_client.ts | 629 ----- .../src/misskey/entities/announcement.ts | 11 - megalodon/src/misskey/entities/app.ts | 9 - megalodon/src/misskey/entities/blocking.ts | 10 - megalodon/src/misskey/entities/createdNote.ts | 7 - megalodon/src/misskey/entities/emoji.ts | 8 - megalodon/src/misskey/entities/favorite.ts | 10 - megalodon/src/misskey/entities/file.ts | 18 - .../src/misskey/entities/followRequest.ts | 9 - megalodon/src/misskey/entities/follower.ts | 11 - megalodon/src/misskey/entities/following.ts | 11 - megalodon/src/misskey/entities/hashtag.ts | 7 - megalodon/src/misskey/entities/list.ts | 8 - megalodon/src/misskey/entities/meta.ts | 47 - megalodon/src/misskey/entities/mute.ts | 10 - megalodon/src/misskey/entities/note.ts | 34 - .../src/misskey/entities/notification.ts | 17 - megalodon/src/misskey/entities/poll.ts | 13 - megalodon/src/misskey/entities/reaction.ts | 10 - megalodon/src/misskey/entities/relation.ts | 12 - megalodon/src/misskey/entities/session.ts | 6 - megalodon/src/misskey/entities/stats.ts | 9 - megalodon/src/misskey/entities/user.ts | 13 - megalodon/src/misskey/entities/userDetail.ts | 32 - megalodon/src/misskey/entities/userkey.ts | 8 - megalodon/src/misskey/entity.ts | 26 - megalodon/src/misskey/notification.ts | 16 - megalodon/src/misskey/web_socket.ts | 413 --- 32 files changed, 2 insertions(+), 3674 deletions(-) delete mode 100644 megalodon/src/misskey.ts delete mode 100644 megalodon/src/misskey/api_client.ts delete mode 100644 megalodon/src/misskey/entities/announcement.ts delete mode 100644 megalodon/src/misskey/entities/app.ts delete mode 100644 megalodon/src/misskey/entities/blocking.ts delete mode 100644 megalodon/src/misskey/entities/createdNote.ts delete mode 100644 megalodon/src/misskey/entities/emoji.ts delete mode 100644 megalodon/src/misskey/entities/favorite.ts delete mode 100644 megalodon/src/misskey/entities/file.ts delete mode 100644 megalodon/src/misskey/entities/followRequest.ts delete mode 100644 megalodon/src/misskey/entities/follower.ts delete mode 100644 megalodon/src/misskey/entities/following.ts delete mode 100644 megalodon/src/misskey/entities/hashtag.ts delete mode 100644 megalodon/src/misskey/entities/list.ts delete mode 100644 megalodon/src/misskey/entities/meta.ts delete mode 100644 megalodon/src/misskey/entities/mute.ts delete mode 100644 megalodon/src/misskey/entities/note.ts delete mode 100644 megalodon/src/misskey/entities/notification.ts delete mode 100644 megalodon/src/misskey/entities/poll.ts delete mode 100644 megalodon/src/misskey/entities/reaction.ts delete mode 100644 megalodon/src/misskey/entities/relation.ts delete mode 100644 megalodon/src/misskey/entities/session.ts delete mode 100644 megalodon/src/misskey/entities/stats.ts delete mode 100644 megalodon/src/misskey/entities/user.ts delete mode 100644 megalodon/src/misskey/entities/userDetail.ts delete mode 100644 megalodon/src/misskey/entities/userkey.ts delete mode 100644 megalodon/src/misskey/entity.ts delete mode 100644 megalodon/src/misskey/notification.ts delete mode 100644 megalodon/src/misskey/web_socket.ts diff --git a/megalodon/src/detector.ts b/megalodon/src/detector.ts index 454b12003..b5ec8dbc2 100644 --- a/megalodon/src/detector.ts +++ b/megalodon/src/detector.ts @@ -51,7 +51,7 @@ type Metadata = { export const detector = async ( url: string, proxyConfig: ProxyConfig | false = false -): Promise<'mastodon' | 'pleroma' | 'misskey' | 'friendica' | 'firefish'> => { +): Promise<'mastodon' | 'pleroma' | 'friendica' | 'firefish'> => { let options: AxiosRequestConfig = { timeout: 20000 } @@ -76,8 +76,6 @@ export const detector = async ( return 'mastodon' case 'wildebeest': return 'mastodon' - case 'misskey': - return 'misskey' case 'friendica': return 'friendica' case 'firefish': @@ -100,8 +98,6 @@ export const detector = async ( return 'mastodon' case 'wildebeest': return 'mastodon' - case 'misskey': - return 'misskey' case 'friendica': return 'friendica' case 'firefish': @@ -124,8 +120,6 @@ export const detector = async ( return 'mastodon' case 'wildebeest': return 'mastodon' - case 'misskey': - return 'misskey' case 'friendica': return 'friendica' case 'firefish': diff --git a/megalodon/src/index.ts b/megalodon/src/index.ts index 03046c18d..2b4a4832b 100644 --- a/megalodon/src/index.ts +++ b/megalodon/src/index.ts @@ -6,7 +6,6 @@ import generator, { MegalodonInterface, WebSocketInterface } from './megalodon' import { detector } from './detector' import Mastodon from './mastodon' import Pleroma from './pleroma' -import Misskey from './misskey' import Firefish from './firefish' import Entity from './entity' import NotificationType from './notification' @@ -25,7 +24,6 @@ export { FilterContext, Mastodon, Pleroma, - Misskey, Firefish, Entity } diff --git a/megalodon/src/megalodon.ts b/megalodon/src/megalodon.ts index 5fab07aa9..03317d736 100644 --- a/megalodon/src/megalodon.ts +++ b/megalodon/src/megalodon.ts @@ -4,7 +4,6 @@ import Pleroma from './pleroma' import { ProxyConfig } from './proxy_config' import Mastodon from './mastodon' import Entity from './entity' -import Misskey from './misskey' import Friendica from './friendica' import Firefish from './firefish' @@ -1426,7 +1425,7 @@ export class NodeinfoError extends Error { * @return Client instance for each SNS you specified. */ const generator = ( - sns: 'mastodon' | 'pleroma' | 'misskey' | 'friendica' | 'firefish', + sns: 'mastodon' | 'pleroma' | 'friendica' | 'firefish', baseUrl: string, accessToken: string | null = null, userAgent: string | null = null, @@ -1437,10 +1436,6 @@ const generator = ( const pleroma = new Pleroma(baseUrl, accessToken, userAgent, proxyConfig) return pleroma } - case 'misskey': { - const misskey = new Misskey(baseUrl, accessToken, userAgent, proxyConfig) - return misskey - } case 'friendica': { const friendica = new Friendica(baseUrl, accessToken, userAgent, proxyConfig) return friendica diff --git a/megalodon/src/misskey.ts b/megalodon/src/misskey.ts deleted file mode 100644 index 521cc041f..000000000 --- a/megalodon/src/misskey.ts +++ /dev/null @@ -1,2245 +0,0 @@ -import FormData from 'form-data' - -import MisskeyAPI from './misskey/api_client' -import { DEFAULT_UA } from './default' -import { ProxyConfig } from './proxy_config' -import OAuth from './oauth' -import Response from './response' -import { MegalodonInterface, WebSocketInterface, NoImplementedError, ArgumentError, UnexpectedError } from './megalodon' -import { UnknownNotificationTypeError } from './notification' - -export default class Misskey implements MegalodonInterface { - public client: MisskeyAPI.Interface - public baseUrl: string - public proxyConfig: ProxyConfig | false - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor( - baseUrl: string, - accessToken: string | null = null, - userAgent: string | null = DEFAULT_UA, - proxyConfig: ProxyConfig | false = false - ) { - let token: string = '' - if (accessToken) { - token = accessToken - } - let agent: string = DEFAULT_UA - if (userAgent) { - agent = userAgent - } - this.client = new MisskeyAPI.Client(baseUrl, token, agent, proxyConfig) - this.baseUrl = baseUrl - this.proxyConfig = proxyConfig - } - - public cancel(): void { - return this.client.cancel() - } - - public async registerApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> = { - scopes: MisskeyAPI.DEFAULT_SCOPE, - redirect_uris: this.baseUrl - } - ): Promise { - 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 - }) - }) - } - - /** - * POST /api/app/create - * - * Create an application. - * @param client_name Your application's name. - * @param options Form data. - */ - public async createApp( - client_name: string, - options: Partial<{ scopes: Array; redirect_uris: string; website: string }> = { - scopes: MisskeyAPI.DEFAULT_SCOPE, - redirect_uris: this.baseUrl - } - ): Promise { - const redirect_uris = options.redirect_uris || this.baseUrl - const scopes = options.scopes || MisskeyAPI.DEFAULT_SCOPE - - const params: { - name: string - description: string - permission: Array - callbackUrl: string - } = { - name: client_name, - description: '', - permission: scopes, - callbackUrl: redirect_uris - } - - /** - * The response is: - { - "id": "xxxxxxxxxx", - "name": "string", - "callbackUrl": "string", - "permission": [ - "string" - ], - "secret": "string" - } - */ - return this.client.post('/api/app/create', params).then((res: Response) => { - const appData: OAuth.AppDataFromServer = { - id: res.data.id, - name: res.data.name, - website: null, - redirect_uri: res.data.callbackUrl, - client_id: '', - client_secret: res.data.secret - } - return OAuth.AppData.from(appData) - }) - } - - /** - * POST /api/auth/session/generate - */ - public async generateAuthUrlAndToken(clientSecret: string): Promise { - return this.client - .post('/api/auth/session/generate', { - appSecret: clientSecret - }) - .then((res: Response) => res.data) - } - - // ====================================== - // apps - // ====================================== - public async verifyAppCredentials(): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // apps/oauth - // ====================================== - /** - * POST /api/auth/session/userkey - * - * @param _client_id This parameter is not used in this method. - * @param client_secret Application secret key which will be provided in createApp. - * @param session_token Session token string which will be provided in generateAuthUrlAndToken. - * @param _redirect_uri This parameter is not used in this method. - */ - public async fetchAccessToken( - _client_id: string | null, - client_secret: string, - session_token: string, - _redirect_uri?: string - ): Promise { - return this.client - .post('/api/auth/session/userkey', { - appSecret: client_secret, - token: session_token - }) - .then(res => { - const token = new OAuth.TokenData(res.data.accessToken, 'misskey', '', 0, null, null) - return token - }) - } - - public async refreshToken(_client_id: string, _client_secret: string, _refresh_token: string): Promise { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async revokeToken(_client_id: string, _client_secret: string, _token: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts - // ====================================== - public async registerAccount( - _username: string, - _email: string, - _password: string, - _agreement: boolean, - _locale: string, - _reason?: string | null - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/i - */ - public async verifyAccountCredentials(): Promise> { - return this.client.post('/api/i').then(res => { - return Object.assign(res, { - data: MisskeyAPI.Converter.userDetail(res.data) - }) - }) - } - - /** - * POST /api/i/update - */ - public async updateCredentials(options?: { - discoverable?: boolean - bot?: boolean - display_name?: string - note?: string - avatar?: string - header?: string - locked?: boolean - source?: { - privacy?: string - sensitive?: boolean - language?: string - } | null - fields_attributes?: Array<{ name: string; value: string }> - }): Promise> { - 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) - }) - }) - } - - /** - * POST /api/users/show - */ - public async getAccount(id: string): Promise> { - return this.client - .post('/api/users/show', { - userId: id - }) - .then(res => { - return Object.assign(res, { - data: MisskeyAPI.Converter.userDetail(res.data) - }) - }) - } - - /** - * POST /api/users/notes - */ - public async getAccountStatuses( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - pinned?: boolean - exclude_replies: boolean - exclude_reblogs: boolean - only_media?: boolean - } - ): Promise>> { - 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)) } - } - 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: Array = res.data.map(note => MisskeyAPI.Converter.note(note)) - return Object.assign(res, { - data: statuses - }) - }) - } - - public async getAccountFavourites( - _id: string, - _options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async subscribeAccount(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unsubscribeAccount(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/users/followers - */ - public async getAccountFollowers( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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)) - }) - }) - } - - /** - * POST /api/users/following - */ - public async getAccountFollowing( - id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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)) - }) - }) - } - - public async getAccountLists(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getIdentityProof(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/following/create - */ - public async followAccount(id: string, _options?: { reblog?: boolean }): Promise> { - 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) - }) - }) - } - - /** - * POST /api/following/delete - */ - public async unfollowAccount(id: string): Promise> { - 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) - }) - }) - } - - /** - * POST /api/blocking/create - */ - public async blockAccount(id: string): Promise> { - 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) - }) - }) - } - - /** - * POST /api/blocking/delete - */ - public async unblockAccount(id: string): Promise> { - 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) - }) - }) - } - - /** - * POST /api/mute/create - */ - public async muteAccount(id: string, _notifications: boolean): Promise> { - 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) - }) - }) - } - - /** - * POST /api/mute/delete - */ - public async unmuteAccount(id: string): Promise> { - 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) - }) - }) - } - - public async pinAccount(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unpinAccount(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/users/relation - * - * @param id The accountID, for example `'1sdfag'` - */ - public async getRelationship(id: string): Promise> { - return this.client - .post('/api/users/relation', { - userId: id - }) - .then(res => { - return Object.assign(res, { - data: MisskeyAPI.Converter.relation(res.data) - }) - }) - } - - /** - * POST /api/users/relation - * - * @param id Array of account ID, for example `['1sdfag', 'ds12aa']`. - */ - public async getRelationships(ids: Array): Promise>> { - return Promise.all(ids.map(id => this.getRelationship(id))).then(results => ({ - ...results[0], - data: results.map(r => r.data) - })) - } - - /** - * POST /api/users/search - */ - public async searchAccount( - q: string, - options?: { - following?: boolean - resolve?: boolean - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - let params = { - query: q, - detail: true - } - if (options) { - if (options.resolve !== undefined) { - 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)) - }) - }) - } - - // ====================================== - // accounts/bookmarks - // ====================================== - public async getBookmarks(_options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/favourites - // ====================================== - /** - * POST /api/i/favorites - */ - public async getFavourites(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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)) - }) - }) - } - - // ====================================== - // accounts/mutes - // ====================================== - /** - * POST /api/mute/list - */ - public async getMutes(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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)) - }) - }) - } - - // ====================================== - // accounts/blocks - // ====================================== - /** - * POST /api/blocking/list - */ - public async getBlocks(options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - 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)) - }) - }) - } - - // ====================================== - // accounts/domain_blocks - // ====================================== - public async getDomainBlocks(_options?: { limit?: number; max_id?: string; min_id?: string }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async blockDomain(_domain: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unblockDomain(_domain: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/filters - // ====================================== - public async getFilters(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getFilter(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async createFilter( - _phrase: string, - _context: Array, - _options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async updateFilter( - _id: string, - _phrase: string, - _context: Array, - _options?: { - irreversible?: boolean - whole_word?: boolean - expires_in?: string - } - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async deleteFilter(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/reports - // ====================================== - /** - * POST /api/users/report-abuse - */ - public async report( - account_id: string, - options: { - status_ids?: Array - comment: string - forward?: boolean - category: Entity.Category - rule_ids?: Array - } - ): Promise> { - const category: Entity.Category = 'other' - 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, - action_taken_at: null, - comment: options.comment, - category: category, - forwarded: false, - status_ids: null, - rule_ids: null - } - }) - }) - } - - // ====================================== - // accounts/follow_requests - // ====================================== - /** - * POST /api/following/requests/list - */ - public async getFollowRequests(_limit?: number): Promise>> { - return this.client.post>('/api/following/requests/list').then(res => { - return Object.assign(res, { - data: res.data.map(r => MisskeyAPI.Converter.user(r.follower)) - }) - }) - } - - /** - * POST /api/following/requests/accept - */ - public async acceptFollowRequest(id: string): Promise> { - 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) - }) - }) - } - - /** - * POST /api/following/requests/reject - */ - public async rejectFollowRequest(id: string): Promise> { - 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) - }) - }) - } - - // ====================================== - // accounts/endorsements - // ====================================== - public async getEndorsements(_options?: { - limit?: number - max_id?: string - since_id?: string - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/featured_tags - // ====================================== - public async getFeaturedTags(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async createFeaturedTag(_name: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async deleteFeaturedTag(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getSuggestedTags(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/preferences - // ====================================== - public async getPreferences(): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/followed_tags - // ====================================== - public async getFollowedTags(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // accounts/suggestions - // ====================================== - /** - * POST /api/users/recommendation - */ - public async getSuggestions(limit?: number): Promise>> { - 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)) })) - } - - // ====================================== - // accounts/tags - // ====================================== - public async getTag(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async followTag(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unfollowTag(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // statuses - // ====================================== - public async postStatus( - status: string, - options?: { - media_ids?: Array - poll?: { options: Array; expires_in: number; multiple?: boolean; hide_totals?: boolean } - in_reply_to_id?: string - sensitive?: boolean - spoiler_text?: string - visibility?: 'public' | 'unlisted' | 'private' | 'direct' - scheduled_at?: string - language?: string - quote_id?: string - } - ): Promise> { - 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.quote_id) { - params = Object.assign(params, { - renoteId: options.quote_id - }) - } - } - return this.client - .post('/api/notes/create', params) - .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote) })) - } - - /** - * POST /api/notes/show - */ - public async getStatus(id: string): Promise> { - return this.client - .post('/api/notes/show', { - noteId: id - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data) })) - } - - public async editStatus( - _id: string, - _options: { - status?: string - spoiler_text?: string - sensitive?: boolean - media_ids?: Array - poll?: { options?: Array; expires_in?: number; multiple?: boolean; hide_totals?: boolean } - } - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/notes/delete - */ - public async deleteStatus(id: string): Promise> { - return this.client.post<{}>('/api/notes/delete', { - noteId: id - }) - } - - /** - * POST /api/notes/children - */ - public async getStatusContext( - id: string, - options?: { limit?: number; max_id?: string; since_id?: string } - ): Promise> { - 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: Entity.Context = { - ancestors: [], - descendants: res.data.map(n => MisskeyAPI.Converter.note(n)) - } - return { - ...res, - data: context - } - }) - } - - public async getStatusSource(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/notes/renotes - */ - public async getStatusRebloggedBy(id: string): Promise>> { - return this.client - .post>('/api/notes/renotes', { - noteId: id - }) - .then(res => ({ - ...res, - data: res.data.map(n => MisskeyAPI.Converter.user(n.user)) - })) - } - - public async getStatusFavouritedBy(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/notes/favorites/create - */ - public async favouriteStatus(id: string): Promise> { - 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) })) - } - - /** - * POST /api/notes/favorites/delete - */ - public async unfavouriteStatus(id: string): Promise> { - 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) })) - } - - /** - * POST /api/notes/create - */ - public async reblogStatus(id: string): Promise> { - return this.client - .post('/api/notes/create', { - renoteId: id - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data.createdNote) })) - } - - /** - * POST /api/notes/unrenote - */ - public async unreblogStatus(id: string): Promise> { - 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) })) - } - - public async bookmarkStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unbookmarkStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async muteStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async unmuteStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/i/pin - */ - public async pinStatus(id: string): Promise> { - 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) })) - } - - /** - * POST /api/i/unpin - */ - public async unpinStatus(id: string): Promise> { - 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) })) - } - - // ====================================== - // statuses/media - // ====================================== - /** - * POST /api/drive/files/create - */ - public async uploadMedia(file: any, _options?: { description?: string; focus?: string }): Promise> { - const formData = new FormData() - formData.append('file', file) - let headers: { [key: string]: string } = {} - 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) })) - } - - public async getMedia(id: string): Promise> { - const res = await this.client.post('/api/drive/files/show', { fileId: id }) - return { ...res, data: MisskeyAPI.Converter.file(res.data) } - } - - /** - * POST /api/drive/files/update - */ - public async updateMedia( - id: string, - options?: { - file?: any - description?: string - focus?: string - is_sensitive?: boolean - } - ): Promise> { - 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) })) - } - - // ====================================== - // statuses/polls - // ====================================== - public async getPoll(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/notes/polls/vote - */ - public async votePoll(_id: string, choices: Array, status_id?: string | null): Promise> { - 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) - 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 } - } - - // ====================================== - // statuses/scheduled_statuses - // ====================================== - public async getScheduledStatuses(_options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getScheduledStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async scheduleStatus(_id: string, _scheduled_at?: string | null): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async cancelScheduledStatus(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // timelines - // ====================================== - /** - * POST /api/notes/global-timeline - */ - public async getPublicTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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)) })) - } - - /** - * POST /api/notes/local-timeline - */ - public async getLocalTimeline(options?: { - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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)) })) - } - - /** - * POST /api/notes/search-by-tag - */ - public async getTagTimeline( - hashtag: string, - options?: { - local?: boolean - only_media?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - 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)) })) - } - - /** - * POST /api/notes/timeline - */ - public async getHomeTimeline(options?: { - local?: boolean - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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)) })) - } - - /** - * POST /api/notes/user-list-timeline - */ - public async getListTimeline( - list_id: string, - options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - } - ): Promise>> { - let params = { - listId: list_id, - 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/user-list-timeline', params) - .then(res => ({ ...res, data: res.data.map(n => MisskeyAPI.Converter.note(n)) })) - } - - // ====================================== - // timelines/conversations - // ====================================== - /** - * POST /api/notes/mentions - */ - public async getConversationTimeline(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - }): Promise>> { - 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)) })) - } - - public async deleteConversation(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async readConversation(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // timelines/lists - // ====================================== - /** - * POST /api/users/lists/list - */ - public async getLists(): Promise>> { - return this.client - .post>('/api/users/lists/list') - .then(res => ({ ...res, data: res.data.map(l => MisskeyAPI.Converter.list(l)) })) - } - - /** - * POST /api/users/lists/show - */ - public async getList(id: string): Promise> { - return this.client - .post('/api/users/lists/show', { - listId: id - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })) - } - - /** - * POST /api/users/lists/create - */ - public async createList(title: string): Promise> { - return this.client - .post('/api/users/lists/create', { - name: title - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })) - } - - /** - * POST /api/users/lists/update - */ - public async updateList(id: string, title: string): Promise> { - return this.client - .post('/api/users/lists/update', { - listId: id, - name: title - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.list(res.data) })) - } - - /** - * POST /api/users/lists/delete - */ - public async deleteList(id: string): Promise> { - return this.client.post<{}>('/api/users/lists/delete', { - listId: id - }) - } - - /** - * POST /api/users/lists/show - */ - public async getAccountsInList( - id: string, - _options?: { - limit?: number - max_id?: string - since_id?: string - } - ): Promise>> { - 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) } - } - - /** - * POST /api/users/lists/push - */ - public async addAccountsToList(id: string, account_ids: Array): Promise> { - return this.client.post<{}>('/api/users/lists/push', { - listId: id, - userId: account_ids[0] - }) - } - - /** - * POST /api/users/lists/pull - */ - public async deleteAccountsFromList(id: string, account_ids: Array): Promise> { - return this.client.post<{}>('/api/users/lists/pull', { - listId: id, - userId: account_ids[0] - }) - } - - // ====================================== - // timelines/markers - // ====================================== - public async getMarkers(_timeline: Array): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async saveMarkers(_options?: { - home?: { last_read_id: string } - notifications?: { last_read_id: string } - }): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // notifications - // ====================================== - /** - * POST /api/i/notifications - */ - public async getNotifications(options?: { - limit?: number - max_id?: string - since_id?: string - min_id?: string - exclude_type?: Array - account_id?: string - }): Promise>> { - 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)) - }) - } - } - const res = await this.client.post>('/api/i/notifications', params) - const notifications: Array = res.data.flatMap(n => { - const notify = MisskeyAPI.Converter.notification(n) - if (notify instanceof UnknownNotificationTypeError) { - return [] - } - return notify - }) - - return { ...res, data: notifications } - } - - public async getNotification(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * POST /api/notifications/mark-all-as-read - */ - public async dismissNotifications(): Promise> { - return this.client.post<{}>('/api/notifications/mark-all-as-read') - } - - public async dismissNotification(_id: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async readNotifications(_options: { - id?: string - max_id?: string - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('mastodon does not support') - reject(err) - }) - } - - // ====================================== - // notifications/push - // ====================================== - public async subscribePushNotification( - _subscription: { endpoint: string; keys: { p256dh: string; auth: string } }, - _data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getPushSubscription(): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async updatePushSubscription( - _data?: { alerts: { follow?: boolean; favourite?: boolean; reblog?: boolean; mention?: boolean; poll?: boolean } } | null - ): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - /** - * DELETE /api/v1/push/subscription - */ - public async deletePushSubscription(): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // search - // ====================================== - public async search( - q: string, - options: { - type: 'accounts' | 'hashtags' | 'statuses' - limit?: number - max_id?: string - min_id?: string - resolve?: boolean - offset?: number - following?: boolean - account_id?: string - exclude_unreviewed?: boolean - } - ): Promise> { - 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 - }) - } - if (options.resolve) { - 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)), - 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)), - hashtags: [] - } - })) - } - case 'hashtags': { - 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 - }) - } - } - return this.client.post>('/api/hashtags/search', params).then(res => ({ - ...res, - data: { - accounts: [], - statuses: [], - hashtags: res.data.map(h => ({ name: h, url: h, history: [], following: false })) - } - })) - } - } - } - - // ====================================== - // instance - // ====================================== - /** - * POST /api/meta - * POST /api/stats - */ - public async getInstance(): Promise> { - const meta = await this.client - .post('/api/meta', { detail: true }) - .then(res => res.data) - return this.client - .post('/api/stats') - .then(res => ({ ...res, data: MisskeyAPI.Converter.meta(meta, res.data) })) - } - - public async getInstancePeers(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async getInstanceActivity(): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // instance/trends - // ====================================== - /** - * POST /api/hashtags/trend - */ - public async getInstanceTrends(_limit?: number | null): Promise>> { - return this.client - .post>('/api/hashtags/trend') - .then(res => ({ ...res, data: res.data.map(h => MisskeyAPI.Converter.hashtag(h)) })) - } - - // ====================================== - // instance/directory - // ====================================== - public async getInstanceDirectory(_options?: { - limit?: number - offset?: number - order?: 'active' | 'new' - local?: boolean - }): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // instance/custom_emojis - // ====================================== - /** - * GET /api/emojis - */ - public async getInstanceCustomEmojis(): Promise>> { - return this.client - .get<{ emojis: Array }>('/api/emojis') - .then(res => ({ ...res, data: res.data.emojis.map(e => MisskeyAPI.Converter.emoji(e)) })) - } - - // ====================================== - // instance/announcements - // ====================================== - /** - * GET /api/announcements - * - * @return Array of announcements. - */ - public async getInstanceAnnouncements(): Promise>> { - return this.client - .post>('/api/announcements') - .then(res => ({ ...res, data: res.data.map(a => MisskeyAPI.Converter.announcement(a)) })) - } - - public async dismissInstanceAnnouncement(_id: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async addReactionToAnnouncement(_id: string, _name: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public async removeReactionFromAnnouncement(_id: string, _name: string): Promise>> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - // ====================================== - // Emoji reactions - // ====================================== - /** - * POST /api/notes/reactions/create - * - * @param {string} id Target note ID. - * @param {string} emoji Reaction emoji string. This string is raw unicode emoji. - */ - public async createEmojiReaction(id: string, emoji: string): Promise> { - await this.client.post<{}>('/api/notes/reactions/create', { - noteId: id, - reaction: emoji - }) - return this.client - .post('/api/notes/show', { - noteId: id - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data) })) - } - - /** - * POST /api/notes/reactions/delete - */ - public async deleteEmojiReaction(id: string, _emoji: string): Promise> { - await this.client.post<{}>('/api/notes/reactions/delete', { - noteId: id - }) - return this.client - .post('/api/notes/show', { - noteId: id - }) - .then(res => ({ ...res, data: MisskeyAPI.Converter.note(res.data) })) - } - - public async getEmojiReactions(id: string): Promise>> { - return this.client - .post>('/api/notes/reactions', { - noteId: id - }) - .then(res => ({ - ...res, - data: MisskeyAPI.Converter.reactions(res.data) - })) - } - - public async getEmojiReaction(_id: string, _emoji: string): Promise> { - return new Promise((_, reject) => { - const err = new NoImplementedError('misskey does not support') - reject(err) - }) - } - - public userSocket(): WebSocketInterface { - return this.client.socket('user') - } - - public publicSocket(): WebSocketInterface { - return this.client.socket('globalTimeline') - } - - public localSocket(): WebSocketInterface { - return this.client.socket('localTimeline') - } - - public tagSocket(_tag: string): WebSocketInterface { - throw new NoImplementedError('TODO: implement') - } - - public listSocket(list_id: string): WebSocketInterface { - return this.client.socket('list', list_id) - } - - public directSocket(): WebSocketInterface { - return this.client.socket('conversation') - } -} diff --git a/megalodon/src/misskey/api_client.ts b/megalodon/src/misskey/api_client.ts deleted file mode 100644 index 4883e7a8c..000000000 --- a/megalodon/src/misskey/api_client.ts +++ /dev/null @@ -1,629 +0,0 @@ -import axios, { AxiosResponse, AxiosRequestConfig } from 'axios' -import dayjs from 'dayjs' -import FormData from 'form-data' - -import { DEFAULT_UA } from '../default' -import proxyAgent, { ProxyConfig } from '../proxy_config' -import Response from '../response' -import MisskeyEntity from './entity' -import MegalodonEntity from '../entity' -import WebSocket from './web_socket' -import MisskeyNotificationType from './notification' -import NotificationType, { UnknownNotificationTypeError } from '../notification' - -namespace MisskeyAPI { - export namespace Entity { - export type Announcement = MisskeyEntity.Announcement - export type App = MisskeyEntity.App - export type Blocking = MisskeyEntity.Blocking - export type Choice = MisskeyEntity.Choice - export type CreatedNote = MisskeyEntity.CreatedNote - export type Emoji = MisskeyEntity.Emoji - export type Favorite = MisskeyEntity.Favorite - export type File = MisskeyEntity.File - export type Follower = MisskeyEntity.Follower - export type Following = MisskeyEntity.Following - export type FollowRequest = MisskeyEntity.FollowRequest - export type Hashtag = MisskeyEntity.Hashtag - export type List = MisskeyEntity.List - export type Meta = MisskeyEntity.Meta - export type Mute = MisskeyEntity.Mute - export type Note = MisskeyEntity.Note - export type Notification = MisskeyEntity.Notification - export type Poll = MisskeyEntity.Poll - export type Reaction = MisskeyEntity.Reaction - export type Relation = MisskeyEntity.Relation - export type User = MisskeyEntity.User - export type UserDetail = MisskeyEntity.UserDetail - export type UserKey = MisskeyEntity.UserKey - export type Session = MisskeyEntity.Session - export type Stats = MisskeyEntity.Stats - } - - export namespace Converter { - export const announcement = (a: Entity.Announcement): MegalodonEntity.Announcement => ({ - id: a.id, - content: a.title + '\n' + a.text, - starts_at: null, - ends_at: null, - published: true, - all_day: true, - published_at: a.createdAt, - updated_at: a.updatedAt, - read: a.isRead !== undefined ? a.isRead : null, - mentions: [], - statuses: [], - tags: [], - emojis: [], - reactions: [] - }) - - export const emoji = (e: Entity.Emoji): MegalodonEntity.Emoji => { - return { - shortcode: e.name, - static_url: e.url, - url: e.url, - visible_in_picker: true, - category: e.category - } - } - - export const user = (u: Entity.User): MegalodonEntity.Account => { - let acct = u.username - if (u.host) { - acct = `${u.username}@${u.host}` - } - return { - id: u.id, - username: u.username, - acct: acct, - display_name: u.name, - locked: false, - group: null, - noindex: null, - suspended: null, - limited: null, - created_at: '', - followers_count: 0, - following_count: 0, - statuses_count: 0, - note: '', - url: acct, - avatar: u.avatarUrl, - avatar_static: u.avatarColor, - header: '', - header_static: '', - emojis: mapEmojis(u.emojis), - moved: null, - fields: [], - bot: null - } - } - - export const userDetail = (u: Entity.UserDetail): MegalodonEntity.Account => { - let acct = u.username - if (u.host) { - acct = `${u.username}@${u.host}` - } - return { - id: u.id, - username: u.username, - acct: acct, - display_name: u.name, - locked: u.isLocked, - group: null, - noindex: null, - suspended: null, - limited: null, - created_at: u.createdAt, - followers_count: u.followersCount, - following_count: u.followingCount, - statuses_count: u.notesCount, - note: u.description, - url: acct, - avatar: u.avatarUrl, - avatar_static: u.avatarColor, - header: u.bannerUrl, - header_static: u.bannerColor, - emojis: mapEmojis(u.emojis), - moved: null, - fields: [], - bot: u.isBot - } - } - - export const visibility = (v: 'public' | 'home' | 'followers' | 'specified'): 'public' | 'unlisted' | 'private' | 'direct' => { - switch (v) { - case 'public': - return v - case 'home': - return 'unlisted' - case 'followers': - return 'private' - case 'specified': - return 'direct' - } - } - - export const encodeVisibility = (v: 'public' | 'unlisted' | 'private' | 'direct'): 'public' | 'home' | 'followers' | 'specified' => { - switch (v) { - case 'public': - return v - case 'unlisted': - return 'home' - case 'private': - return 'followers' - case 'direct': - return 'specified' - } - } - - export const fileType = (s: string): 'unknown' | 'image' | 'gifv' | 'video' | 'audio' => { - if (s === 'image/gif') { - return 'gifv' - } - if (s.includes('image')) { - return 'image' - } - if (s.includes('video')) { - return 'video' - } - if (s.includes('audio')) { - return 'audio' - } - return 'unknown' - } - - export const file = (f: Entity.File): MegalodonEntity.Attachment => { - return { - id: f.id, - type: fileType(f.type), - url: f.url, - remote_url: f.url, - preview_url: f.thumbnailUrl, - text_url: f.url, - meta: { - width: f.properties.width, - height: f.properties.height - }, - description: null, - blurhash: null - } - } - - export const follower = (f: Entity.Follower): MegalodonEntity.Account => { - return user(f.follower) - } - - export const following = (f: Entity.Following): MegalodonEntity.Account => { - return user(f.followee) - } - - export const relation = (r: Entity.Relation): MegalodonEntity.Relationship => { - return { - id: r.id, - following: r.isFollowing, - followed_by: r.isFollowed, - blocking: r.isBlocking, - blocked_by: r.isBlocked, - muting: r.isMuted, - muting_notifications: false, - requested: r.hasPendingFollowRequestFromYou, - domain_blocking: false, - showing_reblogs: true, - endorsed: false, - notifying: false, - note: null - } - } - - export const choice = (c: Entity.Choice): MegalodonEntity.PollOption => { - return { - title: c.text, - votes_count: c.votes - } - } - - export const poll = (p: Entity.Poll): MegalodonEntity.Poll => { - const now = dayjs() - const expire = dayjs(p.expiresAt) - const count = p.choices.reduce((sum, choice) => sum + choice.votes, 0) - return { - id: '', - expires_at: p.expiresAt, - expired: now.isAfter(expire), - multiple: p.multiple, - votes_count: count, - options: Array.isArray(p.choices) ? p.choices.map(c => choice(c)) : [], - voted: Array.isArray(p.choices) ? p.choices.some(c => c.isVoted) : false - } - } - - export const note = (n: Entity.Note): MegalodonEntity.Status => { - return { - id: n.id, - uri: n.uri ? n.uri : '', - url: n.uri ? n.uri : '', - account: user(n.user), - in_reply_to_id: n.replyId, - in_reply_to_account_id: null, - reblog: n.renote ? note(n.renote) : null, - content: n.text - ? n.text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(/`/g, '`') - .replace(/\r?\n/g, '
') - : '', - plain_content: n.text ? n.text : null, - created_at: n.createdAt, - emojis: mapEmojis(n.emojis).concat(mapReactionEmojis(n.reactionEmojis)), - replies_count: n.repliesCount, - reblogs_count: n.renoteCount, - favourites_count: 0, - reblogged: false, - favourited: false, - muted: false, - sensitive: Array.isArray(n.files) ? n.files.some(f => f.isSensitive) : false, - spoiler_text: n.cw ? n.cw : '', - visibility: visibility(n.visibility), - media_attachments: Array.isArray(n.files) ? n.files.map(f => file(f)) : [], - mentions: [], - tags: [], - card: null, - poll: n.poll ? poll(n.poll) : null, - application: null, - language: null, - pinned: null, - emoji_reactions: typeof n.reactions === 'object' ? mapReactions(n.reactions, n.myReaction) : [], - bookmarked: false, - quote: n.renote !== undefined && n.text !== null - } - } - - const mapEmojis = (e: Array | { [key: string]: string }): Array => { - if (Array.isArray(e)) { - return e.map(e => emoji(e)) - } else if (e) { - return mapReactionEmojis(e) - } else { - return [] - } - } - - export const mapReactions = (r: { [key: string]: number }, myReaction?: string): Array => { - return Object.keys(r).map(key => { - if (myReaction && key === myReaction) { - return { - count: r[key], - me: true, - name: key - } - } - return { - count: r[key], - me: false, - name: key - } - }) - } - - const mapReactionEmojis = (r: { [key: string]: string }): Array => { - return Object.keys(r).map(key => ({ - shortcode: key, - static_url: r[key], - url: r[key], - visible_in_picker: true, - category: '' - })) - } - - export const reactions = (r: Array): Array => { - const result: Array = [] - r.map(e => { - const i = result.findIndex(res => res.name === e.type) - if (i >= 0) { - result[i].count++ - } else { - result.push({ - count: 1, - me: false, - name: e.type - }) - } - }) - return result - } - - export const noteToConversation = (n: Entity.Note): MegalodonEntity.Conversation => { - const accounts: Array = [user(n.user)] - if (n.reply) { - accounts.push(user(n.reply.user)) - } - return { - id: n.id, - accounts: accounts, - last_status: note(n), - unread: false - } - } - - export const list = (l: Entity.List): MegalodonEntity.List => ({ - id: l.id, - title: l.name, - replies_policy: null - }) - - export const encodeNotificationType = ( - e: MegalodonEntity.NotificationType - ): MisskeyEntity.NotificationType | UnknownNotificationTypeError => { - switch (e) { - case NotificationType.Follow: - return MisskeyNotificationType.Follow - case NotificationType.Mention: - return MisskeyNotificationType.Reply - case NotificationType.Favourite: - case NotificationType.EmojiReaction: - return MisskeyNotificationType.Reaction - case NotificationType.Reblog: - return MisskeyNotificationType.Renote - case NotificationType.PollVote: - return MisskeyNotificationType.PollVote - case NotificationType.FollowRequest: - return MisskeyNotificationType.ReceiveFollowRequest - default: - return new UnknownNotificationTypeError() - } - } - - export const decodeNotificationType = ( - e: MisskeyEntity.NotificationType - ): MegalodonEntity.NotificationType | UnknownNotificationTypeError => { - switch (e) { - case MisskeyNotificationType.Follow: - return NotificationType.Follow - case MisskeyNotificationType.Mention: - case MisskeyNotificationType.Reply: - return NotificationType.Mention - case MisskeyNotificationType.Renote: - case MisskeyNotificationType.Quote: - return NotificationType.Reblog - case MisskeyNotificationType.Reaction: - return NotificationType.EmojiReaction - case MisskeyNotificationType.PollVote: - return NotificationType.PollVote - case MisskeyNotificationType.ReceiveFollowRequest: - return NotificationType.FollowRequest - case MisskeyNotificationType.FollowRequestAccepted: - return NotificationType.Follow - default: - return new UnknownNotificationTypeError() - } - } - - export const notification = (n: Entity.Notification): MegalodonEntity.Notification | UnknownNotificationTypeError => { - const notificationType = decodeNotificationType(n.type) - if (notificationType instanceof UnknownNotificationTypeError) { - return notificationType - } - let notification = { - id: n.id, - account: user(n.user), - created_at: n.createdAt, - type: notificationType - } - if (n.note) { - notification = Object.assign(notification, { - status: note(n.note) - }) - } - if (n.reaction) { - notification = Object.assign(notification, { - emoji: n.reaction - }) - } - return notification - } - - export const stats = (s: Entity.Stats): MegalodonEntity.Stats => { - return { - user_count: s.usersCount, - status_count: s.notesCount, - domain_count: s.instances - } - } - - export const meta = (m: Entity.Meta, s: Entity.Stats): MegalodonEntity.Instance => { - const wss = m.uri.replace(/^https:\/\//, 'wss://') - return { - uri: m.uri, - title: m.name, - description: m.description, - email: m.maintainerEmail, - version: m.version, - thumbnail: m.bannerUrl, - urls: { - streaming_api: `${wss}/streaming` - }, - stats: stats(s), - languages: m.langs, - registrations: !m.disableRegistration, - approval_required: false, - configuration: { - statuses: { - max_characters: m.maxNoteTextLength, - max_media_attachments: m.policies.clipLimit - } - } - } - } - - export const hashtag = (h: Entity.Hashtag): MegalodonEntity.Tag => { - return { - name: h.tag, - url: h.tag, - history: [], - following: false - } - } - } - - export const DEFAULT_SCOPE = [ - 'read:account', - 'write:account', - 'read:blocks', - 'write:blocks', - 'read:drive', - 'write:drive', - 'read:favorites', - 'write:favorites', - 'read:following', - 'write:following', - 'read:mutes', - 'write:mutes', - 'write:notes', - 'read:notifications', - 'write:notifications', - 'read:reactions', - 'write:reactions', - 'write:votes' - ] - - /** - * Interface - */ - export interface Interface { - get(path: string, params?: any, headers?: { [key: string]: string }): Promise> - post(path: string, params?: any, headers?: { [key: string]: string }): Promise> - cancel(): void - socket(channel: 'user' | 'localTimeline' | 'hybridTimeline' | 'globalTimeline' | 'conversation' | 'list', listId?: string): WebSocket - } - - /** - * Misskey API client. - * - * Usign axios for request, you will handle promises. - */ - export class Client implements Interface { - private accessToken: string | null - private baseUrl: string - private userAgent: string - private abortController: AbortController - private proxyConfig: ProxyConfig | false = false - - /** - * @param baseUrl hostname or base URL - * @param accessToken access token from OAuth2 authorization - * @param userAgent UserAgent is specified in header on request. - * @param proxyConfig Proxy setting, or set false if don't use proxy. - */ - constructor(baseUrl: string, accessToken: string | null, userAgent: string = DEFAULT_UA, proxyConfig: ProxyConfig | false = false) { - this.accessToken = accessToken - this.baseUrl = baseUrl - this.userAgent = userAgent - this.proxyConfig = proxyConfig - this.abortController = new AbortController() - axios.defaults.signal = this.abortController.signal - } - - /** - * GET request to misskey API. - **/ - public async get(path: string, params: any = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - params: params, - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - return axios.get(this.baseUrl + path, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * POST request to misskey REST API. - * @param path relative path from baseUrl - * @param params Form data - * @param headers Request header object - */ - public async post(path: string, params: any = {}, headers: { [key: string]: string } = {}): Promise> { - let options: AxiosRequestConfig = { - headers: headers, - maxContentLength: Infinity, - maxBodyLength: Infinity - } - if (this.proxyConfig) { - options = Object.assign(options, { - httpAgent: proxyAgent(this.proxyConfig), - httpsAgent: proxyAgent(this.proxyConfig) - }) - } - let bodyParams = params - if (this.accessToken) { - if (params instanceof FormData) { - bodyParams.append('i', this.accessToken) - } else { - bodyParams = Object.assign(params, { - i: this.accessToken - }) - } - } - return axios.post(this.baseUrl + path, bodyParams, options).then((resp: AxiosResponse) => { - const res: Response = { - data: resp.data, - status: resp.status, - statusText: resp.statusText, - headers: resp.headers - } - return res - }) - } - - /** - * Cancel all requests in this instance. - * @returns void - */ - public cancel(): void { - return this.abortController.abort() - } - - /** - * Get connection and receive websocket connection for Misskey API. - * - * @param channel Channel name is user, localTimeline, hybridTimeline, globalTimeline, conversation or list. - * @param listId This parameter is required only list channel. - */ - public socket( - channel: 'user' | 'localTimeline' | 'hybridTimeline' | 'globalTimeline' | 'conversation' | 'list', - listId?: string - ): WebSocket { - if (!this.accessToken) { - throw new Error('accessToken is required') - } - const url = this.baseUrl + '/streaming' - const streaming = new WebSocket(url, channel, this.accessToken, listId, this.userAgent, this.proxyConfig) - process.nextTick(() => { - streaming.start() - }) - return streaming - } - } -} - -export default MisskeyAPI diff --git a/megalodon/src/misskey/entities/announcement.ts b/megalodon/src/misskey/entities/announcement.ts deleted file mode 100644 index ec1739a75..000000000 --- a/megalodon/src/misskey/entities/announcement.ts +++ /dev/null @@ -1,11 +0,0 @@ -namespace MisskeyEntity { - export type Announcement = { - id: string - createdAt: string - updatedAt: string | null - text: string - title: string - imageurl: string | null - isRead?: boolean - } -} diff --git a/megalodon/src/misskey/entities/app.ts b/megalodon/src/misskey/entities/app.ts deleted file mode 100644 index 40a704b94..000000000 --- a/megalodon/src/misskey/entities/app.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MisskeyEntity { - export type App = { - id: string - name: string - callbackUrl: string - permission: Array - secret: string - } -} diff --git a/megalodon/src/misskey/entities/blocking.ts b/megalodon/src/misskey/entities/blocking.ts deleted file mode 100644 index 9900a777b..000000000 --- a/megalodon/src/misskey/entities/blocking.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Blocking = { - id: string - createdAt: string - blockeeId: string - blockee: UserDetail - } -} diff --git a/megalodon/src/misskey/entities/createdNote.ts b/megalodon/src/misskey/entities/createdNote.ts deleted file mode 100644 index 88ba60040..000000000 --- a/megalodon/src/misskey/entities/createdNote.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -namespace MisskeyEntity { - export type CreatedNote = { - createdNote: Note - } -} diff --git a/megalodon/src/misskey/entities/emoji.ts b/megalodon/src/misskey/entities/emoji.ts deleted file mode 100644 index 2bd4c8c73..000000000 --- a/megalodon/src/misskey/entities/emoji.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MisskeyEntity { - export type Emoji = { - name: string - url: string - aliases: Array - category: string - } -} diff --git a/megalodon/src/misskey/entities/favorite.ts b/megalodon/src/misskey/entities/favorite.ts deleted file mode 100644 index 8ed7a54bf..000000000 --- a/megalodon/src/misskey/entities/favorite.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Favorite = { - id: string - createdAt: string - noteId: string - note: Note - } -} diff --git a/megalodon/src/misskey/entities/file.ts b/megalodon/src/misskey/entities/file.ts deleted file mode 100644 index 6e4e09eee..000000000 --- a/megalodon/src/misskey/entities/file.ts +++ /dev/null @@ -1,18 +0,0 @@ -namespace MisskeyEntity { - export type File = { - id: string - createdAt: string - name: string - type: string - md5: string - size: number - isSensitive: boolean - properties: { - width: number - height: number - avgColor: string - } - url: string - thumbnailUrl: string - } -} diff --git a/megalodon/src/misskey/entities/followRequest.ts b/megalodon/src/misskey/entities/followRequest.ts deleted file mode 100644 index bd2777b2d..000000000 --- a/megalodon/src/misskey/entities/followRequest.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// - -namespace MisskeyEntity { - export type FollowRequest = { - id: string - follower: User - followee: User - } -} diff --git a/megalodon/src/misskey/entities/follower.ts b/megalodon/src/misskey/entities/follower.ts deleted file mode 100644 index 70ef632e1..000000000 --- a/megalodon/src/misskey/entities/follower.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Follower = { - id: string - createdAt: string - followeeId: string - followerId: string - follower: UserDetail - } -} diff --git a/megalodon/src/misskey/entities/following.ts b/megalodon/src/misskey/entities/following.ts deleted file mode 100644 index 927a91354..000000000 --- a/megalodon/src/misskey/entities/following.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Following = { - id: string - createdAt: string - followeeId: string - followerId: string - followee: UserDetail - } -} diff --git a/megalodon/src/misskey/entities/hashtag.ts b/megalodon/src/misskey/entities/hashtag.ts deleted file mode 100644 index 6a3fe43ad..000000000 --- a/megalodon/src/misskey/entities/hashtag.ts +++ /dev/null @@ -1,7 +0,0 @@ -namespace MisskeyEntity { - export type Hashtag = { - tag: string - chart: Array - usersCount: number - } -} diff --git a/megalodon/src/misskey/entities/list.ts b/megalodon/src/misskey/entities/list.ts deleted file mode 100644 index 8167d2981..000000000 --- a/megalodon/src/misskey/entities/list.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace MisskeyEntity { - export type List = { - id: string - createdAt: string - name: string - userIds: Array - } -} diff --git a/megalodon/src/misskey/entities/meta.ts b/megalodon/src/misskey/entities/meta.ts deleted file mode 100644 index 6d168db23..000000000 --- a/megalodon/src/misskey/entities/meta.ts +++ /dev/null @@ -1,47 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Meta = { - maintainerName: string - maintainerEmail: string - name: string - version: string - uri: string - description: string - langs: Array - disableRegistration: boolean - disableLocalTimeline: boolean - bannerUrl: string - maxNoteTextLength: number - emojis: Array - policies: { - gtlAvailable: boolean - ltlAvailable: boolean - canPublicNote: boolean - canInvite: boolean - canManageCustomEmojis: boolean - canHideAds: boolean - driveCapacityMb: number - pinLimit: number - antennaLimit: number - wordMuteLimit: number - webhookLimit: number - clipLimit: number - noteEachClipsLimit: number - userListLimit: number - userEachUserListsLimit: number - rateLimitFactor: number - } - features: { - registration: boolean - emailRequiredForSignup: boolean - elasticsearch: boolean - hcaptcha: boolean - recaptcha: boolean - turnstile: boolean - objectStorage: boolean - serviceWorker: boolean - miauth: boolean - } - } -} diff --git a/megalodon/src/misskey/entities/mute.ts b/megalodon/src/misskey/entities/mute.ts deleted file mode 100644 index 3cd7ae409..000000000 --- a/megalodon/src/misskey/entities/mute.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Mute = { - id: string - createdAt: string - muteeId: string - mutee: UserDetail - } -} diff --git a/megalodon/src/misskey/entities/note.ts b/megalodon/src/misskey/entities/note.ts deleted file mode 100644 index cc8aa3206..000000000 --- a/megalodon/src/misskey/entities/note.ts +++ /dev/null @@ -1,34 +0,0 @@ -/// -/// -/// -/// - -namespace MisskeyEntity { - export type Note = { - id: string - createdAt: string - userId: string - user: User - text: string | null - cw: string | null - visibility: 'public' | 'home' | 'followers' | 'specified' - renoteCount: number - repliesCount: number - reactions: { [key: string]: number } - // This field includes only remote emojis - reactionEmojis: { [key: string]: string } - emojis: Array | { [key: string]: string } - fileIds: Array - files: Array - replyId: string | null - renoteId: string | null - uri?: string - reply?: Note - renote?: Note - viaMobile?: boolean - tags?: Array - poll?: Poll - mentions?: Array - myReaction?: string - } -} diff --git a/megalodon/src/misskey/entities/notification.ts b/megalodon/src/misskey/entities/notification.ts deleted file mode 100644 index c331a1ec8..000000000 --- a/megalodon/src/misskey/entities/notification.ts +++ /dev/null @@ -1,17 +0,0 @@ -/// -/// - -namespace MisskeyEntity { - export type Notification = { - id: string - createdAt: string - // https://github.com/syuilo/misskey/blob/056942391aee135eb6c77aaa63f6ed5741d701a6/src/models/entities/notification.ts#L50-L62 - type: NotificationType - userId: string - user: User - note?: Note - reaction?: string - } - - export type NotificationType = string -} diff --git a/megalodon/src/misskey/entities/poll.ts b/megalodon/src/misskey/entities/poll.ts deleted file mode 100644 index a3f1d971a..000000000 --- a/megalodon/src/misskey/entities/poll.ts +++ /dev/null @@ -1,13 +0,0 @@ -namespace MisskeyEntity { - export type Choice = { - text: string - votes: number - isVoted: boolean - } - - export type Poll = { - multiple: boolean - expiresAt: string - choices: Array - } -} diff --git a/megalodon/src/misskey/entities/reaction.ts b/megalodon/src/misskey/entities/reaction.ts deleted file mode 100644 index 270ca6eab..000000000 --- a/megalodon/src/misskey/entities/reaction.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -namespace MisskeyEntity { - export type Reaction = { - id: string - createdAt: string - user: User - type: string - } -} diff --git a/megalodon/src/misskey/entities/relation.ts b/megalodon/src/misskey/entities/relation.ts deleted file mode 100644 index 07653b486..000000000 --- a/megalodon/src/misskey/entities/relation.ts +++ /dev/null @@ -1,12 +0,0 @@ -namespace MisskeyEntity { - export type Relation = { - id: string - isFollowing: boolean - hasPendingFollowRequestFromYou: boolean - hasPendingFollowRequestToYou: boolean - isFollowed: boolean - isBlocking: boolean - isBlocked: boolean - isMuted: boolean - } -} diff --git a/megalodon/src/misskey/entities/session.ts b/megalodon/src/misskey/entities/session.ts deleted file mode 100644 index 47fe9cf82..000000000 --- a/megalodon/src/misskey/entities/session.ts +++ /dev/null @@ -1,6 +0,0 @@ -namespace MisskeyEntity { - export type Session = { - token: string - url: string - } -} diff --git a/megalodon/src/misskey/entities/stats.ts b/megalodon/src/misskey/entities/stats.ts deleted file mode 100644 index 7f080efda..000000000 --- a/megalodon/src/misskey/entities/stats.ts +++ /dev/null @@ -1,9 +0,0 @@ -namespace MisskeyEntity { - export type Stats = { - notesCount: number - originalNotesCount: number - usersCount: number - originalUsersCount: number - instances: number - } -} diff --git a/megalodon/src/misskey/entities/user.ts b/megalodon/src/misskey/entities/user.ts deleted file mode 100644 index 78745c20d..000000000 --- a/megalodon/src/misskey/entities/user.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -namespace MisskeyEntity { - export type User = { - id: string - name: string - username: string - host: string | null - avatarUrl: string - avatarColor: string - emojis: Array | { [key: string]: string } - } -} diff --git a/megalodon/src/misskey/entities/userDetail.ts b/megalodon/src/misskey/entities/userDetail.ts deleted file mode 100644 index 607d9a511..000000000 --- a/megalodon/src/misskey/entities/userDetail.ts +++ /dev/null @@ -1,32 +0,0 @@ -/// -/// - -namespace MisskeyEntity { - export type UserDetail = { - id: string - name: string - username: string - host: string | null - avatarUrl: string - avatarColor: string - isAdmin: boolean - isModerator: boolean - isBot: boolean - isCat: boolean - emojis: Array | { [key: string]: string } - createdAt: string - bannerUrl: string - bannerColor: string - isLocked: boolean - isSilenced: boolean - isSuspended: boolean - description: string - followersCount: number - followingCount: number - notesCount: number - avatarId: string - bannerId: string - pinnedNoteIds?: Array - pinnedNotes?: Array - } -} diff --git a/megalodon/src/misskey/entities/userkey.ts b/megalodon/src/misskey/entities/userkey.ts deleted file mode 100644 index 5b66e95b8..000000000 --- a/megalodon/src/misskey/entities/userkey.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -namespace MisskeyEntity { - export type UserKey = { - accessToken: string - user: User - } -} diff --git a/megalodon/src/misskey/entity.ts b/megalodon/src/misskey/entity.ts deleted file mode 100644 index 8498517be..000000000 --- a/megalodon/src/misskey/entity.ts +++ /dev/null @@ -1,26 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// - -export default MisskeyEntity diff --git a/megalodon/src/misskey/notification.ts b/megalodon/src/misskey/notification.ts deleted file mode 100644 index 2909762c1..000000000 --- a/megalodon/src/misskey/notification.ts +++ /dev/null @@ -1,16 +0,0 @@ -import MisskeyEntity from './entity' - -namespace MisskeyNotificationType { - export const Follow: MisskeyEntity.NotificationType = 'follow' - export const Mention: MisskeyEntity.NotificationType = 'mention' - export const Reply: MisskeyEntity.NotificationType = 'reply' - export const Renote: MisskeyEntity.NotificationType = 'renote' - export const Quote: MisskeyEntity.NotificationType = 'quote' - export const Reaction: MisskeyEntity.NotificationType = 'reaction' - export const PollVote: MisskeyEntity.NotificationType = 'pollVote' - export const ReceiveFollowRequest: MisskeyEntity.NotificationType = 'receiveFollowRequest' - export const FollowRequestAccepted: MisskeyEntity.NotificationType = 'followRequestAccepted' - export const GroupInvited: MisskeyEntity.NotificationType = 'groupInvited' -} - -export default MisskeyNotificationType diff --git a/megalodon/src/misskey/web_socket.ts b/megalodon/src/misskey/web_socket.ts deleted file mode 100644 index 181fb1c90..000000000 --- a/megalodon/src/misskey/web_socket.ts +++ /dev/null @@ -1,413 +0,0 @@ -import WS from 'ws' -import dayjs, { Dayjs } from 'dayjs' -import { v4 as uuid } from 'uuid' -import { EventEmitter } from 'events' -import { WebSocketInterface } from '../megalodon' -import proxyAgent, { ProxyConfig } from '../proxy_config' -import MisskeyAPI from './api_client' -import { UnknownNotificationTypeError } from '../notification' - -/** - * WebSocket - * Misskey is not support http streaming. It supports websocket instead of streaming. - * So this class connect to Misskey server with WebSocket. - */ -export default class WebSocket extends EventEmitter implements WebSocketInterface { - public url: string - public channel: 'user' | 'localTimeline' | 'hybridTimeline' | 'globalTimeline' | 'conversation' | 'list' - public parser: Parser - public headers: { [key: string]: string } - public proxyConfig: ProxyConfig | false = false - public listId: string | null = null - private _accessToken: string - private _reconnectInterval: number - private _reconnectMaxAttempts: number - private _reconnectCurrentAttempts: number - private _connectionClosed: boolean - private _client: WS | null = null - private _channelID: string - private _pongReceivedTimestamp: Dayjs - private _heartbeatInterval: number = 60000 - private _pongWaiting: boolean = false - - /** - * @param url Full url of websocket: e.g. wss://misskey.io/streaming - * @param channel Channel name is user, localTimeline, hybridTimeline, globalTimeline, conversation or list. - * @param accessToken The access token. - * @param listId This parameter is required when you specify list as channel. - */ - constructor( - url: string, - channel: 'user' | 'localTimeline' | 'hybridTimeline' | 'globalTimeline' | 'conversation' | 'list', - accessToken: string, - listId: string | undefined, - userAgent: string, - proxyConfig: ProxyConfig | false = false - ) { - super() - this.url = url - this.parser = new Parser() - this.channel = channel - this.headers = { - 'User-Agent': userAgent - } - if (listId === undefined) { - this.listId = null - } else { - this.listId = listId - } - this.proxyConfig = proxyConfig - this._accessToken = accessToken - this._reconnectInterval = 10000 - this._reconnectMaxAttempts = Infinity - this._reconnectCurrentAttempts = 0 - this._connectionClosed = false - this._channelID = uuid() - this._pongReceivedTimestamp = dayjs() - } - - /** - * Start websocket connection. - */ - public start() { - this._connectionClosed = false - this._resetRetryParams() - this._startWebSocketConnection() - } - - /** - * Reset connection and start new websocket connection. - */ - private _startWebSocketConnection() { - this._resetConnection() - this._setupParser() - this._client = this._connect() - this._bindSocket(this._client) - } - - /** - * Stop current connection. - */ - public stop() { - this._connectionClosed = true - this._resetConnection() - this._resetRetryParams() - } - - /** - * Clean up current connection, and listeners. - */ - private _resetConnection() { - if (this._client) { - this._client.close(1000) - this._client.removeAllListeners() - this._client = null - } - - if (this.parser) { - this.parser.removeAllListeners() - } - } - - /** - * Resets the parameters used in reconnect. - */ - private _resetRetryParams() { - this._reconnectCurrentAttempts = 0 - } - - /** - * Connect to the endpoint. - */ - private _connect(): WS { - let options: WS.ClientOptions = { - headers: this.headers - } - if (this.proxyConfig) { - options = Object.assign(options, { - agent: proxyAgent(this.proxyConfig) - }) - } - const cli: WS = new WS(`${this.url}?i=${this._accessToken}`, options) - return cli - } - - /** - * Connect specified channels in websocket. - */ - private _channel() { - if (!this._client) { - return - } - switch (this.channel) { - case 'conversation': - this._client.send( - JSON.stringify({ - type: 'connect', - body: { - channel: 'main', - id: this._channelID - } - }) - ) - break - case 'user': - this._client.send( - JSON.stringify({ - type: 'connect', - body: { - channel: 'main', - id: this._channelID - } - }) - ) - this._client.send( - JSON.stringify({ - type: 'connect', - body: { - channel: 'homeTimeline', - id: this._channelID - } - }) - ) - break - case 'list': - this._client.send( - JSON.stringify({ - type: 'connect', - body: { - channel: 'userList', - id: this._channelID, - params: { - listId: this.listId - } - } - }) - ) - break - default: - this._client.send( - JSON.stringify({ - type: 'connect', - body: { - channel: this.channel, - id: this._channelID - } - }) - ) - break - } - } - - /** - * Reconnects to the same endpoint. - */ - - private _reconnect() { - setTimeout(() => { - // Skip reconnect when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L365 - if (this._client && this._client.readyState === WS.CONNECTING) { - return - } - - if (this._reconnectCurrentAttempts < this._reconnectMaxAttempts) { - this._reconnectCurrentAttempts++ - this._clearBinding() - if (this._client) { - // In reconnect, we want to close the connection immediately, - // because recoonect is necessary when some problems occur. - this._client.terminate() - } - // Call connect methods - console.log('Reconnecting') - this._client = this._connect() - this._bindSocket(this._client) - } - }, this._reconnectInterval) - } - - /** - * Clear binding event for websocket client. - */ - private _clearBinding() { - if (this._client) { - this._client.removeAllListeners('close') - this._client.removeAllListeners('pong') - this._client.removeAllListeners('open') - this._client.removeAllListeners('message') - this._client.removeAllListeners('error') - } - } - - /** - * Bind event for web socket client. - * @param client A WebSocket instance. - */ - private _bindSocket(client: WS) { - client.on('close', (code: number, _reason: Buffer) => { - if (code === 1000) { - this.emit('close', {}) - } else { - console.log(`Closed connection with ${code}`) - if (!this._connectionClosed) { - this._reconnect() - } - } - }) - client.on('pong', () => { - this._pongWaiting = false - this.emit('pong', {}) - this._pongReceivedTimestamp = dayjs() - // It is required to anonymous function since get this scope in checkAlive. - setTimeout(() => this._checkAlive(this._pongReceivedTimestamp), this._heartbeatInterval) - }) - client.on('open', () => { - this.emit('connect', {}) - this._channel() - // Call first ping event. - setTimeout(() => { - client.ping('') - }, 10000) - }) - client.on('message', (data: WS.Data, isBinary: boolean) => { - this.parser.parse(data, isBinary, this._channelID) - }) - client.on('error', (err: Error) => { - this.emit('error', err) - }) - } - - /** - * Set up parser when receive message. - */ - private _setupParser() { - this.parser.on('update', (note: MisskeyAPI.Entity.Note) => { - this.emit('update', MisskeyAPI.Converter.note(note)) - }) - this.parser.on('notification', (notification: MisskeyAPI.Entity.Notification) => { - const n = MisskeyAPI.Converter.notification(notification) - if (n instanceof UnknownNotificationTypeError) { - console.warn(`Unknown notification event has received: ${notification}`) - } else { - this.emit('notification', n) - } - }) - this.parser.on('conversation', (note: MisskeyAPI.Entity.Note) => { - this.emit('conversation', MisskeyAPI.Converter.noteToConversation(note)) - }) - this.parser.on('error', (err: Error) => { - this.emit('parser-error', err) - }) - } - - /** - * Call ping and wait to pong. - */ - private _checkAlive(timestamp: Dayjs) { - const now: Dayjs = dayjs() - // Block multiple calling, if multiple pong event occur. - // It the duration is less than interval, through ping. - if (now.diff(timestamp) > this._heartbeatInterval - 1000 && !this._connectionClosed) { - // Skip ping when client is connecting. - // https://github.com/websockets/ws/blob/7.2.1/lib/websocket.js#L289 - if (this._client && this._client.readyState !== WS.CONNECTING) { - this._pongWaiting = true - this._client.ping('') - setTimeout(() => { - if (this._pongWaiting) { - this._pongWaiting = false - this._reconnect() - } - }, 10000) - } - } - } -} - -/** - * Parser - * This class provides parser for websocket message. - */ -export class Parser extends EventEmitter { - /** - * @param message Message body of websocket. - * @param channelID Parse only messages which has same channelID. - */ - public parse(data: WS.Data, isBinary: boolean, channelID: string) { - const message = isBinary ? data : data.toString() - if (typeof message !== 'string') { - this.emit('heartbeat', {}) - return - } - - if (message === '') { - this.emit('heartbeat', {}) - return - } - - let obj: { - type: string - body: { - id: string - type: string - body: any - } - } - let body: { - id: string - type: string - body: any - } - - try { - obj = JSON.parse(message) - if (obj.type !== 'channel') { - return - } - if (!obj.body) { - return - } - body = obj.body - if (body.id !== channelID) { - return - } - } catch (err) { - this.emit('error', new Error(`Error parsing websocket reply: ${message}, error message: ${err}`)) - return - } - - switch (body.type) { - case 'note': - this.emit('update', body.body as MisskeyAPI.Entity.Note) - break - case 'notification': - this.emit('notification', body.body as MisskeyAPI.Entity.Notification) - break - case 'mention': { - const note = body.body as MisskeyAPI.Entity.Note - if (note.visibility === 'specified') { - this.emit('conversation', note) - } - break - } - // When renote and followed event, the same notification will be received. - case 'renote': - case 'followed': - case 'follow': - case 'unfollow': - case 'receiveFollowRequest': - case 'meUpdated': - case 'readAllNotifications': - case 'readAllUnreadSpecifiedNotes': - case 'readAllAntennas': - case 'readAllUnreadMentions': - case 'unreadNotification': - // Ignore these events - break - default: - this.emit('error', new Error(`Unknown event has received: ${JSON.stringify(body)}`)) - break - } - } -} From a9889ab531508b835fe9c42e91f2d3279d872fb0 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 22 Sep 2023 01:19:20 +0900 Subject: [PATCH 3/4] Remove Misskey tests --- megalodon/test/integration/detector.spec.ts | 8 - megalodon/test/integration/misskey.spec.ts | 218 ---------- .../test/unit/misskey/api_client.spec.ts | 377 ------------------ 3 files changed, 603 deletions(-) delete mode 100644 megalodon/test/integration/misskey.spec.ts delete mode 100644 megalodon/test/unit/misskey/api_client.spec.ts diff --git a/megalodon/test/integration/detector.spec.ts b/megalodon/test/integration/detector.spec.ts index 84559a69a..551c84f07 100644 --- a/megalodon/test/integration/detector.spec.ts +++ b/megalodon/test/integration/detector.spec.ts @@ -17,14 +17,6 @@ describe('detector', () => { }) }) - describe('misskey', () => { - const url = 'https://misskey.io' - it('should be misskey', async () => { - const misskey = await detector(url) - expect(misskey).toEqual('misskey') - }) - }) - describe('fedibird', () => { const url = 'https://fedibird.com' it('should be mastodon', async () => { diff --git a/megalodon/test/integration/misskey.spec.ts b/megalodon/test/integration/misskey.spec.ts deleted file mode 100644 index ed3b9a40f..000000000 --- a/megalodon/test/integration/misskey.spec.ts +++ /dev/null @@ -1,218 +0,0 @@ -import MisskeyEntity from '@/misskey/entity' -import MisskeyNotificationType from '@/misskey/notification' -import Misskey from '@/misskey' -import MegalodonNotificationType from '@/notification' -import axios, { AxiosHeaders, AxiosResponse, InternalAxiosRequestConfig } from 'axios' - -jest.mock('axios') - -const user: MisskeyEntity.User = { - id: '1', - name: 'test_user', - username: 'TestUser', - host: 'misskey.io', - avatarUrl: 'https://example.com/icon.png', - avatarColor: '#000000', - emojis: [] -} - -const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: 'hogehoge', - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: {}, - reactionEmojis: {}, - emojis: [], - fileIds: [], - files: [], - replyId: null, - renoteId: null -} - -const follow: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Follow -} - -const mention: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Mention, - note: note -} - -const reply: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Reply, - note: note -} - -const renote: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Renote, - note: note -} - -const quote: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Quote, - note: note -} - -const reaction: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.Reaction, - note: note, - reaction: '♥' -} - -const pollVote: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.PollVote, - note: note -} - -const receiveFollowRequest: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.ReceiveFollowRequest -} - -const followRequestAccepted: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.FollowRequestAccepted -} - -const groupInvited: MisskeyEntity.Notification = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: user.id, - user: user, - type: MisskeyNotificationType.GroupInvited -} - -;(axios.CancelToken.source as any).mockImplementation(() => { - return { - token: { - throwIfRequested: () => {}, - promise: { - then: () => {}, - catch: () => {} - } - } - } -}) - -describe('getNotifications', () => { - const client = new Misskey('http://localhost', 'sample token') - const cases: Array<{ event: MisskeyEntity.Notification; expected: Entity.NotificationType; title: string }> = [ - { - event: follow, - expected: MegalodonNotificationType.Follow, - title: 'follow' - }, - { - event: mention, - expected: MegalodonNotificationType.Mention, - title: 'mention' - }, - { - event: reply, - expected: MegalodonNotificationType.Mention, - title: 'reply' - }, - { - event: renote, - expected: MegalodonNotificationType.Reblog, - title: 'renote' - }, - { - event: quote, - expected: MegalodonNotificationType.Reblog, - title: 'quote' - }, - { - event: reaction, - expected: MegalodonNotificationType.EmojiReaction, - title: 'reaction' - }, - { - event: pollVote, - expected: MegalodonNotificationType.PollVote, - title: 'pollVote' - }, - { - event: receiveFollowRequest, - expected: MegalodonNotificationType.FollowRequest, - title: 'receiveFollowRequest' - }, - { - event: followRequestAccepted, - expected: MegalodonNotificationType.Follow, - title: 'followRequestAccepted' - } - ] - cases.forEach(c => { - it(`should be ${c.title} event`, async () => { - const config: InternalAxiosRequestConfig = { - headers: new AxiosHeaders() - } - const mockResponse: AxiosResponse> = { - data: [c.event], - status: 200, - statusText: '200OK', - headers: {}, - config: config - } - ;(axios.post as any).mockResolvedValue(mockResponse) - const res = await client.getNotifications() - expect(res.data[0].type).toEqual(c.expected) - }) - }) - it('groupInvited event should be ignored', async () => { - const config: InternalAxiosRequestConfig = { - headers: new AxiosHeaders() - } - const mockResponse: AxiosResponse> = { - data: [groupInvited], - status: 200, - statusText: '200OK', - headers: {}, - config: config - } - ;(axios.post as any).mockResolvedValue(mockResponse) - const res = await client.getNotifications() - expect(res.data).toEqual([]) - }) -}) diff --git a/megalodon/test/unit/misskey/api_client.spec.ts b/megalodon/test/unit/misskey/api_client.spec.ts deleted file mode 100644 index 38039385c..000000000 --- a/megalodon/test/unit/misskey/api_client.spec.ts +++ /dev/null @@ -1,377 +0,0 @@ -import MisskeyAPI from '@/misskey/api_client' -import MegalodonEntity from '@/entity' -import MisskeyEntity from '@/misskey/entity' -import MegalodonNotificationType from '@/notification' -import MisskeyNotificationType from '@/misskey/notification' - -const user: MisskeyEntity.User = { - id: '1', - name: 'test_user', - username: 'TestUser', - host: 'misskey.io', - avatarUrl: 'https://example.com/icon.png', - avatarColor: '#000000', - emojis: [] -} - -describe('api_client', () => { - describe('notification', () => { - describe('encode', () => { - it('megalodon notification type should be encoded to misskey notification type', () => { - const cases: Array<{ src: MegalodonEntity.NotificationType; dist: MisskeyEntity.NotificationType }> = [ - { - src: MegalodonNotificationType.Follow, - dist: MisskeyNotificationType.Follow - }, - { - src: MegalodonNotificationType.Mention, - dist: MisskeyNotificationType.Reply - }, - { - src: MegalodonNotificationType.Favourite, - dist: MisskeyNotificationType.Reaction - }, - { - src: MegalodonNotificationType.EmojiReaction, - dist: MisskeyNotificationType.Reaction - }, - { - src: MegalodonNotificationType.Reblog, - dist: MisskeyNotificationType.Renote - }, - { - src: MegalodonNotificationType.PollVote, - dist: MisskeyNotificationType.PollVote - }, - { - src: MegalodonNotificationType.FollowRequest, - dist: MisskeyNotificationType.ReceiveFollowRequest - } - ] - cases.forEach(c => { - expect(MisskeyAPI.Converter.encodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - describe('decode', () => { - it('misskey notification type should be decoded to megalodon notification type', () => { - const cases: Array<{ src: MisskeyEntity.NotificationType; dist: MegalodonEntity.NotificationType }> = [ - { - src: MisskeyNotificationType.Follow, - dist: MegalodonNotificationType.Follow - }, - { - src: MisskeyNotificationType.Mention, - dist: MegalodonNotificationType.Mention - }, - { - src: MisskeyNotificationType.Reply, - dist: MegalodonNotificationType.Mention - }, - { - src: MisskeyNotificationType.Renote, - dist: MegalodonNotificationType.Reblog - }, - { - src: MisskeyNotificationType.Quote, - dist: MegalodonNotificationType.Reblog - }, - { - src: MisskeyNotificationType.Reaction, - dist: MegalodonNotificationType.EmojiReaction - }, - { - src: MisskeyNotificationType.PollVote, - dist: MegalodonNotificationType.PollVote - }, - { - src: MisskeyNotificationType.ReceiveFollowRequest, - dist: MegalodonNotificationType.FollowRequest - }, - { - src: MisskeyNotificationType.FollowRequestAccepted, - dist: MegalodonNotificationType.Follow - } - ] - cases.forEach(c => { - expect(MisskeyAPI.Converter.decodeNotificationType(c.src)).toEqual(c.dist) - }) - }) - }) - }) - describe('reactions', () => { - it('should be mapped', () => { - const misskeyReactions = [ - { - id: '1', - createdAt: '2020-04-21T13:04:13.968Z', - user: { - id: '81u70uwsja', - name: 'h3poteto', - username: 'h3poteto', - host: null, - avatarUrl: 'https://s3.arkjp.net/misskey/thumbnail-63807d97-20ca-40ba-9493-179aa48065c1.png', - avatarColor: 'rgb(146,189,195)', - emojis: [] - }, - type: '❤' - }, - { - id: '2', - createdAt: '2020-04-21T13:04:13.968Z', - user: { - id: '81u70uwsja', - name: 'h3poteto', - username: 'h3poteto', - host: null, - avatarUrl: 'https://s3.arkjp.net/misskey/thumbnail-63807d97-20ca-40ba-9493-179aa48065c1.png', - avatarColor: 'rgb(146,189,195)', - emojis: [] - }, - type: '❤' - }, - { - id: '3', - createdAt: '2020-04-21T13:04:13.968Z', - user: { - id: '81u70uwsja', - name: 'h3poteto', - username: 'h3poteto', - host: null, - avatarUrl: 'https://s3.arkjp.net/misskey/thumbnail-63807d97-20ca-40ba-9493-179aa48065c1.png', - avatarColor: 'rgb(146,189,195)', - emojis: [] - }, - type: '☺' - }, - { - id: '4', - createdAt: '2020-04-21T13:04:13.968Z', - user: { - id: '81u70uwsja', - name: 'h3poteto', - username: 'h3poteto', - host: null, - avatarUrl: 'https://s3.arkjp.net/misskey/thumbnail-63807d97-20ca-40ba-9493-179aa48065c1.png', - avatarColor: 'rgb(146,189,195)', - emojis: [] - }, - type: '❤' - } - ] - - const reactions = MisskeyAPI.Converter.reactions(misskeyReactions) - expect(reactions).toEqual([ - { - count: 3, - me: false, - name: '❤' - }, - { - count: 1, - me: false, - name: '☺' - } - ]) - }) - }) - - describe('status', () => { - describe('plain content', () => { - it('should be exported plain content and html content', () => { - const plainContent = 'hoge\nfuga\nfuga' - const content = 'hoge
fuga
fuga' - const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: plainContent, - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: {}, - reactionEmojis: {}, - emojis: [], - fileIds: [], - files: [], - replyId: null, - renoteId: null - } - const megalodonStatus = MisskeyAPI.Converter.note(note) - expect(megalodonStatus.plain_content).toEqual(plainContent) - expect(megalodonStatus.content).toEqual(content) - }) - it('html tags should be escaped', () => { - const plainContent = '

hoge\nfuga\nfuga

' - const content = '<p>hoge
fuga
fuga<p>' - const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: plainContent, - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: {}, - reactionEmojis: {}, - emojis: [], - fileIds: [], - files: [], - replyId: null, - renoteId: null - } - const megalodonStatus = MisskeyAPI.Converter.note(note) - expect(megalodonStatus.plain_content).toEqual(plainContent) - expect(megalodonStatus.content).toEqual(content) - }) - }) - describe('emoji reaction', () => { - it('reactionEmojis should be parsed', () => { - const plainContent = 'hoge\nfuga\nfuga' - const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: plainContent, - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: { - ':example1@.:': 1, - ':example2@example.com:': 2 - }, - reactionEmojis: { - 'example2@example.com': 'https://example.com/emoji.png' - }, - emojis: [], - fileIds: [], - files: [], - replyId: null, - renoteId: null - } - const megalodonStatus = MisskeyAPI.Converter.note(note) - expect(megalodonStatus.emojis).toEqual([ - { - shortcode: 'example2@example.com', - static_url: 'https://example.com/emoji.png', - url: 'https://example.com/emoji.png', - visible_in_picker: true, - category: '' - } - ]) - expect(megalodonStatus.emoji_reactions).toEqual([ - { - count: 1, - me: false, - name: ':example1@.:' - }, - { - count: 2, - me: false, - name: ':example2@example.com:' - } - ]) - }) - }) - describe('emoji', () => { - it('emojis in array format should be parsed', () => { - const plainContent = 'hoge\nfuga\nfuga' - const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: plainContent, - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: {}, - reactionEmojis: {}, - emojis: [ - { - aliases: [], - name: ':example1:', - url: 'https://example.com/emoji1.png', - category: '', - }, - { - aliases: [], - name: ':example2:', - url: 'https://example.com/emoji2.png', - category: '', - }, - ], - fileIds: [], - files: [], - replyId: null, - renoteId: null - } - const megalodonStatus = MisskeyAPI.Converter.note(note) - expect(megalodonStatus.emojis).toEqual([ - { - shortcode: ':example1:', - static_url: 'https://example.com/emoji1.png', - url: 'https://example.com/emoji1.png', - visible_in_picker: true, - category: '' - }, - { - shortcode: ':example2:', - static_url: 'https://example.com/emoji2.png', - url: 'https://example.com/emoji2.png', - visible_in_picker: true, - category: '' - } - ]) - }) - it('emojis in object format should be parsed', () => { - const plainContent = 'hoge\nfuga\nfuga' - const note: MisskeyEntity.Note = { - id: '1', - createdAt: '2021-02-01T01:49:29', - userId: '1', - user: user, - text: plainContent, - cw: null, - visibility: 'public', - renoteCount: 0, - repliesCount: 0, - reactions: {}, - reactionEmojis: {}, - emojis: { - ':example1:': 'https://example.com/emoji1.png', - ':example2:': 'https://example.com/emoji2.png', - }, - fileIds: [], - files: [], - replyId: null, - renoteId: null - } - const megalodonStatus = MisskeyAPI.Converter.note(note) - expect(megalodonStatus.emojis).toEqual([ - { - shortcode: ':example1:', - static_url: 'https://example.com/emoji1.png', - url: 'https://example.com/emoji1.png', - visible_in_picker: true, - category: '' - }, - { - shortcode: ':example2:', - static_url: 'https://example.com/emoji2.png', - url: 'https://example.com/emoji2.png', - visible_in_picker: true, - category: '' - } - ]) - }) - }) - }) -}) From ff3cd72dfcf6418d467fc08368577e7eb10f5794 Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Fri, 22 Sep 2023 01:20:50 +0900 Subject: [PATCH 4/4] Update README for dropping misskey --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 41f45acd9..01b35b5dc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![NPM](https://img.shields.io/npm/l/megalodon)](/LICENSE.txt) A Fediverse API Client library for node.js and browser. It provides REST API and streaming methods. -By using this library, you can take Mastodon, Pleroma, Friendica, and Misskey with the same interface. +By using this library, you can take Mastodon, Pleroma, Friendica, and Firefish with the same interface. The Rust version is [megalodon-rs](https://github.com/h3poteto/megalodon-rs). @@ -14,7 +14,7 @@ The Rust version is [megalodon-rs](https://github.com/h3poteto/megalodon-rs). - [x] Mastodon - [x] Pleroma - [x] Friendica -- [x] Misskey +- [x] Firefish - [x] Akkoma (Unofficial) - [x] Widlebeest (Unofficial) @@ -103,7 +103,6 @@ client.uploadMedia(image) ``` ### WebSocket streaming -Mastodon, Pleroma and Misskey provide WebSocket for streaming. ```typescript import generator, { Entity, WebSocketInterface } from 'megalodon' @@ -188,13 +187,13 @@ client.fetchAccessToken(clientId, clientSecret, code) ``` ### Detect each SNS -You have to provide SNS name `mastodon`, `pleroma` or `misskey` to `generator` function. +You have to provide SNS name (e.g. `mastodon`, `pleroma`) to `generator` function. But when you only know the URL and not the SNS, `detector` function can detect the SNS. ```typescript import { detector } from 'megalodon' -const URL = 'https://misskey.io' +const URL = 'https://mastodon.social' const sns = await detector(URL) console.log(sns)