Список пользователей

1
Админ
Постов: 288
2
VIP
Постов: 75
3
Элита
Постов: 62
4
Проверенные
Постов: 46
5
Проверенные
Постов: 45
6
Проверенные
Постов: 39
7
VIP
Постов: 36
8
VIP
Постов: 35

  • Страница 1 из 1
  • 1
Парсер горячих тем - на главную планшета со стилиусом UCOZ
Дата: Пятница, 24.10.2025, 23:04 | Сообщение # 1 | | Написал: Известный
Автор темы
Мурчанн не в сети
        Сообщений:288
         Регистрация:20.10.2016
За уважение окружающих За уважение окружающих За хорошее поведение За преданность форуму За любовь народа

Легкая имитация планшета со стилусом. Это вторая версия модификации парсера. По сути, парсер скрыт за стильным планшетом, а сам скрипт остаётся лёгким и простым: он работает автономно и создаёт визуальные эффекты без какой-либо серверной или сторонней поддержки. Если кого-то раздражает частое обновление, интервал можно легко изменить , например, установить обновление раз в 6 часов.

В принципе, можно реализовать скрытое обновление парсера, при котором пользователь ничего не заметит визуально.
Это называется «скрытая подгрузка с плавной подменой контента» или иногда «lazy update».

Идея проста:

Сначала отображается старый контент или заглушка.

Скрипт в фоне загружает новые данные.

Когда всё готово — старый контент мгновенно заменяется новым, без мигания и визуальной перегрузки.

Такое поведение легко реализуется с помощью CSS и JavaScript.



Код
<!-- <body> -->
<section class="sect flex-grow-1">
<div class="sect__header d-flex">
<h2 class="sect__title flex-grow-1">Горячая тема</h2>

<style>
/* Неоновая сиреневая обёртка */
.nf-dark-border {
position: relative;
border: 1px solid #9D4EDD;
padding: 30px;
background-color: #0a0710;
color: #fff;
width: 850px;
margin: 40px auto;
border-radius: 12px;
box-shadow:
0 0 25px rgba(157, 78, 221, 0.7),
0 0 50px rgba(157, 78, 221, 0.5),
inset 0 0 20px rgba(157, 78, 221, 0.25);
animation: nf-neonGlow 3s ease-in-out infinite alternate;
overflow: visible;
}

/* Анимация сияния */
@keyframes nf-neonGlow {
from {
box-shadow:
0 0 15px rgba(157, 78, 221, 0.5),
0 0 30px rgba(157, 78, 221, 0.3),
inset 0 0 12px rgba(157, 78, 221, 0.15);
}
to {
box-shadow:
0 0 35px rgba(157, 78, 221, 0.9),
0 0 70px rgba(157, 78, 221, 0.7),
inset 0 0 25px rgba(157, 78, 221, 0.3);
}
}

/* Контейнер карусели */
.nf-carousel-container {
position: relative;
width: 100%;
overflow: hidden;
}

/* Трек карточек */
.nf-carousel-track {
display: flex;
transition: transform 0.5s ease;
}

/* Карточки */
.nf-card {
flex: 0 0 100%;
background: linear-gradient(145deg, #1c1122, #2a1735);
border-radius: 14px;
overflow: hidden;
display: flex;
text-decoration: none;
color: #fff;
cursor: pointer;
position: relative;
transition: box-shadow 0.3s ease, filter 0.3s ease;
min-height: 250px;
aspect-ratio: 16 / 9;
}

/* Карточка при наведении */
.nf-card:hover {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
filter: brightness(1.45); /* мягче подсветка */
}

/* Изображение */
.nf-card-img {
width: 55%;
height: 100%;
overflow: hidden;
}

.nf-card-img img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}

.nf-card:hover .nf-card-img img {
transform: scale(1.03);
}

/* Контент карточки */
.nf-card-content {
padding: 25px 30px;
display: flex;
flex-direction: column;
justify-content: flex-start; /* заголовок сверху */
width: 45%;
}

.nf-card-title {
font-weight: bold;
font-size: 26px;
margin-bottom: 20px; /* немного больше пространства */
color: #e0b3ff;
text-shadow: 0 0 10px rgba(157, 78, 221, 0.6);
}

.nf-card-desc {
font-size: 16px;
color: #d8c3f0;
line-height: 1.7;
text-align: justify;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 12; /* длиннее описание */
-webkit-box-orient: vertical;
flex-grow: 1; /* описание заполняет пространство */
}

/* Автор */
.nf-card-meta {
position: absolute;
bottom: 15px;
right: 18px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
z-index: 5;
}

.nf-card-meta img {
width: 55px;
height: 55px;
border-radius: 50%;
border: 2px solid #b367ff;
object-fit: cover;
background: #1a0e25;
box-shadow: 0 0 10px rgba(157, 78, 221, 0.6);
}

.nf-card-meta .author-nick {
font-size: 14px;
font-weight: bold;
color: #d7a7ff;
background: rgba(0, 0, 0, 0.45);
padding: 3px 10px;
border-radius: 8px;
backdrop-filter: blur(3px);
text-shadow: 0 0 6px rgba(157, 78, 221, 0.8);
}

/* Бейдж */
.nf-card-badge {
position: absolute;
top: 10px;
left: 10px;
background: linear-gradient(135deg, #b367ff, #7a3dbd);
padding: 5px 9px;
border-radius: 8px;
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.6px;
box-shadow: 0 0 12px rgba(157, 78, 221, 0.6);
}

/* Стрелки */
.nf-carousel-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 52px;
height: 52px;
background: radial-gradient(circle at center, rgba(157, 78, 221, 0.85), rgba(80, 30, 140, 0.8));
border-radius: 50%;
color: #fff;
font-size: 30px;
text-align: center;
line-height: 52px;
cursor: pointer;
user-select: none;
z-index: 20;
box-shadow: 0 0 20px rgba(157, 78, 221, 0.8), 0 0 35px rgba(157, 78, 221, 0.6);
transition: all 0.3s ease;
}

.nf-carousel-arrow:hover {
background: radial-gradient(circle at center, rgba(180, 100, 255, 0.9), rgba(100, 40, 160, 0.85));
transform: translateY(-50%) scale(1.1);
}

.nf-carousel-arrow:active {
background: rgba(157, 78, 221, 0.7);
}

.nf-carousel-arrow-left {
left: -25px;
}

.nf-carousel-arrow-right {
right: -25px;
}

/* Нижняя панель телевизора */
.nf-tv-bottom {
position: relative;
width: 100%;
height: 40px; /* высота панели */
background-color: #000; /* черная панель */
display: flex;
justify-content: center;
align-items: center;
font-family: 'Arial', sans-serif;
font-weight: bold;
font-size: 18px;
color: #fff;
letter-spacing: 2px;
text-shadow: 0 0 6px rgba(255,255,255,0.5);
border-top: 0px solid rgba(157,78,221,0.5); /* тонкая светящаяся линия сверху */
margin-top: 10px;
border-radius: 0 0 12px 12px; /* скругление как у рамки */
margin-top: 1px; /* или отрицательное значение, например -5px, чтобы поднять выше */
}

.tablet-stylus {
  position: absolute;
  
  /* Горизонтальное положение: left или right */
  left: 280px; ;        /* если хочешь слева */
  right: 100px;      /* если хочешь справа, регулируй значение */

  /* Вертикальное положение */
  top: 30%;          /* центр по высоте */
  transform: translateY(-50%) rotate(0deg) scale(1); /* центровка + угол + масштаб */

  /* Размеры */
  width: 14px;       /* толщина стилуса */
  height: 400px;     /* длина стилуса */

  /* Дизайн */
  background: linear-gradient(180deg, #ffffff, #e6e6e6);
  border-radius: 10px;
  box-shadow:
    inset 0 0 4px rgba(255,255,255,0.7),
    0 0 8px rgba(255,255,255,0.8),
    0 0 12px rgba(255,255,255,0.5);
  z-index: 10;

  /* Дополнительно для регулировки */
  /* margin-left или margin-right можно использовать для точной подстройки */
}

/* Кончик стилуса */
.tablet-stylus::after {
  content: '';
  position: absolute;
  bottom: -6px;
  left: 50%;
  transform: translateX(-50%);
  width: 8px;
  height: 8px;
  background: radial-gradient(circle at center, #ccc 20%, #999 80%);
  border-radius: 50%;
  box-shadow: 0 0 3px rgba(0,0,0,0.4);
}

</style>

<div class="nf-dark-border">
<div class="nf-carousel-container">

<div class="nf-carousel-track" id="nf-forum-cards"></div>

<!-- Нижняя панель телевизора -->
<div class="nf-tv-bottom">
<span>SAMSUNG</span>
</div>

</div>

<div class="nf-carousel-arrow nf-carousel-arrow-left">❮</div>
<div class="nf-carousel-arrow nf-carousel-arrow-right">❯</div>
</div>

<!-- Белый стилус сбоку планшета -->
<div class="tablet-stylus"></div>

<script>
(async function nfForumCarouselHot3_carousel() {
const track = document.querySelector('.nf-carousel-track');
const fallbackContainer = document.querySelector('#nf-forum-cards');
const cardsHost = track || fallbackContainer;
if (!cardsHost) return;

const arrowLeft = document.querySelector('.nf-carousel-arrow-left');
const arrowRight = document.querySelector('.nf-carousel-arrow-right');

const BASE_FORUM_URL = '/forum/0-0-1-34';
const CACHE_KEY = 'nf_forum_hot_3_clean';
const CACHE_TIME = 30 * 60 * 1000;
const MAX_CARDS = 6;

function toAbs(url){
if(!url) return '';
if(url.startsWith('http') || url.startsWith('//')) return url.startsWith('//') ? window.location.protocol + url : url;
return window.location.origin + (url.startsWith('/') ? url : '/' + url);
}

const extra = Array.from(document.querySelectorAll('#nf-forum-cards')).slice(1);
extra.forEach(e => e.remove());

function findHotInDoc(doc) {
const rows = Array.from(doc.querySelectorAll('td.threadNametd, .threadNametd, tr'));
const result = [];

for (let td of rows) {
const badge = td.querySelector('.ipsBadge');
const pages = td.querySelector('.postpSwithces, .postPSwithcesLink');
if (!((badge && /горяч/i.test(badge.textContent || '')) || pages)) continue;

const linkEl = td.querySelector('a.threadLink');
if (!linkEl) continue;

const href = toAbs(linkEl.getAttribute('href') || linkEl.href || '');
const titleEl = linkEl.querySelector('.ipsType_pagetitle') || linkEl;
const title = (titleEl && titleEl.textContent || '').trim() || '(без названия)';

const row = td.closest('tr');
let icon = row ? (row.querySelector('.threadIcoTd img') || row.querySelector('td img')) : null;
icon = icon ? icon.getAttribute('src') || icon.src : '';
icon = toAbs(icon) || '/forumimages/Newsletter-3.png';

let author = '';
const authTd = row ? row.querySelector('.threadAuthTd') : null;
if (authTd) author = authTd.textContent.trim();
if (!author) {
const authorLink = td.querySelector('a[href*="/index/"], .lastPostUser, .postUser, .author');
if (authorLink) author = authorLink.textContent.trim();
}
if (!author) author = 'Аноним';

const viewsEl = row ? row.querySelector('.threadViewTd, .views, .thread-views') : null;
let views = 0;
if (viewsEl) {
const m = (viewsEl.textContent||'').replace(/\s/g,'').match(/(\d{1,})/);
if (m) views = parseInt(m[1],10);
}

result.push({ href, title, author, icon, views });
}

const unique = [];
const seen = new Set();
for (let t of result) {
if (seen.has(t.href)) continue;
seen.add(t.href);
unique.push(t);
if (unique.length >= MAX_CARDS) break;
}
return unique;
}

async function fetchHTML(url) {
const res = await fetch(url, { credentials: 'same-origin' });
return await res.text();
}

async function enrichThread(t) {
try {
const txt = await fetchHTML(t.href);
const parser = new DOMParser();
const doc = parser.parseFromString(txt, 'text/html');

const postEl = doc.querySelector('.post_content, .post_body, .post, .ipsType_richText, .message');
const text = postEl ? (postEl.textContent || '').trim().replace(/\s+/g,' ').slice(0,200) : '';

let img = '';
if (postEl) {
const imgs = Array.from(postEl.querySelectorAll('img'));
for (let im of imgs) {
const src = im.getAttribute('ilo-full-src') || im.getAttribute('data-src') || im.src || '';
if (!src) continue;
if (/avatar|\/forumimages\/|\/template\//i.test(src)) continue;
img = toAbs(src);
break;
}
}

if (!img) img = t.icon;

let author = t.author;
const firstAuthor = doc.querySelector('.postUser, .author, .post-author-name');
if (firstAuthor && firstAuthor.textContent.trim()) author = firstAuthor.textContent.trim();

const avatarEl = doc.querySelector('.ipsUserPhoto, .avatar, .user-avatar img');
let avatar = avatarEl ? (avatarEl.src || '') : '/forumimages/default-avatar.png';
if (avatar && !avatar.startsWith('http')) avatar = window.location.origin + (avatar.startsWith('/') ? avatar : '/' + avatar);

return { ...t, text, img, author, avatar };
} catch (e) {
return { ...t, text: '', img: t.icon, avatar: '/forumimages/default-avatar.png' };
}
}

try {
const cached = localStorage.getItem(CACHE_KEY);
if (cached) {
const data = JSON.parse(cached);
if (Date.now() - data.time < CACHE_TIME) {
renderCarousel(data.cards);
return;
}
}
} catch(e){}

let threads = findHotInDoc(document);
if (!threads.length) {
try {
const html = await fetchHTML(BASE_FORUM_URL);
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
threads = findHotInDoc(doc);
} catch(e){ }
}

if (!threads.length) {
cardsHost.innerHTML = '<div style="color:#fff; padding:12px;">🔥 Нет горячих тем</div>';
return;
}

const cards = await Promise.all(threads.slice(0, MAX_CARDS).map(enrichThread));
try { localStorage.setItem(CACHE_KEY, JSON.stringify({ time: Date.now(), cards })); } catch(e){}

renderCarousel(cards);

function renderCarousel(cards) {
cardsHost.innerHTML = '';
const hostIsTrack = !!track;
const trackEl = hostIsTrack ? cardsHost : document.createElement('div');
if (!hostIsTrack) {
trackEl.className = 'nf-carousel-track';
cardsHost.appendChild(trackEl);
}

cards.forEach(c => {
const a = document.createElement('a');
a.className = 'nf-card';
a.href = c.href;
a.target = '_self';
a.style.flex = '0 0 100%';
a.style.boxSizing = 'border-box';

a.innerHTML = `
<div class="nf-card-img">
<img src="${c.img}" alt="${escapeHtml(c.title)}">
<div class="nf-card-badge">🔥 Горячая тема</div>
</div>
<div class="nf-card-content">
<div class="nf-card-title">${escapeHtml(c.title)}</div>
<div class="nf-card-desc">${escapeHtml(c.text || '')}</div>
<div class="nf-card-meta" style="display:flex; align-items:center; gap:8px;">
<img src="${c.avatar}" alt="${escapeHtml(c.author)}" style="width:48px; height:48px; border-radius:50%;">
<span class="author-nick">${escapeHtml(c.author)}</span>
<span class="views-count"> 🔥 ${c.views} просмотров</span>
</div>
</div>
`;
trackEl.appendChild(a);
});

if (!hostIsTrack) {
const wrap = document.querySelector('.nf-carousel-container') || cardsHost;
wrap.innerHTML = '';
wrap.appendChild(trackEl);
}

let index = 0;
const slides = Array.from(trackEl.children);
const total = slides.length;
const visibleWrap = trackEl.closest('.nf-carousel-container') || trackEl.parentElement;

function update() {
const width = visibleWrap.clientWidth || visibleWrap.getBoundingClientRect().width;
const x = -index * width;
trackEl.style.transform = `translateX(${x}px)`;
if (arrowLeft) arrowLeft.style.opacity = index === 0 ? '0.4' : '1';
if (arrowRight) arrowRight.style.opacity = index >= total - 1 ? '0.4' : '1';
}

function setSlideSizes() {
const width = visibleWrap.clientWidth || visibleWrap.getBoundingClientRect().width;
slides.forEach(s => s.style.width = width + 'px');
trackEl.style.display = 'flex';
trackEl.style.transition = 'transform 0.45s ease';
update();
}

window.addEventListener('resize', setSlideSizes);
setSlideSizes();

if (arrowLeft) arrowLeft.onclick = () => { index = Math.max(0, index - 1); update(); };
if (arrowRight) arrowRight.onclick = () => { index = Math.min(total - 1, index + 1); update(); };

let startX = null;
trackEl.addEventListener('touchstart', e => { startX = e.touches[0].clientX; }, {passive:true});
trackEl.addEventListener('touchend', e => {
if (startX === null) return;
const endX = (e.changedTouches && e.changedTouches[0].clientX) || 0;
const dx = endX - startX;
if (Math.abs(dx) > 50) {
index = dx < 0 ? Math.min(total - 1, index + 1) : Math.max(0, index - 1);
update();
}
startX = null;
}, {passive:true});

window.addEventListener('keydown', e => {
if (e.key === 'ArrowLeft') { index = Math.max(0, index - 1); update(); }
if (e.key === 'ArrowRight') { index = Math.min(total - 1, index + 1); update(); }
});
}

function escapeHtml(s){ return String(s || '').replace(/[&<>"']/g, m=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[m])); }
})();
</script>

</div>


Используем для удобства глобальные блоки 9

Код

$GLOBAL_FORUMERST$

Мурчанн

Признаюсь, не знаю почему, но глядя на звезды мне всегда хочется мечтать.
  • Страница 1 из 1
  • 1
Поиск: