Dune Csv Export

Downloading the queries csv export for free subscription users

当前为 2025-02-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Dune Csv Export
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2.4
  5. // @description Downloading the queries csv export for free subscription users
  6. // @author lulu
  7. // @match https://dune.com/queries*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=dune.com
  9. // @grant none
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js
  11. // ==/UserScript==
  12.  
  13. function getElementByXpath(path){
  14. return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  15. }
  16.  
  17.  
  18. function getNextButton(){
  19. let path0 = '//*[@id="results"]/div/div[2]/div/div[2]/ul/li[5]/button';
  20. let path1 = '//*[@id="results"]/div/div[2]/div/div[2]/ul/li[6]/button';
  21.  
  22. let btn = getElementByXpath(path0);
  23. if (btn === null){
  24. btn = getElementByXpath(path1);
  25. }
  26. // console.log("BTN:", btn)
  27. return btn;
  28.  
  29. }
  30.  
  31. function getHeaders(table){
  32. const headers = [];
  33. $.each($(table).find("thead").find("tr").find("th"), function (key, val2) {
  34. headers[key] = $(val2).find("div").text();
  35. });
  36. return headers;
  37. }
  38.  
  39. async function getCurrentTableValues(){
  40. const maxAttempts = 100; // Adjust as needed - determines maximum wait time. 50 attempts * 100ms = 5 seconds
  41. let attempt = 0;
  42. let table = null;
  43. const values = [];
  44.  
  45. while (attempt < maxAttempts) {
  46. table = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[1]/table');
  47. if (table !== null && table !== undefined ) { // check for both null and undefined
  48. break;
  49. }
  50. // console.log("Table is Null, Waiting and Trying again.., attemp: ", attempt);
  51. // Object is null or undefined, wait and retry
  52. await new Promise(resolve => setTimeout(resolve, 100));
  53. attempt++;
  54. }
  55. if (table === null || table === undefined ) { // check for both null and undefined
  56. console.log("Table Did not collected after 100 attempts, Returning Empty!");
  57. return values;
  58. }
  59.  
  60. // console.log("TABLE:", table);
  61.  
  62. $.each($(table).find("tbody").find("tr"), function (key, val) {
  63. const row = [];
  64. $.each($(val).find("td"), function (tkey, tval) {
  65. row[tkey] = $(tval).find("div").first().text();
  66. });
  67. values[key] = row;
  68. });
  69.  
  70. // console.log("VALUES:", values);
  71. return values;
  72.  
  73.  
  74. }
  75.  
  76. async function collectLoop(last_values=[]){
  77. let nextButton = getNextButton();
  78. let table = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[1]/table');
  79. const values = await getCurrentTableValues();
  80. const newValues = last_values.concat(values);
  81. if (!$(nextButton).is(":disabled") && nextButton != null){
  82. $(nextButton).trigger("click");
  83. await new Promise(resolve => setTimeout(resolve, 20));
  84. return await collectLoop(newValues);
  85. } else {
  86. const headers = getHeaders(table);
  87. download_csv(headers, newValues);
  88. }
  89. }
  90.  
  91.  
  92. function download_csv(headers, rows) {
  93. let csvHeaders = headers.join(",") + "\n";
  94. let csvRows = rows.map(row => row.join(",")).join("\n");
  95. let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');
  96. let custom_name = document.getElementById("customNameCsvFileFree").value;
  97.  
  98.  
  99. var downloadBtn = document.createElement("a");
  100. downloadBtn.href = "data:text/csv;charset=utf-8,"+encodeURI(csvHeaders+csvRows);
  101. downloadBtn.target = "_blank";
  102.  
  103. if (custom_name.length > 1) {
  104. downloadBtn.download = custom_name+".csv";
  105. } else {
  106. let url = window.location.href;
  107.  
  108. downloadBtn.download = "query_"+url.split("queries/")[1].replace("/", "_")+".csv"
  109. }
  110.  
  111. downloadBtn.click();
  112.  
  113. csvButton.disabled = false;
  114.  
  115.  
  116. }
  117.  
  118.  
  119. async function collectCsv() {
  120. let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');
  121.  
  122. csvButton.disabled = "disabled";
  123.  
  124.  
  125. let nextButton = getNextButton(); //getElementByXpath('//*[@id="results"]/div/div[2]/div/div[2]/ul/li[5]/button');
  126. if (nextButton == null){
  127. // console.log("Butt not exists");
  128. await collectLoop();
  129. } else {
  130. // go to first
  131. let firstPageBtn = getElementByXpath('//*[@id="results"]/div/div[2]/div/div[2]/ul/li[3]/button');
  132. if (firstPageBtn != null && !$(firstPageBtn).is(":disabled")){
  133. $(firstPageBtn).trigger("click");
  134. await new Promise(resolve => setTimeout(resolve, 5));
  135. return await collectLoop();
  136.  
  137. } else {
  138. await collectLoop();
  139. }
  140. }
  141.  
  142. }
  143.  
  144. function changeCsvButton(){
  145. // console.log("Running Dune Script");
  146. let csvButton = getElementByXpath('//*[@id="results"]/div/div[1]/div[1]/div/button');
  147. if (csvButton != null){
  148. csvButton.disabled = false;
  149. csvButton.onclick = collectCsv;
  150.  
  151. // adding a input for custom csv file name
  152. var inp_element = document.createElement('input');
  153. inp_element.className = "IconButton_iconButton___v3YQ buttonThemes_button__jfRFC buttonThemes_theme-tertiary__v7VoN IconButton_size-M__FIXfN";
  154. inp_element.id = "customNameCsvFileFree";
  155. inp_element.placeholder = "Custom filename";
  156.  
  157. getElementByXpath('//*[@id="results"]/div/div[1]/div[1]').appendChild(inp_element);
  158.  
  159. // console.log("BTN CREATED");
  160.  
  161. } else {
  162. setTimeout(()=>{
  163. changeCsvButton();
  164. }, 1000)
  165. }
  166. }
  167.  
  168.  
  169. (function() {
  170. 'use strict';
  171. $(document).ready ( function(){
  172. changeCsvButton();
  173. // for (let i = 0; i < 10; i++) {}
  174. });
  175. })();