248 lines
8.9 KiB
JavaScript
248 lines
8.9 KiB
JavaScript
function Searxng(matrixClient) {
|
|
this.matrixClient = matrixClient;
|
|
this.uploadMatrixClient = matrixClient;
|
|
this.blacklistedImgRooms = [];
|
|
this.blacklistedUimgRooms = [];
|
|
this.cooldownImmuneUsers = [];
|
|
this.roomCooldowns = new Map();
|
|
this.searxngInstance = "";
|
|
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"
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
const searchURL = this.searxngInstance + "/search?category_images=1&pageno=1&time_range=&format=json&"+this.searxngParameters+"&safesearch="+(messagePieces[0] == unsafeImageSearchCmd ? "0" : "1")+"&q=" + toSearch;
|
|
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;
|