Skip to content

Commit

Permalink
feat(mastodon): implement mastodon watcher
Browse files Browse the repository at this point in the history
  • Loading branch information
async3619 committed Jul 3, 2023
1 parent 1aa7732 commit dd0c7e3
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 148 deletions.
21 changes: 21 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,27 @@
"type"
],
"additionalProperties": false
},
"mastodon": {
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "mastodon"
},
"url": {
"type": "string"
},
"accessToken": {
"type": "string"
}
},
"required": [
"accessToken",
"type",
"url"
],
"additionalProperties": false
}
},
"additionalProperties": false
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"scripts": {
"build": "tsc --project ./tsconfig.build.json && tsc-alias -p ./tsconfig.build.json",
"dev": "node --watch -r ts-node/register -r dotenv/config -r tsconfig-paths/register ./src/index.ts",
"dev": "node -r ts-node/register -r dotenv/config -r tsconfig-paths/register ./src/index.ts",
"watch": "node --watch -r ts-node/register -r dotenv/config -r tsconfig-paths/register ./src/index.ts",
"semantic-release": "semantic-release",
"lint": "eslint \"src/**/*.ts\"",
"prepublishOnly": "npm run build",
Expand Down Expand Up @@ -89,11 +90,11 @@
"graphql": "^16.6.0",
"graphql-tag": "^2.12.6",
"lodash": "^4.17.21",
"masto": "^5.11.3",
"node-cron": "^3.0.2",
"node-fetch": "^2.6.7",
"pluralize": "^8.0.0",
"pretty-ms": "^7.0.1",
"puppeteer": "^19.3.0",
"reflect-metadata": "^0.1.13",
"set-cookie-parser": "^2.5.1",
"sqlite3": "^5.1.2",
Expand Down
6 changes: 4 additions & 2 deletions src/watchers/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { BaseWatcher, BaseWatcherOptions } from "@watchers/base";
import { TwitterWatcher, TwitterWatcherOptions } from "@watchers/twitter";
import { GitHubWatcher, GitHubWatcherOptions } from "@watchers/github";
import { MastodonWatcher, MastodonWatcherOptions } from "@watchers/mastodon";

import { TypeMap } from "@utils/types";

export type WatcherClasses = TwitterWatcher | GitHubWatcher;
export type WatcherClasses = TwitterWatcher | GitHubWatcher | MastodonWatcher;
export type WatcherTypes = Lowercase<WatcherClasses["name"]>;

export type WatcherOptions = TwitterWatcherOptions | GitHubWatcherOptions;
export type WatcherOptions = TwitterWatcherOptions | GitHubWatcherOptions | MastodonWatcherOptions;
export type WatcherOptionMap = TypeMap<WatcherOptions>;

export type WatcherMap = {
Expand All @@ -23,6 +24,7 @@ export type WatcherPair = [WatcherTypes, BaseWatcher<string>];
const AVAILABLE_WATCHERS: Readonly<WatcherFactoryMap> = {
twitter: options => new TwitterWatcher(options),
github: options => new GitHubWatcher(options),
mastodon: options => new MastodonWatcher(options),
};

export const createWatcher = (options: BaseWatcherOptions): BaseWatcher<string> => {
Expand Down
54 changes: 54 additions & 0 deletions src/watchers/mastodon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as masto from "masto";

import { BaseWatcher, BaseWatcherOptions, PartialUser } from "@watchers/base";

export interface MastodonWatcherOptions extends BaseWatcherOptions<MastodonWatcher> {
url: string;
accessToken: string;
}

export class MastodonWatcher extends BaseWatcher<"Mastodon"> {
private client: masto.mastodon.Client | null = null;
private account: masto.mastodon.v1.Account | null = null;

constructor(private readonly options: MastodonWatcherOptions) {
super("Mastodon");
}

public async initialize(): Promise<void> {
this.client = await masto.login({
url: this.options.url,
accessToken: this.options.accessToken,
});

this.account = await this.client.v1.accounts.lookup({
acct: "@[email protected]",
});

return Promise.resolve(undefined);
}

protected async getFollowers(): Promise<PartialUser[]> {
if (!this.client || !this.account) {
throw new Error("Mastodon watcher has not initialized");
}

const { id, followersCount } = this.account;
const result: PartialUser[] = [];
for await (const followers of this.client.v1.accounts.listFollowers(id, { limit: 80 })) {
const partialUsers = followers.map(follower => ({
profileUrl: follower.url,
uniqueId: follower.acct,
displayName: follower.displayName,
userId: follower.id,
}));

result.push(...partialUsers);
if (result.length >= followersCount) {
break;
}
}

return result;
}
}
Loading

0 comments on commit dd0c7e3

Please sign in to comment.