Ensure recordings exist for a recurring rule within the scheduling horizon.
(rule_id: int, drop_existing: bool = True, horizon_days: int = 14)
| 838 | |
| 839 | |
| 840 | def sync_recurring_rule_impl(rule_id: int, drop_existing: bool = True, horizon_days: int = 14) -> int: |
| 841 | """Ensure recordings exist for a recurring rule within the scheduling horizon.""" |
| 842 | from django.utils import timezone |
| 843 | from .models import RecurringRecordingRule, Recording |
| 844 | |
| 845 | rule = RecurringRecordingRule.objects.filter(pk=rule_id).select_related("channel").first() |
| 846 | now = timezone.now() |
| 847 | removed = 0 |
| 848 | if drop_existing: |
| 849 | removed = purge_recurring_rule_impl(rule_id) |
| 850 | |
| 851 | if not rule or not rule.enabled: |
| 852 | return 0 |
| 853 | |
| 854 | days = rule.cleaned_days() |
| 855 | if not days: |
| 856 | return 0 |
| 857 | |
| 858 | tz_name = CoreSettings.get_system_time_zone() |
| 859 | try: |
| 860 | tz = ZoneInfo(tz_name) |
| 861 | except Exception: |
| 862 | logger.warning("Invalid or unsupported time zone '%s'; falling back to Server default", tz_name) |
| 863 | tz = timezone.get_current_timezone() |
| 864 | local_today = now.astimezone(tz).date() |
| 865 | start_limit = rule.start_date or local_today |
| 866 | end_limit = rule.end_date |
| 867 | horizon = now + timedelta(days=horizon_days) |
| 868 | start_window = max(start_limit, local_today) |
| 869 | if drop_existing and end_limit: |
| 870 | end_window = end_limit |
| 871 | else: |
| 872 | end_window = horizon.astimezone(tz).date() |
| 873 | if end_limit and end_limit < end_window: |
| 874 | end_window = end_limit |
| 875 | if end_window < start_window: |
| 876 | return 0 |
| 877 | total_created = 0 |
| 878 | |
| 879 | for offset in range((end_window - start_window).days + 1): |
| 880 | target_date = start_window + timedelta(days=offset) |
| 881 | if target_date.weekday() not in days: |
| 882 | continue |
| 883 | if end_limit and target_date > end_limit: |
| 884 | continue |
| 885 | try: |
| 886 | start_dt = timezone.make_aware(datetime.combine(target_date, rule.start_time), tz) |
| 887 | end_dt = timezone.make_aware(datetime.combine(target_date, rule.end_time), tz) |
| 888 | except Exception: |
| 889 | continue |
| 890 | if end_dt <= start_dt: |
| 891 | end_dt = end_dt + timedelta(days=1) |
| 892 | if start_dt <= now: |
| 893 | continue |
| 894 | exists = Recording.objects.filter( |
| 895 | channel=rule.channel, |
| 896 | start_time=start_dt, |
| 897 | custom_properties__rule__id=rule.id, |