Substitute illegal attachments with redacted thumbnail
This commit is contained in:
parent
f2bdf5a279
commit
30fecd588f
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
231
script.js
231
script.js
|
@ -298,19 +298,21 @@ function parseRangeHeader(rangeHeader) {
|
|||
|
||||
function resolveResponse(resolve, reject) {
|
||||
return function(e) {
|
||||
var status = e.target.getResponseHeader("Status");
|
||||
const status = e.target.getResponseHeader("Status");
|
||||
|
||||
if (status != null) {
|
||||
var status_code = Number(status.split(" ")[0]);
|
||||
const status_code = Number(status.split(" ")[0]);
|
||||
|
||||
if (status_code >= 200 && status_code < 300) {
|
||||
resolve(e.target.responseText);
|
||||
} else {
|
||||
reject(new Error('API responded with ' + status));
|
||||
reject(new Error('API responded with ' + status + ". " + e.target.responseText));
|
||||
}
|
||||
} else {
|
||||
if (e.target.status >= 200 && e.target.status < 300) {
|
||||
return resolve(e.target);
|
||||
} else {
|
||||
reject(new Error('API responded with ' + e.target.status));
|
||||
reject(new Error('API responded with ' + e.target.status + ". " + e.target.responseText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,6 +343,31 @@ function get(url, xhr_req_follower, headers) {
|
|||
});
|
||||
}
|
||||
|
||||
function post(url, body, xhr_req_follower, headers) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var req = new XMLHttpRequest();
|
||||
xhr_req_follower(req);
|
||||
req.onload = resolveResponse(resolve, reject);
|
||||
req.onerror = reject;
|
||||
req.open('POST', url);
|
||||
|
||||
if (headers) {
|
||||
Object.entries(headers)
|
||||
.forEach(function([header_name, header_value]) {
|
||||
req.setRequestHeader(header_name, header_value);
|
||||
});
|
||||
}
|
||||
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
|
||||
if (body) {
|
||||
req.send(JSON.stringify(body));
|
||||
} else {
|
||||
req.send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Given a BigInt that is packed bytes, unpack the bytes into an ArrayBuffer
|
||||
function unpackBytes(bigint) {
|
||||
const buffer = new ArrayBuffer(8);
|
||||
|
@ -384,100 +411,6 @@ function hammingDistance(buffer1, buffer2) {
|
|||
return distance;
|
||||
}
|
||||
|
||||
function parseFilePath(s) {
|
||||
return JSON.parse(s);
|
||||
}
|
||||
|
||||
function FileSize(s) {
|
||||
this.filesize = s;
|
||||
}
|
||||
|
||||
function tree(rows) {
|
||||
var c = {};
|
||||
|
||||
for (var row of rows) {
|
||||
var path = parseFilePath(row.path);
|
||||
var tree = c;
|
||||
var previous = c;
|
||||
var filename = 'NOPATH';
|
||||
|
||||
for (var p of path) {
|
||||
previous = tree;
|
||||
|
||||
if (p in tree) {
|
||||
tree = tree[p];
|
||||
} else {
|
||||
var newtree = {};
|
||||
tree[p] = newtree;
|
||||
tree = newtree;
|
||||
}
|
||||
|
||||
filename = p;
|
||||
}
|
||||
|
||||
previous[filename] = new FileSize(row.filesize);
|
||||
}
|
||||
|
||||
console.log(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
function renderTree(rows) {
|
||||
var list_elem = ul();
|
||||
|
||||
function draw(list_elem, t) {
|
||||
Object.entries(t)
|
||||
.forEach(function([key, val]) {
|
||||
if (val instanceof FileSize) {
|
||||
var contents = div(span(text(key)));
|
||||
contents.appendChild(italic(text(val.filesize)));
|
||||
list_elem.appendChild(contents);
|
||||
} else {
|
||||
var new_list = ul();
|
||||
var elem = li(text(key));
|
||||
elem.appendChild(new_list);
|
||||
list_elem.appendChild(elem);
|
||||
draw(new_list, val);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
draw(list_elem, tree(rows));
|
||||
|
||||
return list_elem;
|
||||
}
|
||||
|
||||
function assembleTable(rows) {
|
||||
var t = document.createElement('table');
|
||||
|
||||
rows.forEach(function(r) {
|
||||
var row = t.insertRow();
|
||||
|
||||
TableHeadings.forEach(function(header) {
|
||||
var cell = row.insertCell();
|
||||
|
||||
cell.appendChild(header[1](r));
|
||||
});
|
||||
});
|
||||
|
||||
var thead = t.createTHead().insertRow();
|
||||
|
||||
TableHeadingNames.forEach(function(header) {
|
||||
var th = document.createElement('th');
|
||||
|
||||
th.appendChild(text(header));
|
||||
thead.appendChild(th);
|
||||
});
|
||||
|
||||
var countElem = div(text(rows.length + ' rows'))
|
||||
|
||||
var wrapper = div();
|
||||
wrapper.appendChild(t);
|
||||
wrapper.appendChild(countElem);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function text(s) {
|
||||
return document.createTextNode(s);
|
||||
}
|
||||
|
@ -527,20 +460,31 @@ function mkSpamImgElement(img_description) {
|
|||
var mime = img_description.mimetype;
|
||||
var thumb_url;
|
||||
|
||||
if (mime == "audio/mpeg") {
|
||||
var illegal = img_description.illegal;
|
||||
console.log('img_description.illegal', img_description.illegal);
|
||||
|
||||
if (illegal) {
|
||||
thumb_url = `/bin/?path=${GlobalVars.settings.redacted_thumbnail_path}&mimetype=image/jpeg`
|
||||
} else if (mime == "audio/mpeg") {
|
||||
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
|
||||
} else {
|
||||
thumb_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}_thumbnail.jpg&mimetype=image/jpeg`
|
||||
}
|
||||
|
||||
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
|
||||
img_elem.setAttribute('src', thumb_url);
|
||||
img_elem.setAttribute('decoding', 'async');
|
||||
img_elem.setAttribute('loading', 'lazy');
|
||||
|
||||
var a_elem = document.createElement('a');
|
||||
a_elem.setAttribute('href', image_url);
|
||||
a_elem.appendChild(img_elem);
|
||||
var a_elem;
|
||||
|
||||
if (!illegal) {
|
||||
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
|
||||
a_elem = document.createElement('a');
|
||||
a_elem.setAttribute('href', image_url);
|
||||
a_elem.appendChild(img_elem);
|
||||
} else {
|
||||
a_elem = div(img_elem);
|
||||
}
|
||||
|
||||
var img_container_elem = div(a_elem);
|
||||
img_container_elem.classList.add('post--image_container');
|
||||
|
@ -570,6 +514,49 @@ function linkToBoard(website_name, board_name, thread_id) {
|
|||
}
|
||||
}
|
||||
|
||||
function attachmentCanBeMarkedIllegal(attachment) {
|
||||
return attachment.phash != null && !attachment.illegal;
|
||||
}
|
||||
|
||||
function shouldDisplayMarkIllegalButton(post) {
|
||||
let result = false;
|
||||
|
||||
for (let attachment of (post.known_spam_post_attachment || [])) {
|
||||
result = result || attachmentCanBeMarkedIllegal(attachment);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function isIllegal(post) {
|
||||
let result = false;
|
||||
|
||||
for (let attachment of (post.known_spam_post_attachment || [])) {
|
||||
result = result || attachment.illegal;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function onClickMarkIllegal(phashes, e) {
|
||||
console.log('CLICK', phashes);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
const url = new URL('/illegal', window.location.origin);
|
||||
phashes.forEach(function(p) {
|
||||
console.log('onClickMarkIllegal', typeof p, p);
|
||||
url.searchParams.append('phash', p);
|
||||
});
|
||||
|
||||
await post(url.toString(), null, cancel)
|
||||
.then(function() {
|
||||
location.reload();
|
||||
})
|
||||
.catch(caught.bind(this, "Failed to mark post illegal because:"));
|
||||
|
||||
}
|
||||
|
||||
function renderPostElem(post) {
|
||||
const postContainer = div();
|
||||
postContainer.classList.add('post');
|
||||
|
@ -599,6 +586,34 @@ function renderPostElem(post) {
|
|||
|
||||
postHeader.appendChild(span(text((new Date(post.time_stamp).toUTCString()))));
|
||||
|
||||
if (shouldDisplayMarkIllegalButton(post)) {
|
||||
const mark_illegal = span()
|
||||
mark_illegal.classList.add('post--mark_illegal');
|
||||
const mark_illegal_a = document.createElement('a');
|
||||
|
||||
mark_illegal_a.appendChild(text('Mark Illegal'));
|
||||
|
||||
mark_illegal_a.setAttribute('href', '#');
|
||||
mark_illegal_a.setAttribute('title', 'Permanently delete associated pictures and thumbnails but keep metadata for future matching');
|
||||
mark_illegal.appendChild(text('['));
|
||||
mark_illegal.appendChild(mark_illegal_a);
|
||||
mark_illegal.appendChild(text(']'));
|
||||
|
||||
const phashes = (post.known_spam_post_attachment || [])
|
||||
.map(function(p) {
|
||||
return bufferToHex(unpackBytes(BigInt(p.phash)));
|
||||
});
|
||||
|
||||
mark_illegal_a.addEventListener('click',
|
||||
onClickMarkIllegal.bind(this, phashes));
|
||||
|
||||
postHeader.appendChild(mark_illegal);
|
||||
} else if (isIllegal(post)) {
|
||||
const mark_illegal = span(text('illegal'))
|
||||
mark_illegal.classList.add('post--is_illegal');
|
||||
postHeader.appendChild(mark_illegal);
|
||||
}
|
||||
|
||||
postContainer.appendChild(postHeader);
|
||||
|
||||
const postElem = div();
|
||||
|
@ -767,9 +782,13 @@ function loadKnownSpamPosts(params) {
|
|||
json.forEach(function (post) {
|
||||
var postElem = renderOverviewPost(post);
|
||||
|
||||
postElem.addEventListener('click', function() {
|
||||
changeUrl('/spam_post/' + post.text_post_id, new URLSearchParams(), true);
|
||||
});
|
||||
postElem.addEventListener('click',
|
||||
changeUrl.bind(
|
||||
this,
|
||||
'/spam_post/' + post.text_post_id,
|
||||
new URLSearchParams(),
|
||||
true
|
||||
));
|
||||
|
||||
mainElem.appendChild(postElem);
|
||||
});
|
||||
|
|
14
style.css
14
style.css
|
@ -64,6 +64,20 @@ header {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.post--header span.post--mark_illegal {
|
||||
flex-basis: fit-content;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.post--header span.post--is_illegal {
|
||||
flex-basis: fit-content;
|
||||
flex-grow: 0;
|
||||
color: orange;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin: 1rem;
|
||||
font-size: 1.5em;
|
||||
|
|
Loading…
Reference in New Issue