Update ImageUtilities.plugin.js

This commit is contained in:
Mirco Wittrien 2022-12-01 20:44:25 +01:00
parent 169c561c48
commit cd46077c7a
1 changed files with 84 additions and 47 deletions

View File

@ -2,7 +2,7 @@
* @name ImageUtilities
* @author DevilBro
* @authorId 278543574059057154
* @version 4.9.8
* @version 5.0.0
* @description Adds several Utilities for Images/Videos (Gallery, Download, Reverse Search, Zoom, Copy, etc.)
* @invite Jx3TjNS
* @donate https://www.paypal.me/MircoWittrien
@ -14,7 +14,14 @@
module.exports = (_ => {
const changeLog = {
added: {
"Gallery Filter": "You can now filter the Gallery by File Type"
},
fixed: {
"Zoom With native Gallery Mode": "Zooming in an Image no longer will close the Image if you are using Discords native Gallery Mode",
"Download As Location": "Now properly remembers the last selected Location",
"Download Issues": "All Image Download Issues that occured for some people in eastern countries should be fixed now"
}
};
return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class {
@ -73,28 +80,22 @@ module.exports = (_ => {
};
const fileTypes = {
"3gp": {copyable: false, searchable: false, video: true},
"3g2": {copyable: false, searchable: false, video: true},
"amv": {copyable: false, searchable: false, video: true},
"apng": {copyable: false, searchable: true, video: false},
"avi": {copyable: false, searchable: false, video: true},
"flv": {copyable: false, searchable: false, video: true},
"jpeg": {copyable: true, searchable: true, video: false},
"jpg": {copyable: true, searchable: true, video: false},
"gif": {copyable: false, searchable: true, video: false},
"m4v": {copyable: false, searchable: false, video: true},
"mkv": {copyable: false, searchable: false, video: true},
"mov": {copyable: false, searchable: false, video: true},
"mp4": {copyable: false, searchable: false, video: true},
"mpeg-1": {copyable: false, searchable: false, video: true},
"mpeg-2": {copyable: false, searchable: false, video: true},
"ogg": {copyable: false, searchable: false, video: true},
"ogv": {copyable: false, searchable: false, video: true},
"png": {copyable: true, searchable: true, video: false},
"svg": {copyable: false, searchable: false, video: false},
"webm": {copyable: false, searchable: false, video: true},
"webp": {copyable: false, searchable: true, video: false},
"wmv": {copyable: false, searchable: false, video: true}
"3gp": {copyable: false, searchable: false, video: true, signs: [[0x66, 0x74, 0x79, 0x70, 0x33, 0x67]]},
"avi": {copyable: false, searchable: false, video: true, signs: [[0x41, 0x56, 0x49, 0x20]]},
"flv": {copyable: false, searchable: false, video: true, signs: [[0x46, 0x4C, 0x56]]},
"jpeg": {copyable: true, searchable: true, video: false, signs: [[0xFF, 0xD8, 0xFF, 0xEE]]},
"jpg": {copyable: true, searchable: true, video: false, signs: [[0xFF, 0xD8, 0xFF, 0xDB], [0xFF, 0xD8, 0xFF, 0xE0]]},
"gif": {copyable: false, searchable: true, video: false, signs: [[0x47, 0x49, 0x46, 0x38, 0x37, 0x61], [0x47, 0x49, 0x46, 0x38, 0x39, 0x61]]},
"mov": {copyable: false, searchable: false, video: true, signs: [[null, null, null, null, 0x6D, 0x6F, 0x6F, 0x76], [null, null, null, null, 0x66, 0x74, 0x79, 0x70, 0x71, 0x74, 0x20, 0x20]]},
"mp4": {copyable: false, searchable: false, video: true, signs: [[null, null, null, null, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6F, 0x6D]]},
"mpeg-1": {copyable: false, searchable: false, video: true, signs: [[0x00, 0x00, 0x01, 0xBA]]},
"mpeg-2": {copyable: false, searchable: false, video: true, signs: [[0x00, 0x00, 0x01, 0xB3]]},
"ogg": {copyable: false, searchable: false, video: true, signs: [[0x4F, 0x67, 0x67, 0x53]]},
"png": {copyable: true, searchable: true, video: false, signs: [[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]]},
"svg": {copyable: false, searchable: false, video: false, signs: [[0x3C]]},
"webm": {copyable: false, searchable: false, video: true, signs: [[0x1A, 0x45, 0xDF, 0xA3]]},
"webp": {copyable: false, searchable: true, video: false, signs: [[0x57, 0x45, 0x42, 0x50]]},
"wmv": {copyable: false, searchable: false, video: true, signs: [[0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11], [0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C]]}
};
const LazyImageSiblingComponent = class LazyImageSibling extends BdApi.React.Component {
@ -215,6 +216,7 @@ module.exports = (_ => {
saveImage: {value: true, description: "Adds a 'Save Image as' Option"},
jumpTo: {value: true, description: "Adds a 'Jump to Message' Option in Gallery Mode"}
},
galleryFilter: {},
zoomSettings: {
pixelMode: {value: false, label: "Uses Pixel Lens instead of a Blur Lens"},
zoomLevel: {value: 2, digits: 1, minValue: 1, maxValue: 20, unit: "x", label: "ACCESSIBILITY_ZOOM_LEVEL_LABEL"},
@ -251,6 +253,8 @@ module.exports = (_ => {
Yandex: {value: true, name: "Yandex", url: "https://yandex.com/images/search?url=" + imgUrlReplaceString + "&rpt=imageview"}
}
};
for (let fileType in fileTypes) this.defaults.galleryFilter[fileType] = {value: true};
this.modulePatches = {
before: [
@ -263,8 +267,7 @@ module.exports = (_ => {
"LazyImageZoomable",
"ModalCarousel",
"Spoiler",
"UserBanner",
"UserThemedBanner"
"UserBanner"
],
componentDidMount: [
"ImageModal",
@ -456,6 +459,18 @@ module.exports = (_ => {
}))
}));
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
title: "Gallery Filter Settings",
collapseStates: collapseStates,
children: Object.keys(this.defaults.galleryFilter).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
type: "Switch",
plugin: this,
keys: ["galleryFilter", key],
label: key,
value: this.settings.galleryFilter[key]
}))
}));
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
title: "Resize Settings",
collapseStates: collapseStates,
@ -1218,7 +1233,7 @@ module.exports = (_ => {
};
lens.update();
e.node.style.setProperty("pointer-events", "none", "important");
for (let ele of [e.node, document.querySelector(BDFDB.dotCN.modalcarouselwrapper)]) if (ele) ele.style.setProperty("pointer-events", "none", "important");
let dragging = event2 => {
event = event2;
@ -1226,7 +1241,7 @@ module.exports = (_ => {
};
let releasing = event2 => {
BDFDB.ListenerUtils.stopEvent(event2);
e.node.style.removeProperty("pointer-events");
for (let ele of [e.node, document.querySelector(BDFDB.dotCN.modalcarouselwrapper)]) if (ele) ele.style.removeProperty("pointer-events");
this.cleanupListeners("Zoom");
document.removeEventListener("mousemove", dragging);
document.removeEventListener("mouseup", releasing);
@ -1390,7 +1405,7 @@ module.exports = (_ => {
}
}
processUserThemedBanner (e) {
processUserBanner (e) {
if (!this.settings.places.userAvatars || !e.instance.props.displayProfile || !e.instance.props.displayProfile.banner) return;
let div = BDFDB.ReactUtils.findChild(e.returnvalue, {type: "div"});
if (div) div.props.onContextMenu = event => {
@ -1413,10 +1428,6 @@ module.exports = (_ => {
};
}
processUserBanner (e) {
this.processUserThemedBanner(e);
}
cacheClickedImage (target) {
if (!target) return;
const image = (BDFDB.DOMUtils.getParent(BDFDB.dotCN.imagewrapper, target) || target).querySelector("img") || target;
@ -1434,14 +1445,12 @@ module.exports = (_ => {
downloadFile (url, path, fallbackUrl, alternativeName) {
url = url.startsWith("/assets") ? (window.location.origin + url) : url;
BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}, headers: {"Content-Type": "application/json"}}, (error, response, body) => {
let type = this.isValid(url, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE;
if (error || response.statusCode != 200 || response.headers["content-type"].indexOf("text/html") > -1) {
if (fallbackUrl) this.downloadFile(fallbackUrl, path, null, alternativeName);
else BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", type).replace("{{var1}}", ""), {type: "danger"});
}
BDFDB.LibraryModules.FileRequestUtils.getFileData(url).then(body => {
let extension = this.getFileExtension(new Uint8Array(body));
if (!extension) BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", BDFDB.LanguageUtils.LanguageStrings.IMAGE).replace("{{var1}}", path), {type: "danger"});
else {
BDFDB.LibraryRequires.fs.writeFile(this.getFileName(path, (alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35), this.getFileExtenstion(response.headers["content-type"].split("/").pop().split("+")[0]), 0), Buffer.from(body), error => {
let type = fileTypes[extension].video ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE;
BDFDB.LibraryRequires.fs.writeFile(this.getFileName(path, (alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35), extension, 0), Buffer.from(body), error => {
if (error) BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", type).replace("{{var1}}", path), {type: "danger"});
else BDFDB.NotificationUtils.toast(this.labels.toast_save_success.replace("{{var0}}", type).replace("{{var1}}", path), {type: "success"});
});
@ -1451,7 +1460,18 @@ module.exports = (_ => {
downloadFileAs (url, fallbackUrl, alternativeName) {
url = url.startsWith("/assets") ? (window.location.origin + url) : url;
BDFDB.LibraryModules.WindowUtils.saveImage(url.startsWith("/assets") ? (window.location.origin + url) : url);
BDFDB.LibraryModules.FileRequestUtils.getFileData(url).then(body => {
let extension = this.getFileExtension(new Uint8Array(body));
if (!extension) BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", BDFDB.LanguageUtils.LanguageStrings.IMAGE).replace("{{var1}}", "PC"), {type: "danger"});
else {
let hrefURL = window.URL.createObjectURL(new Blob([body], {type: this.getMimeType(extension)}));
let tempLink = document.createElement("a");
tempLink.href = hrefURL;
tempLink.download = `${(alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35)}.${extension}`;
tempLink.click();
window.URL.revokeObjectURL(hrefURL);
}
});
}
copyFile (url) {
@ -1479,9 +1499,14 @@ module.exports = (_ => {
else return wholePath;
}
getFileExtenstion (ext) {
if (ext == "quicktime") ext = "mov";
return ext;
getFileExtension (intArray) {
for (let fileType in fileTypes) if (fileTypes[fileType].signs.some(signs => signs.every((hex, i) => hex === null || hex == intArray[i]))) return fileType;
return "";
}
getMimeType (fileType) {
if (fileTypes[fileType]) return `${fileTypes[fileType].video ? "video" : "image"}/${fileType == "svg" ? "svg+xml" : fileType}`;
return "";
}
getImageSrc (img) {
@ -1494,7 +1519,13 @@ module.exports = (_ => {
}
filterMessagesForImages (messages, img) {
return messages.filter(m => m && m.channel_id == img.channelId && !BDFDB.LibraryStores.RelationshipStore.isBlocked(m.author.id) && (m.id == firstViewedImage.messageId || m.id == img.messageId || m.embeds.filter(e => e.image || e.thumbnail || e.video).length || m.attachments.filter(a => !a.filename.startsWith("SPOILER_")).length)).map(m => [m.attachments, m.embeds].flat(10).filter(n => n).map(i => Object.assign({m, messageId: m.id, channelId: img.channelId}, i, i.image, i.thumbnail, i.video))).flat(10);
return messages.filter(m => m && m.channel_id == img.channelId && !BDFDB.LibraryStores.RelationshipStore.isBlocked(m.author.id) && (m.id == firstViewedImage.messageId || m.id == img.messageId || m.embeds.filter(e => e.image || e.thumbnail || e.video).length || m.attachments.filter(a => !a.filename.startsWith("SPOILER_")).length)).map(m => [m.attachments, m.embeds].flat(10).filter(n => n).map(i => Object.assign({messageId: m.id, channelId: img.channelId}, i, i.image, i.thumbnail, i.video))).flat(10).filter(n => {
if (!n) return false;
if (!n.content_type || img.proxy_url == n.proxy_url || img.proxy_url == n.url || img.proxy_url == n.href) return true;
let extension = (n.content_type.split("/")[1] || "").split("+")[0] || "";
if (extension && this.settings.galleryFilter[extension] === false) return false;
return true;
});
}
switchImages (modalInstance, offset) {
@ -1519,7 +1550,7 @@ module.exports = (_ => {
}).then(result => {
if (result && viewedImage) {
const messages = result.body.flat(10).reverse();
Object.assign(cachedImages, {all: BDFDB.ArrayUtils.removeCopies([].concat(cachedImages.all, this.filterMessagesForImages(messages, viewedImage)))});
Object.assign(cachedImages, {all: this.filterForCopies([].concat(cachedImages.all, this.filterMessagesForImages(messages, viewedImage)))});
const index = this.getImageIndex(cachedImages.all, viewedImage);
cachedImages = Object.assign(cachedImages, {
channelId: viewedImage.channelId,
@ -1546,7 +1577,7 @@ module.exports = (_ => {
}).then(result => {
if (result && viewedImage) {
const messages = result.body.flat(10).reverse();
Object.assign(cachedImages, {all: BDFDB.ArrayUtils.removeCopies([].concat(this.filterMessagesForImages(messages, viewedImage), cachedImages.all))});
Object.assign(cachedImages, {all: this.filterForCopies([].concat(this.filterMessagesForImages(messages, viewedImage), cachedImages.all))});
const index = this.getImageIndex(cachedImages.all, viewedImage);
cachedImages = Object.assign(cachedImages, {
channelId: viewedImage.channelId,
@ -1578,6 +1609,12 @@ module.exports = (_ => {
BDFDB.ReactUtils.forceUpdate(modalInstance);
}
filterForCopies (messages) {
let filtered = [];
for (let message of messages) if (!filtered.find(n => n.id == message.id)) filtered.push(message);
return filtered;
}
addListener (eventType, type, callback) {
if (!type || !eventType || typeof callback != "function") return;
if (!eventTypes[type]) eventTypes[type] = [];