(source_id, force=False)
| 622 | |
| 623 | |
| 624 | def _refresh_epg_data_impl(source_id, force=False): |
| 625 | try: |
| 626 | source = _get_epg_source(source_id) |
| 627 | except EPGSource.DoesNotExist: |
| 628 | logger.warning( |
| 629 | f"EPG source with ID {source_id} not found, but task was triggered. " |
| 630 | "Cleaning up orphaned task." |
| 631 | ) |
| 632 | |
| 633 | if delete_epg_refresh_task_by_id(source_id): |
| 634 | logger.info( |
| 635 | f"Successfully cleaned up orphaned task for EPG source {source_id}" |
| 636 | ) |
| 637 | else: |
| 638 | logger.info(f"No orphaned task found for EPG source {source_id}") |
| 639 | |
| 640 | return f"EPG source {source_id} does not exist, task cleaned up" |
| 641 | |
| 642 | if not source.is_active: |
| 643 | logger.info(f"EPG source {source_id} is not active. Skipping.") |
| 644 | return |
| 645 | |
| 646 | if source.source_type == 'dummy': |
| 647 | logger.info( |
| 648 | f"Skipping refresh for dummy EPG source {source.name} (ID: {source_id})" |
| 649 | ) |
| 650 | return |
| 651 | |
| 652 | logger.info(f"Processing EPGSource: {source.name} (type: {source.source_type})") |
| 653 | if source.source_type == 'xmltv': |
| 654 | # Invalidate the byte-offset index before downloading the new file |
| 655 | # so stale offsets are never used during the refresh window. |
| 656 | EPGSourceIndex.objects.update_or_create( |
| 657 | source_id=source.id, defaults={'data': None} |
| 658 | ) |
| 659 | if not fetch_xmltv(source): |
| 660 | logger.error(f"Failed to fetch XMLTV for source {source.name}") |
| 661 | return |
| 662 | |
| 663 | if not parse_channels_only(source): |
| 664 | logger.error(f"Failed to parse channels for source {source.name}") |
| 665 | return |
| 666 | |
| 667 | # Build byte-offset index after programme data is committed so refresh |
| 668 | # does not compete for memory/IO during the programme swap. |
| 669 | if not parse_programs_for_source(source): |
| 670 | logger.error(f"Failed to parse programs for source {source.name}") |
| 671 | return |
| 672 | |
| 673 | build_programme_index_task.delay(source.id) |
| 674 | |
| 675 | elif source.source_type == 'schedules_direct': |
| 676 | fetch_schedules_direct(source, force=force) |
| 677 | |
| 678 | EPGSource.objects.filter(id=source.id).update(updated_at=timezone.now()) |
| 679 | try: |
| 680 | from apps.channels.tasks import evaluate_series_rules |
| 681 | evaluate_series_rules.delay() |
no test coverage detected