11const fs = require ( 'fs' ) ;
22
33// Configuration
4- const USERNAME = 'FabioDevCode' ;
4+ const CONFIG = JSON . parse ( fs . readFileSync ( 'config.json' , 'utf8' ) ) ; ;
55
6- // Thème de couleur
7- const BG_COLOR = '#202830' ;
8- const BORDER_COLOR = '#151B23' ;
9- const TITLE_COLOR = '#D1D7E0' ;
10- const TEXT_COLOR = '#D1D7E0' ;
11- const PERCENT_COLOR = '#9298A1' ;
12-
13- // Couleurs officielles GitHub
6+ // Couleurs officielles GitHub (NE PAS MODIFIER)
147const LANGUAGE_COLORS = JSON . parse ( fs . readFileSync ( 'github_colors.json' , 'utf8' ) ) ;
158
169async function fetchGitHubStats ( username , token ) {
17- console . log ( `📊 Récupération des stats pour ${ username } ...` ) ;
18-
19- const headers = {
20- 'Authorization' : `token ${ token } ` ,
21- 'Accept' : 'application/vnd.github.v3+json'
22- } ;
23-
24- try {
25- const reposResponse = await fetch (
26- `https://api.github.com/users/${ username } /repos?per_page=100&type=owner` ,
27- { headers }
28- ) ;
29-
30- if ( ! reposResponse . ok ) {
31- throw new Error ( `GitHub API error: ${ reposResponse . status } ` ) ;
32- }
33-
34- const repos = await reposResponse . json ( ) ;
35- console . log ( `✅ ${ repos . length } repositories trouvés` ) ;
36-
37- // Compter les lignes de code par langage
38- const languageStats = { } ;
39-
40- for ( const repo of repos ) {
41- if ( ! repo . fork && repo . language ) {
42- const langResponse = await fetch ( repo . languages_url , { headers } ) ;
43- const languages = await langResponse . json ( ) ;
44-
45- for ( const [ lang , bytes ] of Object . entries ( languages ) ) {
46- languageStats [ lang ] = ( languageStats [ lang ] || 0 ) + bytes ;
47- }
48- }
49- }
50-
51- console . log ( `📝 ${ Object . keys ( languageStats ) . length } langages différents détectés` ) ;
52- return languageStats ;
53-
54- } catch ( error ) {
55- console . error ( '❌ Erreur:' , error . message ) ;
56- throw error ;
57- }
10+ console . log ( `📊 Récupération des stats pour ${ username } ...` ) ;
11+
12+ const headers = {
13+ 'Authorization' : `token ${ token } ` ,
14+ 'Accept' : 'application/vnd.github.v3+json'
15+ } ;
16+
17+ try {
18+ const reposResponse = await fetch (
19+ `https://api.github.com/users/${ username } /repos?per_page=100&type=owner` ,
20+ { headers }
21+ ) ;
22+
23+ if ( ! reposResponse . ok ) {
24+ throw new Error ( `GitHub API error: ${ reposResponse . status } ` ) ;
25+ }
26+
27+ const repos = await reposResponse . json ( ) ;
28+ console . log ( `✅ ${ repos . length } repositories trouvés` ) ;
29+
30+ // Compter les lignes de code par langage
31+ const languageStats = { } ;
32+
33+ for ( const repo of repos ) {
34+ if ( ! repo . fork && repo . language ) {
35+ const langResponse = await fetch ( repo . languages_url , { headers } ) ;
36+ const languages = await langResponse . json ( ) ;
37+
38+ for ( const [ lang , bytes ] of Object . entries ( languages ) ) {
39+ languageStats [ lang ] = ( languageStats [ lang ] || 0 ) + bytes ;
40+ }
41+ }
42+ }
43+
44+ console . log ( `📝 ${ Object . keys ( languageStats ) . length } langages différents détectés` ) ;
45+ return languageStats ;
46+ } catch ( error ) {
47+ console . error ( '❌ Erreur:' , error . message ) ;
48+ throw error ;
49+ }
5850}
5951
6052function getLanguageColor ( language ) {
61- return LANGUAGE_COLORS [ language ] || '#858585' ;
53+ return LANGUAGE_COLORS [ language ] || '#858585' ;
6254}
6355
6456function generateSVG ( languageStats , topN = 5 ) {
65- // Trier et limiter
66- const sortedLangs = Object . entries ( languageStats )
67- . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] )
68- . slice ( 0 , topN ) ;
69-
70- if ( sortedLangs . length === 0 ) {
71- return generateEmptySVG ( topN ) ;
72- }
73-
74- const totalBytes = sortedLangs . reduce ( ( sum , [ , bytes ] ) => sum + bytes , 0 ) ;
75-
76- // Calculer les pourcentages
77- const langData = sortedLangs . map ( ( [ lang , bytes ] ) => ( {
78- name : lang ,
79- bytes : bytes ,
80- percentage : ( bytes / totalBytes * 100 ) . toFixed ( 1 ) ,
81- color : getLanguageColor ( lang )
82- } ) ) ;
83-
84- // Générer la barre de progression
85- let currentX = 10 ;
86- const barHeight = 12 ;
87- const barY = 50 ;
88- const barSegments = langData . map ( lang => {
89- const width = ( lang . percentage / 100 ) * 400 ;
90- const segment = `<rect x="${ currentX } " y="${ barY } " width="${ width } " height="${ barHeight } " fill="${ lang . color } "/>` ;
91- currentX += width ;
92- return segment ;
93- } ) . join ( '' ) ;
94-
95- // Générer la légende
96- let legendY = 85 ;
97- const legendItems = langData . map ( lang => {
98- const item = `
99- <g>
100- <circle cx="20" cy="${ legendY } " r="5" fill="${ lang . color } "/>
101- <text x="35" y="${ legendY + 4 } " font-size="14" fill="${ TEXT_COLOR } ">${ lang . name } </text>
102- <text x="380" y="${ legendY + 4 } " font-size="14" fill="${ PERCENT_COLOR } " text-anchor="end">${ lang . percentage } %</text>
103- </g>
104- ` ;
105- legendY += 25 ;
106- return item ;
107- } ) . join ( '' ) ;
108-
109- const height = 70 + ( topN * 25 ) + 20 ;
110-
111- return `<?xml version="1.0" encoding="UTF-8"?>
112- <svg width="420" height="${ height } " xmlns="http://www.w3.org/2000/svg">
113- <defs>
114- <style>
115- @import url('https://fonts.googleapis.com/css2?family=Segoe+UI:wght@400;500;600&display=swap');
116- * { font-family: 'Segoe UI', Ubuntu, sans-serif; }
117- </style>
118- </defs>
119-
120- <!-- Background -->
121- <rect width="420" height="${ height } " fill="${ BG_COLOR } " rx="10" stroke="${ BORDER_COLOR } " stroke-width="1"/>
122-
123- <!-- Title -->
124- <text x="210" y="30" font-size="18" fill="${ TITLE_COLOR } " font-weight="600" text-anchor="middle">
125- Top Langages
126- </text>
127-
128- <!-- Progress Bar Container -->
129- <rect x="10" y="${ barY } " width="400" height="${ barHeight } " fill="#161b2200" rx="6"/>
130-
131- <!-- Progress Bar Segments -->
132- ${ barSegments }
133-
134- <!-- Legend -->
135- ${ legendItems }
136- </svg>` ;
57+ // Trier et limiter
58+ const sortedLangs = Object . entries ( languageStats )
59+ . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] )
60+ . slice ( 0 , topN ) ;
61+
62+ if ( sortedLangs . length === 0 ) {
63+ return generateEmptySVG ( topN ) ;
64+ }
65+
66+ const totalBytes = sortedLangs . reduce ( ( sum , [ , bytes ] ) => sum + bytes , 0 ) ;
67+
68+ // Calculer les pourcentages
69+ const langData = sortedLangs . map ( ( [ lang , bytes ] ) => ( {
70+ name : lang ,
71+ bytes : bytes ,
72+ percentage : ( bytes / totalBytes * 100 ) . toFixed ( 1 ) ,
73+ color : getLanguageColor ( lang )
74+ } ) ) ;
75+
76+ // Générer la barre de progression
77+ let currentX = 10 ;
78+ const barHeight = 12 ;
79+ const barY = 50 ;
80+ const barSegments = langData . map ( lang => {
81+ const width = ( lang . percentage / 100 ) * 400 ;
82+ const segment = `<rect x="${ currentX } " y="${ barY } " width="${ width } " height="${ barHeight } " fill="${ lang . color } "/>` ;
83+ currentX += width ;
84+ return segment ;
85+ } ) . join ( '' ) ;
86+
87+ // Générer la légende
88+ let legendY = 85 ;
89+ const legendItems = langData . map ( lang => {
90+ const item = `
91+ <g>
92+ <circle cx="20" cy="${ legendY } " r="5" fill="${ lang . color } "/>
93+ <text x="35" y="${ legendY + 4 } " font-size="14" fill="${ CONFIG . TEXT_COLOR } ">${ lang . name } </text>
94+ <text x="380" y="${ legendY + 4 } " font-size="14" fill="${ CONFIG . PERCENT_COLOR } " text-anchor="end">${ lang . percentage } %</text>
95+ </g>
96+ ` ;
97+ legendY += 25 ;
98+ return item ;
99+ } ) . join ( '' ) ;
100+
101+ const height = 70 + ( topN * 25 ) + 20 ;
102+
103+ return `<?xml version="1.0" encoding="UTF-8"?>
104+ <svg width="420" height="${ height } " xmlns="http://www.w3.org/2000/svg">
105+ <defs>
106+ <style>
107+ @import url('https://fonts.googleapis.com/css2?family=Segoe+UI:wght@400;500;600&display=swap');
108+ * { font-family: 'Segoe UI', Ubuntu, sans-serif; }
109+ </style>
110+ </defs>
111+
112+ <!-- Background -->
113+ <rect width="420" height="${ height } " fill="${ CONFIG . BG_COLOR } " rx="10" stroke="${ CONFIG . BORDER_COLOR } " stroke-width="1"/>
114+
115+ <!-- Title -->
116+ <text x="210" y="30" font-size="18" fill="${ CONFIG . TITLE_COLOR } " font-weight="600" text-anchor="middle">
117+ ${ CONFIG . TITLE }
118+ </text>
119+
120+ <!-- Progress Bar Segments -->
121+ ${ barSegments }
122+
123+ <!-- Legend -->
124+ ${ legendItems }
125+ </svg>` ;
137126}
138127
139128function generateEmptySVG ( topN ) {
140- return `<?xml version="1.0" encoding="UTF-8"?>
141- <svg width="420" height="150" xmlns="http://www.w3.org/2000/svg">
142- <rect width="420" height="150" fill="#0d1117" rx="10"/>
143- <text x="210" y="75" font-size="16" fill="#8b949e" text-anchor="middle">
144- Aucune donnée disponible
145- </text>
146- </svg>` ;
129+ return `<?xml version="1.0" encoding="UTF-8"?>
130+ <svg width="420" height="150" xmlns="http://www.w3.org/2000/svg">
131+ <rect width="420" height="150" fill="#0d1117" rx="10"/>
132+ <text x="210" y="75" font-size="16" fill="#8b949e" text-anchor="middle">
133+ Aucune donnée disponible
134+ </text>
135+ </svg>`;
147136}
148137
149138async function main ( ) {
150- const token = process . env . GITHUB_TOKEN ;
151-
152- if ( ! token ) {
153- console . error ( '❌ GITHUB_TOKEN non défini !' ) ;
154- process . exit ( 1 ) ;
155- }
156-
157- try {
158- const languageStats = await fetchGitHubStats ( USERNAME , token ) ;
159-
160- // Générer plusieurs versions
161- const variants = [ 4 , 5 , 6 , 7 , 8 ] ;
162-
163- console . log ( '\n📸 Génération des images SVG...' ) ;
164- variants . forEach ( n => {
165- const svg = generateSVG ( languageStats , n ) ;
166- const filename = `stats-top${ n } .svg` ;
167- fs . writeFileSync ( filename , svg ) ;
168- console . log ( ` ✅ ${ filename } ` ) ;
169- } ) ;
170-
171- // Générer aussi une version "default" (top 5)
172- const defaultSvg = generateSVG ( languageStats , 5 ) ;
173- fs . writeFileSync ( 'stats.svg' , defaultSvg ) ;
174- console . log ( ' ✅ stats.svg (default)' ) ;
175- console . log ( '\n🎉 Toutes les images ont été générées avec succès !' ) ;
176- } catch ( error ) {
177- console . error ( '❌ Erreur lors de la génération:' , error ) ;
178- process . exit ( 1 ) ;
179- }
139+ const token = process . env . GITHUB_TOKEN ;
140+
141+ if ( ! token ) {
142+ console . error ( '❌ GITHUB_TOKEN non défini !' ) ;
143+ process . exit ( 1 ) ;
144+ }
145+
146+ try {
147+ const languageStats = await fetchGitHubStats ( CONFIG . USERNAME , token ) ;
148+
149+ // Générer plusieurs versions
150+ const variants = [ 2 , 4 , 5 , 6 , 7 , 8 ] ;
151+
152+ console . log ( '\n📸 Génération des images SVG...' ) ;
153+ variants . forEach ( n => {
154+ const svg = generateSVG ( languageStats , n ) ;
155+ const filename = `stats/stats-top${ n } .svg` ;
156+ fs . writeFileSync ( filename , svg ) ;
157+ console . log ( ` ✅ ${ filename } ` ) ;
158+ } ) ;
159+
160+ console . log ( '\n🎉 Toutes les images ont été générées avec succès !' ) ;
161+ } catch ( error ) {
162+ console . error ( '❌ Erreur lors de la génération:' , error ) ;
163+ process . exit ( 1 ) ;
164+ }
180165}
181166
182167main ( ) ;
0 commit comments