Skip to content

Add schedule slots engine (time-based and event-based scheduling)#2673

Open
Alex1981-tech wants to merge 3 commits intoScreenly:masterfrom
Alex1981-tech:feature/schedule-slots
Open

Add schedule slots engine (time-based and event-based scheduling)#2673
Alex1981-tech wants to merge 3 commits intoScreenly:masterfrom
Alex1981-tech:feature/schedule-slots

Conversation

@Alex1981-tech
Copy link

Summary

Implements a schedule slot system that enables time-of-day and event-based content scheduling for Anthias, as proposed in #2671.

When ScheduleSlot records exist the viewer switches to "schedule mode": only assets linked to the currently-active slot are played. When the table is empty the viewer falls back to legacy behaviour (asset.is_active()) — full backward compatibility is preserved.

Key features

  • Three slot types: default (fallback), time (daily time window), event (one-time/recurring)
  • Slot priority: event > time > default — higher-priority slots override lower ones
  • Overnight slots: e.g. 22:00→06:00, days_of_week refers to the start day
  • Event modes: one-time (specific date), daily (date range), weekly (selected days)
  • No-loop mode: event slots play their content once, then resume normal schedule
  • Deadline timer: threading.Timer interrupts current asset for on-time slot transitions
  • Duration override: per-slot-item override of asset duration
  • Time overlap validation: prevents conflicting time slots on shared days
  • REST API: full CRUD for slots and items, reorder endpoint, schedule status endpoint
  • OpenAPI schema: all endpoints decorated with @extend_schema

Files changed

File Change
anthias_app/models.py +ScheduleSlot, ScheduleSlotItem models (~170 lines)
anthias_app/migrations/0003_schedule_slots.py Migration for both new tables
viewer/scheduling.py Schedule-aware playlist generation + deadline timer in Scheduler
api/serializers/schedule.py 4 serializers with overlap/default validation
api/views/schedule.py 6 API view classes with @extend_schema
api/urls/v2.py +6 schedule endpoint routes
anthias_app/admin.py Admin for ScheduleSlot + ScheduleSlotItem inline
tests/test_scheduler.py Updated for 4-tuple return + new schedule mode tests
api/tests/test_schedule_endpoints.py API endpoint tests (CRUD, reorder, status)

API endpoints

GET    /api/v2/schedule/slots                          — List all slots
POST   /api/v2/schedule/slots                          — Create slot
GET    /api/v2/schedule/slots/<slot_id>                 — Get slot
PUT    /api/v2/schedule/slots/<slot_id>                 — Update slot
DELETE /api/v2/schedule/slots/<slot_id>                 — Delete slot
GET    /api/v2/schedule/slots/<slot_id>/items           — List slot items
POST   /api/v2/schedule/slots/<slot_id>/items           — Add asset to slot
PUT    /api/v2/schedule/slots/<slot_id>/items/<item_id> — Update item
DELETE /api/v2/schedule/slots/<slot_id>/items/<item_id> — Delete item
POST   /api/v2/schedule/slots/<slot_id>/items/order     — Reorder items
GET    /api/v2/schedule/status                          — Current schedule status

How it works

  1. generate_asset_list() now returns a 4-tuple: (playlist, deadline, no_loop, active_slot_id)
  2. If no ScheduleSlot records exist → legacy path (unchanged)
  3. If slots exist → find active slot by priority → build playlist from ScheduleSlotItems
  4. Scheduler class extended with deadline timer, no-loop support, and event completion handling

Backward compatibility

  • Zero slots = original behaviour — no database records needed, no migration side effects
  • generate_asset_list() returns 4-tuple but legacy callers only need to update unpacking
  • All existing tests updated and passing
  • No changes to viewer/__init__.py or viewer/media_player.py

Test plan

  • ruff check passes on all changed files
  • ruff format --check passes on all changed files
  • python manage.py makemigrations --check — migration is up to date
  • python manage.py test tests.test_scheduler — scheduler tests pass
  • python manage.py test api.tests.test_schedule_endpoints — API tests pass
  • Manual test: create default slot via API, verify viewer plays its assets
  • Manual test: create time slot, verify it activates/deactivates at correct times
  • Manual test: verify legacy mode (delete all slots) still works

Closes #2671

🤖 Generated with Claude Code

Introduce a schedule slot system that enables time-of-day and
event-based content scheduling. When ScheduleSlot records exist,
the viewer switches to "schedule mode" with slot priority
(event > time > default). Without any slots, legacy behaviour
(asset.is_active()) is fully preserved.

Key features:
- ScheduleSlot model with three types: default, time, event
- ScheduleSlotItem links assets to slots with optional duration override
- Overnight slot support (e.g. 22:00-06:00)
- Event slots: one-time, daily, or weekly recurrence with no-loop mode
- Deadline timer interrupts current asset for on-time slot transitions
- Full REST API with overlap validation and OpenAPI schema
- Backward-compatible: zero slots = original Anthias behaviour

Closes Screenly#2671

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace random.shuffle with secrets.SystemRandom.shuffle (security hotspot)
- Deduplicate slot_end datetime construction in _calc_slot_deadline

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- viewer/scheduling.py: apply ruff format (line break in _set_time)
- tests/test_viewer.py: update generate_asset_list mock to return
  4-tuple (playlist, deadline, no_loop, active_slot_id) matching
  the new schedule-aware signature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature proposal: Schedule slots engine (time-based & event-based scheduling)

1 participant