display phash as hex
This commit is contained in:
parent
c745ed8901
commit
d3f3a9aa0f
291
script.js
291
script.js
|
@ -124,13 +124,6 @@ function match(re) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
var ROUTES = RoutePart([
|
|
||||||
[match(/^s$/), new RoutePart([], handleSearch)],
|
|
||||||
[match(/^[a-f0-9]{40}$/), new RoutePart([], handleInfo)]
|
|
||||||
], loadTop);
|
|
||||||
*/
|
|
||||||
|
|
||||||
var ROUTES = RoutePart(
|
var ROUTES = RoutePart(
|
||||||
[
|
[
|
||||||
[ match(/^spam_post$/)
|
[ match(/^spam_post$/)
|
||||||
|
@ -147,24 +140,6 @@ var ROUTES = RoutePart(
|
||||||
, handlePageRoot
|
, handlePageRoot
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
|
||||||
var ROUTES = RoutePart(
|
|
||||||
[
|
|
||||||
[ match(/^static$/)
|
|
||||||
, new RoutePart(
|
|
||||||
[
|
|
||||||
[ match(/^index\.html$/)
|
|
||||||
, new RoutePart([], handlePageRoot)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, null
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
|
||||||
, null
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions
|
* Functions
|
||||||
*/
|
*/
|
||||||
|
@ -214,48 +189,53 @@ function get(url, xhr_req_follower, headers) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var HexArray = "0123456789abcdef";
|
// Given a BigInt that is packed bytes, unpack the bytes into an ArrayBuffer
|
||||||
|
function unpackBytes(bigint) {
|
||||||
|
const buffer = new ArrayBuffer(8);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
view.setBigInt64(0, bigint);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
function bytesToHex(uint8arr) {
|
function hexArrayFromBuffer(buffer) {
|
||||||
var hex_encoded = "";
|
// Create a Uint8Array view to access the bytes
|
||||||
|
const uint8Array = new Uint8Array(buffer);
|
||||||
|
|
||||||
for (var i=0; i < uint8arr.length; i++) {
|
// Convert each byte to its hexadecimal representation
|
||||||
var j = uint8arr[i] & 0xFF;
|
const hexArray = Array.from(uint8Array, byte => byte.toString(16).padStart(2, '0'));
|
||||||
hex_encoded += HexArray[j >>> 4];
|
|
||||||
hex_encoded += HexArray[j & 0x0F];
|
return uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bufferToHex(buffer) {
|
||||||
|
// Join the hexadecimal values into a single string
|
||||||
|
return hexArray(buffer).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hammingDistance(buffer1, buffer2) {
|
||||||
|
if (buffer1.byteLength !== buffer2.byteLength) {
|
||||||
|
throw new Error("Buffer lengths must be equal");
|
||||||
}
|
}
|
||||||
|
|
||||||
return hex_encoded;
|
const view1 = new DataView(buffer1);
|
||||||
|
const view2 = new DataView(buffer2);
|
||||||
|
|
||||||
|
let distance = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < buffer1.byteLength; i++) {
|
||||||
|
const byte1 = view1.getUint8(i);
|
||||||
|
const byte2 = view2.getUint8(i);
|
||||||
|
let xor = byte1 ^ byte2;
|
||||||
|
|
||||||
|
while (xor !== 0) {
|
||||||
|
distance++;
|
||||||
|
xor &= xor - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ESC_STR = '$ESCAPE_PIPE_SYMBOL';
|
|
||||||
|
|
||||||
function splitRawRow(raw_row) {
|
|
||||||
return raw_row
|
|
||||||
.replace('\\|', ESC_STR)
|
|
||||||
.split('|')
|
|
||||||
.map(function(s) {
|
|
||||||
return s.replace(ESC_STR, '|')
|
|
||||||
.trim();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseTable(results) {
|
|
||||||
var raw_rows = results.split('\n').slice(0, -1);
|
|
||||||
var headers = splitRawRow(raw_rows[0]);
|
|
||||||
|
|
||||||
return raw_rows.slice(2, -1)
|
|
||||||
.map(splitRawRow)
|
|
||||||
.map(function(row) {
|
|
||||||
return row.reduce(function(acc, val, i) {
|
|
||||||
acc[headers[i]] = val;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function parseFilePath(s) {
|
function parseFilePath(s) {
|
||||||
return JSON.parse(s);
|
return JSON.parse(s);
|
||||||
}
|
}
|
||||||
|
@ -385,43 +365,16 @@ function keepElements(elem_selectors) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureElementExist(selector) {
|
|
||||||
var document_root = document.querySelector('main');
|
|
||||||
var elem = document_root.querySelector(selector);
|
|
||||||
|
|
||||||
if (!elem) {
|
|
||||||
document_root.appendChild(global_elements[selector]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadJwt() {
|
function loadJwt() {
|
||||||
cancelGlobalEvts();
|
cancelGlobalEvts();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTop() {
|
|
||||||
//TODO: dispatch changeurl event
|
|
||||||
cancelGlobalEvts();
|
|
||||||
ensureElementExist('style.loading');
|
|
||||||
pageInfoText.innerText = 'Loading Top 100...';
|
|
||||||
get('/cgi-bin/top_100', cancel)
|
|
||||||
.then(function(response) {
|
|
||||||
CurrentScore = currentScore();
|
|
||||||
console.log("Current score:", CurrentScore);
|
|
||||||
|
|
||||||
var document_root = document.querySelector('main');
|
|
||||||
var t = parseTable(response);
|
|
||||||
console.log(t);
|
|
||||||
keepElements(['style', '.info']);
|
|
||||||
pageInfoText.innerText = 'Top 100';
|
|
||||||
document_root.appendChild(assembleTable(t));
|
|
||||||
})
|
|
||||||
.catch(caught.bind(this, "Failed to load top 100: "));
|
|
||||||
}
|
|
||||||
|
|
||||||
function caught(m, e) {
|
function caught(m, e) {
|
||||||
console.error(m);
|
console.error(m);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
for (var property in e) {
|
||||||
|
console.error(property + ": " + e[property]);
|
||||||
|
}
|
||||||
alert(new Error(m + e.message));
|
alert(new Error(m + e.message));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -430,13 +383,13 @@ function mkSpamImgElement(img_description) {
|
||||||
var mime = img_description.mimetype;
|
var mime = img_description.mimetype;
|
||||||
var thumb_url;
|
var thumb_url;
|
||||||
|
|
||||||
if (!img_description.thumbnail) {
|
if (mime == "audio/mpeg") {
|
||||||
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
|
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
|
||||||
} else {
|
} else {
|
||||||
thumb_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}_thumbnail.jpg&mimetype=image/jpeg`
|
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}&mimetype=${mime}`
|
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('src', thumb_url);
|
||||||
img_elem.setAttribute('decoding', 'async');
|
img_elem.setAttribute('decoding', 'async');
|
||||||
img_elem.setAttribute('loading', 'lazy');
|
img_elem.setAttribute('loading', 'lazy');
|
||||||
|
@ -485,9 +438,45 @@ function renderPostElem(post) {
|
||||||
function renderKnownSpamAttachments(attachments) {
|
function renderKnownSpamAttachments(attachments) {
|
||||||
var container = div();
|
var container = div();
|
||||||
container.classList.add('attachment');
|
container.classList.add('attachment');
|
||||||
|
|
||||||
attachments.forEach(function(a) {
|
attachments.forEach(function(a) {
|
||||||
container.appendChild(mkSpamImgElement(a));
|
container.appendChild(mkSpamImgElement(a));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderThings(things_map) {
|
||||||
|
var container = div();
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(things_map)) {
|
||||||
|
var entry = div();
|
||||||
|
entry.appendChild(span(bold(text(key + ": "))));
|
||||||
|
entry.appendChild(span(text(value)));
|
||||||
|
container.appendChild(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderAttachmentReason(attachment) {
|
||||||
|
var container = div();
|
||||||
|
|
||||||
|
container.classList.add('attachment-reason');
|
||||||
|
container.appendChild(mkSpamImgElement(attachment));
|
||||||
|
|
||||||
|
var things = {
|
||||||
|
'mimetype': attachment['mimetype'],
|
||||||
|
'time stamp': attachment['time_stamp'],
|
||||||
|
'md5': attachment['md5_hash'],
|
||||||
|
'phash raw': BigInt(attachment['phash']).toString(2),
|
||||||
|
'phash (hex)': hexArrayFromBuffer(unpackBytes(BigInt(attachment['phash']))),
|
||||||
|
//'distance': hammingDistance(unpackBytes(BigInt(attachment['phash'])), unpackBytes(BigInt(attachment['phash']))),
|
||||||
|
'distance': hammingDistance(unpackBytes(BigInt(attachment['phash'])), unpackBytes(BigInt(0))),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
container.appendChild(renderThings(things));
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,12 +490,10 @@ function renderReasons(post) {
|
||||||
reasonDetailsContainer.className = 'reason-details';
|
reasonDetailsContainer.className = 'reason-details';
|
||||||
|
|
||||||
if (reasonDetails.frequent_attachment_details) {
|
if (reasonDetails.frequent_attachment_details) {
|
||||||
var attachmentList = ul();
|
|
||||||
reasonDetails.frequent_attachment_details.forEach(function (attachment) {
|
|
||||||
attachmentList.appendChild(li(text(attachment.filename)));
|
|
||||||
});
|
|
||||||
reasonDetailsContainer.appendChild(h4(text('Previously posted matching attachments:')));
|
reasonDetailsContainer.appendChild(h4(text('Previously posted matching attachments:')));
|
||||||
reasonDetailsContainer.appendChild(div(attachmentList));
|
reasonDetails.frequent_attachment_details.forEach(function (attachment) {
|
||||||
|
reasonDetailsContainer.appendChild(renderAttachmentReason(attachment));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reasonDetails.frequent_text_details) {
|
if (reasonDetails.frequent_text_details) {
|
||||||
|
@ -562,14 +549,14 @@ function renderOverviewPost(post) {
|
||||||
var postContainer = renderPostElem(post);
|
var postContainer = renderPostElem(post);
|
||||||
postContainer.appendChild(h3(text('Reasons:')));
|
postContainer.appendChild(h3(text('Reasons:')));
|
||||||
postContainer.appendChild(div(renderReasonsUl(post)));
|
postContainer.appendChild(div(renderReasonsUl(post)));
|
||||||
|
postContainer.classList.add('post--overview');
|
||||||
return postContainer;
|
return postContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadKnownSpamPosts() {
|
function loadKnownSpamPosts() {
|
||||||
pageInfoText.innerText = 'Loading known spam post';
|
pageInfoText.innerText = 'Loading all known spam posts...';
|
||||||
cancelGlobalEvts();
|
cancelGlobalEvts();
|
||||||
|
|
||||||
//var url = GlobalVars.settings.postgrest_url + '/known_spam_post?select=*,known_spam_attachments(*)'
|
|
||||||
var url = GlobalVars.settings.postgrest_url + '/known_spam_post?select=*,known_spam_post_attachment(*)'
|
var url = GlobalVars.settings.postgrest_url + '/known_spam_post?select=*,known_spam_post_attachment(*)'
|
||||||
var headers = {
|
var headers = {
|
||||||
'Authorization': 'Bearer ' + GlobalVars.settings.jwt
|
'Authorization': 'Bearer ' + GlobalVars.settings.jwt
|
||||||
|
@ -578,8 +565,7 @@ function loadKnownSpamPosts() {
|
||||||
get(url, cancel, headers)
|
get(url, cancel, headers)
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
var json = JSON.parse(response);
|
var json = JSON.parse(response);
|
||||||
console.log("results for", url, json);
|
console.log("results for", url, response);
|
||||||
//console.log("have known spam images:", json);
|
|
||||||
pageInfoText.innerText = 'Have these known spam posts:';
|
pageInfoText.innerText = 'Have these known spam posts:';
|
||||||
var mainElem = document.querySelector('main');
|
var mainElem = document.querySelector('main');
|
||||||
mainElem.innerHTML = '';
|
mainElem.innerHTML = '';
|
||||||
|
@ -597,88 +583,6 @@ function loadKnownSpamPosts() {
|
||||||
.catch(caught.bind(this, "Failed to load known spam posts. Reason:"));
|
.catch(caught.bind(this, "Failed to load known spam posts. Reason:"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadInfo(info_hash) {
|
|
||||||
var preLoad_executed = false;
|
|
||||||
var page = document.createElement('div');
|
|
||||||
|
|
||||||
function preLoad() {
|
|
||||||
if (preLoad_executed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
preLoad_executed = true;
|
|
||||||
keepElements(['style', '.info']);
|
|
||||||
pageInfoText.innerText = info_hash;
|
|
||||||
document.querySelector('main').appendChild(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureElementExist('style.loading');
|
|
||||||
pageInfoText.innerText = 'Loading info for ' + info_hash;
|
|
||||||
|
|
||||||
cancelGlobalEvts();
|
|
||||||
|
|
||||||
get('/cgi-bin/files?i=' + info_hash, cancel)
|
|
||||||
.then(function(response) {
|
|
||||||
preLoad();
|
|
||||||
var files = parseTable(response);
|
|
||||||
console.log(files);
|
|
||||||
var h = document.createElement('h2');
|
|
||||||
h.innerText = 'Contents';
|
|
||||||
page.appendChild(h);
|
|
||||||
var t = renderTree(files);
|
|
||||||
page.appendChild(t);
|
|
||||||
})
|
|
||||||
.catch(caught.bind(this, "Failed to info details. Reason:"));
|
|
||||||
|
|
||||||
get('/cgi-bin/info?i=' + info_hash, cancel)
|
|
||||||
.then(function(response) {
|
|
||||||
preLoad();
|
|
||||||
var info = parseTable(response)[0];
|
|
||||||
pageInfoText.innerText = info.name;
|
|
||||||
var first_seen = new Date(info.added.split('.')[0]+'Z');
|
|
||||||
var mlink = magnet(info);
|
|
||||||
mlink.innerText = mlink.href;
|
|
||||||
|
|
||||||
var last_seen = new Date(Math.min(
|
|
||||||
invertScore(Number(info.score)) * 1000,
|
|
||||||
new Date().getTime())
|
|
||||||
);
|
|
||||||
|
|
||||||
prepend(page, div(text('First Indexed: ' + first_seen)));
|
|
||||||
prepend(page, div(text('Approximately last seen: ' + last_seen)));
|
|
||||||
var filecount = div(text('Files: '));
|
|
||||||
filecount.appendChild(bold(text(info.filecount)))
|
|
||||||
prepend(page, filecount);
|
|
||||||
var total_size = div(text('Total Size: '));
|
|
||||||
total_size.appendChild(bold(text(info.total_size)))
|
|
||||||
prepend(page, total_size);
|
|
||||||
prepend(page, div(mlink));
|
|
||||||
})
|
|
||||||
.catch(caught.bind(this, "Failed to load file list. Details:"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadResults(search_query) {
|
|
||||||
var encoder = new TextEncoder();
|
|
||||||
var hex = bytesToHex(encoder.encode(search_query));
|
|
||||||
console.log(hex);
|
|
||||||
cancelGlobalEvts();
|
|
||||||
ensureElementExist('style.loading');
|
|
||||||
pageInfoText.innerText = 'Loading results for "' + search_query + '"...';
|
|
||||||
get('/cgi-bin/search?q=' + hex, cancel)
|
|
||||||
.then(function(response) {
|
|
||||||
CurrentScore = currentScore();
|
|
||||||
console.log("Current score:", CurrentScore);
|
|
||||||
|
|
||||||
var t = assembleTable(parseTable(response));
|
|
||||||
var document_root = document.querySelector('main');
|
|
||||||
|
|
||||||
keepElements(['style', '.info'])
|
|
||||||
pageInfoText.innerText = 'Results for "' + search_query + '"';
|
|
||||||
document_root.appendChild(t);
|
|
||||||
})
|
|
||||||
.catch(caught.bind(this, "Failed to results: "));
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeUrl(path, search_query, push_state) {
|
function changeUrl(path, search_query, push_state) {
|
||||||
var event = new CustomEvent(
|
var event = new CustomEvent(
|
||||||
'urlchange',
|
'urlchange',
|
||||||
|
@ -694,7 +598,7 @@ function changeUrl(path, search_query, push_state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePageRoot(_, query_params) {
|
function handlePageRoot(_, query_params) {
|
||||||
console.log("handlePageRoot", query_params);
|
console.log("handlePageRoot", JSON.stringify(query_params));
|
||||||
return loadKnownSpamPosts();
|
return loadKnownSpamPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -759,23 +663,6 @@ function showSpamPost(path_data, _) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSearch(_, query_params) {
|
|
||||||
var search_query = query_params.q;
|
|
||||||
|
|
||||||
if (!search_query) {
|
|
||||||
console.log("nothing to query");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
console.log(search_query);
|
|
||||||
loadResults(search_query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInfo(parts, query_params) {
|
|
||||||
console.log('info request', parts, query_params);
|
|
||||||
loadInfo(parts[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onUrlChange(e) {
|
function onUrlChange(e) {
|
||||||
var path = e.detail.path.split('/').filter(function(s){ return s.length; });
|
var path = e.detail.path.split('/').filter(function(s){ return s.length; });
|
||||||
console.log(e, e.detail, path);
|
console.log(e, e.detail, path);
|
||||||
|
|
|
@ -14,7 +14,7 @@ header {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post:hover {
|
.post--overview:hover {
|
||||||
background-color: #FFEEEE;
|
background-color: #FFEEEE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ header {
|
||||||
}
|
}
|
||||||
|
|
||||||
.post--body_container,
|
.post--body_container,
|
||||||
|
.attachment-reason,
|
||||||
.attachment {
|
.attachment {
|
||||||
display: flow-root;
|
display: flow-root;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue