import logging from .parser import LyngSatParser from .models import LyngSat from mainapp.models import Polarization, Standard, Modulation, Satellite logger = logging.getLogger(__name__) def fill_lyngsat_data( target_sats: list[str], regions: list[str] = None, task_id: str = None, update_progress=None ): """ Заполняет данные Lyngsat для указанных спутников и регионов. Args: target_sats: Список названий спутников для обработки regions: Список регионов для парсинга (по умолчанию все) task_id: ID задачи Celery для логирования update_progress: Функция для обновления прогресса (current, total, status) Returns: dict: Статистика обработки с ключами: - total_satellites: общее количество спутников - total_sources: общее количество источников - created: количество созданных записей - updated: количество обновленных записей - errors: список ошибок """ log_prefix = f"[Task {task_id}]" if task_id else "[Lyngsat]" stats = { 'total_satellites': 0, 'total_sources': 0, 'created': 0, 'updated': 0, 'errors': [] } if regions is None: regions = ["europe", "asia", "america", "atlantic"] logger.info(f"{log_prefix} Начало парсинга данных") logger.info(f"{log_prefix} Спутники: {', '.join(target_sats)}") logger.info(f"{log_prefix} Регионы: {', '.join(regions)}") if update_progress: update_progress(0, len(target_sats), "Инициализация парсера...") try: parser = LyngSatParser( flaresolver_url="http://localhost:8191/v1", target_sats=target_sats, regions=regions ) logger.info(f"{log_prefix} Получение данных со спутников...") if update_progress: update_progress(0, len(target_sats), "Получение данных со спутников...") lyngsat_data = parser.get_satellites_data() stats['total_satellites'] = len(lyngsat_data) logger.info(f"{log_prefix} Получено данных по {stats['total_satellites']} спутникам") for idx, (sat_name, data) in enumerate(lyngsat_data.items(), 1): logger.info(f"{log_prefix} Обработка спутника {idx}/{stats['total_satellites']}: {sat_name}") if update_progress: update_progress(idx, stats['total_satellites'], f"Обработка {sat_name}...") url = data['url'] sources = data['sources'] stats['total_sources'] += len(sources) logger.info(f"{log_prefix} Найдено {len(sources)} источников для {sat_name}") # Находим спутник в базе по имени или альтернативному имени (lowercase) from django.db.models import Q sat_name_lower = sat_name.lower() try: sat_obj = Satellite.objects.get( Q(name__icontains=sat_name_lower) | Q(alternative_name__icontains=sat_name_lower) ) logger.debug(f"{log_prefix} Спутник {sat_name} найден в базе (ID: {sat_obj.id})") except Satellite.DoesNotExist: error_msg = f"Спутник '{sat_name}' не найден в базе данных" logger.warning(f"{log_prefix} {error_msg}") stats['errors'].append(error_msg) continue except Satellite.MultipleObjectsReturned: error_msg = f"Найдено несколько спутников с именем '{sat_name}'" logger.warning(f"{log_prefix} {error_msg}") stats['errors'].append(error_msg) continue for source_idx, source in enumerate(sources, 1): try: # Парсим частоту try: freq = float(source['freq']) except (ValueError, TypeError): freq = -1.0 error_msg = f"Некорректная частота для {sat_name}: {source.get('freq')}" logger.debug(f"{log_prefix} {error_msg}") stats['errors'].append(error_msg) last_update = source['last_update'] fec = source['metadata'].get('fec') modulation_name = source['metadata'].get('modulation') standard_name = source['metadata'].get('standard') symbol_velocity = source['metadata'].get('symbol_rate') polarization_name = source['pol'] channel_info = source['provider_name'] # Создаем или получаем связанные объекты pol_obj, _ = Polarization.objects.get_or_create( name=polarization_name if polarization_name else "-" ) mod_obj, _ = Modulation.objects.get_or_create( name=modulation_name if modulation_name else "-" ) standard_obj, _ = Standard.objects.get_or_create( name=standard_name if standard_name else "-" ) # Создаем или обновляем запись Lyngsat lyng_obj, created = LyngSat.objects.update_or_create( id_satellite=sat_obj, frequency=freq, polarization=pol_obj, defaults={ "modulation": mod_obj, "standard": standard_obj, "sym_velocity": symbol_velocity if symbol_velocity else 0, "channel_info": channel_info[:20] if channel_info else "", "last_update": last_update, "fec": fec[:30] if fec else "", "url": url } ) if created: stats['created'] += 1 logger.debug(f"{log_prefix} Создана запись для {sat_name} {freq} МГц") else: stats['updated'] += 1 logger.debug(f"{log_prefix} Обновлена запись для {sat_name} {freq} МГц") # Логируем прогресс каждые 10 источников if source_idx % 10 == 0: logger.info(f"{log_prefix} Обработано {source_idx}/{len(sources)} источников для {sat_name}") except Exception as e: error_msg = f"Ошибка при обработке источника {sat_name}: {str(e)}" logger.error(f"{log_prefix} {error_msg}", exc_info=True) stats['errors'].append(error_msg) continue logger.info(f"{log_prefix} Завершена обработка {sat_name}: создано {stats['created']}, обновлено {stats['updated']}") except Exception as e: error_msg = f"Критическая ошибка: {str(e)}" logger.error(f"{log_prefix} {error_msg}", exc_info=True) stats['errors'].append(error_msg) logger.info(f"{log_prefix} Обработка завершена. Итого: создано {stats['created']}, обновлено {stats['updated']}, ошибок {len(stats['errors'])}") if update_progress: update_progress(stats['total_satellites'], stats['total_satellites'], "Завершено") return stats def link_lyngsat_to_sources(): pass