Skip to content

Commit 8d9fdb8

Browse files
committed
Add script to generate minified category files
1 parent 9edb952 commit 8d9fdb8

2 files changed

Lines changed: 226 additions & 0 deletions

File tree

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
// Function to recursively find all metadata.json files
7+
function findMetadataFiles(dir) {
8+
const metadataFiles = [];
9+
10+
if (!fs.existsSync(dir)) {
11+
return metadataFiles;
12+
}
13+
14+
const items = fs.readdirSync(dir, { withFileTypes: true });
15+
16+
for (const item of items) {
17+
const fullPath = path.join(dir, item.name);
18+
19+
if (item.isDirectory()) {
20+
// Recursively search subdirectories
21+
metadataFiles.push(...findMetadataFiles(fullPath));
22+
} else if (item.name === 'metadata.json') {
23+
metadataFiles.push(fullPath);
24+
}
25+
}
26+
27+
return metadataFiles;
28+
}
29+
30+
// Function to load and validate metadata
31+
function loadMetadata(filePath) {
32+
try {
33+
const content = fs.readFileSync(filePath, 'utf8');
34+
const metadata = JSON.parse(content);
35+
36+
// Basic validation - ensure required fields exist
37+
const requiredFields = ['name', 'category', 'description', 'version', 'commit', 'owner', 'repo', 'path'];
38+
for (const field of requiredFields) {
39+
if (!(field in metadata) || metadata[field] === null || metadata[field] === undefined || metadata[field] === '') {
40+
console.warn(`⚠️ Skipping ${filePath}: missing or empty field '${field}'`);
41+
return null;
42+
}
43+
}
44+
45+
// Add file path for reference
46+
metadata.filePath = path.dirname(filePath).replace(/\\/g, '/');
47+
48+
return metadata;
49+
} catch (error) {
50+
console.warn(`⚠️ Skipping ${filePath}: ${error.message}`);
51+
return null;
52+
}
53+
}
54+
55+
// Function to load valid categories
56+
function loadValidCategories() {
57+
try {
58+
const categoriesPath = path.join(__dirname, '../../', 'categories.json');
59+
const categoriesContent = fs.readFileSync(categoriesPath, 'utf8');
60+
return JSON.parse(categoriesContent);
61+
} catch (error) {
62+
console.warn(`⚠️ Could not load categories.json: ${error.message}`);
63+
return [];
64+
}
65+
}
66+
67+
// Main function
68+
async function main() {
69+
console.log('🔄 Generating minified category files...');
70+
71+
// Load valid categories
72+
const validCategories = loadValidCategories();
73+
console.log(`📋 Valid categories: ${validCategories.join(', ')}`);
74+
75+
// Find all metadata files
76+
const repositoriesDir = path.join(__dirname, '../..', 'repositories');
77+
const metadataFiles = findMetadataFiles(repositoriesDir);
78+
console.log(`📁 Found ${metadataFiles.length} metadata files`);
79+
80+
if (metadataFiles.length === 0) {
81+
console.log('ℹ️ No metadata files found. No category files will be generated.');
82+
return;
83+
}
84+
85+
// Group metadata by category
86+
const categorizedApps = {};
87+
let processedCount = 0;
88+
let skippedCount = 0;
89+
90+
for (const filePath of metadataFiles) {
91+
const metadata = loadMetadata(filePath);
92+
if (metadata) {
93+
const category = metadata.category;
94+
95+
if (!categorizedApps[category]) {
96+
categorizedApps[category] = [];
97+
}
98+
99+
categorizedApps[category].push(metadata);
100+
processedCount++;
101+
console.log(`✅ Added ${metadata.name} to category '${category}'`);
102+
} else {
103+
skippedCount++;
104+
}
105+
}
106+
107+
console.log(`📊 Processed: ${processedCount}, Skipped: ${skippedCount}`);
108+
109+
// Create releases directory if it doesn't exist
110+
const releasesDir = path.join(__dirname, '../..', 'releases');
111+
if (!fs.existsSync(releasesDir)) {
112+
fs.mkdirSync(releasesDir, { recursive: true });
113+
console.log(`📁 Created releases directory`);
114+
}
115+
116+
// Generate category files
117+
const generatedFiles = [];
118+
const categoriesWithReleases = [];
119+
for (const [category, apps] of Object.entries(categorizedApps)) {
120+
const releaseFileName = `category-${category.toLowerCase().replace(/[^a-z0-9]/g, '-')}.min.json`;
121+
const releaseFilePath = path.join(releasesDir, releaseFileName);
122+
123+
// Sort apps by name for consistent ordering
124+
apps.sort((a, b) => a.name.localeCompare(b.name));
125+
126+
// Filter out unwanted fields from apps for category files
127+
const filteredApps = apps.map(app => {
128+
const { commit, owner, repo, path, filePath, category, files, name, description, version, 'supported-devices': supportedDevices, ...cleanApp } = app;
129+
// Add slug in format: owner/repo/subfolder_name
130+
const subfolderName = filePath.split('/').pop();
131+
const slug = `${owner}/${repo}/${subfolderName}`;
132+
133+
// Add only shortened field names
134+
cleanApp.n = name; // name -> n
135+
cleanApp.d = description; // description -> d
136+
cleanApp.v = version; // version -> v
137+
cleanApp.s = slug; // slug -> s
138+
139+
// Include supported-devices if present (apps/scripts only, not themes)
140+
const isTheme = app.category === 'Themes';
141+
if (supportedDevices && !isTheme) {
142+
cleanApp['sd'] = supportedDevices;
143+
}
144+
145+
// Include supported-screen-size if present (themes only)
146+
if (app['supported-screen-size'] && isTheme) {
147+
cleanApp['sss'] = app['supported-screen-size'];
148+
}
149+
150+
return cleanApp;
151+
});
152+
153+
const releaseData = {
154+
category: category,
155+
count: apps.length,
156+
apps: filteredApps
157+
};
158+
159+
try {
160+
// Write without pretty formatting (minified)
161+
fs.writeFileSync(releaseFilePath, JSON.stringify(releaseData), 'utf8');
162+
generatedFiles.push(releaseFileName);
163+
categoriesWithReleases.push(category);
164+
console.log(`📄 Generated ${releaseFileName} with ${apps.length} apps (minified)`);
165+
} catch (error) {
166+
console.error(`❌ Failed to write ${releaseFileName}: ${error.message}`);
167+
}
168+
}
169+
170+
// Clean up old minified category files that are no longer needed
171+
const existingReleaseFiles = fs.readdirSync(releasesDir)
172+
.filter(file => file.startsWith('category-') && file.endsWith('.min.json'));
173+
174+
for (const existingFile of existingReleaseFiles) {
175+
if (!generatedFiles.includes(existingFile)) {
176+
try {
177+
fs.unlinkSync(path.join(releasesDir, existingFile));
178+
console.log(`🗑️ Removed obsolete file: ${existingFile}`);
179+
} catch (error) {
180+
console.warn(`⚠️ Could not remove ${existingFile}: ${error.message}`);
181+
}
182+
}
183+
}
184+
185+
// Generate summary
186+
console.log('');
187+
console.log('📋 Summary:');
188+
console.log(` Categories: ${Object.keys(categorizedApps).length}`);
189+
console.log(` Total apps: ${processedCount}`);
190+
console.log(` Minified category files: ${generatedFiles.length}`);
191+
192+
if (generatedFiles.length > 0) {
193+
console.log('');
194+
console.log('📄 Generated minified category files:');
195+
for (const file of generatedFiles) {
196+
console.log(` - ${file}`);
197+
}
198+
}
199+
200+
console.log('✅ Minified category file generation complete!');
201+
}
202+
203+
// Run the script
204+
main().catch(error => {
205+
console.error('❌ Script failed:', error);
206+
process.exit(1);
207+
});

.github/workflows/generate-releases.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ jobs:
4444
echo "No category.json files to commit"
4545
fi
4646
47+
- name: Generate category.min files
48+
run: |
49+
node .github/scripts/generate-category-min.json-files.js
50+
51+
- name: Commit category.min.json files
52+
run: |
53+
git config --local user.email "action@github.com"
54+
git config --local user.name "GitHub Action"
55+
if [ -d "releases" ] && [ "$(ls -A releases/category-*.min.json 2>/dev/null)" ]; then
56+
git add releases/category-*.min.json
57+
if git diff --staged --quiet; then
58+
echo "No category.min.json file changes to commit"
59+
else
60+
git commit -m "Update category.min.json files [skip ci]"
61+
fi
62+
else
63+
echo "No category.min.json files to commit"
64+
fi
65+
4766
- name: Generate categories.json
4867
run: |
4968
node .github/scripts/generate-categories.json.js

0 commit comments

Comments
 (0)