The Google gadget is back and running

 


It seems Google has finally gotten around to fixing its Blogs I Follow gadget! The original issue was that it had completely stopped updating. You can read my previous post to see the workaround I used while waiting for the folks at Google to address the problem.

Below is the code I used to bring back the official Blogs I Follow gadget while hiding the temporary HTML/JavaScript fix.

To keep things organized, I saved both code snippets in OpenOffice. That way, if Google's gadget ever breaks again, it’s a quick copy and paste to deploy the temporary fix, and another simple copy and paste to switch back once it's resolved.

Note: The only change you will need to make is replacing my followed blog URLs with your own. I detailed step-by-step instructions on how to do this in the post linked above. Also you do this at your own risk. 


 HTML

<div style="display: none;">

  <div id="blogger-bloglist-feed">
    <p style="font-size: 0.9em; color: #ffffff; margin: 0;">Loading blog updates...</p>
  </div>

  <style>
    .bloglist-item {
      margin-bottom: 14px !important;
      padding-bottom: 10px !important;
      border-bottom: 1px dashed rgba(255, 255, 255, 0.3) !important;
      font-family: inherit !important;
    }
    /* Blog Name */
    .bloglist-name {
      display: block !important;
      font-size: 1.05em !important;
      font-weight: bold !important;
      color: #ffffff !important;
      margin-bottom: 4px !important;
      line-height: 1.3 !important;
    }
    /* Article Post Title Link */
    a.bloglist-link,
    a.bloglist-link:visited {
      display: block !important;
      font-size: 1.0em !important;
      font-weight: normal !important;
      color: #ffffff !important;
      text-decoration: none !important;
      line-height: 1.3 !important;
    }
    a.bloglist-link:hover {
      text-decoration: underline !important;
    }
    /* Updated Date */
    .bloglist-date {
      font-size: 0.85em !important;
      color: #ffffff !important;
      margin-top: 3px !important;
      display: block !important;
      opacity: 0.9 !important;
    }
  </style>

  <script>
    (function() {
      var followedFeeds = [
        "http://ae5x.blogspot.com/feeds/posts/default",
        "https://www.kb6nu.com/feed/",
        "http://w2lj.blogspot.com/feeds/posts/default",
        "http://pa1b-qrp.blogspot.com/feeds/posts/default",
        "https://ve7sar.blogspot.com/feeds/posts/default",
        "https://swling.com/blog/feed/",
        "https://www.arrl.org/arrl.rss",
        "http://ve3clq.blogspot.com/feeds/posts/default",
        "https://wb3gck.com/feed/",
        "https://tommcquiggan.blogspot.com/feeds/posts/default",
        "http://ve3vn.blogspot.com/feeds/posts/default",
        "https://ke9v.net/feed.xml",
        "https://kg3v.com/feed/",
        "http://offgridham.com/feed/",
        "http://pe4bas.blogspot.com/feeds/posts/default",
        "https://qrper.com/feed/",
        "https://www.amateurradio.com/feed/",
        "https://k9zw.wordpress.com/feed/"
      ];

      var container = document.getElementById("blogger-bloglist-feed");
      var loadedCount = 0;
      var items = [];

      // Helper function to fetch feeds that rss2json fails to parse
      async function fetchXmlFallback(feedUrl) {
        try {
          var proxyUrl = "https://api.allorigins.win/get?url=" + encodeURIComponent(feedUrl);
          var res = await fetch(proxyUrl);
          var data = await res.json();
          if (!data.contents) return null;
          
          var parser = new DOMParser();
          var xmlDoc = parser.parseFromString(data.contents, "text/xml");
          var item = xmlDoc.querySelector("item") || xmlDoc.querySelector("entry");
          if (!item) return null;
          
          var title = item.querySelector("title") ? item.querySelector("title").textContent : "Untitled";
          var link = item.querySelector("link") ? item.querySelector("link").textContent : "#";
          
          if (!link || link.trim() === "") {
            link = item.querySelector("link") ? item.querySelector("link").getAttribute("href") : "#";
          }
          
          var dateStr = item.querySelector("pubDate") ? item.querySelector("pubDate").textContent :
                        (item.querySelector("published") ? item.querySelector("published").textContent :
                        (item.querySelector("updated") ? item.querySelector("updated").textContent : ""));
                        
          var blogTitle = (xmlDoc.querySelector("channel > title") ? xmlDoc.querySelector("channel > title").textContent :
                          (xmlDoc.querySelector("feed > title") ? xmlDoc.querySelector("feed > title").textContent : "Blog"));
                          
          var pubDateObj = new Date(dateStr);
          return {
            blogTitle: blogTitle,
            title: title,
            link: link,
            date: pubDateObj,
            dateStr: isNaN(pubDateObj) ? "" : pubDateObj.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
          };
        } catch (e) {
          return null;
        }
      }

      followedFeeds.forEach(function(feedUrl) {
        var apiUrl = "https://api.rss2json.com/v1/api.json?rss_url=" + encodeURIComponent(feedUrl);
        fetch(apiUrl)
          .then(function(res) { return res.json(); })
          .then(async function(data) {
            if (data.status === "ok" && data.items && data.items.length > 0) {
              var blogTitle = data.feed.title || "Blog";
              var latestPost = data.items[0];
              var pubDateObj = new Date(latestPost.pubDate);
              items.push({
                blogTitle: blogTitle,
                title: latestPost.title,
                link: latestPost.link,
                date: pubDateObj,
                dateStr: isNaN(pubDateObj) ? "" : pubDateObj.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
              });
            } else {
              var fallbackItem = await fetchXmlFallback(feedUrl);
              if (fallbackItem) items.push(fallbackItem);
            }
          })
          .catch(async function(err) {
            var fallbackItem = await fetchXmlFallback(feedUrl);
            if (fallbackItem) items.push(fallbackItem);
          })
          .finally(function() {
            loadedCount++;
            if (loadedCount === followedFeeds.length) {
              if (items.length > 0) {
                items.sort(function(a, b) { return b.date - a.date; });
                var htmlBuffer = "";
                items.forEach(function(item) {
                  htmlBuffer += '<div class="bloglist-item">';
                  htmlBuffer += '<span class="bloglist-name">' + item.blogTitle + '</span>';
                  htmlBuffer += '<a class="bloglist-link" href="' + item.link + '" target="_blank" rel="noopener">' + item.title + '</a>';
                  if (item.dateStr) {
                    htmlBuffer += '<span class="bloglist-date">Updated: ' + item.dateStr + '</span>';
                  }
                  htmlBuffer += '</div>';
                });
                container.innerHTML = htmlBuffer;
              } else {
                container.innerHTML = "<p style='font-size:0.85em; color: #ffffff;'>No recent updates available.</p>";
              }
            }
          });
      });
    })();
  </script>

</div>

Mike Weir, VE9KK, is a regular contributor to AmateurRadio.com and writes from New Brunswick, Canada. Contact him at [email protected].

Leave a Comment

Subscribe FREE to AmateurRadio.com's
Amateur Radio Newsletter
News, Opinion, Giveaways & More!

E-mail 
Join over 7,000 subscribers!
We never share your e-mail address.



Also available via RSS feed, Twitter, and Facebook.

The Google gadget is back and running

 


It seems Google has finally gotten around to fixing its Blogs I Follow gadget! The original issue was that it had completely stopped updating. You can read my previous post to see the workaround I used while waiting for the folks at Google to address the problem.

Below is the code I used to bring back the official Blogs I Follow gadget while hiding the temporary HTML/JavaScript fix.

To keep things organized, I saved both code snippets in OpenOffice. That way, if Google's gadget ever breaks again, it’s a quick copy and paste to deploy the temporary fix, and another simple copy and paste to switch back once it's resolved.

Note: The only change you will need to make is replacing my followed blog URLs with your own. I detailed step-by-step instructions on how to do this in the post linked above. Also you do this at your own risk. 


 HTML

<div style="display: none;">

  <div id="blogger-bloglist-feed">
    <p style="font-size: 0.9em; color: #ffffff; margin: 0;">Loading blog updates...</p>
  </div>

  <style>
    .bloglist-item {
      margin-bottom: 14px !important;
      padding-bottom: 10px !important;
      border-bottom: 1px dashed rgba(255, 255, 255, 0.3) !important;
      font-family: inherit !important;
    }
    /* Blog Name */
    .bloglist-name {
      display: block !important;
      font-size: 1.05em !important;
      font-weight: bold !important;
      color: #ffffff !important;
      margin-bottom: 4px !important;
      line-height: 1.3 !important;
    }
    /* Article Post Title Link */
    a.bloglist-link,
    a.bloglist-link:visited {
      display: block !important;
      font-size: 1.0em !important;
      font-weight: normal !important;
      color: #ffffff !important;
      text-decoration: none !important;
      line-height: 1.3 !important;
    }
    a.bloglist-link:hover {
      text-decoration: underline !important;
    }
    /* Updated Date */
    .bloglist-date {
      font-size: 0.85em !important;
      color: #ffffff !important;
      margin-top: 3px !important;
      display: block !important;
      opacity: 0.9 !important;
    }
  </style>

  <script>
    (function() {
      var followedFeeds = [
        "http://ae5x.blogspot.com/feeds/posts/default",
        "https://www.kb6nu.com/feed/",
        "http://w2lj.blogspot.com/feeds/posts/default",
        "http://pa1b-qrp.blogspot.com/feeds/posts/default",
        "https://ve7sar.blogspot.com/feeds/posts/default",
        "https://swling.com/blog/feed/",
        "https://www.arrl.org/arrl.rss",
        "http://ve3clq.blogspot.com/feeds/posts/default",
        "https://wb3gck.com/feed/",
        "https://tommcquiggan.blogspot.com/feeds/posts/default",
        "http://ve3vn.blogspot.com/feeds/posts/default",
        "https://ke9v.net/feed.xml",
        "https://kg3v.com/feed/",
        "http://offgridham.com/feed/",
        "http://pe4bas.blogspot.com/feeds/posts/default",
        "https://qrper.com/feed/",
        "https://www.amateurradio.com/feed/",
        "https://k9zw.wordpress.com/feed/"
      ];

      var container = document.getElementById("blogger-bloglist-feed");
      var loadedCount = 0;
      var items = [];

      // Helper function to fetch feeds that rss2json fails to parse
      async function fetchXmlFallback(feedUrl) {
        try {
          var proxyUrl = "https://api.allorigins.win/get?url=" + encodeURIComponent(feedUrl);
          var res = await fetch(proxyUrl);
          var data = await res.json();
          if (!data.contents) return null;
          
          var parser = new DOMParser();
          var xmlDoc = parser.parseFromString(data.contents, "text/xml");
          var item = xmlDoc.querySelector("item") || xmlDoc.querySelector("entry");
          if (!item) return null;
          
          var title = item.querySelector("title") ? item.querySelector("title").textContent : "Untitled";
          var link = item.querySelector("link") ? item.querySelector("link").textContent : "#";
          
          if (!link || link.trim() === "") {
            link = item.querySelector("link") ? item.querySelector("link").getAttribute("href") : "#";
          }
          
          var dateStr = item.querySelector("pubDate") ? item.querySelector("pubDate").textContent :
                        (item.querySelector("published") ? item.querySelector("published").textContent :
                        (item.querySelector("updated") ? item.querySelector("updated").textContent : ""));
                        
          var blogTitle = (xmlDoc.querySelector("channel > title") ? xmlDoc.querySelector("channel > title").textContent :
                          (xmlDoc.querySelector("feed > title") ? xmlDoc.querySelector("feed > title").textContent : "Blog"));
                          
          var pubDateObj = new Date(dateStr);
          return {
            blogTitle: blogTitle,
            title: title,
            link: link,
            date: pubDateObj,
            dateStr: isNaN(pubDateObj) ? "" : pubDateObj.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
          };
        } catch (e) {
          return null;
        }
      }

      followedFeeds.forEach(function(feedUrl) {
        var apiUrl = "https://api.rss2json.com/v1/api.json?rss_url=" + encodeURIComponent(feedUrl);
        fetch(apiUrl)
          .then(function(res) { return res.json(); })
          .then(async function(data) {
            if (data.status === "ok" && data.items && data.items.length > 0) {
              var blogTitle = data.feed.title || "Blog";
              var latestPost = data.items[0];
              var pubDateObj = new Date(latestPost.pubDate);
              items.push({
                blogTitle: blogTitle,
                title: latestPost.title,
                link: latestPost.link,
                date: pubDateObj,
                dateStr: isNaN(pubDateObj) ? "" : pubDateObj.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
              });
            } else {
              var fallbackItem = await fetchXmlFallback(feedUrl);
              if (fallbackItem) items.push(fallbackItem);
            }
          })
          .catch(async function(err) {
            var fallbackItem = await fetchXmlFallback(feedUrl);
            if (fallbackItem) items.push(fallbackItem);
          })
          .finally(function() {
            loadedCount++;
            if (loadedCount === followedFeeds.length) {
              if (items.length > 0) {
                items.sort(function(a, b) { return b.date - a.date; });
                var htmlBuffer = "";
                items.forEach(function(item) {
                  htmlBuffer += '<div class="bloglist-item">';
                  htmlBuffer += '<span class="bloglist-name">' + item.blogTitle + '</span>';
                  htmlBuffer += '<a class="bloglist-link" href="' + item.link + '" target="_blank" rel="noopener">' + item.title + '</a>';
                  if (item.dateStr) {
                    htmlBuffer += '<span class="bloglist-date">Updated: ' + item.dateStr + '</span>';
                  }
                  htmlBuffer += '</div>';
                });
                container.innerHTML = htmlBuffer;
              } else {
                container.innerHTML = "<p style='font-size:0.85em; color: #ffffff;'>No recent updates available.</p>";
              }
            }
          });
      });
    })();
  </script>

</div>

Mike Weir, VE9KK, is a regular contributor to AmateurRadio.com and writes from New Brunswick, Canada. Contact him at [email protected].

Leave a Comment

Subscribe FREE to AmateurRadio.com's
Amateur Radio Newsletter
News, Opinion, Giveaways & More!

E-mail 
Join over 7,000 subscribers!
We never share your e-mail address.



Also available via RSS feed, Twitter, and Facebook.


Subscribe FREE to AmateurRadio.com's
Amateur Radio Newsletter

 
We never share your e-mail address.


Do you like to write?
Interesting project to share?
Helpful tips and ideas for other hams?

Submit an article and we will review it for publication on AmateurRadio.com!

Have a ham radio product or service?
Consider advertising on our site.

Are you a reporter covering ham radio?
Find ham radio experts for your story.

How to Set Up a Ham Radio Blog
Get started in less than 15 minutes!


  • Matt W1MST, Managing Editor