+
-
+
-
-
Loading repository data...
-
+
+
Loading repository data...
+
-
- Last updated:
-
+
-
-
-
-
+
diff --git a/gh-pages-template/styles.css b/gh-pages-template/styles.css
deleted file mode 100644
index 9f758ed1..00000000
--- a/gh-pages-template/styles.css
+++ /dev/null
@@ -1,180 +0,0 @@
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
- line-height: 1.6;
- color: #24292f;
- background-color: #ffffff;
- padding: 20px;
-}
-
-.container {
- max-width: 1200px;
- margin: 0 auto;
-}
-
-header {
- text-align: center;
- margin-bottom: 40px;
- padding-bottom: 20px;
- border-bottom: 1px solid #d1d9e0;
-}
-
-h1 {
- color: #0969da;
- margin-bottom: 10px;
-}
-
-.subtitle {
- color: #656d76;
- font-size: 18px;
-}
-
-.search-container {
- margin-bottom: 30px;
-}
-
-#searchInput {
- width: 100%;
- padding: 12px 16px;
- border: 1px solid #d1d9e0;
- border-radius: 6px;
- font-size: 16px;
- background-color: #f6f8fa;
-}
-
-#searchInput:focus {
- outline: none;
- border-color: #0969da;
- background-color: #ffffff;
-}
-
-.stats {
- display: flex;
- justify-content: center;
- gap: 30px;
- margin-bottom: 30px;
- flex-wrap: wrap;
-}
-
-.stat {
- text-align: center;
- padding: 15px;
- background-color: #f6f8fa;
- border-radius: 6px;
- min-width: 120px;
-}
-
-.stat-number {
- font-size: 24px;
- font-weight: bold;
- color: #0969da;
-}
-
-.stat-label {
- color: #656d76;
- font-size: 14px;
-}
-
-.repository-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- gap: 20px;
-}
-
-.repository-card {
- border: 1px solid #d1d9e0;
- border-radius: 8px;
- padding: 20px;
- background-color: #ffffff;
- transition: box-shadow 0.2s ease;
-}
-
-.repository-card:hover {
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-}
-
-.repository-name {
- font-size: 18px;
- font-weight: 600;
- color: #0969da;
- margin-bottom: 15px;
- text-decoration: none;
-}
-
-.repository-name:hover {
- text-decoration: underline;
-}
-
-.release-list {
- list-style: none;
-}
-
-.release-item {
- padding: 8px 0;
- border-bottom: 1px solid #f6f8fa;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.release-item:last-child {
- border-bottom: none;
-}
-
-.release-tag {
- font-weight: 500;
- color: #24292f;
-}
-
-.asset-count {
- font-size: 12px;
- color: #656d76;
- background-color: #f6f8fa;
- padding: 2px 8px;
- border-radius: 12px;
-}
-
-.release-link {
- text-decoration: none;
- color: inherit;
-}
-
-.release-link:hover .release-tag {
- color: #0969da;
-}
-
-.no-results {
- text-align: center;
- color: #656d76;
- font-style: italic;
- padding: 40px;
-}
-
-.last-updated {
- text-align: center;
- margin-top: 40px;
- padding-top: 20px;
- border-top: 1px solid #d1d9e0;
- color: #656d76;
- font-size: 14px;
-}
-
-@media (max-width: 768px) {
- .repository-grid {
- grid-template-columns: 1fr;
- }
-
- .stats {
- gap: 15px;
- }
-
- .stat {
- min-width: 100px;
- padding: 10px;
- }
-}
From dc2c55c7ab8302a9ca0164b94ce13d6e4cbe5c7e Mon Sep 17 00:00:00 2001
From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
Date: Tue, 23 Sep 2025 22:11:05 -0400
Subject: [PATCH 2/5] reduce github api calls
---
.github/scripts/generate-packages.js | 170 ++++++++++++++++++++++
.github/workflows/sync-release-assets.yml | 19 +++
gh-pages-template/assets/js/app.js | 144 ++++--------------
3 files changed, 216 insertions(+), 117 deletions(-)
create mode 100644 .github/scripts/generate-packages.js
diff --git a/.github/scripts/generate-packages.js b/.github/scripts/generate-packages.js
new file mode 100644
index 00000000..07e74603
--- /dev/null
+++ b/.github/scripts/generate-packages.js
@@ -0,0 +1,170 @@
+const fs = require('fs');
+const path = require('path');
+
+/**
+ * Generate packages.json file by scanning the dist directory structure
+ * @param {string} distPath - Path to the dist directory
+ * @returns {Object} Generated packages data
+ */
+function generatePackagesJson(distPath = '.') {
+ console.log(`Scanning dist directory: ${distPath}`);
+
+ const repositories = [];
+
+ try {
+ // Read the dist directory
+ const distDir = fs.readdirSync(distPath, { withFileTypes: true });
+
+ // Process each subdirectory as a potential repository
+ for (const dirent of distDir) {
+ if (dirent.isDirectory() && dirent.name !== '.git') {
+ console.log(`Processing repository: ${dirent.name}`);
+ const repoData = scanRepositoryDirectory(path.join(distPath, dirent.name));
+ if (repoData) {
+ repositories.push(repoData);
+ console.log(` Found ${repoData.releases.length} releases`);
+ } else {
+ console.log(` No releases with assets found`);
+ }
+ }
+ }
+
+ // Sort repositories by name
+ repositories.sort((a, b) => a.name.localeCompare(b.name));
+
+ // Calculate totals
+ const totalReleases = repositories.reduce((sum, repo) => sum + repo.releases.length, 0);
+ const totalAssets = repositories.reduce((sum, repo) =>
+ sum + repo.releases.reduce((releaseSum, release) => releaseSum + release.assetCount, 0), 0
+ );
+
+ const packagesData = {
+ lastUpdated: new Date().toISOString(),
+ repositories: repositories,
+ stats: {
+ totalRepositories: repositories.length,
+ totalReleases: totalReleases,
+ totalAssets: totalAssets
+ }
+ };
+
+ console.log(`Generated packages data:`);
+ console.log(` Repositories: ${repositories.length}`);
+ console.log(` Total Releases: ${totalReleases}`);
+ console.log(` Total Assets: ${totalAssets}`);
+
+ return packagesData;
+
+ } catch (error) {
+ console.error('Error scanning dist directory:', error);
+ throw error;
+ }
+}
+
+/**
+ * Scan a repository directory to find releases and count assets
+ * @param {string} repoPath - Path to the repository directory
+ * @returns {Object|null} Repository data with releases or null if no valid releases
+ */
+function scanRepositoryDirectory(repoPath) {
+ const repoName = path.basename(repoPath);
+ const releases = [];
+
+ try {
+ if (!fs.existsSync(repoPath) || !fs.statSync(repoPath).isDirectory()) {
+ return null;
+ }
+
+ // Scan for release directories
+ const repoDirContents = fs.readdirSync(repoPath, { withFileTypes: true });
+
+ for (const dirent of repoDirContents) {
+ if (dirent.isDirectory()) {
+ const releaseData = scanReleaseDirectory(path.join(repoPath, dirent.name));
+ if (releaseData) {
+ releases.push(releaseData);
+ }
+ }
+ }
+
+ // Sort releases by tag name (newest first, assuming semantic versioning)
+ releases.sort((a, b) => b.tag.localeCompare(a.tag, undefined, { numeric: true, sensitivity: 'base' }));
+
+ if (releases.length > 0) {
+ return {
+ name: repoName,
+ releases: releases
+ };
+ }
+
+ return null;
+
+ } catch (error) {
+ console.error(`Error processing repository ${repoName}:`, error);
+ return null;
+ }
+}
+
+/**
+ * Scan a release directory to count asset files
+ * @param {string} releasePath - Path to the release directory
+ * @returns {Object|null} Release data with asset count or null if no assets
+ */
+function scanReleaseDirectory(releasePath) {
+ const releaseTag = path.basename(releasePath);
+
+ try {
+ if (!fs.existsSync(releasePath) || !fs.statSync(releasePath).isDirectory()) {
+ return null;
+ }
+
+ // Count actual asset files (exclude hash files and README)
+ const releaseContents = fs.readdirSync(releasePath, { withFileTypes: true });
+ const assetFiles = releaseContents.filter(dirent => {
+ if (!dirent.isFile()) return false;
+
+ const filename = dirent.name;
+ // Skip hash files and README
+ return !(filename.endsWith('.sha256') ||
+ filename.endsWith('.sha512') ||
+ filename.endsWith('.md5') ||
+ filename === 'README.md');
+ });
+
+ if (assetFiles.length > 0) {
+ return {
+ tag: releaseTag,
+ assetCount: assetFiles.length
+ };
+ }
+
+ return null;
+
+ } catch (error) {
+ console.error(`Error processing release ${releaseTag}:`, error);
+ return null;
+ }
+}
+
+/**
+ * Write packages.json file to the specified path
+ * @param {Object} packagesData - The packages data to write
+ * @param {string} outputPath - Path where to write the packages.json file
+ */
+function writePackagesJson(packagesData, outputPath = './packages.json') {
+ try {
+ const jsonString = JSON.stringify(packagesData, null, 2);
+ fs.writeFileSync(outputPath, jsonString, 'utf8');
+ console.log(`Generated packages.json: ${outputPath}`);
+ } catch (error) {
+ console.error('Error writing packages.json:', error);
+ throw error;
+ }
+}
+
+module.exports = {
+ generatePackagesJson,
+ scanRepositoryDirectory,
+ scanReleaseDirectory,
+ writePackagesJson
+};
diff --git a/.github/workflows/sync-release-assets.yml b/.github/workflows/sync-release-assets.yml
index 13cfd3c6..7e19a7f1 100644
--- a/.github/workflows/sync-release-assets.yml
+++ b/.github/workflows/sync-release-assets.yml
@@ -67,6 +67,25 @@ jobs:
process.chdir('./dist');
await syncReleaseAssets(github, context, isPullRequest, maxNewAssets);
+ - name: Generate packages.json
+ uses: actions/github-script@v8
+ with:
+ github-token: ${{ secrets.GH_BOT_TOKEN }}
+ script: |
+ // Import the packages generation module
+ const { generatePackagesJson, writePackagesJson } = require('./.github/scripts/generate-packages.js');
+
+ console.log('Generating packages.json from dist directory...');
+
+ // Change to dist directory
+ process.chdir('./dist');
+
+ // Generate the packages data
+ const packagesData = generatePackagesJson('.');
+
+ // Write the packages.json file
+ writePackagesJson(packagesData, './packages.json');
+
- name: Commit and push changes
if: github.event_name != 'pull_request'
uses: actions-js/push@v1.5
diff --git a/gh-pages-template/assets/js/app.js b/gh-pages-template/assets/js/app.js
index 1803da9b..8fa0ece1 100644
--- a/gh-pages-template/assets/js/app.js
+++ b/gh-pages-template/assets/js/app.js
@@ -1,151 +1,61 @@
/**
* Repository Data Manager
- * Handles loading and managing repository data from GitHub API
+ * Handles loading and managing repository data from a single JSON file
*/
class RepositoryDataManager {
constructor() {
this.repositoryData = [];
this.orgName = 'LizardByte'; // Organization name
this.distBranch = 'dist';
- this.apiBase = 'https://api.github.com';
this.rawBase = 'https://raw.githubusercontent.com';
}
/**
- * Load repository data by scanning the dist branch via GitHub API
+ * Load repository data from packages.json in the dist branch
*/
async loadRepositoryData() {
try {
- console.log('Loading repository data from GitHub API...');
+ console.log('Loading repository data from packages.json...');
- // Get the contents of the dist branch
- const response = await fetch(`${this.apiBase}/repos/${this.orgName}/packages/contents?ref=${this.distBranch}`);
+ // Fetch the packages.json file from the dist branch
+ const response = await fetch(`${this.rawBase}/${this.orgName}/packages/${this.distBranch}/packages.json`);
if (!response.ok) {
- throw new Error(`GitHub API error: ${response.status}`);
+ throw new Error(`Failed to fetch packages.json: ${response.status}`);
}
- const contents = await response.json();
+ const data = await response.json();
- // Filter for directories (repositories)
- const repoDirs = contents.filter(item => item.type === 'dir');
-
- console.log(`Found ${repoDirs.length} repository directories`);
-
- this.repositoryData = [];
-
- // Process each repository directory
- for (const repoDir of repoDirs) {
- const repoData = await this.processRepository(repoDir.name);
- if (repoData && repoData.releases.length > 0) {
- this.repositoryData.push(repoData);
- }
+ // Validate the data structure
+ if (!data.repositories || !Array.isArray(data.repositories)) {
+ throw new Error('Invalid packages.json format: missing repositories array');
}
- console.log(`Loaded data for ${this.repositoryData.length} repositories with releases`);
+ this.repositoryData = data.repositories;
+
+ console.log(`Loaded data for ${this.repositoryData.length} repositories from packages.json`);
return {
repositories: this.repositoryData,
- lastUpdated: new Date().toISOString(),
+ lastUpdated: data.lastUpdated || new Date().toISOString(),
totalRepositories: this.repositoryData.length,
- totalReleases: this.repositoryData.reduce((sum, repo) => sum + repo.releases.length, 0),
+ totalReleases: this.repositoryData.reduce((sum, repo) => sum + (repo.releases ? repo.releases.length : 0), 0),
totalAssets: this.repositoryData.reduce((sum, repo) =>
- sum + repo.releases.reduce((releaseSum, release) => releaseSum + release.assetCount, 0), 0)
+ sum + (repo.releases ? repo.releases.reduce((releaseSum, release) => releaseSum + (release.assetCount || 0), 0) : 0), 0)
};
} catch (error) {
console.error('Error loading repository data:', error);
// Fallback to empty data
this.repositoryData = [];
- return null;
- }
- }
-
- /**
- * Process a single repository directory to get release information
- */
- async processRepository(repoName) {
- try {
- console.log(`Processing repository: ${repoName}`);
-
- // Get repository directory contents
- const response = await fetch(`${this.apiBase}/repos/${this.orgName}/packages/contents/${repoName}?ref=${this.distBranch}`);
-
- if (!response.ok) {
- console.warn(`Could not fetch contents for ${repoName}: ${response.status}`);
- return null;
- }
-
- const contents = await response.json();
-
- // Filter for directories (releases)
- const releaseDirs = contents.filter(item => item.type === 'dir');
-
- if (releaseDirs.length === 0) {
- console.log(`No release directories found for ${repoName}`);
- return null;
- }
-
- const repoData = {
- name: repoName,
- releases: []
- };
-
- // Process each release directory
- for (const releaseDir of releaseDirs) {
- const releaseData = await this.processRelease(repoName, releaseDir.name);
- if (releaseData) {
- repoData.releases.push(releaseData);
- }
- }
-
- // Sort releases by tag name (newest first, assuming semantic versioning)
- repoData.releases.sort((a, b) => b.tag.localeCompare(a.tag, undefined, { numeric: true, sensitivity: 'base' }));
-
- return repoData;
-
- } catch (error) {
- console.error(`Error processing repository ${repoName}:`, error);
- return null;
- }
- }
-
- /**
- * Process a single release directory to count assets
- */
- async processRelease(repoName, releaseTag) {
- try {
- // Get release directory contents
- const response = await fetch(`${this.apiBase}/repos/${this.orgName}/packages/contents/${repoName}/${releaseTag}?ref=${this.distBranch}`);
-
- if (!response.ok) {
- console.warn(`Could not fetch release contents for ${repoName}/${releaseTag}: ${response.status}`);
- return null;
- }
-
- const contents = await response.json();
-
- // Count actual asset files (exclude hash files)
- const assetFiles = contents.filter(item =>
- item.type === 'file' &&
- !item.name.endsWith('.sha256') &&
- !item.name.endsWith('.sha512') &&
- !item.name.endsWith('.md5') &&
- item.name !== 'README.md'
- );
-
- if (assetFiles.length === 0) {
- return null;
- }
-
return {
- tag: releaseTag,
- assetCount: assetFiles.length
+ repositories: [],
+ error: error.message,
+ lastUpdated: new Date().toISOString(),
+ totalRepositories: 0,
+ totalReleases: 0,
+ totalAssets: 0
};
-
- } catch (error) {
- console.error(`Error processing release ${repoName}/${releaseTag}:`, error);
- return null;
}
}
@@ -166,7 +76,7 @@ class RepositoryDataManager {
return this.repositoryData.filter(repo => {
const repoMatch = repo.name.toLowerCase().includes(searchTerm.toLowerCase());
- const releaseMatch = repo.releases.some(release =>
+ const releaseMatch = repo.releases && repo.releases.some(release =>
release.tag.toLowerCase().includes(searchTerm.toLowerCase()));
return repoMatch || releaseMatch;
});
@@ -203,7 +113,7 @@ class UIManager {
${repo.name}
- ${repo.releases.map(release => `
+ ${repo.releases ? repo.releases.map(release => `
-
@@ -211,7 +121,7 @@ class UIManager {
${release.assetCount}
- `).join('')}
+ `).join('') : '- No releases found
'}
@@ -224,9 +134,9 @@ class UIManager {
*/
updateStats(repos) {
const repoCount = repos.length;
- const releaseCount = repos.reduce((sum, repo) => sum + repo.releases.length, 0);
+ const releaseCount = repos.reduce((sum, repo) => sum + (repo.releases ? repo.releases.length : 0), 0);
const assetCount = repos.reduce((sum, repo) =>
- sum + repo.releases.reduce((releaseSum, release) => releaseSum + release.assetCount, 0), 0);
+ sum + (repo.releases ? repo.releases.reduce((releaseSum, release) => releaseSum + (release.assetCount || 0), 0) : 0), 0);
this.repoCountElement.textContent = repoCount;
this.releaseCountElement.textContent = releaseCount;
From 699704c0552d92c07be7e36cd5691164c42d0683 Mon Sep 17 00:00:00 2001
From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
Date: Tue, 23 Sep 2025 22:20:03 -0400
Subject: [PATCH 3/5] Update index.html
---
gh-pages-template/index.html | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/gh-pages-template/index.html b/gh-pages-template/index.html
index 6afc168a..2c35260c 100644
--- a/gh-pages-template/index.html
+++ b/gh-pages-template/index.html
@@ -22,24 +22,24 @@