n30v1m / TGStat Exporter

// ==UserScript==
// @name        TGStat Exporter
// @namespace   Scripts
// @author      n30v1m
// @match       https://tgstat.ru/channels/search*
// @grant       none
// @version     1.12
// @require     https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2
// @description TGStat Search CSV Exporter Button
// @license     MIT
// @downloadURL https://openuserjs.org/install/n30v1m/TGStat_Exporter.user.js
// @updateURL   https://openuserjs.org/meta/n30v1m/TGStat_Exporter.meta.js
// ==/UserScript==

(function () {
  'use strict';

  let channelsData = [];
  let uniqueLinks = new Set();
  let downloadButtonText = "Download " + channelsData.length;

  function convertLink(tgstatLink) {
    const match = tgstatLink.match(/@([\w\d_]+)/);
    return match ? `https://t.me/${match[1]}` : tgstatLink;
  }

  function csvSafe(value) {
    if (value.includes(',') || value.includes('"')) {
      value = value.replace(/"/g, '""');
      return `"${value}"`;
    }
    return value;
  }

  function parseChannels() {
    document.querySelectorAll('.peer-item-row').forEach(channel => {
      let name = channel.querySelector('.row .font-16')?.textContent.trim() || "Unknown";
      let link = channel.querySelector('#sticky-center-column > div.channels-list.lm-list-container > div:nth-child(n) > div > div > div > a')?.href || "";
      link = convertLink(link);

      if (link && !uniqueLinks.has(link)) {
        channelsData.push({
          'name': name,
          'link': link
        });
        uniqueLinks.add(link);
      }
    });
    downloadButtonText = "Download " + channelsData.length;
    updateDownloadButton();
  }

  function downloadCSV() {
    let csvContent = "data:text/csv;charset=utf-8," +
      "название канала,ссылка\n" +
      channelsData.map(e => `${csvSafe(e.name)},${csvSafe(e.link)}`).join("\n");

    let encodedUri = encodeURI(csvContent);
    let link = document.createElement("a");
    link.setAttribute("href", encodedUri);
    link.setAttribute("download", "tgstat_channels.csv");
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }

  let prevButton = null;

  function updateDownloadButton() {
    const container = document.querySelector('#sticky-right-column__inner > div > div');
    if (container) {
      if (prevButton) {
        prevButton.remove();
      }
      let button = document.createElement("button");
      prevButton = button;
      button.innerText = downloadButtonText;
      button.className = "btn btn-warning w-100";
      button.setAttribute("id", "gtstat-csv-download-button-111");
      button.addEventListener("click", function (event) {
        event.preventDefault();
        downloadCSV();
      });
      container.appendChild(button);
    }
  }

  VM.observe(document.body, () => {
    const targetNode = document.querySelector('.channels-list');
    if (targetNode) {
      parseChannels();
      VM.observe(targetNode, () => {
        parseChannels();
      });
      return true;
    }
  });
})();