#113 - RSS Feeds v0.2

Use a Webflow UI to display an RSS feed directly on your Website.

Ver demostración

<!-- 💙 MEMBERSCRIPT #113 v0.2 💙 - RSS FEEDS IN WEBFLOW -->
<script>
(function() {
  // console.log('RSS Feed Script starting...');

  const CORS_PROXIES = [
    'https://corsproxy.io/?',
    'https://api.allorigins.win/raw?url=',
    'https://cors-anywhere.herokuapp.com/',
    'https://thingproxy.freeboard.io/fetch/',
    'https://yacdn.org/proxy/'
  ];

  function loadScript(src, onLoad, onError) {
    const script = document.createElement('script');
    script.src = src;
    script.onload = onLoad;
    script.onerror = onError;
    document.head.appendChild(script);
  }

  async function fetchWithFallback(url) {
    for (const proxy of CORS_PROXIES) {
      try {
        const response = await fetch(proxy + encodeURIComponent(url));
        if (response.ok) {
          return await response.text();
        }
      } catch (error) {
        console.warn(`Failed to fetch with proxy ${proxy}:`, error);
      }
    }
    throw new Error('All CORS proxies failed');
  }

  function initRSSFeed() {
    if (typeof RSSParser === 'undefined') {
      console.error('RSSParser is not defined.');
      return;
    }

    const parser = new RSSParser({
      customFields: {
        item: [
          ['media:content', 'mediaContent', {keepArray: true}],
          ['media:thumbnail', 'mediaThumbnail', {keepArray: true}],
          ['enclosure', 'enclosure', {keepArray: true}],
        ]
      }
    });

    document.querySelectorAll('[ms-code-rss-feed]').forEach(element => {
      const url = element.getAttribute('ms-code-rss-url');
      const limit = parseInt(element.getAttribute('ms-code-rss-limit')) || 5;

      fetchWithFallback(url)
        .then(str => parser.parseString(str))
        .then(feed => {
          renderRSSItems(element, feed.items.slice(0, limit), {
            showImage: element.getAttribute('ms-code-rss-show-image') !== 'false',
            showDate: element.getAttribute('ms-code-rss-show-date') !== 'false',
            dateFormat: element.getAttribute('ms-code-rss-date-format') || 'short',
            target: element.getAttribute('ms-code-rss-target') || '_self'
          });
        })
        .catch(err => {
          console.error('Error fetching or parsing RSS feed:', err);
          element.textContent = `Failed to load RSS feed from ${url}. Error: ${err.message}`;
        });
    });
  }

  function renderRSSItems(element, items, options) {
    const templateItem = element.querySelector('[ms-code-rss-item]');
    if (!templateItem) return;

    element.innerHTML = ''; // Clear existing items

    items.forEach(item => {
      const itemElement = templateItem.cloneNode(true);

      const title = itemElement.querySelector('[ms-code-rss-title]');
      if (title) {
        const titleLength = parseInt(title.getAttribute('ms-code-rss-title-length')) || Infinity;
        title.textContent = truncate(item.title, titleLength);
      }

      const description = itemElement.querySelector('[ms-code-rss-description]');
      if (description) {
        const descriptionLength = parseInt(description.getAttribute('ms-code-rss-description-length')) || Infinity;
        description.textContent = truncate(stripHtml(item.content || item.description), descriptionLength);
      }

      const date = itemElement.querySelector('[ms-code-rss-date]');
      if (date && options.showDate && item.pubDate) {
        date.textContent = formatDate(new Date(item.pubDate), options.dateFormat);
      }

      const img = itemElement.querySelector('[ms-code-rss-image]');
      if (img && options.showImage) {
        const imgUrl = getImageUrl(item);
        if (imgUrl) {
          img.src = imgUrl;
          img.alt = item.title;
          img.removeAttribute('srcset');
        }
      }

      const linkElement = itemElement.querySelector('[ms-code-rss-link]');
      if (linkElement) {
        linkElement.setAttribute('href', item.link);
        linkElement.setAttribute('target', options.target);
      }

      element.appendChild(itemElement);
    });
  }

  function getImageUrl(item) {
    const sources = ['mediaContent', 'mediaThumbnail', 'enclosure'];
    for (let source of sources) {
      if (item[source] && item[source][0]) {
        return item[source][0].$ ? item[source][0].$.url : item[source][0].url;
      }
    }
    return null;
  }

  function truncate(str, length) {
    if (!str) return '';
    if (length === Infinity) return str;
    return str.length > length ? str.slice(0, length) + '...' : str;
  }

  function stripHtml(html) {
    const tmp = document.createElement('DIV');
    tmp.innerHTML = html || '';
    return tmp.textContent || tmp.innerText || '';
  }

  function formatDate(date, format) {
    if (!(date instanceof Date) || isNaN(date)) return '';
    const options = format === 'long' ? 
          { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' } : 
    undefined;
    return format === 'relative' ? getRelativeTimeString(date) : date.toLocaleDateString(undefined, options);
  }

  function getRelativeTimeString(date, lang = navigator.language) {
    const timeMs = date.getTime();
    const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);
    const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];
    const units = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'];
    const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));
    const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
    const rtf = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' });
    return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
  }

  loadScript('https://cdn.jsdelivr.net/npm/rss-parser@3.12.0/dist/rss-parser.min.js', initRSSFeed, () => {
    console.error('Error loading RSS Parser script');
    loadScript('https://unpkg.com/rss-parser@3.12.0/dist/rss-parser.min.js', initRSSFeed, () => {
      console.error('Error loading RSS Parser script from backup CDN');
    });
  });

})();
</script>

Creación del escenario Make.com

1. Descargue el proyecto JSON a continuación para empezar.

2. Navegue hasta Make.com y Cree un nuevo escenario...

3. Haga clic en el pequeño cuadro con 3 puntos y luego Importar Blueprint...

4. Sube tu archivo y ¡voilá! Ya está listo para vincular sus propias cuentas.

¿Necesitas ayuda con este MemberScript?

Todos los clientes de Memberstack pueden solicitar asistencia en el Slack 2.0. Tenga en cuenta que no se trata de funciones oficiales y que no se puede garantizar la asistencia.

Únete al Slack 2.0
Notas de la versión

v0.2 - CORS Proxy Rotation

Changed the script to try multiple different CORS proxies if one fails or is slow.

Atributos
Descripción
Atributo
No se han encontrado artículos.
Guías / Tutoriales
No se han encontrado artículos.
Tutorial
¿Qué es Memberstack?

Autenticación y pagos para sitios Webflow

Añada inicios de sesión, suscripciones, contenido cerrado y mucho más a su sitio Webflow: fácil y totalmente personalizable.

Más información