mirror of
https://github.com/Ry3yr/Fake-Social-MediaWriter.git
synced 2026-08-19 17:20:03 -04:00
441 lines
13 KiB
Plaintext
441 lines
13 KiB
Plaintext
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Alcea ↔ Akkoma Match Viewer</title>
|
|
<style>
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, sans-serif;
|
|
padding: 20px;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
background-color: #f8f9fa;
|
|
color: #333;
|
|
}
|
|
h1 {
|
|
color: #2c3e50;
|
|
border-bottom: 2px solid #3498db;
|
|
padding-bottom: 10px;
|
|
}
|
|
.stats {
|
|
font-weight: bold;
|
|
margin: 20px 0;
|
|
padding: 15px;
|
|
background: #e8f4f8;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.stat-item {
|
|
display: inline-block;
|
|
margin: 0 15px;
|
|
cursor: pointer;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
transition: background-color 0.2s;
|
|
}
|
|
.stat-item:hover {
|
|
background-color: #d1e7f5;
|
|
}
|
|
.stat-count {
|
|
color: #2980b9;
|
|
font-weight: bold;
|
|
font-size: 1.2em;
|
|
}
|
|
.match {
|
|
background: white;
|
|
padding: 16px;
|
|
margin: 16px 0;
|
|
border-left: 5px solid #2ecc71;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
|
|
}
|
|
.url {
|
|
font-family: monospace;
|
|
font-size: 0.9em;
|
|
color: #7f8c8d;
|
|
margin: 8px 0;
|
|
}
|
|
.preview {
|
|
font-style: italic;
|
|
color: #555;
|
|
margin: 10px 0;
|
|
padding: 10px;
|
|
background-color: #f9f9f9;
|
|
border-left: 3px solid #bdc3c7;
|
|
}
|
|
pre {
|
|
background: #f5f5f5;
|
|
padding: 12px;
|
|
border: 1px solid #ddd;
|
|
overflow-x: auto;
|
|
border-radius: 4px;
|
|
font-size: 0.95em;
|
|
}
|
|
.match-type {
|
|
display: inline-block;
|
|
padding: 4px 10px;
|
|
border-radius: 4px;
|
|
color: white;
|
|
font-size: 0.8em;
|
|
margin-left: 10px;
|
|
background: #7f8c8d;
|
|
}
|
|
.match-type.raw { background: #27ae60; }
|
|
.match-type.normalized { background: #2ecc71; }
|
|
.match-type.noBreaks { background: #3498db; }
|
|
.match-type.loose { background: #9b59b6; }
|
|
.match-type.finalNormalized { background: #e67e22; }
|
|
.filter-active {
|
|
background-color: #d1e7f5;
|
|
box-shadow: 0 0 0 2px #3498db inset;
|
|
}
|
|
.no-matches {
|
|
text-align: center;
|
|
padding: 30px;
|
|
color: #7f8c8d;
|
|
font-style: italic;
|
|
}
|
|
.loading {
|
|
text-align: center;
|
|
padding: 30px;
|
|
color: #7f8c8d;
|
|
}
|
|
.error {
|
|
color: #c0392b;
|
|
background: #fadbd8;
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
margin: 20px 0;
|
|
}
|
|
a {
|
|
color: #2980b9;
|
|
text-decoration: none;
|
|
}
|
|
a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
.preview-link {
|
|
cursor: pointer;
|
|
color: #2980b9;
|
|
text-decoration: none;
|
|
}
|
|
.preview-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
.refresh-button {
|
|
background-color: #3498db;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin-left: 10px;
|
|
font-size: 0.9em;
|
|
}
|
|
.refresh-button:hover {
|
|
background-color: #2980b9;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h1>Compare Alcea with Akkoma</h1>
|
|
<div class="stats" id="stats">Loading data...</div>
|
|
<div id="matches"></div>
|
|
|
|
<script>
|
|
// Store the original data and matches for filtering
|
|
let allData = {
|
|
alceaEntries: [],
|
|
akkomaEntries: [],
|
|
matches: []
|
|
};
|
|
|
|
// Get filter parameters from URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const filterType = urlParams.get('filter');
|
|
const filterValue = urlParams.get('value');
|
|
|
|
// Generate cache-busting timestamp
|
|
function getCacheBustingTimestamp() {
|
|
return new Date().getTime();
|
|
}
|
|
|
|
function normalizeLineBreaks(str) {
|
|
return str.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
}
|
|
|
|
function normalizeText(str) {
|
|
return normalizeLineBreaks(str).normalize('NFC').trim();
|
|
}
|
|
|
|
function removeLineBreaks(str) {
|
|
return normalizeText(str).replace(/\n/g, '');
|
|
}
|
|
|
|
function normalizeTextCompletely(str) {
|
|
return str
|
|
.replace(/\r\n|\r/g, '\n')
|
|
.replace(/\s+/g, ' ')
|
|
.replace(/^\s+|\s+$/g, '')
|
|
.normalize('NFC');
|
|
}
|
|
|
|
async function fetchJson(url) {
|
|
// Add cache-busting parameter to URL
|
|
const cacheBuster = getCacheBustingTimestamp();
|
|
const urlWithCacheBusting = url.includes('?')
|
|
? `${url}&_=${cacheBuster}`
|
|
: `${url}?_=${cacheBuster}`;
|
|
|
|
const res = await fetch(urlWithCacheBusting);
|
|
if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);
|
|
return await res.json();
|
|
}
|
|
|
|
// Extract all entries from the nested Alcea structure
|
|
function extractAlceaEntries(alceaData) {
|
|
const entries = [];
|
|
|
|
// Handle both array and object structures
|
|
if (Array.isArray(alceaData)) {
|
|
// If it's an array, process each item
|
|
alceaData.forEach(item => {
|
|
if (typeof item === 'object' && item !== null) {
|
|
// Extract all values from date keys
|
|
Object.values(item).forEach(entry => {
|
|
if (entry && typeof entry.value === 'string' && entry.value.includes('#acws')) {
|
|
entries.push(entry);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} else if (typeof alceaData === 'object' && alceaData !== null) {
|
|
// If it's an object, extract all values
|
|
Object.values(alceaData).forEach(entry => {
|
|
if (entry && typeof entry.value === 'string' && entry.value.includes('#acws')) {
|
|
entries.push(entry);
|
|
}
|
|
});
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
function filterMatches() {
|
|
if (!filterType || !filterValue) return allData.matches;
|
|
|
|
switch(filterType) {
|
|
case 'alcea':
|
|
return allData.matches.filter(match =>
|
|
match.value.includes(filterValue) ||
|
|
match.value === filterValue
|
|
);
|
|
case 'akkoma':
|
|
return allData.matches.filter(match =>
|
|
match.preview.includes(filterValue) ||
|
|
match.url === filterValue
|
|
);
|
|
case 'type':
|
|
return allData.matches.filter(match => match.type === filterValue);
|
|
default:
|
|
return allData.matches;
|
|
}
|
|
}
|
|
|
|
function updateStats() {
|
|
const stats = document.getElementById('stats');
|
|
const filteredMatches = filterMatches();
|
|
|
|
stats.innerHTML = `
|
|
<span class="stat-item" id="alcea-stat">
|
|
Alcea entries with #acws: <span class="stat-count">${allData.alceaEntries.length}</span>
|
|
</span> |
|
|
<span class="stat-item" id="akkoma-stat">
|
|
Akkoma entries: <span class="stat-count">${allData.akkomaEntries.length}</span>
|
|
</span> |
|
|
<span class="stat-item" id="matches-stat">
|
|
Matches found: <span class="stat-count">${filteredMatches.length}</span>
|
|
</span>
|
|
${filterType ? `<br><div style="margin-top:10px;font-weight:normal;">Active filter: ${filterType} = ${filterValue} | <a href="${window.location.pathname}">Clear filter</a></div>` : ''}
|
|
<br>
|
|
<button class="refresh-button" id="refresh-data">Refresh Data</button>
|
|
`;
|
|
|
|
// Add click handlers to stats
|
|
document.getElementById('alcea-stat').addEventListener('click', () => {
|
|
window.location.href = `${window.location.pathname}?filter=alcea&value=all`;
|
|
});
|
|
|
|
document.getElementById('akkoma-stat').addEventListener('click', () => {
|
|
window.location.href = `${window.location.pathname}?filter=akkoma&value=all`;
|
|
});
|
|
|
|
document.getElementById('matches-stat').addEventListener('click', () => {
|
|
window.location.href = `${window.location.pathname}?filter=matches&value=all`;
|
|
});
|
|
|
|
// Add click handler to refresh button
|
|
document.getElementById('refresh-data').addEventListener('click', () => {
|
|
loadData();
|
|
});
|
|
|
|
// Highlight active filter
|
|
if (filterType) {
|
|
const activeElement = document.getElementById(`${filterType}-stat`);
|
|
if (activeElement) activeElement.classList.add('filter-active');
|
|
}
|
|
}
|
|
|
|
function displayMatches() {
|
|
const matchesDiv = document.getElementById('matches');
|
|
const filteredMatches = filterMatches();
|
|
|
|
if (filteredMatches.length === 0) {
|
|
matchesDiv.innerHTML = '<div class="no-matches">No matches found with the current filter.</div>';
|
|
return;
|
|
}
|
|
|
|
matchesDiv.innerHTML = '';
|
|
|
|
filteredMatches.forEach(({ type, preview, url, value }) => {
|
|
const div = document.createElement('div');
|
|
div.className = 'match';
|
|
div.innerHTML = `
|
|
<div>
|
|
<strong>Match type:</strong> ${type}
|
|
<span class="match-type ${type}">${type}</span>
|
|
</div>
|
|
<div class="url"><strong>Akkoma URL:</strong> <a href="${url}" target="_blank">${url}</a></div>
|
|
<div class="preview"><strong>Preview:</strong> <span class="preview-link" data-preview="${encodeURIComponent(preview)}">${preview}</span></div>
|
|
<div><strong>Alcea value snippet:</strong>
|
|
<pre>${value.slice(0, 500)}${value.length > 500 ? '...' : ''}</pre>
|
|
</div>
|
|
<div style="margin-top: 10px; font-size: 0.9em;">
|
|
<a href="?filter=alcea&value=${encodeURIComponent(value)}">Filter by this Alcea entry</a> |
|
|
<a href="?filter=akkoma&value=${encodeURIComponent(url)}">Filter by this Akkoma entry</a> |
|
|
<a href="?filter=type&value=${type}">Filter by match type (${type})</a>
|
|
</div>
|
|
`;
|
|
matchesDiv.appendChild(div);
|
|
});
|
|
|
|
const previewLinks = document.querySelectorAll('.preview-link');
|
|
previewLinks.forEach(link => {
|
|
link.addEventListener('click', function() {
|
|
// Get the value of the Alcea entry (instead of previewText)
|
|
//const value = this.closest('.match').querySelector('pre').textContent.trim();
|
|
const value = this.closest('.match').querySelector('pre').innerHTML.trim(); // Using innerHTML here
|
|
|
|
|
|
// Replace newline characters with CRLF
|
|
const formattedText = value.replace(/\n/g, '\r\n');
|
|
|
|
// Slice to the first 40 characters
|
|
const slicedValue = formattedText.slice(0, 40);
|
|
|
|
// Encode the sliced and formatted value for the URL
|
|
const commentLoadUrl = `https://alceawis.de/other/extra/scripts/fakesocialmedia/commentload.html?number=10000&text=${encodeURIComponent(slicedValue)}`;
|
|
|
|
// Open the comment load URL in a new window
|
|
window.open(commentLoadUrl, '_blank');
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
async function loadData() {
|
|
const stats = document.getElementById('stats');
|
|
const matchesDiv = document.getElementById('matches');
|
|
|
|
stats.innerHTML = 'Loading data...';
|
|
matchesDiv.innerHTML = '<div class="loading">Loading data...</div>';
|
|
|
|
try {
|
|
const [alceaJson, akkomaJson] = await Promise.all([
|
|
fetchJson('/other/extra/scripts/fakesocialmedia/data_alcea.json'),
|
|
fetchJson('/other/extra/scripts/fakesocialmedia/0ld/data_akkoma.json')
|
|
]);
|
|
|
|
// Extract Alcea entries from the nested structure
|
|
allData.alceaEntries = extractAlceaEntries(alceaJson);
|
|
|
|
// Akkoma: extract previews
|
|
allData.akkomaEntries = Array.isArray(akkomaJson) ? akkomaJson : Object.values(akkomaJson);
|
|
allData.matches = [];
|
|
|
|
for (const alcea of allData.alceaEntries) {
|
|
const value = alcea.value;
|
|
const rawValue = value;
|
|
const normValue = normalizeText(value);
|
|
const noBreaksValue = removeLineBreaks(value);
|
|
const normValueCompletely = normalizeTextCompletely(value);
|
|
|
|
let matched = false;
|
|
|
|
for (const akkoma of allData.akkomaEntries) {
|
|
if (!akkoma.preview) continue;
|
|
|
|
const rawPreview = akkoma.preview;
|
|
const normPreview = normalizeText(rawPreview);
|
|
const noBreaksPreview = removeLineBreaks(rawPreview);
|
|
const normPreviewCompletely = normalizeTextCompletely(rawPreview);
|
|
const url = akkoma.url;
|
|
|
|
if (rawValue.startsWith(rawPreview)) {
|
|
allData.matches.push({ type: 'raw', preview: rawPreview, url, value });
|
|
matched = true;
|
|
break;
|
|
}
|
|
if (normValue.startsWith(normPreview)) {
|
|
allData.matches.push({ type: 'normalized', preview: rawPreview, url, value });
|
|
matched = true;
|
|
break;
|
|
}
|
|
if (noBreaksValue.startsWith(noBreaksPreview)) {
|
|
allData.matches.push({ type: 'noBreaks', preview: rawPreview, url, value });
|
|
matched = true;
|
|
break;
|
|
}
|
|
|
|
const indexInNorm = normValue.indexOf(normPreview);
|
|
if (indexInNorm >= 0 && indexInNorm <= 30) {
|
|
allData.matches.push({ type: 'loose', preview: rawPreview, url, value });
|
|
matched = true;
|
|
break;
|
|
}
|
|
|
|
const indexInNormCompletely = normValueCompletely.indexOf(normPreviewCompletely);
|
|
if (indexInNormCompletely >= 0 && indexInNormCompletely <= 30) {
|
|
allData.matches.push({ type: 'finalNormalized', preview: rawPreview, url, value });
|
|
matched = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
updateStats();
|
|
displayMatches();
|
|
|
|
} catch (err) {
|
|
stats.textContent = '❌ Error loading or processing data';
|
|
stats.className = 'error';
|
|
matchesDiv.innerHTML = `
|
|
<div class="error">
|
|
<p><strong>Error Details:</strong></p>
|
|
<p>${err.message}</p>
|
|
<p>Check the browser console for more information.</p>
|
|
</div>
|
|
`;
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
// Start loading data when page loads
|
|
loadData();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|