RSSreader.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>超RSSニュースリーダー</title>
  <style>
    body {
      font-family: "Segoe UI", sans-serif;
      background: #f4f4f4;
      margin: 0;
      padding: 20px;
    }
    h1 {
      text-align: center;
      color: #222;
    }
    #search {
      display: block;
      margin: 10px auto;
      padding: 10px;
      width: 80%;
      font-size: 16px;
      border-radius: 8px;
      border: 1px solid #ccc;
    }
    #feeds {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 20px;
    }
    .feed-card {
      background: white;
      border-radius: 12px;
      box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      width: 320px;
      padding: 12px;
      box-sizing: border-box;
    }
    .feed-card img {
      width: 100%;
      height: auto;
      border-radius: 8px;
      margin-bottom: 10px;
    }
    .feed-card h2 {
      font-size: 16px;
      margin: 0 0 5px;
    }
    .feed-card p {
      font-size: 14px;
      color: #555;
    }
    .feed-card time {
      display: block;
      font-size: 12px;
      color: #999;
      margin-top: 5px;
    }
  </style>
</head>
<body>
  <h1>超RSSニュースリーダー</h1>
  <input type="text" id="search" placeholder="記事を検索...">

  <div id="feeds"></div>

  <script>
    const rssUrls = [
      "https://news.yahoo.co.jp/rss/topics/top-picks.xml",
      "https://b.hatena.ne.jp/hotentry/it.rss",
      "https://www.nhk.or.jp/rss/news/cat0.xml",
      "http://tyosuke20xx.com/rss"
    ];
    const proxy = "https://api.allorigins.win/get?url=";
    const feedsContainer = document.getElementById("feeds");
    const searchInput = document.getElementById("search");

    let allCards = [];

    function formatDate(pubDateStr) {
      const date = new Date(pubDateStr);
      return isNaN(date) ? "" : `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
    }

    function extractImageFromDescription(desc) {
      const match = desc.match(/<img.*?src="(.*?)"/);
      return match ? match[1] : null;
    }

    async function fetchAndDisplayFeeds() {
      feedsContainer.innerHTML = "🔄 更新中…";
      allCards = [];

      for (const url of rssUrls) {
        try {
          const res = await fetch(proxy + encodeURIComponent(url));
          const data = await res.json();
          const parser = new DOMParser();
          const xml = parser.parseFromString(data.contents, "text/xml");
          const items = xml.querySelectorAll("item");

          items.forEach((item, i) => {
            if (i >= 5) return;

            const title = item.querySelector("title")?.textContent || "";
            const link = item.querySelector("link")?.textContent || "#";
            const desc = item.querySelector("description")?.textContent || "";
            const pubDate = item.querySelector("pubDate")?.textContent || "";
            const dateFormatted = formatDate(pubDate);
            const img = extractImageFromDescription(desc);

            const card = document.createElement("div");
            card.className = "feed-card";
            card.innerHTML = `
              ${img ? `<img src="${img}" alt="thumbnail">` : ""}
              <h2><a href="${link}" target="_blank">${title}</a></h2>
              <p>${desc.replace(/<[^>]+>/g, '').slice(0, 100)}...</p>
              <time>${dateFormatted}</time>
            `;
            allCards.push({ title, desc, element: card });
            feedsContainer.appendChild(card);
          });
        } catch (e) {
          console.error("RSS取得失敗:", url, e);
        }
      }
    }

    searchInput.addEventListener("input", () => {
      const keyword = searchInput.value.toLowerCase();
      feedsContainer.innerHTML = "";
      allCards.forEach(({ title, desc, element }) => {
        if (title.toLowerCase().includes(keyword) || desc.toLowerCase().includes(keyword)) {
          feedsContainer.appendChild(element);
        }
      });
    });

    fetchAndDisplayFeeds();
    setInterval(fetchAndDisplayFeeds, 60000); // 60秒ごと自動更新
  </script>
</body>
</html>

投稿者: chosuke

趣味はゲームやアニメや漫画などです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です