2024-08-15 21:12:34 +02:00
|
|
|
import {
|
2024-08-15 22:37:15 +02:00
|
|
|
MatrixClient,
|
|
|
|
SimpleFsStorageProvider,
|
2024-08-15 21:12:34 +02:00
|
|
|
AutojoinUpgradedRoomsMixin,
|
2024-08-15 22:37:15 +02:00
|
|
|
RichRepliesPreprocessor,
|
2024-08-15 21:12:34 +02:00
|
|
|
} from "matrix-bot-sdk";
|
|
|
|
|
2024-08-15 21:57:13 +02:00
|
|
|
import axios from "axios";
|
|
|
|
|
|
|
|
import config from "./config.json" assert {type: "json"};
|
|
|
|
|
|
|
|
const homeserverUrl = config.homeserver;
|
2024-08-15 22:37:15 +02:00
|
|
|
const token = config.token;
|
2024-08-15 21:57:13 +02:00
|
|
|
const prefix = config.prefix;
|
2024-08-15 22:37:15 +02:00
|
|
|
const rooms = config.rooms;
|
2024-08-16 00:31:24 +02:00
|
|
|
const doorbellWebhook = config.doorbellWebhook;
|
|
|
|
|
|
|
|
function configNotFound(name) {
|
|
|
|
throw new Error(`ERROR: Config option "${name}" not found`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!homeserverUrl) configNotFound("homeserver");
|
|
|
|
if (!token) configNotFound("token");
|
|
|
|
if (!prefix) configNotFound("prefix");
|
|
|
|
if (!rooms) configNotFound("rooms");
|
|
|
|
if (!doorbellWebhook) configNotFound("doorbellWebhook");
|
2024-08-15 22:37:15 +02:00
|
|
|
|
|
|
|
// We'll want to make sure the bot doesn't have to do an initial sync every
|
|
|
|
// time it restarts, so we need to prepare a storage provider. Here we use
|
|
|
|
// a simple JSON database.
|
|
|
|
const storage = new SimpleFsStorageProvider("bot-storage.json");
|
2024-08-15 21:57:13 +02:00
|
|
|
|
|
|
|
// Now we can create the client and set it up to automatically join rooms.
|
2024-08-15 22:37:15 +02:00
|
|
|
const client = await new MatrixClient(homeserverUrl, token, storage);
|
2024-08-15 21:57:13 +02:00
|
|
|
AutojoinUpgradedRoomsMixin.setupOnClient(client);
|
|
|
|
client.addPreprocessor(new RichRepliesPreprocessor(false));
|
|
|
|
|
|
|
|
// We also want to make sure we can receive events - this is where we will
|
|
|
|
// handle our command.
|
|
|
|
client.on("room.message", handleCommand);
|
2024-08-15 23:14:31 +02:00
|
|
|
client.on("room.invite", (roomId) => {
|
2024-08-15 22:37:15 +02:00
|
|
|
if (rooms.includes(roomId)) {
|
|
|
|
return client.joinRoom(roomId);
|
|
|
|
}
|
2024-08-15 21:57:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
// Now that the client is all set up and the event handler is registered, start the
|
|
|
|
// client up. This will start it syncing.
|
|
|
|
client.start().then(() => console.log("Client started!"));
|
|
|
|
|
2024-08-15 23:14:31 +02:00
|
|
|
// This is our event handler for dealing with commands.
|
2024-08-15 21:57:13 +02:00
|
|
|
async function handleCommand(roomId, event) {
|
|
|
|
// Don't handle events that don't have contents (they were probably redacted)
|
|
|
|
if (!event["content"]) return;
|
|
|
|
|
|
|
|
// Don't handle non-text events
|
|
|
|
if (event["content"]["msgtype"] !== "m.text") return;
|
|
|
|
|
|
|
|
// We never send `m.text` messages so this isn't required, however this is
|
|
|
|
// how you would filter out events sent by the bot itself.
|
|
|
|
if (event["sender"] === await client.getUserId()) return;
|
|
|
|
// Make sure that the event looks like a command we're expecting
|
|
|
|
|
2024-08-15 22:37:15 +02:00
|
|
|
// If not in any authorized rooms, ignore
|
|
|
|
if (!rooms.includes(roomId)) return;
|
|
|
|
|
2024-08-15 23:14:31 +02:00
|
|
|
// Check that the message starts with the prefix, and get the prefix-less message
|
|
|
|
const rawText = event["content"]["body"];
|
|
|
|
if (!rawText || !rawText.startsWith(prefix)) return;
|
|
|
|
const text = rawText.substring(prefix.length);
|
2024-08-15 21:57:13 +02:00
|
|
|
|
2024-08-15 23:16:54 +02:00
|
|
|
if (["doorbell", "open", "ring", "knock", "ding", "dong", "dingdong"].includes(text)) {
|
2024-08-16 00:31:24 +02:00
|
|
|
|
|
|
|
fetch(doorbellWebhook, { method: 'POST' }).then(response => {
|
|
|
|
if (response.ok) {
|
|
|
|
console.log("DING DONG!");
|
|
|
|
} else {
|
|
|
|
console.log("No ding dong :(");
|
|
|
|
console.log(response);
|
|
|
|
}
|
|
|
|
});
|
2024-08-15 23:16:54 +02:00
|
|
|
}
|
2024-08-15 21:57:13 +02:00
|
|
|
|
|
|
|
var tags = [];
|
|
|
|
|
|
|
|
var re = /`([a-z1-9:. æøå]*)`/g;
|
|
|
|
do {
|
|
|
|
var m = re.exec(text);
|
|
|
|
if (m) {
|
|
|
|
tags.push(m[1]);
|
|
|
|
}
|
|
|
|
} while (m);
|
|
|
|
|
|
|
|
if (tags == false) return;
|
|
|
|
|
|
|
|
var encoded_tags = encodeURI(JSON.stringify(tags));
|
|
|
|
|
|
|
|
var file_ids = (await axios.get(hydrusURI + "/get_files/search_files?system_inbox=true&tags=" + encoded_tags, {headers: {'Hydrus-Client-API-Access-Key': hydrusToken}})).data.file_ids;
|
|
|
|
|
|
|
|
if (file_ids == false) return;
|
|
|
|
|
|
|
|
console.log(file_ids);
|
|
|
|
|
|
|
|
var random_id = [file_ids[Math.floor(Math.random() * file_ids.length)]];
|
|
|
|
|
|
|
|
var encoded_id = encodeURI(JSON.stringify(random_id));
|
|
|
|
|
|
|
|
var metadata = (await axios.get(hydrusURI + "/get_files/file_metadata?&file_ids=" + encoded_id, {headers: {'Hydrus-Client-API-Access-Key': hydrusToken}})).data.metadata[0];
|
|
|
|
console.log(metadata);
|
|
|
|
|
|
|
|
var hash = metadata.hash;
|
|
|
|
var width = metadata.width;
|
|
|
|
var height = metadata.height;
|
|
|
|
var mime = metadata.mime;
|
|
|
|
var ext = metadata.ext;
|
|
|
|
var size = metadata.size;
|
|
|
|
|
|
|
|
var mxc = "mxc://" + fake_hs + "/" + prefix + hash;
|
|
|
|
|
|
|
|
var event = {
|
|
|
|
"body": hash + ext,
|
|
|
|
"info": {
|
|
|
|
"h": height,
|
|
|
|
"w": width,
|
|
|
|
"mimetype": mime,
|
|
|
|
"size": size,
|
|
|
|
},
|
|
|
|
"msgtype": "m.image",
|
|
|
|
"url": mxc
|
|
|
|
};
|
|
|
|
|
|
|
|
client.sendMessage(roomId, event);
|
|
|
|
}
|