Lichess Hourly Bullet Tournament Creator

A new extension

Size

11.8 KB

Version

1.1.1

Created

Nov 8, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		Lichess Hourly Bullet Tournament Creator
3// @description		A new extension
4// @version		1.1.1
5// @match		https://*.lichess.org/*
6// @icon		https://lichess1.org/assets/logo/lichess-favicon-32.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Lichess Hourly Bullet Tournament Creator loaded');
12
13    // Configuration
14    const TOURNAMENT_CONFIG = {
15        clockTime: 60,        // 1 minute in seconds
16        clockIncrement: 0,    // 0 seconds increment
17        minutes: 57,          // Tournament duration
18        name: 'Hourly Bullet 1+0',
19        waitMinutes: 3,       // Wait 3 minutes before starting
20        variant: 'standard',
21        rated: true,
22        berserk: true,
23        scheduledHour: 23     // 11pm in 24-hour format
24    };
25
26    // Check if we're on a team page
27    function isTeamPage() {
28        return window.location.pathname.startsWith('/team/');
29    }
30
31    // Get team ID from URL
32    function getTeamId() {
33        const match = window.location.pathname.match(/\/team\/([^\/]+)/);
34        return match ? match[1] : null;
35    }
36
37    // Create tournament button
38    function createTournamentButton() {
39        const button = document.createElement('button');
40        button.textContent = '⚡ Create Hourly Bullet Tournament';
41        button.style.cssText = `
42            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
43            color: white;
44            border: none;
45            padding: 12px 24px;
46            font-size: 16px;
47            font-weight: bold;
48            border-radius: 8px;
49            cursor: pointer;
50            margin: 16px 0;
51            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
52            transition: all 0.3s ease;
53            display: flex;
54            align-items: center;
55            gap: 8px;
56        `;
57
58        button.addEventListener('mouseenter', () => {
59            button.style.transform = 'translateY(-2px)';
60            button.style.boxShadow = '0 6px 12px rgba(0, 0, 0, 0.15)';
61        });
62
63        button.addEventListener('mouseleave', () => {
64            button.style.transform = 'translateY(0)';
65            button.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
66        });
67
68        button.addEventListener('click', async () => {
69            await createTournament(button);
70        });
71
72        return button;
73    }
74
75    // Create tournament via API
76    async function createTournament(button) {
77        const teamId = getTeamId();
78        
79        button.disabled = true;
80        button.textContent = '⏳ Creating tournament...';
81        button.style.opacity = '0.7';
82
83        try {
84            // Build form data
85            const formData = new URLSearchParams();
86            formData.append('name', TOURNAMENT_CONFIG.name);
87            formData.append('clockTime', TOURNAMENT_CONFIG.clockTime);
88            formData.append('clockIncrement', TOURNAMENT_CONFIG.clockIncrement);
89            formData.append('minutes', TOURNAMENT_CONFIG.minutes);
90            formData.append('waitMinutes', TOURNAMENT_CONFIG.waitMinutes);
91            formData.append('variant', TOURNAMENT_CONFIG.variant);
92            formData.append('rated', TOURNAMENT_CONFIG.rated);
93            formData.append('berserk', TOURNAMENT_CONFIG.berserk);
94            
95            if (teamId) {
96                formData.append('teamBattleByTeam', teamId);
97            }
98
99            console.log('Creating tournament with config:', Object.fromEntries(formData));
100
101            // Make API request
102            const response = await GM.xmlhttpRequest({
103                method: 'POST',
104                url: 'https://lichess.org/api/tournament',
105                headers: {
106                    'Content-Type': 'application/x-www-form-urlencoded',
107                },
108                data: formData.toString(),
109                responseType: 'json'
110            });
111
112            console.log('Tournament creation response:', response);
113
114            if (response.status === 200) {
115                const data = typeof response.response === 'string' 
116                    ? JSON.parse(response.response) 
117                    : response.response;
118                
119                console.log('Tournament created successfully:', data);
120                
121                button.textContent = '✅ Tournament Created!';
122                button.style.background = 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)';
123                
124                // Show success message with tournament link
125                showNotification('Tournament created successfully!', data.id);
126                
127                // Reset button after 3 seconds
128                setTimeout(() => {
129                    button.disabled = false;
130                    button.textContent = '⚡ Create Hourly Bullet Tournament';
131                    button.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
132                    button.style.opacity = '1';
133                }, 3000);
134            } else {
135                throw new Error(`Failed to create tournament: ${response.status} ${response.statusText}`);
136            }
137        } catch (error) {
138            console.error('Error creating tournament:', error);
139            button.textContent = '❌ Failed to create';
140            button.style.background = 'linear-gradient(135deg, #eb3349 0%, #f45c43 100%)';
141            
142            showNotification('Failed to create tournament. Check console for details.', null, true);
143            
144            setTimeout(() => {
145                button.disabled = false;
146                button.textContent = '⚡ Create Hourly Bullet Tournament';
147                button.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
148                button.style.opacity = '1';
149            }, 3000);
150        }
151    }
152
153    // Check if tournament should be created now
154    async function checkAndCreateScheduledTournament() {
155        const now = new Date();
156        const currentHour = now.getHours();
157        const currentMinute = now.getMinutes();
158        
159        // Check if it's 11pm (23:00) and within the first minute
160        if (currentHour === TOURNAMENT_CONFIG.scheduledHour && currentMinute === 0) {
161            // Check if we already created a tournament today
162            const lastCreated = await GM.getValue('lastTournamentCreated', '');
163            const today = now.toDateString();
164            
165            if (lastCreated !== today) {
166                console.log('Creating scheduled tournament at 11pm');
167                await createScheduledTournament();
168                await GM.setValue('lastTournamentCreated', today);
169            }
170        }
171    }
172
173    // Create scheduled tournament (without button UI)
174    async function createScheduledTournament() {
175        const teamId = getTeamId();
176        
177        try {
178            const formData = new URLSearchParams();
179            formData.append('name', TOURNAMENT_CONFIG.name);
180            formData.append('clockTime', TOURNAMENT_CONFIG.clockTime);
181            formData.append('clockIncrement', TOURNAMENT_CONFIG.clockIncrement);
182            formData.append('minutes', TOURNAMENT_CONFIG.minutes);
183            formData.append('waitMinutes', TOURNAMENT_CONFIG.waitMinutes);
184            formData.append('variant', TOURNAMENT_CONFIG.variant);
185            formData.append('rated', TOURNAMENT_CONFIG.rated);
186            formData.append('berserk', TOURNAMENT_CONFIG.berserk);
187            
188            if (teamId) {
189                formData.append('teamBattleByTeam', teamId);
190            }
191
192            console.log('Creating scheduled tournament with config:', Object.fromEntries(formData));
193
194            const response = await GM.xmlhttpRequest({
195                method: 'POST',
196                url: 'https://lichess.org/api/tournament',
197                headers: {
198                    'Content-Type': 'application/x-www-form-urlencoded',
199                },
200                data: formData.toString(),
201                responseType: 'json'
202            });
203
204            console.log('Scheduled tournament creation response:', response);
205
206            if (response.status === 200) {
207                const data = typeof response.response === 'string' 
208                    ? JSON.parse(response.response) 
209                    : response.response;
210                
211                console.log('Scheduled tournament created successfully:', data);
212                showNotification('Scheduled tournament created at 11pm!', data.id);
213            } else {
214                throw new Error(`Failed to create scheduled tournament: ${response.status}`);
215            }
216        } catch (error) {
217            console.error('Error creating scheduled tournament:', error);
218            showNotification('Failed to create scheduled tournament. Check console for details.', null, true);
219        }
220    }
221
222    // Show notification
223    function showNotification(message, tournamentId = null, isError = false) {
224        const notification = document.createElement('div');
225        notification.style.cssText = `
226            position: fixed;
227            top: 20px;
228            right: 20px;
229            background: ${isError ? '#f45c43' : '#38ef7d'};
230            color: white;
231            padding: 16px 24px;
232            border-radius: 8px;
233            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
234            z-index: 10000;
235            font-weight: bold;
236            max-width: 400px;
237        `;
238        
239        notification.textContent = message;
240        
241        if (tournamentId) {
242            const link = document.createElement('a');
243            link.href = `https://lichess.org/tournament/${tournamentId}`;
244            link.textContent = 'View Tournament';
245            link.style.cssText = `
246                display: block;
247                margin-top: 8px;
248                color: white;
249                text-decoration: underline;
250            `;
251            notification.appendChild(link);
252        }
253        
254        document.body.appendChild(notification);
255        
256        setTimeout(() => {
257            notification.remove();
258        }, 5000);
259    }
260
261    // Add button to page
262    function addButtonToPage() {
263        // Wait for page to load
264        const checkInterval = setInterval(() => {
265            const targetContainer = document.querySelector('.team__info') || 
266                                   document.querySelector('.page-menu__content') ||
267                                   document.querySelector('main.page-small');
268            
269            if (targetContainer && !document.getElementById('tournament-creator-button')) {
270                const button = createTournamentButton();
271                button.id = 'tournament-creator-button';
272                
273                // Insert button at the top of the container
274                targetContainer.insertBefore(button, targetContainer.firstChild);
275                
276                console.log('Tournament creator button added to page');
277                clearInterval(checkInterval);
278            }
279        }, 1000);
280        
281        // Stop checking after 10 seconds
282        setTimeout(() => clearInterval(checkInterval), 10000);
283    }
284
285    // Initialize
286    function init() {
287        console.log('Initializing Lichess Hourly Bullet Tournament Creator');
288        
289        // Add button to current page
290        addButtonToPage();
291        
292        // Start checking for scheduled tournament creation every minute
293        setInterval(checkAndCreateScheduledTournament, 60000); // Check every minute
294        checkAndCreateScheduledTournament(); // Check immediately on load
295        
296        // Watch for navigation changes (Lichess uses client-side routing)
297        const observer = new MutationObserver(() => {
298            if (!document.getElementById('tournament-creator-button')) {
299                addButtonToPage();
300            }
301        });
302        
303        observer.observe(document.body, {
304            childList: true,
305            subtree: true
306        });
307    }
308
309    // Start when DOM is ready
310    if (document.readyState === 'loading') {
311        document.addEventListener('DOMContentLoaded', init);
312    } else {
313        init();
314    }
315})();
Lichess Hourly Bullet Tournament Creator | Robomonkey