import os import time import asyncio import aiosqlite from quart import Quart, render_template, request, send_from_directory, Response from datetime import datetime from babel.dates import format_datetime <<<<<<< HEAD from urllib.parse import quote ======= >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a app = Quart(__name__, template_folder='frontend', static_folder='frontend') DB_PATH = 'maps.db' DATA = "/data" GAME_MODES = { "Classic": "Классический", "Deathmatch": "Бой насмерть", "Demolition": "Уничтожение объекта", "Armsrace": "Гонка вооружений", "Custom": "Пользовательский", "Training": "Обучение", "Co-op Strike": "Совместный налёт", "Wingman": "Напарники", "Flying Scoutsman": "Перелётные снайперы" } last_download_times = {} DOWNLOAD_COOLDOWN = 10 async def get_maps(page=1, per_page=30): print(f"Запрос карт на странице {page}, с {per_page} картами на странице.") async with aiosqlite.connect(DB_PATH) as conn: cursor = await conn.cursor() offset = (page - 1) * per_page await cursor.execute(''' SELECT FilePath, Title, COALESCE(Stars, 0) as Stars, Description FROM maps ORDER BY DateTime DESC LIMIT ? OFFSET ? ''', (per_page, offset)) maps = await cursor.fetchall() print(f"Получено {len(maps)} карт на странице {page}.") return maps def get_image_path(filepath): <<<<<<< HEAD print(f"Получение пути изображения для файла: {filepath}") image_path = os.path.join(DATA, filepath) if not os.path.exists(image_path): print("Изображение не найдено, возвращаем дефолтное.") ======= image_path = os.path.join(DATA, filepath) if not os.path.exists(image_path): >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a return "/images/image.jpg" return f"/images/{filepath.split('/')[0]}/{filepath.split('/')[1]}/{filepath.split('/')[1]}.jpg" def get_star_image(stars): print(f"Получение изображения для {stars} звезд.") if stars is None or stars == 0: return "/stars/0-star.png" return f"/stars/{stars}-star.png" @app.route('/images/') async def serve_image(filename): <<<<<<< HEAD print(f"Запрос изображения с именем: {filename}") image_path = os.path.join(DATA, filename) if os.path.exists(image_path): print(f"Изображение {filename} найдено и отправляется.") ======= image_path = os.path.join(DATA, filename) if os.path.exists(image_path): >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a return await send_from_directory(DATA, filename) else: default_image_path = os.path.join(DATA, 'image.jpg') if os.path.exists(default_image_path): <<<<<<< HEAD print("Изображение не найдено, отправляем дефолтное.") return await send_from_directory(DATA, 'image.jpg') print("Не найдено ни одного изображения.") ======= return await send_from_directory(DATA, 'image.jpg') >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a return "Default image not found", 404 @app.route('/stars/') async def serve_star_image(filename): <<<<<<< HEAD print(f"Запрос изображения звезды: {filename}") stars = os.path.join(DATA, 'stars') star_path = os.path.join(stars, filename) if os.path.exists(star_path): print(f"Звезда {filename} найдена и отправляется.") ======= stars = os.path.join(DATA, 'stars') star_path = os.path.join(stars, filename) if os.path.exists(star_path): >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a return await send_from_directory(stars, filename) else: print("Изображение звезды не найдено.") return "Star image not found", 404 @app.route('/download_bsp') async def download_bsp(): user_ip = request.remote_addr print(f"Запрос на скачивание от IP: {user_ip}") current_time = time.time() last_time = last_download_times.get(user_ip, 0) if current_time - last_time < DOWNLOAD_COOLDOWN: wait_time = DOWNLOAD_COOLDOWN - (current_time - last_time) print(f"Пользователь должен подождать {int(wait_time)} секунд до следующего скачивания.") return f"Please wait {int(wait_time)} seconds before downloading again.", 429 last_download_times[user_ip] = current_time print("Тайм-аут скачивания обновлен.") image_path = request.args.get('image_path') if not image_path: print("Не указан путь к изображению.") return "No image path provided", 400 image_folder = os.path.dirname(image_path.replace("/images/", "")) bsp_filename = None for file in os.listdir(os.path.join(DATA, image_folder)): if file.endswith('.bsp'): bsp_filename = file break if not bsp_filename: print("Не найден .bsp файл в той же директории.") return "No .bsp file found in the same directory", 404 file_path = os.path.join(DATA, image_folder, bsp_filename) <<<<<<< HEAD print(f"Найден файл для скачивания: {file_path}") ======= >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a SPEED_LIMIT = 60 * 1024 * 1024 // 8 async def file_stream(): print("Начало передачи файла по частям.") with open(file_path, 'rb') as f: while chunk := f.read(SPEED_LIMIT): yield chunk await asyncio.sleep(1) headers = { "Content-Disposition": f"attachment; filename={bsp_filename}" } return Response(file_stream(), headers=headers, content_type='application/octet-stream') @app.route('/main') async def main_page(): print("Запрос страницы карты с параметрами:", request.args) image_url = request.args.get('image_url', 'default_image.jpg') map_title = request.args.get('map_title', 'Default Map Title') async with aiosqlite.connect(DB_PATH) as conn: cursor = await conn.cursor() await cursor.execute(''' SELECT GameMode, Tags, FilePath, DateTime, YoutubeLink, Description FROM maps WHERE Title = ? ''', (map_title,)) row = await cursor.fetchone() game_mode = row[0] if row else None tags = row[1] if row else None file_path = row[2] if row else None date_time = row[3] if row else None youtube_link = row[4] if row else None description = row[5] if row else "Нет описания" if date_time: dt = datetime.fromisoformat(date_time) added_time = format_datetime(dt, format='d MMM y г., HH:mm', locale='ru_RU') else: added_time = 'Не найдено' if game_mode: game_modes = game_mode.split(', ') game_modes = [GAME_MODES.get(mode, mode) for mode in game_modes] game_mode = ', '.join(game_modes) else: game_mode = 'Не найден' if tags: tags_list = tags.split(', ') tags_list = [GAME_MODES.get(tag, tag) for tag in tags_list] tags = ', '.join(tags_list) else: tags = 'Не найдено' if file_path: file_size = os.path.getsize(os.path.join(DATA, file_path)) file_size_mb = file_size / (1024 * 1024) file_size_display = f"{file_size_mb:.2f} MB" else: file_size_display = 'Не найден' print(f"Отправка страницы карты {map_title} с данными:") print(f"Игра: {game_mode}, Теги: {tags}, Размер файла: {file_size_display}, Время добавления: {added_time}") return await render_template( 'main.html', image_url=image_url, map_title=map_title, game_mode=game_mode, tags=tags, file_size=file_size_display, added_time=added_time, youtube_link=youtube_link, description=description ) @app.route('/') async def index(): print("Запрос главной страницы с параметрами фильтрации:", request.args) page = int(request.args.get('page', 1)) selected_game_modes = request.args.getlist('game_modes') start_date = request.args.get('start_date') end_date = request.args.get('end_date') search_title = request.args.get('search_title') selected_stars = request.args.get('stars') maps_data = await get_maps_filtered(page, selected_game_modes, start_date, end_date, search_title, selected_stars) async with aiosqlite.connect(DB_PATH) as conn: cursor = await conn.cursor() query = 'SELECT COUNT(*) FROM maps WHERE 1=1' params = [] if selected_game_modes: placeholders = ', '.join('?' for _ in selected_game_modes) query += f' AND GameMode IN ({placeholders})' params.extend(selected_game_modes) if start_date: query += ' AND DateTime >= ?' params.append(start_date) if end_date: query += ' AND DateTime <= ?' params.append(end_date) if search_title: query += ' AND Title LIKE ?' params.append(f'%{search_title}%') if selected_stars: query += ' AND Stars = ?' params.append(selected_stars) await cursor.execute(query, params) total_maps = await cursor.fetchone() total_maps = total_maps[0] per_page = 30 total_pages = (total_maps + per_page - 1) // per_page filters = '&'.join( [f'game_modes={mode}' for mode in selected_game_modes] + ([f'start_date={start_date}'] if start_date else []) + ([f'end_date={end_date}'] if end_date else []) + ([f'search_title={search_title}'] if search_title else []) + ([f'stars={selected_stars}'] if selected_stars else []) ) print(f"Общее количество карт: {total_maps}, Страниц: {total_pages}") return await render_template( 'workshop.html', maps_data=maps_data, page=page, total_pages=total_pages, get_image_path=get_image_path, get_star_image=get_star_image, selected_game_modes=selected_game_modes, filters=filters, selected_stars=selected_stars ) async def get_maps_filtered(page=1, selected_game_modes=None, start_date=None, end_date=None, search_title=None, selected_stars=None): print(f"Фильтрация карт с параметрами: {locals()}") async with aiosqlite.connect(DB_PATH) as conn: cursor = await conn.cursor() offset = (page - 1) * 30 query = ''' SELECT FilePath, Title, COALESCE(Stars, 0) as Stars, Description FROM maps WHERE 1=1 ''' params = [] if selected_stars: query += ' AND Stars = ?' params.append(selected_stars) if search_title: query += ' AND Title LIKE ?' params.append(f'%{search_title}%') if selected_game_modes: query += ' AND GameMode IN ({})'.format(','.join('?' for _ in selected_game_modes)) params.extend(selected_game_modes) if start_date: query += ' AND DateTime >= ?' params.append(start_date) if end_date: query += ' AND DateTime <= ?' params.append(end_date) query += ' ORDER BY DateTime DESC LIMIT ? OFFSET ?' params.extend([30, offset]) await cursor.execute(query, params) maps = await cursor.fetchall() print(f"Найдено {len(maps)} карт после фильтрации.") return maps @app.route('/favicon.ico') async def favicon(): return await send_from_directory(os.getcwd(), 'favicon.ico') @app.route('/sitemap.xml') async def sitemap(): domain = "https://csgoworkshop.ru" async with aiosqlite.connect(DB_PATH) as conn: cursor = await conn.cursor() # Получаем список всех карт await cursor.execute('SELECT Title FROM maps') maps = await cursor.fetchall() # Создаем базовые URL для sitemap urls = [ f"{domain}/", f"{domain}/main", ] # Добавляем URL-адреса для всех карт for map_title, in maps: encoded_title = quote(map_title) urls.append(f"{domain}/main?map_title={encoded_title}") # Генерируем XML sitemap_xml = '\n' sitemap_xml += '\n' for url in urls: sitemap_xml += " \n" sitemap_xml += f" {url}\n" sitemap_xml += f" {datetime.utcnow().strftime('%Y-%m-%d')}\n" sitemap_xml += " weekly\n" sitemap_xml += " 0.8\n" sitemap_xml += " \n" sitemap_xml += '' return Response(sitemap_xml, content_type='application/xml') @app.route('/robots.txt') async def robots_txt(): content = """ User-agent: * Disallow: """ return Response(content, content_type='text/plain') if __name__ == '__main__': <<<<<<< HEAD print("Запуск приложения...") import hypercorn.asyncio from hypercorn.config import Config config = Config() config.bind = ["0.0.0.0:5000"] hypercorn.asyncio.run(app, config) ======= import hypercorn.asyncio from hypercorn.config import Config config = Config() config.bind = ["0.0.0.0:5000"] hypercorn.asyncio.run(app, config) >>>>>>> 9cc0929a09596abeb93ee7f2711527fb5da25f7a