@@ -48,6 +48,12 @@ document.addEventListener('DOMContentLoaded', function() {
4848 color: #666;
4949 margin-top: 0.5rem;
5050 }
51+ .github-discussion-link .api-limit-note {
52+ font-size: 0.8rem;
53+ color: #d73a49;
54+ margin-top: 0.5rem;
55+ font-style: italic;
56+ }
5157 ` ;
5258 document . head . appendChild ( style ) ;
5359
@@ -57,7 +63,7 @@ document.addEventListener('DOMContentLoaded', function() {
5763 content . appendChild ( discussionContainer ) ;
5864 }
5965
60- // Known discussions mapping
66+ // Known discussions mapping - Add your known discussions here to avoid API calls
6167 const knownDiscussions = {
6268 'allen_institute_787727_2025-03-27' : 22
6369 // Add more mappings as needed
@@ -80,6 +86,86 @@ document.addEventListener('DOMContentLoaded', function() {
8086 return ;
8187 }
8288
89+ // Local storage cache keys
90+ const CACHE_PREFIX = 'github_discussion_' ;
91+ const CACHE_TIMESTAMP = 'github_discussion_timestamp' ;
92+ const CACHE_DURATION = 24 * 60 * 60 * 1000 ; // 24 hours in milliseconds
93+
94+ // Check cache first
95+ function checkCacheForDiscussion ( ) {
96+ try {
97+ // Check if cache exists and is not expired
98+ const timestamp = localStorage . getItem ( CACHE_TIMESTAMP ) ;
99+ const now = new Date ( ) . getTime ( ) ;
100+ const cacheValid = timestamp && ( now - parseInt ( timestamp ) < CACHE_DURATION ) ;
101+
102+ if ( cacheValid ) {
103+ const cachedItem = localStorage . getItem ( CACHE_PREFIX + pageIdentifier ) ;
104+ if ( cachedItem ) {
105+ const cache = JSON . parse ( cachedItem ) ;
106+ if ( cache . url ) {
107+ // Create link from cached data
108+ discussionContainer . innerHTML = `
109+ <hr>
110+ <p>
111+ <a href="${ cache . url } " target="_blank">
112+ 💬 Join the discussion for this page on GitHub
113+ </a>
114+ </p>
115+ ` ;
116+ return true ;
117+ } else if ( cache . noDiscussion ) {
118+ // No discussion found in previous search
119+ createNewDiscussionLink ( ) ;
120+ return true ;
121+ }
122+ }
123+ } else {
124+ // Cache expired, clear it
125+ clearCacheItems ( ) ;
126+ }
127+ } catch ( e ) {
128+ console . error ( 'Error checking cache:' , e ) ;
129+ }
130+
131+ return false ;
132+ }
133+
134+ // Clear expired cache items
135+ function clearCacheItems ( ) {
136+ try {
137+ // Get all localStorage keys
138+ for ( let i = 0 ; i < localStorage . length ; i ++ ) {
139+ const key = localStorage . key ( i ) ;
140+ if ( key && key . startsWith ( CACHE_PREFIX ) ) {
141+ localStorage . removeItem ( key ) ;
142+ }
143+ }
144+ localStorage . removeItem ( CACHE_TIMESTAMP ) ;
145+ } catch ( e ) {
146+ console . error ( 'Error clearing cache:' , e ) ;
147+ }
148+ }
149+
150+ // Save to cache
151+ function saveToCache ( url ) {
152+ try {
153+ localStorage . setItem ( CACHE_TIMESTAMP , new Date ( ) . getTime ( ) . toString ( ) ) ;
154+ if ( url ) {
155+ localStorage . setItem ( CACHE_PREFIX + pageIdentifier , JSON . stringify ( { url } ) ) ;
156+ } else {
157+ localStorage . setItem ( CACHE_PREFIX + pageIdentifier , JSON . stringify ( { noDiscussion : true } ) ) ;
158+ }
159+ } catch ( e ) {
160+ console . error ( 'Error saving to cache:' , e ) ;
161+ }
162+ }
163+
164+ // Check cache before proceeding with API calls
165+ if ( checkCacheForDiscussion ( ) ) {
166+ return ;
167+ }
168+
83169 // Construct search queries to find matching discussions
84170 const queries = [
85171 `"${ pageIdentifier } " in:title repo:allenneuraldynamics/openscope-community-predictive-processing` ,
@@ -92,22 +178,47 @@ document.addEventListener('DOMContentLoaded', function() {
92178 if ( queryIndex >= queries . length ) {
93179 // We've exhausted all queries, create a new discussion
94180 createNewDiscussionLink ( ) ;
181+ saveToCache ( null ) ; // Cache that no discussion was found
95182 return ;
96183 }
97184
98185 const searchQuery = encodeURIComponent ( queries [ queryIndex ] ) ;
99186 console . log ( 'Searching with query:' , queries [ queryIndex ] ) ;
100187
101- fetch ( `https://api.github.com/search/issues?q=${ searchQuery } ` )
102- . then ( response => response . json ( ) )
188+ // Prepare request options
189+ const requestOptions = {
190+ method : 'GET' ,
191+ headers : {
192+ 'Accept' : 'application/vnd.github.v3+json'
193+ // If you want to use token-based auth, uncomment and add your token:
194+ // 'Authorization': 'token YOUR_GITHUB_TOKEN'
195+ }
196+ } ;
197+
198+ fetch ( `https://api.github.com/search/issues?q=${ searchQuery } ` , requestOptions )
199+ . then ( response => {
200+ // Check for rate limit errors
201+ if ( response . status === 403 ) {
202+ // Handle rate limit exceeded
203+ console . warn ( 'GitHub API rate limit exceeded' ) ;
204+ showRateLimitMessage ( ) ;
205+ return null ;
206+ }
207+ return response . json ( ) ;
208+ } )
103209 . then ( data => {
104- console . log ( 'GitHub API Response for query' , queryIndex , ':' , data ) ;
210+ if ( ! data ) return ; // Handled by the rate limit code above
211+
212+ console . log ( 'GitHub API Response for query' , queryIndex + 1 , ':' , data ) ;
105213
106214 if ( data . items && data . items . length > 0 ) {
107215 // Found an existing discussion or issue
108216 const discussion = data . items [ 0 ] ;
109217 const discussionUrl = discussion . html_url ;
110218
219+ // Cache the result
220+ saveToCache ( discussionUrl ) ;
221+
111222 // Create the link
112223 discussionContainer . innerHTML = `
113224 <hr>
@@ -124,11 +235,23 @@ document.addEventListener('DOMContentLoaded', function() {
124235 } )
125236 . catch ( error => {
126237 console . error ( 'Error fetching discussions:' , error ) ;
127- // Try the next query on error
128- searchWithQuery ( queryIndex + 1 ) ;
238+ // Show fallback for errors
239+ createNewDiscussionLink ( ) ;
129240 } ) ;
130241 }
131242
243+ function showRateLimitMessage ( ) {
244+ discussionContainer . innerHTML = `
245+ <hr>
246+ <p>
247+ <a href="https://github.com/allenneuraldynamics/openscope-community-predictive-processing/discussions" target="_blank">
248+ 💬 View GitHub discussions
249+ </a>
250+ <span class="api-limit-note">GitHub API rate limit exceeded. Please try again later or browse all discussions.</span>
251+ </p>
252+ ` ;
253+ }
254+
132255 function createNewDiscussionLink ( ) {
133256 // No discussion exists - create new one
134257 discussionContainer . innerHTML = `
0 commit comments