11console . log ( 'Script loaded' ) ;
22
3+ // Add your GitHub token here (optional - increases rate limit from 60 to 5000 requests/hour)
4+ // Get a token at: https://github.com/settings/tokens (no scopes needed)
5+ const GITHUB_TOKEN = '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' ; // Example: 'ghp_xxxxxxxxxxxx'
6+
37// State
48const state = {
59 platforms : [ ] ,
@@ -15,24 +19,25 @@ function getRepoPath() {
1519 return parts [ 1 ] && parts [ 2 ] ? `${ parts [ 1 ] } /${ parts [ 2 ] } ` : 'Vic-Nas/PythonSolutions' ;
1620}
1721
18- // Users can set their own token in browser console:
19- // localStorage.setItem('github_token', 'ghp_your_token_here')
20- const GITHUB_TOKEN = localStorage . getItem ( 'github_token' ) || '' ;
21-
22- // Fetch folder contents
22+ // Fetch folder contents with in-memory caching
2323async function fetchFolderContents ( path ) {
24+ // Return cached data if available
2425 if ( state . folderCache [ path ] ) {
2526 return state . folderCache [ path ] ;
2627 }
2728
2829 try {
29- const headers = { } ;
30+ const headers = { 'Accept' : 'application/vnd.github.v3+json' } ;
3031 if ( GITHUB_TOKEN ) {
3132 headers [ 'Authorization' ] = `token ${ GITHUB_TOKEN } ` ;
3233 }
3334
3435 const res = await fetch ( `https://api.github.com/repos/${ getRepoPath ( ) } /contents/${ path } ` , { headers } ) ;
35- if ( ! res . ok ) return null ;
36+
37+ if ( ! res . ok ) {
38+ console . error ( `Failed to fetch ${ path } : ${ res . status } ${ res . statusText } ` ) ;
39+ return null ;
40+ }
3641
3742 const items = await res . json ( ) ;
3843 state . folderCache [ path ] = items ;
@@ -57,15 +62,17 @@ function hasFiles(items) {
5762async function loadPlatforms ( ) {
5863 console . log ( 'Loading platforms...' ) ;
5964 const rootItems = await fetchFolderContents ( '' ) ;
60- if ( ! rootItems ) return ;
65+ if ( ! rootItems ) {
66+ console . error ( 'Failed to load root directory' ) ;
67+ return ;
68+ }
6169
6270 const platformFolders = rootItems . filter ( item =>
6371 item . type === 'dir' &&
6472 ! [ 'utils' , '.git' ] . includes ( item . name ) &&
6573 ! item . name . startsWith ( '.' )
6674 ) ;
6775
68- // Clear platforms before loading
6976 state . platforms = [ ] ;
7077
7178 for ( const folder of platformFolders ) {
@@ -76,28 +83,19 @@ async function loadPlatforms() {
7683 count : 0
7784 } ;
7885
79- // Add platform immediately so it shows up
80- state . platforms . push ( platformData ) ;
81-
82- // Then load details asynchronously
83- ( async ( ) => {
84- // Check for platform.png
85- const contents = await fetchFolderContents ( folder . name ) ;
86- if ( contents ) {
87- const platformImg = contents . find ( f => f . name === 'platform.png' ) ;
88- if ( platformImg ) {
89- platformData . image = platformImg . download_url || `${ folder . name } /platform.png` ;
90- }
91-
92- // Count items recursively
93- platformData . count = await countItems ( folder . name ) ;
94-
95- // Re-render to show updated count
96- if ( state . currentView === 'platforms' ) {
97- renderPlatforms ( ) ;
98- }
86+ // Check for platform.png
87+ const contents = await fetchFolderContents ( folder . name ) ;
88+ if ( contents ) {
89+ const platformImg = contents . find ( f => f . name === 'platform.png' ) ;
90+ if ( platformImg ) {
91+ platformData . image = platformImg . download_url || `${ folder . name } /platform.png` ;
9992 }
100- } ) ( ) ;
93+
94+ // Count items recursively
95+ platformData . count = await countItems ( folder . name ) ;
96+ }
97+
98+ state . platforms . push ( platformData ) ;
10199 }
102100
103101 state . platforms . sort ( ( a , b ) => a . name . localeCompare ( b . name ) ) ;
@@ -275,7 +273,12 @@ async function renderProblem() {
275273
276274 if ( pyFiles . length > 0 ) {
277275 try {
278- const res = await fetch ( `https://api.github.com/repos/${ getRepoPath ( ) } /contents/${ pathStr } /${ pyFiles [ 0 ] . name } ` ) ;
276+ const headers = { 'Accept' : 'application/vnd.github.v3+json' } ;
277+ if ( GITHUB_TOKEN ) {
278+ headers [ 'Authorization' ] = `token ${ GITHUB_TOKEN } ` ;
279+ }
280+
281+ const res = await fetch ( `https://api.github.com/repos/${ getRepoPath ( ) } /contents/${ pathStr } /${ pyFiles [ 0 ] . name } ` , { headers } ) ;
279282 if ( res . ok ) {
280283 const data = await res . json ( ) ;
281284 pythonCode = atob ( data . content ) ;
@@ -372,7 +375,9 @@ async function renderProblem() {
372375 }
373376
374377 view . innerHTML = html ;
375- hljs . highlightAll ( ) ;
378+ if ( typeof hljs !== 'undefined' ) {
379+ hljs . highlightAll ( ) ;
380+ }
376381}
377382
378383// Navigation
@@ -401,22 +406,18 @@ function goBack() {
401406 // If we're viewing a problem, go back to its parent folder
402407 if ( state . currentView === 'problem' ) {
403408 if ( state . currentPath . length > 1 ) {
404- // Go to parent folder
405409 const parentPath = state . currentPath . slice ( 0 , - 1 ) ;
406410 window . location . hash = parentPath . map ( encodeURIComponent ) . join ( '/' ) ;
407411 } else {
408- // Go to home
409412 window . location . hash = '' ;
410413 }
411414 }
412415 // If we're in a folder view, go back one level
413416 else if ( state . currentView === 'folder' ) {
414417 if ( state . currentPath . length > 1 ) {
415- // Go to parent folder
416418 const parentPath = state . currentPath . slice ( 0 , - 1 ) ;
417419 window . location . hash = parentPath . map ( encodeURIComponent ) . join ( '/' ) ;
418420 } else {
419- // Go to home
420421 window . location . hash = '' ;
421422 }
422423 }
@@ -472,10 +473,10 @@ window.addEventListener('hashchange', async () => {
472473 // Make goBack globally available
473474 window . goBack = goBack ;
474475
475- // Start loading platforms but don't wait
476- loadPlatforms ( ) ;
476+ // Load platforms
477+ await loadPlatforms ( ) ;
477478
478- // Immediately parse hash and show the requested view
479+ // Parse hash and render
479480 const parsed = parseHash ( ) ;
480481 state . currentView = parsed . view ;
481482 state . currentPath = parsed . path ;
0 commit comments