GrreasyFork User Script Data Visualization

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

Versione datata 22/09/2024. Vedi la nuova versione l'ultima versione.

  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. })();