Greasy Fork is available in English.

GrreasyFork User Script Data Visualization

Fetch and visualize user script data with Chart.js and display totals below the chart

Od 22.09.2024.. Pogledajte najnovija verzija.

  1. // ==UserScript==
  2. // @name GrreasyFork User Script Data Visualization
  3. // @name:en GrreasyFork User Script Data Visualization
  4. // @name:es Visualización de datos del script de usuario de GrreasyFork
  5. // @name:fr Visualisation des données de script utilisateur de GrreasyFork
  6. // @name:zh GrreasyFork 用户发布的脚本数据可视化
  7. // @name:zh-TW GrreasyFork 用戶發佈的腳本數據視覺化
  8. // @namespace http://tampermonkey.net/
  9. // @version 0.2.2
  10. // @description Fetch and visualize user script data with Chart.js and display totals below the chart
  11. // @description:en Fetch and visualize user script data with Chart.js and display totals below the chart
  12. // @description:es Obtener y visualizar datos del script de usuario con Chart.js y mostrar totales debajo del gráfico
  13. // @description:fr Récupérer et visualiser les données du script utilisateur avec Chart.js et afficher les totaux sous le graphique
  14. // @description:zh-TW 使用 Chart.js 獲取和可視化使用者腳本數據,並在圖表下方顯示總數
  15. // @description:zh 使用Chart.js获取和可视化使用者脚本数据,并在图表下方显示总数
  16. // @locale:en en
  17. // @locale:es es
  18. // @locale:fr fr
  19. // @locale:zh-TW zh-TW
  20. // @author aspen138
  21. // @match *://greatest.deepsurf.us/*/users/*
  22. // @grant none
  23. // @license MIT
  24. // @icon https://greatest.deepsurf.us//vite/assets/blacklogo16-37ZGLlXh.png
  25. // ==/UserScript==
  26.  
  27.  
  28.  
  29. (function() {
  30. 'use strict';
  31.  
  32. // Function to inject Chart.js from a CDN if the target element exists
  33. const injectChartJs = () => {
  34. const userHeader = document.querySelector('#about-user h2');
  35. if (!userHeader) return;
  36.  
  37. const script = document.createElement('script');
  38. script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
  39. script.onload = () => fetchDataAndPlot(); // Fetch data and plot chart once Chart.js is loaded
  40. document.head.appendChild(script);
  41. };
  42.  
  43. // Function to fetch user data
  44. const getUserData = (userID) => {
  45. return fetch(`https://${window.location.hostname}/users/${userID}.json`)
  46. .then((response) => {
  47. console.log(`${response.status}: ${response.url}`);
  48. return response.json();
  49. })
  50. .then((data) => {
  51. data.scripts.sort((a, b) => b.total_installs - a.total_installs);
  52. return data;
  53. });
  54. };
  55.  
  56. // Function to plot the chart
  57. const plotDistribution = (labels, totalInstalls, dailyInstalls) => {
  58. const canvasHtml = '<canvas id="installDistributionCanvas" width="100" height="50"></canvas>';
  59. const userHeader = document.querySelector('#about-user h2');
  60. if (userHeader) {
  61. userHeader.insertAdjacentHTML('afterend', canvasHtml);
  62. const ctx = document.getElementById('installDistributionCanvas').getContext('2d');
  63.  
  64. // Plot chart
  65. new Chart(ctx, {
  66. type: 'bar', // Change this to 'line', 'bar', etc. as needed
  67. data: {
  68. labels: labels, // X-axis labels
  69. datasets: [{
  70. label: 'Total Installs',
  71. data: totalInstalls, // Y-axis data for Total Installs
  72. backgroundColor: 'rgba(54, 162, 235, 0.2)',
  73. borderColor: 'rgba(54, 162, 235, 1)',
  74. borderWidth: 1,
  75. yAxisID: 'y-axis-1', // Associate this dataset with the first y-axis
  76. },
  77. {
  78. label: 'Daily Installs',
  79. data: dailyInstalls, // Y-axis data for Daily Installs
  80. backgroundColor: 'rgba(255, 99, 132, 0.2)',
  81. borderColor: 'rgba(255, 99, 132, 1)',
  82. borderWidth: 1,
  83. yAxisID: 'y-axis-2', // Associate this dataset with the second y-axis
  84. }
  85. ]
  86. },
  87. options: {
  88. scales: {
  89. yAxes: [{
  90. id: 'y-axis-1',
  91. type: 'linear',
  92. position: 'left', // This places the first y-axis on the left
  93. beginAtZero: true,
  94. },
  95. {
  96. id: 'y-axis-2',
  97. type: 'linear',
  98. position: 'right', // This places the second y-axis on the right
  99. beginAtZero: true,
  100. grid: {
  101. drawOnChartArea: false, // Ensures grid lines from this axis do not overlap with the first axis
  102. },
  103. }
  104. ]
  105. }
  106. }
  107. });
  108. }
  109. };
  110.  
  111. // Function to display totals
  112. const displayTotals = (daily, total, publishedScriptsNumber) => {
  113. const userHeader = document.querySelector('#about-user h2');
  114. const language = document.documentElement.lang; // Get the current language of the document
  115.  
  116. let dailyInstallsText = '';
  117. let totalInstallsText = '';
  118.  
  119. // Determine the text based on the current language
  120. switch (language) {
  121. case 'zh-CN':
  122. publishedScriptsNumber = `已发布脚本总数:${publishedScriptsNumber}`;
  123. dailyInstallsText = `该用户所有脚本的今日总安装次数:${daily}`;
  124. totalInstallsText = `该用户所有脚本的迄今总安装次数:${total}`;
  125. break;
  126. case 'zh-TW':
  127. publishedScriptsNumber = `已發布腳本總數:${publishedScriptsNumber}`;
  128. dailyInstallsText = `該用戶所有腳本的今日總安裝次數:${daily}`;
  129. totalInstallsText = `該用戶所有腳本的迄今總安裝次數:${total}`;
  130. break;
  131. case 'ja':
  132. publishedScriptsNumber = `公開されたスクリプトの合計:${publishedScriptsNumber}`;
  133. dailyInstallsText = `本日の全スクリプトの合計インストール回数:${daily}`;
  134. totalInstallsText = `全スクリプトの累計インストール回数:${total}`;
  135. break;
  136. case 'ko':
  137. publishedScriptsNumber = `게시된 스크립트 수: ${publishedScriptsNumber}`;
  138. dailyInstallsText = `해당 사용자의 모든 스크립트에 대한 오늘의 설치 횟수: ${daily}`;
  139. totalInstallsText = `해당 사용자의 모든 스크립트에 대한 설치 횟수: ${total}`;
  140. break;
  141. case 'es':
  142. publishedScriptsNumber = `Número de scripts publicados: ${publishedScriptsNumber}`;
  143. dailyInstallsText = `Instalaciones diarias totales para todos los scripts: ${daily}`;
  144. totalInstallsText = `Instalaciones totales hasta la fecha para todos los scripts: ${total}`;
  145. break;
  146. case 'fr':
  147. publishedScriptsNumber = `Nombre de scripts publiés : ${publishedScriptsNumber}`;
  148. dailyInstallsText = `Installations quotidiennes totales pour tous les scripts : ${daily}`;
  149. totalInstallsText = `Installations totales à ce jour pour tous les scripts : ${total}`;
  150. break;
  151. case 'de':
  152. publishedScriptsNumber = `Anzahl der veröffentlichten Skripte: ${publishedScriptsNumber}`;
  153. dailyInstallsText = `Tägliche Gesamtinstallationen für alle Skripte: ${daily}`;
  154. totalInstallsText = `Gesamtinstallationen bis heute für alle Skripte: ${total}`;
  155. break;
  156. case 'it':
  157. publishedScriptsNumber = `Numero di script pubblicati: ${publishedScriptsNumber}`;
  158. dailyInstallsText = `Installazioni giornaliere totali per tutti gli script: ${daily}`;
  159. totalInstallsText = `Installazioni totali ad oggi per tutti gli script: ${total}`;
  160. break;
  161. case 'pt':
  162. publishedScriptsNumber = `Número de scripts publicados: ${publishedScriptsNumber}`;
  163. dailyInstallsText = `Total de instalações diárias para todos os scripts: ${daily}`;
  164. totalInstallsText = `Total de instalações até à data para todos os scripts: ${total}`;
  165. break;
  166. case 'ru':
  167. publishedScriptsNumber = `Количество опубликованных скриптов: ${publishedScriptsNumber}`;
  168. dailyInstallsText = `Общее количество ежедневных установок для всех скриптов: ${daily}`;
  169. totalInstallsText = `Общее количество установок на сегодняшний день для всех скриптов: ${total}`;
  170. break;
  171. default:
  172. publishedScriptsNumber = `Number of published scripts: ${publishedScriptsNumber}`;
  173. dailyInstallsText = `Total daily installations for all scripts: ${daily}`;
  174. totalInstallsText = `Total installations to date for all scripts: ${total}`;
  175. }
  176.  
  177. if (userHeader) {
  178. userHeader.insertAdjacentHTML('afterend', `
  179. <div>${publishedScriptsNumber}</div>
  180. <div>${dailyInstallsText}</div>
  181. <div>${totalInstallsText}</div>
  182. `);
  183. }
  184. };
  185.  
  186. // Function to fetch data and plot the chart
  187. const fetchDataAndPlot = () => {
  188. const currentURL = window.location.href;
  189. const userIDMatch = currentURL.match(/users\/(\d+)/); // if you do concern hyphen `-`, you should use const userIDMatch = currentURL.match(/users\/(\d+)-/);
  190. const userID = userIDMatch ? userIDMatch[1] : null;
  191.  
  192. getUserData(userID)
  193. .then((data) => {
  194. //console.log("data=", data);
  195. const scripts = data.all_listable_scripts || data.scripts || [];
  196. const filteredScripts = scripts.filter(script => !script.deleted);
  197. const labels = filteredScripts.map(script => script.name);
  198. const totalInstalls = filteredScripts.map(script => script.total_installs);
  199. const dailyInstalls = filteredScripts.map(script => script.daily_installs);
  200. const totalDailyInstalls = dailyInstalls.reduce((sum, value) => sum + value, 0);
  201. const totalTotalInstalls = totalInstalls.reduce((sum, value) => sum + value, 0);
  202. const publishedScriptsNumber = filteredScripts.length;
  203.  
  204. plotDistribution(labels, totalInstalls, dailyInstalls);
  205. displayTotals(totalDailyInstalls, totalTotalInstalls, publishedScriptsNumber);
  206. })
  207. .catch((error) => console.error('Error fetching user data:', error));
  208. };
  209.  
  210. // Inject Chart.js and initiate data fetching and plotting
  211. injectChartJs();
  212. })();