initial work
This commit is contained in:
commit
51539a25d2
5 changed files with 259 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
node_modules
|
||||
.env.secret
|
||||
*.d.ts
|
||||
*.js
|
||||
*.tsbuildinfo
|
||||
image_cache
|
113
index.ts
Normal file
113
index.ts
Normal file
|
@ -0,0 +1,113 @@
|
|||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import notifier from 'node-notifier';
|
||||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||
import { WebSocket } from 'ws';
|
||||
|
||||
const INSTANCE = process.env.FK_INSTANCE;
|
||||
const TOKEN = process.env.FK_TOKEN;
|
||||
|
||||
const image_cache = path.resolve('image_cache');
|
||||
await fs.mkdir(image_cache, { recursive: true });
|
||||
|
||||
const iconPath = path.join(image_cache, 'instance.jpg');
|
||||
{
|
||||
const resp = await fetch(`https://${INSTANCE}/api/meta`, { method: 'POST', headers: { authorization: `bearer ${TOKEN}` } });
|
||||
const meta = await resp.json();
|
||||
const iconResp = await fetch(meta.iconUrl);
|
||||
const iconBuf = await iconResp.blob();
|
||||
await fs.writeFile(iconPath, iconBuf.stream());
|
||||
}
|
||||
|
||||
const socket = new ReconnectingWebSocket(`wss://${INSTANCE}/streaming?i=${TOKEN}`, undefined, { WebSocket });
|
||||
socket.addEventListener('open', ({ type }) => console.log({ type }));
|
||||
socket.addEventListener('close', ({ code, reason, wasClean, type }) => console.log({ code, reason, wasClean, type }));
|
||||
socket.addEventListener('error', ({ error, message, type }) => console.log({ error, message, type }));
|
||||
|
||||
socket.addEventListener('open', (ev) => {
|
||||
socket.send(JSON.stringify({ type: "connect", body: { channel: "main", id: "1" } }))
|
||||
});
|
||||
socket.addEventListener('message', ({ data }) => {
|
||||
const payload = JSON.parse(data);
|
||||
if (payload.type === 'channel' && payload.body.type === 'notification') {
|
||||
const notification = payload.body.body;
|
||||
const user = notification.user;
|
||||
const note = notification.note;
|
||||
const userName = user.host !== null ? `${user.username}@${user.host}` : user.username;
|
||||
let title: string;
|
||||
let body = 'note' in notification ? (note.cw != null ? note.cw : (note.text || '')) : undefined;
|
||||
switch (notification.type) {
|
||||
case 'pollEnded':
|
||||
title = `${userName}'s poll has ended`;
|
||||
break;
|
||||
case 'follow':
|
||||
title = `follow from ${userName}`;
|
||||
break;
|
||||
case 'followRequestAccepted':
|
||||
title = `accept from ${userName}`;
|
||||
break;
|
||||
case 'mention':
|
||||
title = `mention from ${userName}`;
|
||||
break;
|
||||
case 'pollVote':
|
||||
title = `vote from ${userName}`;
|
||||
break;
|
||||
case 'quote':
|
||||
title = `quote from ${userName}`;
|
||||
break;
|
||||
case 'reaction':
|
||||
{
|
||||
let reaction: string = notification.reaction;
|
||||
reaction = reaction.split('@')[0];
|
||||
if (reaction.startsWith(':'))
|
||||
reaction = reaction.slice(1);
|
||||
title = `${reaction} from ${userName}`;
|
||||
}
|
||||
break;
|
||||
case 'receiveFollowRequest':
|
||||
title = `follow req from ${userName}`;
|
||||
break;
|
||||
case 'renote':
|
||||
title = `renote from ${userName}`;
|
||||
break;
|
||||
case 'reply':
|
||||
title = `reply from ${userName}`;
|
||||
break;
|
||||
case 'groupInvited':
|
||||
title = `group invite from ${userName}`;
|
||||
break;
|
||||
default:
|
||||
console.log({ type: notification.type });
|
||||
return;
|
||||
}
|
||||
|
||||
const avatarUrl = new URL(user.avatarUrl);
|
||||
const avatarServerPath = avatarUrl.pathname.split('/');
|
||||
const avatarStem = avatarServerPath[avatarServerPath.length - 1];
|
||||
const avatarFilename = `${avatarStem}.webp`;
|
||||
const avatarPath = path.join(image_cache, avatarFilename);
|
||||
(async () => {
|
||||
try {
|
||||
await fs.access(avatarPath);
|
||||
} catch {
|
||||
const resp = await fetch(avatarUrl);
|
||||
if (!resp.ok) {
|
||||
throw resp;
|
||||
}
|
||||
const buf = await resp.blob();
|
||||
await fs.writeFile(avatarPath, buf.stream());
|
||||
}
|
||||
|
||||
// console.log(user, userName, title, body);
|
||||
notifier.notify({
|
||||
title,
|
||||
message: body,
|
||||
icon: iconPath,
|
||||
contentImage: avatarPath,
|
||||
});
|
||||
})()
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise(() => { });
|
21
package.json
Normal file
21
package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "fk-macos-notif",
|
||||
"version": "1.0.0",
|
||||
"main": "index.ts",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"prestart": "tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-notifier": "^10.0.1",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"typescript": "^4.8.3",
|
||||
"ws": "^8.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node-notifier": "^8.0.2",
|
||||
"@types/ws": "^8.5.3"
|
||||
}
|
||||
}
|
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"composite": true,
|
||||
"noEmitOnError": false
|
||||
}
|
||||
}
|
107
yarn.lock
Normal file
107
yarn.lock
Normal file
|
@ -0,0 +1,107 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node-notifier@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-notifier/-/node-notifier-8.0.2.tgz#77c5de29c6e8adb915222b01864128cc3e78d553"
|
||||
integrity sha512-5v0PhPv0AManpxT7W25Zipmj/Lxp1WqfkcpZHyqSloB+gGoAHRBuzhrCelFKrPvNF5ki3gAcO4kxaGO2/21u8g==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*":
|
||||
version "18.7.21"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.21.tgz#63ee6688070e456325b6748dc492a7b948593871"
|
||||
integrity sha512-rLFzK5bhM0YPyCoTC8bolBjMk7bwnZ8qeZUBslBfjZQou2ssJdWslx9CZ8DGM+Dx7QXQiiTVZ/6QO6kwtHkZCA==
|
||||
|
||||
"@types/ws@^8.5.3":
|
||||
version "8.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"
|
||||
integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
growly@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||
integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==
|
||||
|
||||
is-docker@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
|
||||
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
||||
|
||||
is-wsl@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
|
||||
dependencies:
|
||||
is-docker "^2.0.0"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
node-notifier@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-10.0.1.tgz#0e82014a15a8456c4cfcdb25858750399ae5f1c7"
|
||||
integrity sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==
|
||||
dependencies:
|
||||
growly "^1.3.0"
|
||||
is-wsl "^2.2.0"
|
||||
semver "^7.3.5"
|
||||
shellwords "^0.1.1"
|
||||
uuid "^8.3.2"
|
||||
which "^2.0.2"
|
||||
|
||||
reconnecting-websocket@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
|
||||
integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
|
||||
|
||||
semver@^7.3.5:
|
||||
version "7.3.7"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
|
||||
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
shellwords@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
||||
|
||||
typescript@^4.8.3:
|
||||
version "4.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88"
|
||||
integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==
|
||||
|
||||
uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
which@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
ws@^8.9.0:
|
||||
version "8.9.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e"
|
||||
integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
Loading…
Reference in a new issue