From 71dacd527cedb5efcb3e62146c9a50c294642b76 Mon Sep 17 00:00:00 2001
From: Deepak Yadav
Date: Mon, 2 Sep 2024 13:23:33 +0530
Subject: [PATCH] fix: changes in updateProjects() cronjob for pypi packages
---
src/app/packages/page.tsx | 345 +++++++++++++----------------
src/app/projects/assets/stats.json | 11 +
updateProject.mjs | 69 ++++--
3 files changed, 224 insertions(+), 201 deletions(-)
diff --git a/src/app/packages/page.tsx b/src/app/packages/page.tsx
index 8a38f3f1..e247e98c 100644
--- a/src/app/packages/page.tsx
+++ b/src/app/packages/page.tsx
@@ -4,6 +4,7 @@ import React, { useEffect, useState, Fragment } from "react";
import statsList from "../projects/assets/stats.json";
import Link from "next/link";
import npm from "../../../public/images/social-media/npm-svgrepo-com.svg";
+import pypi from "../../../public/images/social-media/pypi-svg.svg";
import filter from "../../../public/images/social-media/bx-filter-alt.svg";
import download from "../../../public/images/bxs-download.svg";
import github from "../../../public/images/bxl-github.svg";
@@ -11,31 +12,39 @@ import Image from "next/image";
import { Dialog, Transition } from "@headlessui/react";
import moment from "moment";
-type stats = {
- downloads: download[];
+type Package = {
+ name: string;
+ type: "npm" | "pypi";
+ day?: number;
+ week?: number;
+ year?: number;
+ total?: number;
+ last_day?: number;
+ last_week?: number;
+ last_month?: number;
};
-type download = {
- downloads: number;
- day: string;
+type NpmStats = {
+ downloads: { downloads: number; day: string }[];
};
const Stats = () => {
const [startDate, setStartDate] = useState(moment().format("YYYY-MM-DD"));
const [endDate, setEndDate] = useState(moment().format("YYYY-MM-DD"));
- const [loading, setLoading] = useState(false); // State to track loading status
+ const [loading, setLoading] = useState(false);
const [count, setCount] = useState(0);
const [selectedRange, setSelectedRange] = useState(false);
const [isOpen, setIsOpen] = useState(false);
- const [npmPackage, setNpmPackage] = useState({
+ const [selectedPackage, setSelectedPackage] = useState({
name: "fmdapi-node-weaver",
+ type: "npm",
day: 0,
week: 3,
year: 70,
total: 70,
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- const [packages, setPackages] = useState(statsList);
+ const [packages, setPackages] = useState(statsList as Package[]);
function closeModal() {
setIsOpen(false);
@@ -43,18 +52,28 @@ const Stats = () => {
}
useEffect(() => {
- if (npmPackage) {
- setCount(npmPackage.total); //update total count when npmPackage is updated
+ if (selectedPackage) {
+ setCount(
+ selectedPackage.type === "npm"
+ ? selectedPackage.total || 0
+ : selectedPackage.last_month || 0
+ ); //update total count when npmPackage is updated
}
- }, [npmPackage]);
+ }, [selectedPackage]);
function openModal() {
setIsOpen(true);
- setCount(npmPackage.total);
+ setCount(
+ selectedPackage.type === "npm"
+ ? selectedPackage.total || 0
+ : selectedPackage.last_month || 0
+ );
}
- // Function to fetch download statistics for a given package and period
- async function fetchDownloadStats(packageName: string, period: string) {
+ async function fetchNpmStats(
+ packageName: string,
+ period: string
+ ): Promise {
setLoading(true);
const url = `https://api.npmjs.org/downloads/range/${period}/@mindfiredigital/${packageName}`;
const response = await fetch(url);
@@ -64,6 +83,7 @@ const Stats = () => {
`Failed to fetch download stats for ${packageName} (${period}): ${response.statusText}`
);
setLoading(false);
+ throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
@@ -71,67 +91,37 @@ const Stats = () => {
return data;
}
- function calculateDownloads(stats: stats): number {
+ function calculateDownloads(stats: NpmStats): number {
if (!stats || !stats.downloads) {
- return 0; // Return 0 if stats or stats.downloads is undefined
+ return 0;
}
return stats.downloads.reduce(
- (accumulator, download) => accumulator + download.downloads,
+ (acc, download) => acc + download.downloads,
0
);
}
- // Function to fetch and process statistics for a package and period
- async function getStats(packageName: string, period: string) {
- try {
- // Fetch download statistics
- const stats = await fetchDownloadStats(packageName, period);
+ function handleChange(event: React.ChangeEvent) {
+ if (!selectedPackage) return;
- // Check if stats exist
- if (!stats || !stats.package) return 0;
+ const range = getDateRange(event.target.value);
- // Calculate average downloads
- return stats;
- } catch (error) {
- // Log and handle errors
- console.error(`${packageName} not present`);
- return 0;
- }
- }
- function handleChange(
- event: React.ChangeEvent,
- _package: {
- name: string;
- day: number;
- week: number;
- year: number;
- total: number;
- }
- ) {
- const range: { start: string; end: string } = getDateRange(
- event.target.value as string
- );
-
- getStats(_package.name, `${range?.start}:${range?.end}`).then((res) => {
- setLoading(true);
- const count = calculateDownloads(res);
- // console.log(count);
-
- packages.map((npmPackage) => {
- if (npmPackage.name === _package.name) {
+ if (selectedPackage.type === "npm") {
+ fetchNpmStats(selectedPackage.name, `${range.start}:${range.end}`).then(
+ (res) => {
+ setLoading(true);
+ const count = calculateDownloads(res);
setCount(count);
setLoading(false);
}
- return npmPackage;
- });
- });
+ );
+ } else if (selectedPackage.type === "pypi") {
+ setCount(Number(event.target.value) || 0);
+ }
}
function formatDate(date: Date) {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, "0");
- const day = String(date.getDate()).padStart(2, "0");
- return `${year}-${month}-${day}`;
+ return date.toISOString().split("T")[0];
}
function getDateRange(range: string) {
@@ -141,13 +131,12 @@ const Stats = () => {
const currentDay = currentDate.getDate();
switch (range.toLowerCase()) {
- case "today": {
+ case "today":
setSelectedRange(false);
return {
start: formatDate(new Date(currentYear, currentMonth, currentDay)),
end: formatDate(new Date(currentYear, currentMonth, currentDay)),
};
- }
case "yesterday": {
setSelectedRange(false);
const yesterdayDate = new Date(
@@ -169,9 +158,17 @@ const Stats = () => {
end: formatDate(lastMonthEndDate),
};
}
+ case "this month": {
+ setSelectedRange(false);
+ const thisMonthStartDate = new Date(currentYear, currentMonth, 1);
+ return {
+ start: formatDate(thisMonthStartDate),
+ end: formatDate(currentDate),
+ };
+ }
case "last quarter": {
setSelectedRange(false);
- const quarterStartMonth = Math.floor(currentMonth / 3) * 3; // Get the start month of the current quarter
+ const quarterStartMonth = Math.floor(currentMonth / 3) * 3;
const lastQuarterStartDate = new Date(
currentYear,
quarterStartMonth - 3,
@@ -191,14 +188,6 @@ const Stats = () => {
end: formatDate(currentDate),
};
}
- case "this month": {
- setSelectedRange(false);
- const thisMonthStartDate = new Date(currentYear, currentMonth, 1);
- return {
- start: formatDate(thisMonthStartDate),
- end: formatDate(currentDate),
- };
- }
case "custom": {
setSelectedRange(true);
setCount(0);
@@ -207,26 +196,30 @@ const Stats = () => {
end: formatDate(new Date(currentYear, currentMonth, currentDay)),
};
}
- default:
+ default: {
setSelectedRange(false);
return {
start: "1000-01-01",
end: "3000-01-01",
};
+ }
}
}
-
const generateChart = async () => {
- const stats = await fetchDownloadStats(
- npmPackage.name,
- `${startDate}:${endDate}`
- );
- setCount(calculateDownloads(stats));
+ if (selectedPackage.type === "npm") {
+ const stats = await fetchNpmStats(
+ selectedPackage.name,
+ `${startDate}:${endDate}`
+ );
+ setCount(calculateDownloads(stats));
+ }
};
useEffect(() => {
- generateChart();
- }, [startDate, endDate]);
+ if (selectedRange && selectedPackage.type === "npm") {
+ generateChart();
+ }
+ }, [startDate, endDate, selectedRange, selectedPackage]);
return (
@@ -238,16 +231,16 @@ const Stats = () => {
Elevate your projects with Mindfire's game-changing open-source
packages.
-
- {packages.map((package_list) => (
+
+ {packages.map((package_item) => (
- {package_list.name.replaceAll("-", " ")}
+ {package_item.name.replaceAll("-", " ")}
@@ -255,7 +248,7 @@ const Stats = () => {
@@ -298,15 +293,19 @@ const Stats = () => {
@@ -314,7 +313,7 @@ const Stats = () => {
@@ -322,7 +321,7 @@ const Stats = () => {
src={github}
height={30}
width={30}
- alt='npm_img'
+ alt='github_img'
loading='lazy'
quality={75}
/>
@@ -385,31 +384,45 @@ const Stats = () => {
as='h1'
className='text-lg font-large leading-6 text-gray-900 capitalize text-center mb-4 font-extrabold'
>
- {npmPackage.name.replaceAll("-", " ")}
+ {selectedPackage.name.replaceAll("-", " ")}
-
+
Select
-
+ {selectedPackage.type === "npm" ? (
+
+ ) : (
+
+ )}
- {selectedRange === true ? (
-
+ {selectedRange && selectedPackage.type === "npm" ? (
+
-
-
-
-
-
-
- {loading ? (
- // Render loading indicator while count is being fetched
-
-
-
- ) : (
- // Render count when it is available
-
- {count}
-
- )}
+
+ ) : null}
+
+
+
+
+
+
+ {loading ? (
+
+
-
-
+ ) : (
+
+ {count}
+
+ )}
-
-
- ) : (
-
-
-
-
-
-
- {loading ? (
- // Render loading indicator while count is being fetched
-
-
-
- ) : (
- // Render count when it is available
-
- {count}
-
- )}
-
-
-
+
- )}
+
diff --git a/src/app/projects/assets/stats.json b/src/app/projects/assets/stats.json
index e03009ca..36f756e8 100644
--- a/src/app/projects/assets/stats.json
+++ b/src/app/projects/assets/stats.json
@@ -1,6 +1,7 @@
[
{
"name": "fmdapi-node-weaver",
+ "type": "npm",
"day": 0,
"week": 3,
"year": 70,
@@ -8,6 +9,7 @@
},
{
"name": "react-canvas-editor",
+ "type": "npm",
"day": 1,
"week": 22,
"year": 947,
@@ -15,9 +17,18 @@
},
{
"name": "canvas-editor",
+ "type": "npm",
"day": 0,
"week": 7,
"year": 1063,
"total": 1063
+ },
+ {
+ "name": "neo-pusher",
+ "type": "pypi",
+ "last_day": 46,
+ "last_week": 935,
+ "last_month": 1011,
+ "total": 1011
}
]
diff --git a/updateProject.mjs b/updateProject.mjs
index 40569664..496d79dd 100644
--- a/updateProject.mjs
+++ b/updateProject.mjs
@@ -188,8 +188,13 @@ async function updateProjects() {
JSON.stringify(sortedContributions, null, 2)
);
console.log("Contributors list updated successfully.");
-
- getAllStats(repoNames)
+ const npmPackages = [
+ "fmdapi-node-weaver",
+ "react-canvas-editor",
+ "canvas-editor",
+ ];
+ const pypiPackages = ["neo-pusher"];
+ getAllStats(npmPackages, pypiPackages)
.then((statsMap) => {
fs.writeFileSync(
path.join(__dirname, "src/app/projects/assets/stats.json"),
@@ -221,6 +226,22 @@ async function fetchDownloadStats(packageName, period) {
return data;
}
+// Function to fetch PyPI download statistics for a given package
+async function fetchPyPIDownloadStats(packageName) {
+ const url = `https://pypistats.org/api/packages/${packageName}/recent`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ console.log(
+ `Failed to fetch download stats for ${packageName} (PyPI): ${response.statusText}`
+ );
+ return null;
+ }
+
+ const data = await response.json();
+ return data.data; // { last_day, last_week, last_month }
+}
+
// Function to calculate average downloads from the statistics
function calculateAverageDownloads(stats) {
return stats.downloads.reduce(
@@ -229,8 +250,8 @@ function calculateAverageDownloads(stats) {
);
}
-// Function to fetch and process statistics for a package and period
-async function getStats(packageName, period) {
+// Function to fetch and process statistics for a package and period (npm)
+async function getNpmStats(packageName, period) {
try {
// Fetch download statistics
const stats = await fetchDownloadStats(packageName, period);
@@ -247,26 +268,25 @@ async function getStats(packageName, period) {
}
}
-// Function to fetch and aggregate statistics for all packages and periods
-async function getAllStats(npmPackages) {
+// Function to fetch and aggregate statistics for all npm and PyPI packages
+async function getAllStats(npmPackages, pypiPackages) {
const statsMap = [];
- // Fetch stats for each package and period
+ // Fetch stats for npm packages
await Promise.all(
npmPackages.map(async (packageName) => {
try {
- // Fetch stats for different periods
const [dayStats, weekStats, yearStats, totalStats] = await Promise.all([
- getStats(packageName, "last-day"),
- getStats(packageName, "last-week"),
- getStats(packageName, "last-year"),
- getStats(packageName, "1000-01-01:3000-01-01"),
+ getNpmStats(packageName, "last-day"),
+ getNpmStats(packageName, "last-week"),
+ getNpmStats(packageName, "last-year"),
+ getNpmStats(packageName, "1000-01-01:3000-01-01"),
]);
- // If any stats exist, add to the map
if (dayStats !== 0 || weekStats !== 0 || yearStats !== 0) {
statsMap.push({
name: packageName,
+ type: "npm",
day: dayStats,
week: weekStats,
year: yearStats,
@@ -274,12 +294,33 @@ async function getAllStats(npmPackages) {
});
}
} catch (error) {
- // Log and handle errors
console.error(`Error fetching stats for ${packageName}:`, error);
}
})
);
+ // Fetch stats for PyPI packages
+ await Promise.all(
+ pypiPackages.map(async (packageName) => {
+ try {
+ const stats = await fetchPyPIDownloadStats(packageName);
+
+ if (stats) {
+ statsMap.push({
+ name: packageName,
+ type: "pypi",
+ last_day: stats.last_day,
+ last_week: stats.last_week,
+ last_month: stats.last_month,
+ total: stats.last_month,
+ });
+ }
+ } catch (error) {
+ console.error(`Error fetching stats for ${packageName} (PyPI):`, error);
+ }
+ })
+ );
+
return statsMap;
}