Благодарим за выбор нашего сервиса!
Тестовое сообщение
Страница: 1
Сообщений 1 страница 8 из 8
Поделиться22026-06-16 20:38:43
Код:
(function () {
const FORUM_ID = 2;
let characters = [];
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/api.php?method=post.get&topic_id=${t.id}&limit=1`)
.then(r => r.json())
)
);
})
.then(postsArray => {
characters = postsArray.map(r => {
const html = r.response?.[0]?.message || "";
// создаём временный DOM
const temp = document.createElement("div");
temp.innerHTML = html;
const name =
temp.querySelector(".m-name")?.innerText.trim() || "NO NAME";
const face =
temp.querySelector(".m-face")?.innerText.trim() || "";
const gender =
temp.querySelector(".m-gender")?.innerText.trim() || "";
return { name, face, gender };
});
console.log("CHARACTERS:", characters);
render(characters);
});
function render(chars) {
const root = document.getElementById("faces-root");
if (!root) return;
root.innerHTML = chars
.map(c => `<div>${c.name} — ${c.face} — ${c.gender}</div>`)
.join("");
}
})();
Поделиться32026-06-21 16:36:43
Код:
<script type="text/javascript">
(function () {
const FORUM_ID = 2;
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/api.php?method=post.get&topic_id=${t.id}&limit=1`)
.then(r => r.json())
)
);
})
.then(postsArray => {
const characters = postsArray.map(r => {
const html = r.response?.[0]?.message || "";
const temp = document.createElement("div");
temp.innerHTML = html;
const name =
temp.querySelector(".m-name")?.innerText.trim() || "NO NAME";
const face =
temp.querySelector(".m-face")?.innerText.trim() || "";
const gender =
temp.querySelector(".m-gender")?.innerText.trim().toLowerCase() || "";
return { name, face, gender };
});
console.log("ALL CHARACTERS:", characters);
// 💥 нормализация пола
const maleWords = ["м", "муж", "мужской", "male", "man", "m"];
const femaleWords = ["ж", "жен", "женский", "female", "woman", "f"];
const males = [];
const females = [];
characters.forEach(c => {
const g = c.gender;
if (femaleWords.includes(g)) {
females.push(c);
} else if (maleWords.includes(g)) {
males.push(c);
} else {
females.push(c);
}
});
render(males, females);
});
function render(males, females) {
const root = document.getElementById("faces-root");
if (!root) return;
root.innerHTML = `
<div class="faces-wrapper">
<div class="faces-column">
<h2>Мужские внешности</h2>
${males.map(c => `
<div class="face-item">
${c.name} — ${c.face}
</div>
`).join("")}
</div>
<div class="faces-column">
<h2>Женские внешности</h2>
${females.map(c => `
<div class="face-item">
${c.name} — ${c.face}
</div>
`).join("")}
</div>
</div>
`;
}
})();
</script>Поделиться42026-06-21 16:59:35
Код:
<script type="text/javascript">
(function () {
const FORUM_ID = 2;
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/api.php?method=post.get&topic_id=${t.id}&limit=1`)
.then(r => r.json())
)
);
})
.then(postsArray => {
const characters = postsArray.map(r => {
let html = r.response?.[0]?.message || "";
// 💥 чистим html от <p> и [html]
html = html
.replace(/\[html\]|\[\/html\]/gi, "")
.replace(/<p>/gi, "")
.replace(/<\/p>/gi, "")
.replace(/ /gi, " ");
const temp = document.createElement("div");
temp.innerHTML = html;
const name =
temp.querySelector(".m-name")?.innerText.trim() || "NO NAME";
const face =
temp.querySelector(".m-face")?.innerText.trim() || "";
const gender =
temp.querySelector(".m-gender")?.innerText.trim().toLowerCase() || "";
return { name, face, gender };
});
console.log("ALL:", characters);
// 💥 варианты пола
const maleWords = ["м", "муж", "мужской", "male", "man", "m"];
const femaleWords = ["ж", "жен", "женский", "female", "woman", "f"];
const males = [];
const females = [];
characters.forEach(c => {
const g = c.gender;
if (femaleWords.includes(g)) {
females.push(c);
} else if (maleWords.includes(g)) {
males.push(c);
} else {
females.push(c);
}
});
render(males, females);
});
// 💥 группировка по буквам
function groupByLetters(list) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = c.face.trim().charAt(0).toLowerCase();
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
function renderColumn(title, list) {
const sorted = list.sort((a, b) => {
const cleanA = a.face.trim().toLowerCase();
const cleanB = b.face.trim().toLowerCase();
return cleanA.localeCompare(cleanB, 'en', { sensitivity: 'base' });
});
const groups = groupByLetters(sorted);
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([group, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${group}</div>
${items.map(c => `
<div class="face-item">
${c.face} — ${c.name}
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
function render(males, females) {
const root = document.getElementById("faces-root");
if (!root) return;
root.innerHTML = `
<div class="faces-wrapper">
${renderColumn("Мужские внешности", males)}
${renderColumn("Женские внешности", females)}
</div>
`;
}
})();
</script>Поделиться52026-06-21 19:43:54
Код:
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
const FORUM_ID = 2;
const CACHE_KEY = `faces_cache_forum_${FORUM_ID}`;
const CACHE_TTL = 1000 * 60 * 60;
let isLoading = false;
const root = document.getElementById("faces-root");
if (!root) {
console.error("❌ НЕТ <div id='faces-root'></div>");
return;
}
console.log("SCRIPT STARTED");
// ======================
// START (CACHE OR LOAD)
// ======================
try {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const parsed = JSON.parse(cached);
if (Date.now() - parsed.time < CACHE_TTL) {
console.log("CACHE HIT");
render(parsed.data.males, parsed.data.females);
} else {
load();
}
} else {
load();
}
} catch (e) {
console.warn("CACHE ERROR", e);
load();
}
// ======================
// LOAD API
// ======================
function load() {
if (isLoading) return;
isLoading = true;
console.log("LOADING API...");
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/api.php?method=post.get&topic_id=${t.id}&limit=1`)
.then(r => r.json())
)
);
})
.then(postsArray => {
const characters = postsArray.map(r => {
let html = r.response?.[0]?.message || "";
const temp = document.createElement("div");
temp.innerHTML = html;
return {
name: temp.querySelector(".m-name")?.innerText.trim() || "NO NAME",
face: temp.querySelector(".m-face")?.innerText.trim() || "",
gender: (temp.querySelector(".m-gender")?.innerText || "").toLowerCase()
};
}).filter(c => c.face);
const males = [];
const females = [];
const maleWords = ["м", "муж", "male", "man", "m"];
const femaleWords = ["ж", "жен", "female", "woman", "f"];
characters.forEach(c => {
if (femaleWords.includes(c.gender)) females.push(c);
else if (maleWords.includes(c.gender)) males.push(c);
else females.push(c);
});
localStorage.setItem(CACHE_KEY, JSON.stringify({
time: Date.now(),
data: { males, females }
}));
console.log("RENDER");
render(males, females);
isLoading = false;
})
.catch(err => {
console.error("API ERROR", err);
isLoading = false;
});
}
// ======================
// GROUPING
// ======================
function groupByLetters(list) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = (c.face || "").trim().charAt(0).toLowerCase();
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
function renderColumn(title, list) {
const sorted = list.slice().sort((a, b) =>
(a.face || "").toLowerCase().localeCompare((b.face || "").toLowerCase())
);
const groups = groupByLetters(sorted);
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([group, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${group}</div>
${items.map(c => `
<div class="face-item">
${c.face} — ${c.name}
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
// ======================
// RENDER + BUTTON
// ======================
function render(males, females) {
const malesColumn = document.getElementById("males-column");
const femalesColumn = document.getElementById("females-column");
malesColumn.innerHTML = renderColumn("Мужские внешности", males);
femalesColumn.innerHTML = renderColumn("Женские внешности", females);
document.getElementById("faces-refresh-btn").onclick = () => {
localStorage.removeItem(CACHE_KEY);
load();
};
}
});
</script>Поделиться62026-06-21 21:51:15
Код:
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
const FORUM_ID = 2;
const CACHE_KEY = `faces_cache_forum_${FORUM_ID}`;
const CACHE_TTL = 1000 * 60 * 60;
let isLoading = false;
const root = document.getElementById("faces-root");
if (!root) {
console.error("❌ НЕТ faces-root");
return;
}
console.log("SCRIPT STARTED");
// ======================
// CACHE
// ======================
try {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const parsed = JSON.parse(cached);
if (Date.now() - parsed.time < CACHE_TTL) {
console.log("CACHE HIT");
render(parsed.data.males, parsed.data.females);
} else {
load();
}
} else {
load();
}
} catch (e) {
console.warn("CACHE ERROR", e);
load();
}
// ======================
// LOAD
// ======================
function load() {
if (isLoading) return;
isLoading = true;
console.log("LOADING TOPICS...");
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
console.log("TOPICS TEST:", topics[0]); // 🔥 TEST 1
return Promise.all(
topics.map(t =>
fetch(`/viewtopic.php?id=${t.id}`)
.then(r => r.text())
.then(html => {
const temp = document.createElement("div");
temp.innerHTML = html;
// ======================
// ПЕРВЫЙ ПОСТ ТЕМЫ
// ======================
const firstPost = temp.querySelector(".post");
// ======================
// ID АВТОРА
// ======================
const userId = firstPost?.dataset?.userId;
console.log("DEBUG USER ID:", userId, "TOPIC:", t.id); // 🔥 TEST 2
// ======================
// АНКЕТНЫЕ ДАННЫЕ
// ======================
return {
id: userId,
name: temp.querySelector(".m-name")?.innerText.trim() || "NO NAME",
face: temp.querySelector(".m-face")?.innerText.trim() || "",
gender: (temp.querySelector(".m-gender")?.innerText || "").toLowerCase()
};
})
)
);
})
.then(results => {
const characters = results
.filter(Boolean)
.filter(c => c.face);
console.log("CHARACTERS TEST:", characters[0]); // 🔥 TEST 3
const males = [];
const females = [];
const maleWords = ["м", "муж", "male", "man", "m"];
const femaleWords = ["ж", "жен", "female", "woman", "f"];
characters.forEach(c => {
if (femaleWords.includes(c.gender)) females.push(c);
else if (maleWords.includes(c.gender)) males.push(c);
else females.push(c);
});
localStorage.setItem(CACHE_KEY, JSON.stringify({
time: Date.now(),
data: { males, females }
}));
render(males, females);
isLoading = false;
})
.catch(err => {
console.error("API ERROR", err);
isLoading = false;
});
}
// ======================
// GROUPING
// ======================
function groupByLetters(list) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = (c.face || "").trim().charAt(0).toLowerCase();
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
// ======================
// RENDER
// ======================
function renderColumn(title, list) {
const sorted = list.slice().sort((a, b) =>
(a.face || "").toLowerCase().localeCompare((b.face || "").toLowerCase())
);
const groups = groupByLetters(sorted);
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([group, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${group}</div>
${items.map(c => `
<div class="face-item">
<a href="/profile.php?id=${c.id}">
${c.face} — ${c.name}
</a>
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
function render(males, females) {
root.innerHTML = `
<div style="display:flex; justify-content:flex-end; margin-bottom:10px;">
<button id="faces-refresh-btn">Обновить</button>
</div>
<div class="faces-wrapper">
<div class="faces-columns">
${renderColumn("Мужские внешности", males)}
${renderColumn("Женские внешности", females)}
</div>
</div>
`;
document.getElementById("faces-refresh-btn").onclick = () => {
localStorage.removeItem(CACHE_KEY);
load();
};
}
});
</script>Поделиться72026-06-22 20:14:17
Код:
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
const FORUM_ID = 2;
const root = document.getElementById("names-root");
if (!root) {
console.error("❌ НЕТ names-root");
return;
}
console.log("NAMES SCRIPT STARTED");
// ======================
// SPLIT NAME
// ======================
function splitName(fullName) {
const parts = fullName.trim().split(/\s+/);
return {
firstName: parts[0] || "",
lastName: parts.slice(1).join(" ") || ""
};
}
// ======================
// LOAD DATA
// ======================
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/viewtopic.php?id=${t.id}`)
.then(r => r.text())
.then(html => {
const temp = document.createElement("div");
temp.innerHTML = html;
const firstPost = temp.querySelector(".post");
const userId = firstPost?.dataset?.userId;
const fullName = temp.querySelector(".m-name")?.innerText.trim() || "";
const { firstName, lastName } = splitName(fullName);
return {
id: userId,
fullName,
firstName: firstName.toLowerCase(),
lastName: lastName.toLowerCase()
};
})
)
);
})
.then(characters => {
// ======================
// УБИРАЕМ ПУСТОЕ
// ======================
characters = characters.filter(c => c.fullName);
// ======================
// УНИКАЛЬНЫЕ ИМЕНА
// ======================
const firstNames = [];
const lastNames = [];
characters.forEach(c => {
if (c.firstName) {
firstNames.push({
key: c.firstName,
label: c.fullName,
id: c.id
});
}
if (c.lastName) {
lastNames.push({
key: c.lastName,
label: c.fullName,
id: c.id
});
}
});
render(firstNames, lastNames);
});
// ======================
// GROUP
// ======================
function groupByLetters(list) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = (c.key || "").charAt(0);
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
// ======================
// COLUMN
// ======================
function renderColumn(title, list) {
const sorted = list.sort((a, b) =>
a.key.localeCompare(b.key)
);
const groups = groupByLetters(sorted);
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([group, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${group}</div>
${items.map(c => `
<div class="face-item">
<a href="/profile.php?id=${c.id}">
${c.key} — ${c.label}
</a>
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
// ======================
// RENDER
// ======================
function render(firstNames, lastNames) {
root.innerHTML = `
<div class="faces-wrapper">
<div class="faces-columns">
${renderColumn("Имена", firstNames)}
${renderColumn("Фамилии", lastNames)}
</div>
</div>
`;
}
});
</script>
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
const FORUM_ID = 2;
const CACHE_KEY = `faces_cache_forum_${FORUM_ID}`;
const CACHE_TTL = 1000 * 60 * 60;
let isLoading = false;
const root = document.getElementById("faces-root");
if (!root) {
console.error("❌ НЕТ faces-root");
return;
}
console.log("SCRIPT STARTED");
// ======================
// CACHE
// ======================
try {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const parsed = JSON.parse(cached);
if (Date.now() - parsed.time < CACHE_TTL) {
console.log("CACHE HIT");
render(parsed.data.males, parsed.data.females);
} else {
load();
}
} else {
load();
}
} catch (e) {
console.warn("CACHE ERROR", e);
load();
}
// ======================
// LOAD
// ======================
function load() {
if (isLoading) return;
isLoading = true;
console.log("LOADING TOPICS...");
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
console.log("TOPICS TEST:", topics[0]); // 🔥 TEST 1
return Promise.all(
topics.map(t =>
fetch(`/viewtopic.php?id=${t.id}`)
.then(r => r.text())
.then(html => {
const temp = document.createElement("div");
temp.innerHTML = html;
// ======================
// ПЕРВЫЙ ПОСТ ТЕМЫ
// ======================
const firstPost = temp.querySelector(".post");
// ======================
// ID АВТОРА
// ======================
const userId = firstPost?.dataset?.userId;
console.log("DEBUG USER ID:", userId, "TOPIC:", t.id); // 🔥 TEST 2
// ======================
// АНКЕТНЫЕ ДАННЫЕ
// ======================
return {
id: userId,
name: temp.querySelector(".m-name")?.innerText.trim() || "NO NAME",
face: temp.querySelector(".m-face")?.innerText.trim() || "",
gender: (temp.querySelector(".m-gender")?.innerText || "").toLowerCase()
};
})
)
);
})
.then(results => {
const characters = results
.filter(Boolean)
.filter(c => c.face);
// ======================
// ДУБЛИ ВНЕШНОСТЕЙ
// ======================
const faceCount = {};
characters.forEach(c => {
const key = (c.face || "").toLowerCase().trim();
faceCount[key] = (faceCount[key] || 0) + 1;
});
characters.forEach(c => {
const key = (c.face || "").toLowerCase().trim();
c.isDuplicate = faceCount[key] > 1;
});
console.log("CHARACTERS TEST:", characters[0]); // 🔥 TEST 3
const males = [];
const females = [];
const maleWords = ["м", "муж", "male", "man", "m"];
const femaleWords = ["ж", "жен", "female", "woman", "f"];
characters.forEach(c => {
if (femaleWords.includes(c.gender)) females.push(c);
else if (maleWords.includes(c.gender)) males.push(c);
else females.push(c);
});
localStorage.setItem(CACHE_KEY, JSON.stringify({
time: Date.now(),
data: { males, females }
}));
render(males, females);
isLoading = false;
})
.catch(err => {
console.error("API ERROR", err);
isLoading = false;
});
}
// ======================
// GROUPING
// ======================
function groupByLetters(list) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = (c.face || "").trim().charAt(0).toLowerCase();
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
// ======================
// RENDER
// ======================
function renderColumn(title, list) {
const sorted = list.slice().sort((a, b) =>
(a.face || "").toLowerCase().localeCompare((b.face || "").toLowerCase())
);
const groups = groupByLetters(sorted);
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([group, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${group}</div>
${items.map(c => `
<div class="face-item">
<a href="/profile.php?id=${c.id}">
${c.face}${c.isDuplicate ? " ★" : ""} — ${c.name}
</a>
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
function render(males, females) {
root.innerHTML = `
<div style="display:flex; justify-content:flex-end; margin-bottom:10px;">
<button id="faces-refresh-btn">Обновить</button>
</div>
<div class="faces-wrapper">
<div class="faces-columns">
${renderColumn("Мужские внешности", males)}
${renderColumn("Женские внешности", females)}
</div>
</div>
`;
document.getElementById("faces-refresh-btn").onclick = () => {
localStorage.removeItem(CACHE_KEY);
load();
};
}
});
</script>
Поделиться82026-06-22 20:36:53
Код:
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", function () {
const FORUM_ID = 2;
const CACHE_KEY = `characters_cache_${FORUM_ID}`;
const CACHE_TTL = 1000 * 60 * 60;
const facesRoot = document.getElementById("faces-root");
const namesRoot = document.getElementById("names-root");
if (!facesRoot && !namesRoot) return;
console.log("SCRIPT STARTED");
// ======================
// CACHE
// ======================
try {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const parsed = JSON.parse(cached);
if (Date.now() - parsed.time < CACHE_TTL) {
renderAll(parsed.data);
} else {
load();
}
} else {
load();
}
} catch (e) {
console.warn("CACHE ERROR", e);
load();
}
// ======================
// HELPERS
// ======================
function getField(root, cls) {
return (root?.querySelector(`.${cls}`)?.innerText || "").trim();
}
// ======================
// LOAD DATA
// ======================
function load() {
console.log("LOADING...");
fetch(`/api.php?method=topic.get&forum_id=${FORUM_ID}`)
.then(r => r.json())
.then(d => {
const topics = d.response || [];
return Promise.all(
topics.map(t =>
fetch(`/viewtopic.php?id=${t.id}`)
.then(r => r.text())
.then(html => {
const temp = document.createElement("div");
temp.innerHTML = html;
const firstPost = temp.querySelector(".post");
const userId = firstPost?.dataset?.userId;
const ank = temp.querySelector(".m-ank");
const name = getField(ank, "m-name");
const face = getField(ank, "m-face");
// 💥 ВАЖНО: берём ВСЁ как текст (обход битой кодировки)
const genderRaw = (ank?.innerText || "").toLowerCase();
return {
id: userId,
name,
face,
genderRaw
};
})
)
);
})
.then(characters => {
characters = characters.filter(c => c.face || c.name);
// ======================
// ДУБЛИ ВНЕШНОСТЕЙ
// ======================
const faceCount = {};
characters.forEach(c => {
const key = (c.face || "").toLowerCase().trim();
faceCount[key] = (faceCount[key] || 0) + 1;
});
characters.forEach(c => {
const key = (c.face || "").toLowerCase().trim();
c.isDuplicate = faceCount[key] > 1;
});
// ======================
// ПОЛ (СТАБИЛЬНО ЧЕРЕЗ TEXT)
// ======================
const males = [];
const females = [];
const maleWords = ["м", "муж", "male", "man"];
const femaleWords = ["ж", "жен", "female", "woman"];
characters.forEach(c => {
const g = c.genderRaw;
if (femaleWords.some(w => g.includes(w))) {
females.push(c);
} else if (maleWords.some(w => g.includes(w))) {
males.push(c);
} else {
females.push(c); // дефолт
}
});
// ======================
// ИМЕНА / ФАМИЛИИ
// ======================
const firstNames = [];
const lastNames = [];
characters.forEach(c => {
const parts = (c.name || "").split(/\s+/);
const first = (parts[0] || "").toLowerCase();
const last = (parts.slice(1).join(" ") || "").toLowerCase();
if (first) {
firstNames.push({ key: first, label: c.name, id: c.id });
}
if (last) {
lastNames.push({ key: last, label: c.name, id: c.id });
}
});
const data = { males, females, firstNames, lastNames };
localStorage.setItem(CACHE_KEY, JSON.stringify({
time: Date.now(),
data
}));
renderAll(data);
})
.catch(err => {
console.error("API ERROR", err);
});
}
// ======================
// GROUPING
// ======================
function groupByLetters(list, keyName) {
const groups = {
"a-b-c-d": [],
"e-f-g-h": [],
"i-j-k-l": [],
"m-n-o-p": [],
"q-r-s-t": [],
"u-v-w-x-y-z": []
};
list.forEach(c => {
const first = (c[keyName] || "")
.trim()
.charAt(0)
.toLowerCase();
if ("abcd".includes(first)) groups["a-b-c-d"].push(c);
else if ("efgh".includes(first)) groups["e-f-g-h"].push(c);
else if ("ijkl".includes(first)) groups["i-j-k-l"].push(c);
else if ("mnop".includes(first)) groups["m-n-o-p"].push(c);
else if ("qrst".includes(first)) groups["q-r-s-t"].push(c);
else groups["u-v-w-x-y-z"].push(c);
});
return groups;
}
// ======================
// RENDER FACES
// ======================
function renderFaces(root, males, females) {
function column(title, list) {
const sorted = list.slice().sort((a, b) =>
(a.face || "").localeCompare(b.face || "")
);
const groups = groupByLetters(sorted, "face");
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([g, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${g}</div>
${items.map(c => `
<div class="face-item">
<a href="/profile.php?id=${c.id}">
${c.face}${c.isDuplicate ? " ★" : ""} — ${c.name}
</a>
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
root.innerHTML = `
<div style="display:flex; justify-content:flex-end; margin-bottom:10px;">
<button id="refresh-all">Обновить</button>
</div>
<div class="faces-wrapper">
<div class="faces-columns">
${column("Мужские внешности", males)}
${column("Женские внешности", females)}
</div>
</div>
`;
}
// ======================
// RENDER NAMES
// ======================
function renderNames(root, firstNames, lastNames) {
function column(title, list) {
const sorted = list.slice().sort((a, b) =>
a.key.localeCompare(b.key)
);
const groups = groupByLetters(sorted, "key");
return `
<div class="faces-column">
<h2>${title}</h2>
${Object.entries(groups).map(([g, items]) => {
if (!items.length) return "";
return `
<div class="face-group">
<div class="face-letter">${g}</div>
${items.map(c => `
<div class="face-item">
<a href="/profile.php?id=${c.id}">
${c.key} — ${c.label}
</a>
</div>
`).join("")}
</div>
`;
}).join("")}
</div>
`;
}
root.innerHTML = `
<div class="faces-wrapper">
<div class="faces-columns">
${column("Имена", firstNames)}
${column("Фамилии", lastNames)}
</div>
</div>
`;
}
// ======================
// RENDER ALL
// ======================
function renderAll(data) {
if (facesRoot) {
renderFaces(facesRoot, data.males, data.females);
}
if (namesRoot) {
renderNames(namesRoot, data.firstNames, data.lastNames);
}
const btn = document.getElementById("refresh-all");
if (btn) {
btn.onclick = () => {
localStorage.removeItem(CACHE_KEY);
load();
};
}
}
});
</script>Страница: 1