matrix-searxng/index.js

248 lines
8.9 KiB
JavaScript
Raw Normal View History

2023-02-11 22:27:52 -05:00
function Searxng(matrixClient) {
this.matrixClient = matrixClient;
this.uploadMatrixClient = matrixClient;
this.blacklistedImgRooms = [];
this.blacklistedUimgRooms = [];
this.cooldownImmuneUsers = [];
this.roomCooldowns = new Map();
this.searxngInstance = "";
2023-02-11 22:49:50 -05:00
this.searxngParameters = "enabled_engines=duckduckgo images__images,google images__images,bing images__images&disabled_engines=flickr__images,nyaa__images,qwant images__images,artic__images,deviantart__images,library of congress__images,unsplash__images,openverse__images"
2023-02-11 22:27:52 -05:00
}
Searxng.prototype.setUploadMatrixClient = function(uploadMatrixClient){ this.uploadMatrixClient = uploadMatrixClient; };
Searxng.prototype.setBlacklistedImgRooms = function(blacklistedImgRooms){ this.blacklistedImgRooms = blacklistedImgRooms; };
Searxng.prototype.setBlacklistedUimgRooms = function(blacklistedUimgRooms){ this.blacklistedUimgRooms = blacklistedUimgRooms; };
Searxng.prototype.setCooldownImmuneUsers = function(cooldownImmuneUsers){ this.cooldownImmuneUsers = cooldownImmuneUsers; };
Searxng.prototype.setRoomCooldowns = function(roomCooldowns){ this.roomCooldowns = roomCooldowns; };
Searxng.prototype.setSearxngInstance = function(searxngInstance){ this.searxngInstance = searxngInstance; };
Searxng.prototype.setSearxngParameters = function(searxngParameters){ this.searxngParameters = searxngParameters; };
const axios = require('axios');
const request = require('request');
const lastCooldownTimes = new Map();
const lastWarningTimes = new Map();
const imageSearchCmd = "!img"
const unsafeImageSearchCmd = "!uimg"
const searxngCommands = [
imageSearchCmd,
unsafeImageSearchCmd
];
function sendImage(results, resultIndex, roomId, name, searchCommand, retryCount, matrixClient, uploadMatrixClient) {
const resultObj = results[resultIndex]
var imageURL;
if (typeof resultObj === 'undefined' || resultObj == null || typeof resultObj.img_src === 'undefined' || resultObj.img_src == null || resultObj.img_src === '') {
imageURL = "";
}
else {
imageURL = resultObj.img_src;
if (imageURL.startsWith("//")) {
imageURL = "https:" + imageURL;
}
}
(async () => {
try {
const imageResponse = await axios.get(imageURL, { responseType: 'arraybuffer' });
var imageType = imageResponse.headers['content-type'];
console.debug("[Search text: "+searchCommand+"], "+"[imageURL: "+imageURL+"], "+"[retryCount: "+retryCount+"]"+", [Engine: "+resultObj.engines[0]+"]"+", [content-type: "+imageType+"]");
const uploadResponse = await uploadMatrixClient.uploadContent(imageResponse.data, { rawResponse: false, type: imageType });
const matrixUrl = uploadResponse.content_uri;
switch(imageType) {
case "image/jpeg":
case "image/jpg":
name = name + ".jpg";
break;
case "image/png":
name = name + ".png";
break;
case "image/gif":
name = name + ".gif";
break;
case "application/octet-stream":
const urlImageType = imageURL.substring(imageURL.lastIndexOf("."));
switch(urlImageType) {
case ".jpg":
case ".jpeg":
imageType = "image/jpg";
name = name + ".jpg";
break;
case ".png":
imageType = "image/png";
name = name + ".png";
break;
case ".gif":
imageType = "image/gif";
name = name + ".gif";
break;
}
break;
}
matrixClient.sendImageMessage(roomId, matrixUrl, {"mimetype": imageType}, name, null);
matrixClient.sendTyping(roomId, false, 3000);
} catch (error) {
retryCount = retryCount + 1;
resultIndex = resultIndex + 1;
if (retryCount > 3 || resultIndex > (results.length - 1)) {
matrixClient.sendNotice(roomId, "Error occurred during \"" + searchCommand + "\"");
console.error("ERROR! [Search text: "+searchCommand+"], "+"[imageURL: "+imageURL+"], "+"[retryCount: "+retryCount+"]"+", [Engine: "+resultObj.engines[0]+"]");
console.error(error);
}
else {
console.warn("Trying next result for '"+searchCommand+"'");
console.error(error);
sendImage(results, resultIndex, roomId, name, searchCommand, retryCount, matrixClient, uploadMatrixClient);
}
}
})();
}
Searxng.prototype.handleMessage = function(event, room) {
const messagePieces = event.getContent().body.split(" ");
if (searxngCommands.indexOf(messagePieces[0]) > -1) {
var cooldown = false;
if (this.blacklistedImgRooms.indexOf(room.roomId) >=0) {
this.matrixClient.sendNotice(room.roomId, "Image searching has been disabled in this room.");
return;
}
else if (this.blacklistedUimgRooms.indexOf(room.roomId) >=0 && messagePieces[0] == unsafeImageSearchCmd) {
this.matrixClient.sendNotice(room.roomId, "Image searching without safesearch is disabled in this room.");
return;
}
else if (!room.currentState.maySendMessage(this.matrixClient.getUserId())) {
console.warn("Don't have permission to post in room "+room.roomId);
return;
}
else if (this.cooldownImmuneUsers.indexOf(event.getSender()) < 0) {
const roomCooldown = this.roomCooldowns.get(room.roomId);
if (roomCooldown != undefined) {
const currentTime = Date.now();
const lastRoomCooldownTime = lastCooldownTimes.get(room.roomId);
if (lastRoomCooldownTime != undefined) {
const timeSinceLastCooldown = currentTime - lastRoomCooldownTime;
if (!isNaN(timeSinceLastCooldown) && (currentTime - lastRoomCooldownTime) < roomCooldown) {
const lastRoomWarningTime = lastWarningTimes.get(room.roomId);
if (isNaN(lastRoomWarningTime) || lastRoomWarningTime != lastRoomCooldownTime) {
this.matrixClient.sendNotice(room.roomId, "This room has a mandatory cooldown between image commands. Try again later.");
lastWarningTimes.set(room.roomId, lastRoomCooldownTime);
}
return;
}
}
lastCooldownTimes.set(room.roomId, currentTime);
cooldown = true;
}
}
try {
var toSearch;
var resultIndex = 0;
if (messagePieces.length <= 1) {
this.matrixClient.sendNotice(room.roomId, "No search terms provided");
return;
}
else if (messagePieces.length == 2) {
toSearch = messagePieces[1].trim();
}
else {
if (isNaN(messagePieces[1])) {
toSearch = event.getContent().body.substr(messagePieces[0].length+1);
}
else {
resultIndex = Number(messagePieces[1]) - 1;
if (resultIndex < 0) {
this.matrixClient.sendNotice(room.roomId, "Invalid result index given.");
return;
}
toSearch = event.getContent().body.substr(messagePieces[0].length+messagePieces[1].length+2);
}
}
2023-02-12 01:16:04 -05:00
const searchURL = this.searxngInstance + "/search?category_images=1&pageno=1&time_range=&format=json&"+this.searxngParameters+"&safesearch="+(messagePieces[0] == unsafeImageSearchCmd ? "0" : "1")+"&q=" + toSearch;
2023-02-11 22:27:52 -05:00
this.matrixClient.sendTyping(room.roomId, true, 3000);
const matrixClient = this.matrixClient;
const uploadMatrixClient = this.uploadMatrixClient;
request(searchURL, function (error, response, body) {
try {
if (error == null || error == "") {
const bodyObj = JSON.parse(body);
const results = bodyObj.results;
if (typeof results === 'undefined' || results == null || results.length <= 0) {
matrixClient.sendNotice(room.roomId, "No results found for \""+toSearch+"\"");
return;
}
else if (resultIndex > (results.length - 1)) {
matrixClient.sendNotice(room.roomId, "No result found for \""+toSearch+"\" at position "+(resultIndex+1));
return;
}
sendImage(results, resultIndex, room.roomId, toSearch, event.getContent().body, 0, matrixClient, uploadMatrixClient);
}
else {
matrixClient.sendNotice(room.roomId, "Error occurred during \"" + event.getContent().body + "\"");
console.error(error);
}
} catch (error) {
matrixClient.sendNotice(room.roomId, "Error occurred during \"" + event.getContent().body + "\"");
console.error(error);
}
if (cooldown) {
lastCooldownTimes.set(room.roomId, Date.now());
}
});
} catch (error) {
this.matrixClient.sendNotice(room.roomId, "Error occurred during \"" + event.getContent().body + "\"");
console.error(error);
}
}
};
Searxng.prototype.startUploadMatrixClient = function() {
(async () => {
this.uploadMatrixClient.startClient({initialSyncLimit: 1});
})();
}
Searxng.prototype.getFormattedHelp = function() {
return "\
<code>!img [image_search_text]</code> - Return top result for image<br />\
<code>!img [n] [image_search_text]</code> - Return nth result for image. [n] must be a positive number (example: <code>!img 3 cat memes</code>)<br />\
<code>!uimg</code> - Same as !img but without safesearch";
}
Searxng.prototype.getHelp = function() {
return "!img [image_search_text]\" - Return top result for image\r\n\
\"!img [n] [image_search_text]\" - Return nth result for image. [n] must be a positive number (example: '!img 3 cat memes')\r\n\
\"!uimg\" - Same as !img but without safesearch";
}
module.exports = Searxng;