PageSourceSearch

https://guess-the-jumpshot.com/js/supabase-simple.js

js guess-the-jumpshot.com collected 2026-10-04 00:21:11 UTC 11,604 bytes, 353 lines download raw bytes

1(() => {
2// Simplified Supabase Client - No Authentication Required
3const SUPABASE_URL = 'https://nlxfcofiakviwoulbumt.supabase.co';
4const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im5seGZjb2ZpYWt2aXdvdWxidW10Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDM0MjM2NjAsImV4cCI6MjA1ODk5OTY2MH0.Is-JSFMT2Ce_ua8f9uoqAvKW_q5OUyhnoSoN-yiJA1E';
5
6// Initialize Supabase client
7let supabase = null;
8
9// Load Supabase from CDN
10function loadSupabase() {
11    return new Promise((resolve, reject) => {
12        if (window.supabase) {
13            // Supabase库已经加载,初始化客户端
14            supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
15            resolve();
16            return;
17        }
18        
19        const script = document.createElement('script');
20        script.src = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2';
21        script.onload = () => {
22            supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
23            resolve();
24        };
25        script.onerror = reject;
26        document.head.appendChild(script);
27    });
28}
29
30// Game Statistics Manager - No Auth Required
31class GameStats {
32    static async saveGameResult(playerName, gameData) {
33        try {
34            const result = {
35                player_name: playerName || 'Anonymous',
36                score: gameData.score,
37                correct_answers: gameData.correctAnswers,
38                total_questions: gameData.totalQuestions,
39                accuracy: (gameData.correctAnswers / gameData.totalQuestions * 100).toFixed(2),
40                game_mode: gameData.mode || 'normal',
41                time_played: gameData.timePlayed || 0,
42                streak: gameData.streak || 0,
43                created_at: new Date().toISOString()
44            };
45            
46            const { data, error } = await supabase
47                .from('game_scores')
48                .insert(result)
49                .select();
50            
51            if (error) throw error;
52            
53            return { success: true, data };
54        } catch (error) {
55            console.error('Save game result error:', error);
56            return { success: false, error: error.message };
57        }
58    }
59    
60    static async getRecentGames(limit = 10) {
61        try {
62            const { data, error } = await supabase
63                .from('game_scores')
64                .select('*')
65                .order('created_at', { ascending: false })
66                .limit(limit);
67            
68            if (error) throw error;
69            return data;
70        } catch (error) {
71            console.error('Get recent games error:', error);
72            return [];
73        }
74    }
75}
76
77// Leaderboard Manager - No Auth Required
78class Leaderboard {
79    static async getTopScores(limit = 100) {
80        try {
81            // Ensure supabase is initialized
82            if (!supabase) {
83                console.error('Supabase not initialized. Call GameDB.loadSupabase() first.');
84                return [];
85            }
86            
87            const { data, error } = await supabase
88                .from('game_scores')
89                .select('*')
90                .order('score', { ascending: false })
91                .limit(limit);
92            
93            if (error) throw error;
94            return data;
95        } catch (error) {
96            console.error('Get leaderboard error:', error);
97            return [];
98        }
99    }
100    
101    static async getDailyTopScores() {
102        try {
103            // Ensure supabase is initialized
104            if (!supabase) {
105                console.error('Supabase not initialized. Call GameDB.loadSupabase() first.');
106                return [];
107            }
108            
109            const today = new Date();
110            today.setHours(0, 0, 0, 0);
111            
112            const { data, error } = await supabase
113                .from('game_scores')
114                .select('*')
115                .gte('created_at', today.toISOString())
116                .order('score', { ascending: false })
117                .limit(50);
118            
119            if (error) throw error;
120            return data;
121        } catch (error) {
122            console.error('Get daily leaderboard error:', error);
123            return [];
124        }
125    }
126    
127    static async getWeeklyTopScores() {
128        try {
129            // Ensure supabase is initialized
130            if (!supabase) {
131                console.error('Supabase not initialized. Call GameDB.loadSupabase() first.');
132                return [];
133            }
134            
135            const weekAgo = new Date();
136            weekAgo.setDate(weekAgo.getDate() - 7);
137            
138            const { data, error } = await supabase
139                .from('game_scores')
140                .select('*')
141                .gte('created_at', weekAgo.toISOString())
142                .order('score', { ascending: false })
143                .limit(50);
144            
145            if (error) throw error;
146            return data;
147        } catch (error) {
148            console.error('Get weekly leaderboard error:', error);
149            return [];
150        }
151    }
152}
153
154// Comments Manager - No Auth Required
155class Comments {
156    static async postComment(playerName, content) {
157        try {
158            const comment = {
159                player_name: playerName || 'Anonymous',
160                content,
161                likes: 0,
162                created_at: new Date().toISOString()
163            };
164            
165            const { data, error } = await supabase
166                .from('comments_public')
167                .insert(comment)
168                .select();
169            
170            if (error) throw error;
171            return { success: true, data };
172        } catch (error) {
173            console.error('Post comment error:', error);
174            return { success: false, error: error.message };
175        }
176    }
177    
178    static async getComments(limit = 50, offset = 0) {
179        try {
180            const { data, error } = await supabase
181                .from('comments_public')
182                .select('*')
183                .order('created_at', { ascending: false })
184                .range(offset, offset + limit - 1);
185            
186            if (error) throw error;
187            return data || [];
188        } catch (error) {
189            console.error('Get comments error:', error);
190            return [];
191        }
192    }
193    
194    static async getCommentsCount() {
195        try {
196            const { count, error } = await supabase
197                .from('comments_public')
198                .select('*', { count: 'exact', head: true });
199            
200            if (error) throw error;
201            return count || 0;
202        } catch (error) {
203            console.error('Get comments count error:', error);
204            return 0;
205        }
206    }
207    
208    static async likeComment(commentId) {
209        try {
210            // Get current likes
211            const { data: comment } = await supabase
212                .from('comments_public')
213                .select('likes')
214                .eq('id', commentId)
215                .single();
216            
217            if (comment) {
218                // Increment likes
219                const { error } = await supabase
220                    .from('comments_public')
221                    .update({ likes: (comment.likes || 0) + 1 })
222                    .eq('id', commentId);
223                
224                if (error) throw error;
225                return { success: true };
226            }
227            
228            return { success: false, error: 'Comment not found' };
229        } catch (error) {
230            console.error('Like comment error:', error);
231            return { success: false, error: error.message };
232        }
233    }
234}
235
236// Player Stats
237class PlayerStats {
238    static getStoredPlayerName() {
239        return localStorage.getItem('playerName') || '';
240    }
241    
242    static setPlayerName(name) {
243        localStorage.setItem('playerName', name);
244    }
245    
246    static async getPlayerStats(playerName) {
247        if (!playerName) return null;
248        
249        try {
250            const { data, error } = await supabase
251                .from('game_scores')
252                .select('*')
253                .eq('player_name', playerName)
254                .order('score', { ascending: false });
255            
256            if (error) throw error;
257            
258            if (data && data.length > 0) {
259                const totalGames = data.length;
260                const totalScore = data.reduce((sum, game) => sum + game.score, 0);
261                const bestScore = data[0].score;
262                const avgAccuracy = data.reduce((sum, game) => sum + parseFloat(game.accuracy), 0) / totalGames;
263                const bestStreak = Math.max(...data.map(game => game.streak || 0));
264                
265                return {
266                    totalGames,
267                    totalScore,
268                    bestScore,
269                    avgAccuracy: avgAccuracy.toFixed(1),
270                    bestStreak,
271                    recentGames: data.slice(0, 5)
272                };
273            }
274            
275            return null;
276        } catch (error) {
277            console.error('Get player stats error:', error);
278            return null;
279        }
280    }
281}
282
283// Player Feedback Manager - No Auth Required
284class PlayerFeedback {
285    static async submitFeedback(feedbackData) {
286        try {
287            const feedback = {
288                type: feedbackData.type,
289                rating: feedbackData.rating,
290                email: feedbackData.email || null,
291                message: feedbackData.message,
292                user_agent: feedbackData.user_agent || navigator.userAgent,
293                screen_resolution: feedbackData.screen_resolution || `${window.screen.width}x${window.screen.height}`,
294                created_at: new Date().toISOString()
295            };
296            
297            const { data, error } = await supabase
298                .from('player_feedback')
299                .insert(feedback)
300                .select();
301            
302            if (error) throw error;
303            return { success: true, data };
304        } catch (error) {
305            console.error('Submit feedback error:', error);
306            return { success: false, error: error.message };
307        }
308    }
309    
310    static async getFeedbackStats() {
311        try {
312            const { data, error } = await supabase
313                .from('player_feedback')
314                .select('type, rating')
315                .order('created_at', { ascending: false })
316                .limit(100);
317            
318            if (error) throw error;
319            
320            // Calculate average rating and type distribution
321            const stats = {
322                totalFeedback: data.length,
323                averageRating: 0,
324                typeDistribution: {}
325            };
326            
327            if (data.length > 0) {
328                const totalRating = data.reduce((sum, item) =>
328 sum + (item.rating || 0), 0);
329                stats.averageRating = (totalRating / data.length).toFixed(1);
330                
331                data.forEach(item => {
332                    stats.typeDistribution[item.type] = (stats.typeDistribution[item.type] || 0) + 1;
333                });
334            }
335            
336            return stats;
337        } catch (error) {
338            console.error('Get feedback stats error:', error);
339            return null;
340        }
341    }
342}
343
344// Export for use in other files
345window.GameDB = {
346    loadSupabase,
347    GameStats,
348    Leaderboard,
349    Comments,
350    PlayerStats,
351    PlayerFeedback
352};
353})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.