4chan-XZ/src/Images/Sauce.ts
2023-04-27 22:28:26 +02:00

179 lines
5.5 KiB
TypeScript

import Callbacks from "../classes/Callbacks";
import Notice from "../classes/Notice";
import Filter from "../Filtering/Filter";
import { g, Conf, doc } from "../globals/globals";
import $ from "../platform/$";
import { dict } from "../platform/helpers";
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS104: Avoid inline assignments
* DS204: Change includes calls to have a more natural evaluation order
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
*/
var Sauce = {
init() {
let link;
if (!['index', 'thread'].includes(g.VIEW) || !Conf['Sauce']) { return; }
$.addClass(doc, 'show-sauce');
const links = [];
for (link of Conf['sauces'].split('\n')) {
var linkData;
if ((link[0] !== '#') && (linkData = this.parseLink(link))) {
links.push(linkData);
}
}
if (!links.length) { return; }
this.links = links;
this.link = $.el('a', {
target: '_blank',
className: 'sauce'
}
);
return Callbacks.Post.push({
name: 'Sauce',
cb: this.node
});
},
parseLink(link) {
if (!(link = link.trim())) { return null; }
const parts = dict();
const iterable = link.split(/;(?=(?:text|boards|types|regexp|sandbox):?)/);
for (let i = 0; i < iterable.length; i++) {
var part = iterable[i];
if (i === 0) {
parts['url'] = part;
} else {
var m = part.match(/^(\w*):?(.*)$/);
parts[m[1]] = m[2];
}
}
if (!parts['text']) { parts['text'] = parts['url'].match(/(\w+)\.\w+\//)?.[1] || '?'; }
if ('boards' in parts) {
parts['boards'] = Filter.parseBoards(parts['boards']);
}
if ('regexp' in parts) {
try {
let regexp;
if (regexp = parts['regexp'].match(/^\/(.*)\/(\w*)$/)) {
parts['regexp'] = RegExp(regexp[1], regexp[2]);
} else {
parts['regexp'] = RegExp(parts['regexp']);
}
} catch (err) {
new Notice('warning', [
$.tn("Invalid regexp for Sauce link:"),
$.el('br'),
$.tn(link),
$.el('br'),
$.tn(err.message)
], 60);
return null;
}
}
return parts;
},
createSauceLink(link, post, file) {
let a, matches, needle;
const ext = file.url.match(/[^.]*$/)[0];
const parts = dict();
$.extend(parts, link);
if (!!parts['boards'] && !parts['boards'][`${post.siteID}/${post.boardID}`] && !parts['boards'][`${post.siteID}/*`]) { return null; }
if (!!parts['types'] && (needle = ext, !parts['types'].split(',').includes(needle))) { return null; }
if (!!parts['regexp'] && (!(matches = file.name.match(parts['regexp'])))) { return null; }
const missing = [];
for (var key of ['url', 'text']) {
parts[key] = parts[key].replace(/%(T?URL|IMG|[sh]?MD5|board|name|%|semi|\$\d+)/g, function(orig, parameter) {
let type;
if (parameter[0] === '$') {
if (!matches) { return orig; }
type = matches[parameter.slice(1)] || '';
} else {
type = Sauce.formatters[parameter](post, file, ext);
if ((type == null)) {
missing.push(parameter);
return '';
}
}
if ((key === 'url') && !['%', 'semi'].includes(parameter)) {
if (/^javascript:/i.test(parts['url'])) { type = JSON.stringify(type); }
type = encodeURIComponent(type);
}
return type;
});
}
if (g.SITE.areMD5sDeferred?.(post.board) && missing.length && !missing.filter(x => !/^.?MD5$/.test(x)).length) {
a = Sauce.link.cloneNode(false);
a.dataset.skip = '1';
return a;
}
if (missing.length) { return null; }
a = Sauce.link.cloneNode(false);
a.href = parts['url'];
a.textContent = parts['text'];
if (/^javascript:/i.test(parts['url'])) { a.removeAttribute('target'); }
return a;
},
node() {
if (this.isClone) { return; }
for (var file of this.files) {
Sauce.file(this, file);
}
},
file(post, file) {
let link, node;
const nodes = [];
const skipped = [];
for (link of Sauce.links) {
if (node = Sauce.createSauceLink(link, post, file)) {
nodes.push($.tn(' '), node);
if (node.dataset.skip) { skipped.push([link, node]); }
}
}
$.add(file.text, nodes);
if (skipped.length) {
var observer = new MutationObserver(function() {
if (file.text.dataset.md5) {
for ([link, node] of skipped) {
var node2;
if (node2 = Sauce.createSauceLink(link, post, file)) {
$.replace(node, node2);
}
}
return observer.disconnect();
}
});
return observer.observe(file.text, {attributes: true});
}
},
formatters: {
TURL(post, file) { return file.thumbURL; },
URL(post, file) { return file.url; },
IMG(post, file, ext) { if (['gif', 'jpg', 'jpeg', 'png'].includes(ext)) { return file.url; } else { return file.thumbURL; } },
MD5(post, file) { return file.MD5; },
sMD5(post, file) { return file.MD5?.replace(/[+/=]/g, c => ({'+': '-', '/': '_', '=': ''})[c]); },
hMD5(post, file) { if (file.MD5) { return (atob(file.MD5).map((c) => `0${c.charCodeAt(0).toString(16)}`.slice(-2))).join(''); } },
board(post) { return post.board.ID; },
name(post, file) { return file.name; },
'%'() { return '%'; },
semi() { return ';'; }
}
};
export default Sauce;