Dune Csv Export

Downloading the queries csv export for free subscription users

目前为 2025-02-15 提交的版本。查看 最新版本

// ==UserScript==
// @name         Dune Csv Export
// @namespace    http://tampermonkey.net/
// @version      0.2.3
// @description  Downloading the queries csv export for free subscription users
// @author       lulu
// @match        https://dune.com/queries*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=dune.com
// @grant        none
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js
// ==/UserScript==

function getElementByXpath(path){
  return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

function getHeaders(table){
    const headers = [];
    $.each($(table).find("thead").find("tr").find("th"), function (key, val2) {
        headers[key] = $(val2).find("div").text();
    });
    return headers;
}

async function getCurrentTableValues(){
    const maxAttempts = 100; // Adjust as needed - determines maximum wait time.  50 attempts * 100ms = 5 seconds
    let attempt = 0;
    let table = null;
    const values = [];

    while (attempt < maxAttempts) {
        table = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[1]/table');
        if (table !== null && table !== undefined ) { // check for both null and undefined
            break;
        }
        console.log("Table is Null, Waiting and Trying again.., attemp: ", attempt);
        // Object is null or undefined, wait and retry
        await new Promise(resolve => setTimeout(resolve, 100));
        attempt++;
    }
    if (table === null || table === undefined ) { // check for both null and undefined
        console.log("Table Did not collected after 100 attempts, Returning Empty!");
        return values;
    }

    // console.log("TABLE:", table);

    $.each($(table).find("tbody").find("tr"), function (key, val) {
        const row = [];
        $.each($(val).find("td"), function (tkey, tval) {
            row[tkey] = $(tval).find("div").first().text();
        });
        values[key] = row;
    });

    // console.log("VALUES:", values);
    return values;


}

async function collectLoop(last_values=[]){
    let nextButton = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[2]/ul/li[5]/button'); // '//*[@id="results"]/div/div[2]/div/div[2]/ul/li[6]/button');
    let table = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[1]/table');
    const values = await getCurrentTableValues();
    const newValues = last_values.concat(values);
    if (!$(nextButton).is(":disabled") && nextButton != null){
        $(nextButton).trigger("click");
        await new Promise(resolve => setTimeout(resolve, 20));
        return await collectLoop(newValues);
    } else {
        const headers = getHeaders(table);
        download_csv(headers, newValues);
    }
}


function download_csv(headers, rows) {
    let csvHeaders = headers.join(",") + "\n";
    let csvRows = rows.map(row => row.join(",")).join("\n");
    let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');
    let custom_name = document.getElementById("customNameCsvFileFree").value;


    var downloadBtn = document.createElement("a");
    downloadBtn.href = "data:text/csv;charset=utf-8,"+encodeURI(csvHeaders+csvRows);
    downloadBtn.target = "_blank";

    if (custom_name.length > 1) {
        downloadBtn.download = custom_name+".csv";
    } else {
        let url = window.location.href;

        downloadBtn.download = "query_"+url.split("queries/")[1].replace("/", "_")+".csv"
    }

    downloadBtn.click();

    csvButton.disabled = false;


}


async function collectCsv() {
    let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');

    csvButton.disabled = "disabled";


    let nextButton = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[2]/ul/li[5]/button');
    if (nextButton == null){
        // console.log("Butt not exists");
        await collectLoop();
    } else {
        // go to first
        let firstPageBtn = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[2]/ul/li[3]/button');
        if (firstPageBtn != null && !$(firstPageBtn).is(":disabled")){
            $(firstPageBtn).trigger("click");
            await new Promise(resolve => setTimeout(resolve, 5));
            return await collectLoop();

        } else {
            await collectLoop();
        }
    }

}

function changeCsvButton(){
    // console.log("Running Dune Script");
    let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');
    if (csvButton != null){
        csvButton.disabled = false;
        csvButton.onclick = collectCsv;

        // adding a input for custom csv file name
        var inp_element = document.createElement('input');
        inp_element.className = "IconButton_iconButton___v3YQ buttonThemes_button__jfRFC buttonThemes_theme-tertiary__v7VoN IconButton_size-M__FIXfN";
        inp_element.id = "customNameCsvFileFree";
        inp_element.placeholder = "Custom filename";

        getElementByXpath('//*[@id="results"]/div/div[1]/div[1]').appendChild(inp_element);

        // console.log("BTN CREATED");

    } else {
        setTimeout(()=>{
            changeCsvButton();
        }, 1000)
    }
}


(function() {
    'use strict';
    $(document).ready ( function(){
        changeCsvButton();
        // for (let i = 0; i < 10; i++) {}
    });
})();