Aleksmorshen commited on
Commit
0e39e5b
1 Parent(s): be02c61

Rename index.html to index.js

Browse files
Files changed (2) hide show
  1. index.html +0 -44
  2. index.js +518 -0
index.html DELETED
@@ -1,44 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Сюрпрайз!</title>
7
- <style>
8
- body {
9
- background-color: black;
10
- display: flex;
11
- justify-content: center;
12
- align-items: center;
13
- height: 100vh;
14
- margin: 0;
15
- }
16
-
17
- #neonText {
18
- font-size: 2em;
19
- color: #00ccff;
20
- text-align: center;
21
- text-transform: uppercase;
22
- font-weight: bold;
23
- text-shadow: 0 0 10px #00ccff, 0 0 20px #00ccff, 0 0 30px #00ccff, 0 0 40px #00ccff;
24
- animation: flicker 1.5s infinite alternate;
25
- }
26
-
27
- @keyframes flicker {
28
- 0% {
29
- opacity: 0.6;
30
- }
31
- 100% {
32
- opacity: 1;
33
- }
34
- }
35
- </style>
36
- </head>
37
- <body>
38
- <div id="neonText">Эльяра я Люблю тебя</div>
39
-
40
- <script>
41
- // JavaScript код, если необходим
42
- </script>
43
- </body>
44
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
index.js ADDED
@@ -0,0 +1,518 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const sqlite3 = require('sqlite3').verbose();
3
+ const randomstring = require('randomstring');
4
+ const cookieParser = require('cookie-parser');
5
+ const multer = require('multer');
6
+ const path = require('path');
7
+ const session = require('express-session');
8
+ const fs = require('fs-extra');
9
+
10
+ const app = express();
11
+ const port = process.env.PORT || 5000;
12
+
13
+ app.use(cookieParser());
14
+ app.use(session({
15
+ secret: 'ваш_секретный_ключ',
16
+ resave: true,
17
+ saveUninitialized: false
18
+ }));
19
+
20
+ const db = new sqlite3.Database('chat.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
21
+ if (err) {
22
+ console.error(err.message);
23
+ } else {
24
+ console.log('Подключено к базе данных.');
25
+
26
+ db.run(`
27
+ CREATE TABLE IF NOT EXISTS messages (
28
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
29
+ nickname TEXT,
30
+ message TEXT,
31
+ photo_path TEXT,
32
+ date TEXT
33
+ )
34
+ `);
35
+
36
+ db.run(`
37
+ CREATE TABLE IF NOT EXISTS active_users (
38
+ nickname TEXT PRIMARY KEY,
39
+ last_activity INTEGER
40
+ )
41
+ `);
42
+
43
+ db.run(`
44
+ CREATE TABLE IF NOT EXISTS online_record (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ record INTEGER
47
+ )
48
+ `);
49
+
50
+ db.get('SELECT record FROM online_record WHERE id = 1', (err, row) => {
51
+ if (err) {
52
+ console.error(err.message);
53
+ } else if (row) {
54
+ recordOnlineUsers = row.record;
55
+ } else {
56
+ db.run('INSERT INTO online_record (record) VALUES (0)');
57
+ }
58
+ });
59
+
60
+ setInterval(() => {
61
+ db.run('DELETE FROM active_users', (err) => {
62
+ if (err) {
63
+ console.error(err.message);
64
+ }
65
+ });
66
+ }, 5 * 60 * 1000);
67
+ }
68
+ });
69
+
70
+ let recordOnlineUsers = 0;
71
+
72
+ const uploadDir = path.join(__dirname, 'uploads');
73
+
74
+ if (!fs.existsSync(uploadDir)) {
75
+ fs.mkdirSync(uploadDir);
76
+ }
77
+
78
+ const storage = multer.diskStorage({
79
+ destination: function (req, file, cb) {
80
+ cb(null, uploadDir);
81
+ },
82
+ filename: function (req, file, cb) {
83
+ const timestamp = Date.now();
84
+ const extension = path.extname(file.originalname);
85
+ cb(null, `${timestamp}${extension}`);
86
+ },
87
+ });
88
+
89
+ const upload = multer({ storage: storage });
90
+
91
+ app.use(express.urlencoded({ extended: true }));
92
+ app.use('/uploads', express.static('uploads'));
93
+
94
+ function getMessages(callback) {
95
+ db.all('SELECT nickname, message, photo_path, date FROM messages', (err, rows) => {
96
+ if (err) {
97
+ console.error(err.message);
98
+ callback([]);
99
+ } else {
100
+ callback(rows.reverse());
101
+ }
102
+ });
103
+ }
104
+
105
+ function cleanUp() {
106
+ db.run('DELETE FROM messages', (err) => {
107
+ if (err) {
108
+ console.error(err.message);
109
+ }
110
+ });
111
+
112
+ fs.emptyDir(uploadDir, (err) => {
113
+ if (err) {
114
+ console.error(err.message);
115
+ } else {
116
+ console.log('История сообщений и содержимое папки "uploads" очищены.');
117
+ }
118
+ });
119
+ }
120
+
121
+ setInterval(cleanUp, 1440 * 60 * 1000);
122
+
123
+ app.get('/', (req, res) => {
124
+ const currentTime = Date.now();
125
+ const lastNicknameChange = req.session.lastNicknameChange || 0;
126
+
127
+ if (!req.cookies.nickname || currentTime - lastNicknameChange >= 5 * 60 * 1000) {
128
+ const newNickname = randomstring.generate(8);
129
+ res.cookie('nickname', newNickname);
130
+ req.session.lastNicknameChange = currentTime;
131
+ }
132
+
133
+ getMessages((messages) => {
134
+ db.all('SELECT COUNT(*) AS onlineUsers FROM active_users', (err, activeUserRows) => {
135
+ if (err) {
136
+ console.error(err.message);
137
+ res.status(500).send('Внутренняя ошибка сервера');
138
+ return;
139
+ }
140
+
141
+ const onlineUsers = activeUserRows[0].onlineUsers || 0;
142
+
143
+ if (onlineUsers > recordOnlineUsers) {
144
+ recordOnlineUsers = onlineUsers;
145
+ db.run('UPDATE online_record SET record = ? WHERE id = 1', [recordOnlineUsers], (err) => {
146
+ if (err) {
147
+ console.error(err.message);
148
+ }
149
+ });
150
+ }
151
+
152
+ let html = `
153
+ <!DOCTYPE html>
154
+ <html>
155
+ <head>
156
+ <title>CHANGR MAIN CHAT</title>
157
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
158
+ <style>
159
+ /* Ваши стили CSS */
160
+ body {
161
+ font-family: 'Inconsolata', monospace;
162
+ background-color: #f0f0f0;
163
+ margin: 0;
164
+ padding: 0;
165
+ position: relative;
166
+ }
167
+
168
+ .container {
169
+ margin: 0 auto;
170
+ padding: 20px;
171
+ background-color: #fff;
172
+ border-radius: 5px;
173
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
174
+ }
175
+
176
+ h1 {
177
+ text-align: center;
178
+ font-size: 36px;
179
+ margin-bottom: 20px;
180
+ }
181
+
182
+ ul {
183
+ list-style-type: none;
184
+ padding: 0;
185
+ }
186
+
187
+ li {
188
+ margin-bottom: 10px;
189
+ }
190
+
191
+ /* Стили для поля чата */
192
+ #messageInput {
193
+ border: 2px solid #6A5ACD;
194
+ border-radius: 15px;
195
+ padding: 10px;
196
+ width: 100%;
197
+ font-size: 14px;
198
+ }
199
+
200
+ input[type="text"] {
201
+ width: 100%;
202
+ padding: 10px;
203
+ border: 1px solid #ccc;
204
+ border-radius: 25px;
205
+ margin-top: 10px;
206
+ }
207
+
208
+ .btn-container {
209
+ display: flex;
210
+ justify-content: space-between;
211
+ margin-top: 10px;
212
+ }
213
+
214
+ /* Стили для кнопки с анимацией */
215
+ .btn-container input[type="submit"],
216
+ .btn-container input[type="button"] {
217
+ background-color: #6A5ACD;
218
+ color: white;
219
+ border: none;
220
+ padding: 10px 20px;
221
+ border-radius: 10px;
222
+ cursor: pointer;
223
+ width: 48%;
224
+ font-size: 12px;
225
+ font-weight: bold;
226
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
227
+ transition: background-color 0.2s;
228
+ position: relative;
229
+ }
230
+
231
+ /* Анимация при нажатии на кнопку */
232
+ .btn-container input[type="submit"]:hover,
233
+ .btn-container input[type="button"]:hover {
234
+ background-color: #8A2BE2;
235
+ }
236
+
237
+ .file-input-label {
238
+ background-color: #6A5ACD;
239
+ color: white;
240
+ border: none;
241
+ padding: 5px 10px;
242
+ border-radius: 10px;
243
+ cursor: pointer;
244
+ font-size: 12px;
245
+ font-weight: bold;
246
+ display: inline-block;
247
+ margin-top: 10px;
248
+ }
249
+
250
+ .file-input {
251
+ display: none;
252
+ }
253
+
254
+ .online-users {
255
+ font-size: 12px;
256
+ display: flex;
257
+ align-items: center;
258
+ }
259
+
260
+ .online-dot {
261
+ width: 10px;
262
+ height: 10px;
263
+ background-color: #00FF00;
264
+ border-radius: 50%;
265
+ margin-right: 5px;
266
+ box-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
267
+ }
268
+
269
+ @media screen and (max-width: 600px) {
270
+ .container {
271
+ max-width: 100%;
272
+ border-radius: 0;
273
+ }
274
+
275
+ h1 {
276
+ font-size: 24px;
277
+ }
278
+
279
+ input[type="text"] {
280
+ border-radius: 25px;
281
+ }
282
+
283
+ .btn-container input[type="submit"],
284
+ .btn-container input[type="button"] {
285
+ padding: 10px 20px;
286
+ border-radius: 10px;
287
+ }
288
+ }
289
+
290
+ .back-button {
291
+ position: absolute;
292
+ top: 10px;
293
+ left: 10px;
294
+ background-color: #ff5733;
295
+ color: white;
296
+ border: none;
297
+ padding: 5px 10px;
298
+ border-radius: 5px;
299
+ cursor: pointer;
300
+ font-weight: bold;
301
+ font-size: 12px;
302
+ }
303
+
304
+ .message-date {
305
+ font-size: 12px;
306
+ color: #888;
307
+ margin-left: 10px;
308
+ }
309
+
310
+ .message-divider {
311
+ width: 100%;
312
+ height: 2px;
313
+ background-color: rgba(0, 0, 0, 0.1);
314
+ margin: 10px 0;
315
+ }
316
+
317
+ .record-dot {
318
+ width: 10px;
319
+ height: 10px;
320
+ background-color: gold;
321
+ border-radius: 50%;
322
+ margin-right: 5px;
323
+ box-shadow: 0 0 5px rgba(255, 215, 0, 0.5);
324
+ }
325
+
326
+ .record-online-users {
327
+ font-size: 12px;
328
+ display: flex;
329
+ align-items: center;
330
+ margin-top: 10px;
331
+ }
332
+
333
+ .message-container {
334
+ border: 2px solid #6A5ACD;
335
+ border-radius: 15px;
336
+ padding: 10px;
337
+ margin-top: 20px;
338
+ max-height: 500px;
339
+ overflow-y: auto;
340
+ }
341
+
342
+ .message-container::-webkit-scrollbar {
343
+ width: 10px;
344
+ }
345
+
346
+ .message-container::-webkit-scrollbar-thumb {
347
+ background-color: #6A5ACD;
348
+ border-radius: 5px;
349
+ }
350
+
351
+ .message-container::-webkit-scrollbar-track {
352
+ background-color: #f0f0f0;
353
+ }
354
+
355
+ /* Анимация кнопки с неоновым огоньком */
356
+ .neon-button::before {
357
+ content: '';
358
+ position: absolute;
359
+ width: 0;
360
+ height: 100%;
361
+ top: 0;
362
+ left: 0;
363
+ background-color: white;
364
+ opacity: 0.5;
365
+ border-radius: 10px;
366
+ animation: neon 1s linear infinite;
367
+ }
368
+
369
+ @keyframes neon {
370
+ 0% {
371
+ left: -50%;
372
+ width: 50%;
373
+ }
374
+ 50% {
375
+ left: 130%;
376
+ width: 20%;
377
+ }
378
+ 100% {
379
+ left: 130%;
380
+ width: 20%;
381
+ }
382
+ }
383
+ </style>
384
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inconsolata">
385
+ </head>
386
+ <body>
387
+ <a href="https://main.changr.repl.co" class="back-button">Назад</a>
388
+ <div class="container">
389
+ <h1>CHANGR главный чат</h1>
390
+ <div class="online-users">
391
+ <div class="online-dot"></div>
392
+ <span>${onlineUsers} онлайн</span>
393
+ </div>
394
+ <div class="record-online-users">
395
+ <div class="record-dot"></div>
396
+ <span>Рекорд онлайна: <span id="recordOnlineUsers">${recordOnlineUsers}</span></span>
397
+ </div>
398
+ <form method="POST" enctype="multipart/form-data" id="chatForm">
399
+ <input type="text" name="message" id="messageInput" placeholder="Введите сообщение">
400
+ <label for="photo" class="file-input-label">
401
+ Выбрать файлы <span id="fileCount">0</span>
402
+ </label>
403
+ <input type="file" name="photo" id="photo" multiple class="file-input">
404
+ <div class="btn-container">
405
+ <input type="submit" value="Отправить" class="neon-button">
406
+ </div>
407
+ </form>
408
+ <div class="message-container">
409
+ <ul id="messageList">
410
+ <!-- Сообщения будут отображаться здесь -->
411
+ </ul>
412
+ </div>
413
+ </div>
414
+ </body>
415
+ <script>
416
+ // JavaScript для автообновления списка сообщений и счетчика файлов
417
+ function updateMessageList() {
418
+ fetch('/messages')
419
+ .then(response => response.json())
420
+ .then(data => {
421
+ const messageList = document.getElementById('messageList');
422
+ messageList.innerHTML = '';
423
+
424
+ data.messages.forEach(message => {
425
+ const li = document.createElement('li');
426
+ li.innerHTML = \`<strong>\${message.nickname}</strong>: \${message.message} <span class="message-date">\${message.date}</span>\`;
427
+ messageList.appendChild(li);
428
+
429
+ if (message.photo_path) {
430
+ const photoPaths = message.photo_path.split(',');
431
+ photoPaths.forEach(photoPath => {
432
+ const img = document.createElement('img');
433
+ img.src = \`/uploads/\${photoPath}\`;
434
+ img.alt = 'Фото';
435
+ img.style.maxWidth = '100%';
436
+ img.style.height = 'auto';
437
+ const photoLi = document.createElement('li');
438
+ photoLi.appendChild(img);
439
+ messageList.appendChild(photoLi);
440
+ });
441
+ }
442
+
443
+ const divider = document.createElement('div');
444
+ divider.className = 'message-divider';
445
+ messageList.appendChild(divider);
446
+ });
447
+ });
448
+ }
449
+
450
+ setInterval(updateMessageList, 2000);
451
+ updateMessageList();
452
+
453
+ const fileCountSpan = document.getElementById('fileCount');
454
+ const fileInput = document.getElementById('photo');
455
+
456
+ fileInput.addEventListener('change', () => {
457
+ fileCountSpan.textContent = fileInput.files.length;
458
+ });
459
+ </script>
460
+ </html>
461
+ `;
462
+
463
+ res.send(html);
464
+ });
465
+ });
466
+ });
467
+
468
+ app.get('/messages', (req, res) => {
469
+ getMessages((messages) => {
470
+ res.json({ messages });
471
+ });
472
+ });
473
+
474
+ app.post('/', upload.array('photo', 3), (req, res) => {
475
+ const nickname = req.cookies.nickname;
476
+ const message = req.body.message;
477
+ const photos = req.files;
478
+ const date = new Date().toISOString();
479
+
480
+ db.run('INSERT INTO messages (nickname, message, date) VALUES (?, ?, ?)', [nickname, message, date], (err) => {
481
+ if (err) {
482
+ console.error(err.message);
483
+ res.status(500).send('Ошибка сохранения сообщения');
484
+ return;
485
+ }
486
+
487
+ if (photos && photos.length > 0) {
488
+ const photoPaths = photos.map((photo) => photo.filename);
489
+
490
+ db.run('UPDATE messages SET photo_path = ? WHERE nickname = ? AND date = ?', [photoPaths.join(','), nickname, date], (err) => {
491
+ if (err) {
492
+ console.error(err.message);
493
+ }
494
+ });
495
+ }
496
+
497
+ res.redirect('/');
498
+ });
499
+ });
500
+
501
+ app.listen(port, () => {
502
+ console.log(`Сервер запущен на порту ${port}`);
503
+ });
504
+
505
+ app.use((req, res, next) => {
506
+ if (req.cookies.nickname) {
507
+ const nickname = req.cookies.nickname;
508
+
509
+ db.run('INSERT OR REPLACE INTO active_users (nickname, last_activity) VALUES (?, ?)', [nickname, Date.now()], (err) => {
510
+ if (err) {
511
+ console.error(err.message);
512
+ }
513
+ });
514
+ }
515
+
516
+ next();
517
+ });
518
+