Qiita Advent Calendar Feed Export

export subscription list of Qiita Advent Calendar as OPML

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Qiita Advent Calendar Feed Export
// @namespace    https://fuwa.dev
// @version      2024-11-30
// @description  export subscription list of Qiita Advent Calendar as OPML
// @author       fuwa2003
// @match        https://qiita.com/advent-calendar/*/feed
// @icon         https://www.google.com/s2/favicons?sz=64&domain=qiita.com
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  // https://stackoverflow.com/questions/3665115/how-to-create-a-file-in-memory-for-user-to-download-but-not-through-server
  function download(filename, text) {
    const element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
  }

  function run() {

    const entries = Array.from(document.querySelectorAll('main > div > section ol li > div a'))
      .map((a) => ({
        text: a.innerText + " Advent Calendar - Qiita",
        href: a.href,
      }));

    const entries_text = entries.map((entry) => (
          `  <outline title="${entry.text}" text="${entry.text}" type="rss" xmlUrl="${entry.href}/feed" />`
    )).join('\n');

    const opml = `
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
  <head>
    <title>Qiita Advent Calendar subscriptions</title>
  </head>
  <body>
${entries_text}
  </body>
</opml>
    `.trim();

    // download file
    download('qiita.opml', opml);
  }

  const btn = document.createElement('button');
  btn.innerText = 'Export OPML';
  btn.addEventListener('click', run);
  document.querySelector('main > div > section').prepend(btn);
  console.log(btn);

  // when btn removed, add again
  btn.addEventListener('DOMNodeRemoved', (e) => {
    console.log('removed', e);
    setTimeout(() => {
      document.querySelector('main > div > section').prepend(btn);
    }, 100);
  });

})();