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

1
Админ
Постов: 162
2
Элита
Постов: 45
3
VIP
Постов: 35
4
Проверенные
Постов: 31
5
Проверенные
Постов: 30
6
Пользователи
Постов: 27
7
VIP
Постов: 26
8
Пользователи
Постов: 24

  • Страница 1 из 1
  • 1
Парсер новостей карточек последних тем UCOZ V2.5
Дата: Воскресенье, 09.11.2025, 20:27 | Сообщение # 1 | | Написал: Узнаваемый
Автор темы
Мурчанн не в сети
        Сообщений:162
         Регистрация:20.10.2016

Тут полное описание как работает Парсер.

Описание работы Парсера



Код
<style>

/* Контейнер */
#custom-forum-cards {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  justify-content: flex-start;
  width: 100%;

  /* Отступ снизу под последним рядом карточек */
  margin-bottom: -25px; /* <- здесь можно регулировать отступы */
}

/* Карточка с эффектом DVD-диска */
.custom-card {
  flex: 0 0 calc(25% - 15px);
  box-sizing: border-box;
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  color: #fff;
  cursor: pointer;
  text-decoration: none;
margin-bottom: 10px; /* вертикальный отступ между рядами */

  /* Основной фон + блики */
  background: radial-gradient(circle at 30% 20%, #2a2a2a 0%, #141414 80%);
  background-image:
    radial-gradient(circle at 50% 10%, rgba(255,255,255,0.28) 0%, transparent 60%),
    radial-gradient(circle at 30% 80%, rgba(255,255,255,0.08) 0%, transparent 70%),
    radial-gradient(circle at 80% 30%, rgba(133,91,151,0.1) 0%, transparent 70%);
  background-blend-mode: screen;

  border: 1px solid rgba(255,255,255,0.06);

  /* Глубокие тени и выпуклость */
  box-shadow:
    inset 0 4px 8px rgba(255,255,255,0.18),
    inset 0 -6px 12px rgba(0,0,0,0.9),
    0 12px 30px rgba(0,0,0,0.95),
    0 0 35px rgba(133,91,151,0.35);

  transform: perspective(600px) translateZ(0);
  transition: transform 0.4s ease, box-shadow 0.4s ease, border-color 0.4s ease;
}

.custom-card:hover {
  transform: translateY(-0px);
  box-shadow:
    inset 0 3px 6px rgba(255,255,255,0.15),
    inset 0 -6px 14px rgba(0,0,0,0.85),
    0 24px 50px rgba(0,0,0,0.9),
    0 0 50px rgba(133,91,151,0.45);
  border-color: #855b97;
}

/* Верхняя обложка «DVD-крышка» */
.custom-card-header {
  position: absolute;
  top: -25px;
  left: 0;
  width: 100%;
  height: 50px;
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  background: linear-gradient(145deg, #5b85a1 0%, #855b97 50%, #2a2a2a 100%);
  box-shadow: inset 0 4px 6px rgba(255,255,255,0.2),
              inset 0 -4px 6px rgba(0,0,0,0.6),
              0 2px 6px rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  pointer-events: none;
  font-size: 12px;
  font-weight: bold;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
}

/* Текст внутри крышки (его можно двигать) */
.custom-card-header-text {
  display: inline-block;
  transform: translate(var(--header-text-x, 0px), var(--header-text-y, 0px));
}

/* Обложка темы с учетом верхней крышки */
.custom-card-img {
  width: 100%;
  height: 170px;
  overflow: hidden;
  position: relative;
  border-bottom: 1px solid #333;
  margin-top: 20px; /* отступ, чтобы крышка не перекрывала */
}

.custom-card-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s ease, filter 0.4s ease;
}

.custom-card:hover .custom-card-img img {
  transform: scale(1.08);
  filter: brightness(1.1);
}

/* Заголовок карточки */
.custom-card-title {
  font-weight: 700;
  font-size: 14px;
  padding: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 3px rgba(0,0,0,0.8), 0 0 6px rgba(255,255,255,0.1);
}

/* Краткое описание */
.custom-card-desc {
  font-size: 12px;
  color: #ccc;
  padding: 0 10px 10px 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 6;
  -webkit-box-orient: vertical;
  white-space: normal;
  opacity: 0.9;
  text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}

/* Бейдж */
.custom-card-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  background: linear-gradient(135deg,#855b97,#5b85a1);
  padding: 4px 8px;
  border-radius: 8px;
  font-size: 11px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  box-shadow: 0 0 12px rgba(133,59,151,0.7), inset 0 1px 2px rgba(255,255,255,0.25);
}

/* Эффект затемнения при наведении (сильный) */
.custom-card::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0); /* изначально прозрачный */
  transition: background-color 0.3s ease;
  pointer-events: none;
  border-radius: 14px; /* чтобы совпадало с радиусом карточки */
}

.custom-card:hover::after {
  background-color: rgba(0, 0, 0, 0.6); /* сильное затемнение */
}

/* Контейнер для теней */
.dark-border {
  overflow: visible !important;
  position: relative;
  z-index: 2;
  background: transparent;
}
</style>

<section class="sect flex-grow-1">
<div class="sect__header d-flex">
<h2 class="sect__title flex-grow-1">
Forum Updates
<img src="https://jordan.moy.su/forumimages/3droom.png" alt="3D Room Icon" style="height:24px; margin-left:-2px; vertical-align:middle;">
</h2>
</div>

<div class="dark-border">
<div id="custom-forum-cards"></div>
</div>
</section>

<script>
(async function() {
  const container = document.querySelector('#custom-forum-cards');
  if (!container) return;

  const forumListUrl = '/forum/0-0-1-34';
  const MAX_CARDS = 8;
  const CACHE_KEY = 'forum_cards_cache';
  const CACHE_TIME = 30 * 60 * 1000; // 30 минут

  // Функция для рендера карточек
  function renderCards(cards) {
    container.innerHTML = '';
    cards.forEach(parsed => {
      const title = parsed.title || 'Без названия';
      const desc = parsed.text || '';
      const img = parsed.img || '/forumimages/Newsletter-3.png';

      const card = document.createElement('a');
      card.className = 'custom-card';
      card.href = parsed.href;
      card.target = '_self';
      card.innerHTML = `
        <div class="custom-card-header">
          <div class="custom-card-header-text" style="--header-text-x: 0px; --header-text-y: 8px;">
            Forum Updates
          </div>
        </div>
        <div class="custom-card-img">
          <img src="${img}" alt="${title}">
          <div class="custom-card-badge">Новое</div>
        </div>
        <div class="custom-card-title">${title}</div>
        <div class="custom-card-desc">${desc}</div>
      `;
      container.appendChild(card);
    });
  }

  // Функция для загрузки HTML
  async function fetchHTML(url) {
    const res = await fetch(url);
    return await res.text();
  }

  // Парсинг списка тем
  function parseThreadsFromList(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const arr = [];
    const items = doc.querySelectorAll('.threadNametd .threadLink');
    for (let i = 0; i < items.length && arr.length < MAX_CARDS; i++) {
      const a = items[i];
      const titleEl = a.querySelector('.ipsType_pagetitle') || a;
      const title = (titleEl && titleEl.textContent || '').trim();
      let href = a.getAttribute('href') || a.href || '';
      if (href && !href.startsWith('http')) {
        href = window.location.origin + (href.startsWith('/') ? href : '/' + href);
      }
      if (href) arr.push({ href, title });
    }
    return arr;
  }

  // Парсинг первого поста каждой темы
  function parseFirstPost(html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const post = doc.querySelector('.post_content, .post_body, .post, .ipsType_richText');
    let text = '', img = '';
    if (post) {
      text = post.textContent.trim().substring(0, 89);
      const imgEl = post.querySelector('img');
      if (imgEl) {
        img = imgEl.getAttribute('src') || '';
        if (img && !img.startsWith('http')) {
          const base = window.location.origin;
          img = img.startsWith('/') ? (base + img) : (base + '/' + img);
        }
      }
    }
    return { text, img };
  }

  // Проверка кэша
  const cached = localStorage.getItem(CACHE_KEY);
  if (cached) {
    const data = JSON.parse(cached);
    const now = Date.now();
    if (now - data.time < CACHE_TIME) {
      renderCards(data.cards);
      return;
    }
  }

  // Загрузка и рендер
  try {
    const listHtml = await fetchHTML(forumListUrl);
    const threads = parseThreadsFromList(listHtml);

    const promises = threads.map(t =>
      fetchHTML(t.href)
        .then(html => ({ ...t, ...parseFirstPost(html) }))
        .catch(() => null)
    );

    const results = (await Promise.all(promises)).filter(Boolean);

    localStorage.setItem(CACHE_KEY, JSON.stringify({ time: Date.now(), cards: results }));

    renderCards(results);
  } catch (e) {
    console.error('Ошибка:', e);
  }
})();
</script>

Мурчанн

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