GrreasyFork User Script Data Visualization

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

目前為 2024-07-05 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name GrreasyFork User Script Data Visualization
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description Fetch and visualize user script data with Chart.js and display totals below the chart
  6. // @author aspen138
  7. // @match https://greasyfork.org/*/users/*
  8. // @grant none
  9. // @license MIT
  10. // @icon https://greasyfork.org//vite/assets/blacklogo16-37ZGLlXh.png
  11. // ==/UserScript==
  12.  
  13.  
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // Function to inject Chart.js from a CDN if the target element exists
  19. const injectChartJs = () => {
  20. const userHeader = document.querySelector('#about-user h2');
  21. if (!userHeader) return;
  22.  
  23. const script = document.createElement('script');
  24. script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
  25. script.onload = () => fetchDataAndPlot(); // Fetch data and plot chart once Chart.js is loaded
  26. document.head.appendChild(script);
  27. };
  28.  
  29. // Function to fetch user data
  30. const getUserData = (userID) => {
  31. return fetch(`https://${window.location.hostname}/users/${userID}.json`)
  32. .then((response) => {
  33. console.log(`${response.status}: ${response.url}`);
  34. return response.json();
  35. });
  36. };
  37.  
  38. // Function to plot the chart
  39. const plotDistribution = (labels, totalInstalls, dailyInstalls) => {
  40. const canvasHtml = '<canvas id="installDistributionCanvas" width="100" height="50"></canvas>';
  41. const userHeader = document.querySelector('#about-user h2');
  42. if (userHeader) {
  43. userHeader.insertAdjacentHTML('afterend', canvasHtml);
  44. const ctx = document.getElementById('installDistributionCanvas').getContext('2d');
  45.  
  46. // Plot chart
  47. new Chart(ctx, {
  48. type: 'bar', // Change this to 'line', 'bar', etc. as needed
  49. data: {
  50. labels: labels, // X-axis labels
  51. datasets: [{
  52. label: 'Total Installs',
  53. data: totalInstalls, // Y-axis data for Total Installs
  54. backgroundColor: 'rgba(54, 162, 235, 0.2)',
  55. borderColor: 'rgba(54, 162, 235, 1)',
  56. borderWidth: 1,
  57. yAxisID: 'y-axis-1', // Associate this dataset with the first y-axis
  58. },
  59. {
  60. label: 'Daily Installs',
  61. data: dailyInstalls, // Y-axis data for Daily Installs
  62. backgroundColor: 'rgba(255, 99, 132, 0.2)',
  63. borderColor: 'rgba(255, 99, 132, 1)',
  64. borderWidth: 1,
  65. yAxisID: 'y-axis-2', // Associate this dataset with the second y-axis
  66. }
  67. ]
  68. },
  69. options: {
  70. scales: {
  71. yAxes: [{
  72. id: 'y-axis-1',
  73. type: 'linear',
  74. position: 'left', // This places the first y-axis on the left
  75. beginAtZero: true,
  76. },
  77. {
  78. id: 'y-axis-2',
  79. type: 'linear',
  80. position: 'right', // This places the second y-axis on the right
  81. beginAtZero: true,
  82. grid: {
  83. drawOnChartArea: false, // Ensures grid lines from this axis do not overlap with the first axis
  84. },
  85. }
  86. ]
  87. }
  88. }
  89. });
  90. }
  91. };
  92.  
  93. // Function to display totals
  94. const displayTotals = (daily, total, publishedScriptsNumber) => {
  95. const userHeader = document.querySelector('#about-user h2');
  96. const language = document.documentElement.lang; // Get the current language of the document
  97.  
  98. let dailyInstallsText = '';
  99. let totalInstallsText = '';
  100.  
  101. // Determine the text based on the current language
  102. switch (language) {
  103. case 'zh-CN':
  104. publishedScriptsNumber = `已发布脚本总数:${publishedScriptsNumber}`;
  105. dailyInstallsText = `该用户所有脚本的今日总安装次数:${daily}`;
  106. totalInstallsText = `该用户所有脚本的迄今总安装次数:${total}`;
  107. break;
  108. case 'zh-TW':
  109. publishedScriptsNumber = `已發布腳本總數:${publishedScriptsNumber}`;
  110. dailyInstallsText = `該用戶所有腳本的今日總安裝次數:${daily}`;
  111. totalInstallsText = `該用戶所有腳本的迄今總安裝次數:${total}`;
  112. break;
  113. case 'ja':
  114. publishedScriptsNumber = `公開されたスクリプトの合計:${publishedScriptsNumber}`;
  115. dailyInstallsText = `本日の全スクリプトの合計インストール回数:${daily}`;
  116. totalInstallsText = `全スクリプトの累計インストール回数:${total}`;
  117. break;
  118. case 'ko':
  119. publishedScriptsNumber = `게시된 스크립트 수: ${publishedScriptsNumber}`;
  120. dailyInstallsText = `해당 사용자의 모든 스크립트에 대한 오늘의 설치 횟수: ${daily}`;
  121. totalInstallsText = `해당 사용자의 모든 스크립트에 대한 설치 횟수: ${total}`;
  122. break;
  123. default:
  124. publishedScriptsNumber = `Number of published scripts: ${publishedScriptsNumber}`;
  125. dailyInstallsText = `Total daily installations for all scripts: ${daily}`;
  126. totalInstallsText = `Total installations to date for all scripts: ${total}`;
  127. }
  128.  
  129. if (userHeader) {
  130. userHeader.insertAdjacentHTML('afterend', `
  131. <div>${publishedScriptsNumber}</div>
  132. <div>${dailyInstallsText}</div>
  133. <div>${totalInstallsText}</div>
  134. `);
  135. }
  136. };
  137.  
  138. // Function to fetch data and plot the chart
  139. const fetchDataAndPlot = () => {
  140. const userID = '1177387'; // Replace this with the desired user ID
  141. getUserData(userID)
  142. .then((data) => {
  143. const filteredScripts = data.scripts.filter(script => !script.deleted);
  144. const labels = filteredScripts.map(script => script.name);
  145. const totalInstalls = filteredScripts.map(script => script.total_installs);
  146. const dailyInstalls = filteredScripts.map(script => script.daily_installs);
  147. const totalDailyInstalls = dailyInstalls.reduce((sum, value) => sum + value, 0);
  148. const totalTotalInstalls = totalInstalls.reduce((sum, value) => sum + value, 0);
  149. const publishedScriptsNumber = filteredScripts.length;
  150.  
  151. plotDistribution(labels, totalInstalls, dailyInstalls);
  152. displayTotals(totalDailyInstalls, totalTotalInstalls, publishedScriptsNumber);
  153. })
  154. .catch((error) => console.error('Error fetching user data:', error));
  155. };
  156.  
  157. // Inject Chart.js and initiate data fetching and plotting
  158. injectChartJs();
  159. })();