Создаем свой RSS канал с помощью Google Apps Script

в 12:20, , рубрики: feed, gas, Google API, google app engine, google apps script, rss, tcl, tcl/tk, wiki, метки: , , , , , ,

Есть такой замечательный wiki ресурс по языку Tcl/Tk как wiki.tcl.tk. Есть у этого ресурса RSS лента последних изменений. Но вот беда — лента изменений самая минимальная. Там указано только кем, когда и какая страница редактировалась. Нет полных изменений и нет GUID у элементов ленты, поэтому некоторые RSS клиенты (например, Google Reader) не показывают большую часть новостей, считая их одинаковыми.

Для преобразования ленты в свой, удобный формат, выбор пал на такой специализированный инструмент, как Yahoo Pipes. Но тут постигла неудача. Для получения изменений странички, wiki строго требовала наличия cookie с именем «wikit_e» в http запросе, а научить Yahoo Pipes отсылать куки не получилось. Фокус с HTTP запросом GET и параметром в виде "?COOKIE=" так же не проходил.
В итоге, выбор пал на более гибкий инструмент — Google Apps Script. В итоге получился вот такой скрипт:

// Эта функция будет выполняться автоматически, при вызова скрипта как веб-приложения
function doGet() {
  // Задаем URL исходной RSS ленты
  var feed = 'http://wiki.tcl.tk/rss.xml';
  
  // Определяем ID для доступа к кэшу
  var id = Utilities.base64Encode(feed);
  
  // Определяем кэш и пробуем забрать уже собранную ленту из него
  var cache = CacheService.getPublicCache();
  var rss   = cache.get(id);
  
  // Если в кэше лента не сохранена - переходим к ее созданию
  if (rss == null) {
    // Получаем данные RSS ленты в виде XML
    var data = UrlFetchApp.fetch(feed).getContentText();
    var doc = Xml.parse(data);
    // Выбираем канал
    var channel = doc.getElement().getElement("channel");

    // Выбираем название канала, ссылку, описание ленты
    var title = channel.getElement("title").getText();
    var link = channel.getElement("link").getText();
    var desc = channel.getElement("description").getText();
    var guid, date;
    
    // Начинаем создавать свою RSS ленту, заполняем название, ссылку и описание
    rss = '<rss version="2.0">';
    rss += "<channel>"
    rss += "<title>" + title + "</title>n";
    rss += "<link>" + link + "</link>n";
    rss += "<description>" + desc + "</description>n";
    
    // Выбираем все элементы ленты и последовательно проходим по каждому
    var items = channel.getElements("item");  
    for (var i in items) {
      item  = items[i];
      
      // Выбираем из ленты заголовок, ссылку, дату новости, описание
      title = item.getElement("title").getText();
      link  = item.getElement("link").getText();
      // Ссылка должна указывать на diff странички
      link  = link.replace(//(d+)$/, "/_/diff?N=$1#diff0");
      date  = item.getElement("pubDate").getText();
      desc  = item.getElement("description").getText();
      // Формируем GUID для элемента ленты      
      guid  = Utilities.base64Encode(link + date);

      // Скачиваем diff страницы, используя при этом Cookie "wikit_e" как "rss"
      var fullpage = UrlFetchApp.fetch(link, {"headers":{"Cookie":"wikit_e=rss"}}).getContentText();
      // Вырезаем из страницы только body
      var matched = fullpage.match(/<body[^>]*>([wW]*)</body>/i)[1];
      // Вырезаем заголовки и подвал страницы
      matched = matched.replace(/<div id='menu_area'>[wW]+$/i, "");
      matched = matched.replace(/^[wW]+<div id='content'>/i, "");
      // Заменяем относительные ссылки внутри документа на абсолютные
      matched = matched.replace(/(href|src)=(["'])//ig, "$1=$2http://wiki.tcl.tk/");
      // Т.к. CSS в RSS не подключен, явно прописываем стили для элементов
      matched = matched.replace(/class='newwikiline'/g, "style='margin:0;background:#80ff80;'");
      matched = matched.replace(/class='oldwikiline'/g, "style='margin:0;background:#ffa0a0;'");
      matched = matched.replace(/class='whitespacediff'/g, "style='margin:0;background:#f0f0ff;'");
      matched = matched.replace(/class='wikit_categories'/g, "style='padding:2px 5px 2px 5px;text-align:left;border:1px solid gray;background-color:#DDD;'");
      matched = matched.replace(/<pre>/g, "<pre style='color:#331100;background-color:#eeeeee;font-family:monospace;'>");
      
      // Добавляем к нашей RSS ленте новость
      rss += "<item>n";
      rss += "  <title>"   + title + "</title>n";
      rss += "  <link>"    + link  + "</link>n";
      rss += "  <pubDate>" + date  + "</pubDate>n";
      rss += "  <guid isPermaLink='false'>"    + guid  + "</guid>n";
      rss += "  <description><![CDATA[" + desc + "<br>n" + matched + "]]></description>n";
      rss += "</item>n";
    };
    
    // Завершаем создание RSS
    rss += "</channel></rss>";
    
    // Пробуем поместить нашу ленту в кэш сроком хранения 30 минут
    // максимальный размер кэша - 100kb
    // при превышении этого значения будет ошибка, игнорируем ее
    try {
      cache.put(id, rss, 1800);
    } catch (e) {
      Logger.log(e);
    };
  };
  
  // Возвращаем клиенту нашу собранную ленту
  return ContentService.createTextOutput(rss).setMimeType(ContentService.MimeType.RSS);   
};

После сохранения скрипта, настраиваем уровень доступа как «Просмотреть элемент может любой пользователь, обладающий ссылкой» либо «Общедоступно в Интернете: найти и просмотреть элемент может любой пользователь». В меню «Файл->Версии...» создаем новую версию приложения. Далее, в меню «Публикация->Развернуть как веб-приложение...» выбираем сохраненную версию, в выпадающем списке «Как запускать приложение» выбираем «От моего имени», в выпадающем списке «Кто имеет доступ к приложению» выбираем «Все, включая анонимных пользователей». Получаем ссылку в виде "https://script.google.com/macros/s/<тут ID приложения>/exec", которую и используем в любой RSS читалке.

Бонусы:

  1. Пример использования Google Apps Script для автоматического перевода ленты на другой язык с помощью Google Translate
  2. Спецификация RSS 2.0

Автор: Chpock

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js