NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name TGStat Exporter
// @namespace Scripts
// @author n30v1m
// @match https://tgstat.ru/channels/search*
// @grant none
// @version 1.13
// @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 0";
function convertLink(tgstatLink) {
if (!tgstatLink || typeof tgstatLink !== 'string') {
return "";
}
const usernameMatch = tgstatLink.match(/@([\w\d_]+)/);
if (usernameMatch && usernameMatch[1]) {
return `https://t.me/${usernameMatch[1]}`;
}
if (tgstatLink.includes('tgstat.ru/channel/')) {
const basePathMatch = tgstatLink.match(/(https:\/\/tgstat\.ru\/channel\/[^/?#]+)/);
if (basePathMatch && basePathMatch[1]) {
return basePathMatch[1];
}
return tgstatLink;
}
return "";
}
function csvSafe(value) {
if (value === null || typeof value === 'undefined') {
return '';
}
let strValue = String(value);
strValue = strValue.replace(/[\r\n]+/g, ' ');
strValue = strValue.replace(/"/g, '""');
if (strValue.includes(',') || strValue.includes('"')) {
return `"${strValue}"`;
}
return strValue;
}
function parseChannels() {
let newChannelsFound = false;
document.querySelectorAll('.peer-item-row').forEach(channelElement => {
let name = channelElement.querySelector('.row .font-16')?.textContent.trim() || "Unknown";
let linkAnchor = channelElement.querySelector('a[href*="/channel/"]');
let tgstatPageLink = "";
if (linkAnchor) {
tgstatPageLink = new URL(linkAnchor.getAttribute('href'), document.baseURI).href;
}
let finalLink = convertLink(tgstatPageLink);
if (finalLink && !uniqueLinks.has(finalLink)) {
channelsData.push({
'name': name,
'link': finalLink
});
uniqueLinks.add(finalLink);
newChannelsFound = true;
}
});
if (newChannelsFound || (channelsData.length > 0 && downloadButtonText === "Download 0") || (channelsData.length === 0 && document.querySelector('.peer-item-row') && downloadButtonText === "Download 0")) {
downloadButtonText = "Download " + channelsData.length;
updateDownloadButton();
}
else if (channelsData.length === 0 && !document.querySelector('.peer-item-row')) {
downloadButtonText = "Download 0";
updateDownloadButton();
}
}
function downloadCSV() {
if (channelsData.length === 0) {
alert("Нет данных для экспорта.");
return;
}
const csvHeader = "название канала,ссылка\n";
const csvRows = channelsData.map(e => {
const name = csvSafe(e.name);
const link = csvSafe(e.link);
return `${name},${link}`;
}).join("\n");
const csvString = csvHeader + csvRows;
const BOM = "";
const blob = new Blob([BOM + csvString], {
type: 'text/csv;charset=utf-8;'
});
const url = URL.createObjectURL(blob);
const linkElement = document.createElement("a");
linkElement.setAttribute("href", url);
linkElement.setAttribute("download", "tgstat_channels.csv");
linkElement.style.visibility = 'hidden';
document.body.appendChild(linkElement);
linkElement.click();
document.body.removeChild(linkElement);
URL.revokeObjectURL(url);
}
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 mt-2";
button.setAttribute("id", "gtstat-csv-download-button-111");
button.addEventListener("click", function (event) {
event.preventDefault();
downloadCSV();
});
container.appendChild(button);
}
}
parseChannels();
VM.observe(document.body, () => {
const targetNode = document.querySelector('.channels-list');
if (targetNode) {
VM.observe(targetNode, () => {
parseChannels();
});
return true;
}
return false;
});
})();