'boolean', 'weekdays' => 'array', 'active_from' => 'datetime:H:i', 'active_until' => 'datetime:H:i', 'refresh_time' => 'integer', ]; public function device(): BelongsTo { return $this->belongsTo(Device::class); } public function items(): HasMany { return $this->hasMany(PlaylistItem::class); } public function isActiveNow(): bool { if (! $this->is_active) { return false; } // Get user's timezone or fall back to app timezone $timezone = $this->device->user->timezone ?? config('app.timezone'); $now = now($timezone); // Check weekday (using timezone-aware time) if ($this->weekdays !== null && ! in_array($now->dayOfWeek, $this->weekdays)) { return false; } if ($this->active_from !== null && $this->active_until !== null) { // Create timezone-aware datetime objects for active_from and active_until $activeFrom = $now->copy() ->setTimeFrom($this->active_from) ->timezone($timezone); $activeUntil = $now->copy() ->setTimeFrom($this->active_until) ->timezone($timezone); // Handle time ranges that span across midnight if ($activeFrom > $activeUntil) { // Time range spans midnight (e.g., 09:01 to 03:58) if ($now >= $activeFrom || $now <= $activeUntil) { return true; } } elseif ($now >= $activeFrom && $now <= $activeUntil) { return true; } return false; } return true; } public function getNextPlaylistItem(): ?PlaylistItem { if (! $this->isActiveNow()) { return null; } // Get active playlist items ordered by display order /** @var \Illuminate\Support\Collection|PlaylistItem[] $playlistItems */ $playlistItems = $this->items() ->where('is_active', true) ->orderBy('order') ->get(); if ($playlistItems->isEmpty()) { return null; } // Get the last displayed item $lastDisplayed = $playlistItems ->sortByDesc('last_displayed_at') ->first(); if (! $lastDisplayed || ! $lastDisplayed->last_displayed_at) { // If no item has been displayed yet, return the first one return $playlistItems->first(); } // Find the next item in sequence $currentOrder = $lastDisplayed->order; $nextItem = $playlistItems ->where('order', '>', $currentOrder) ->first(); // If there's no next item, loop back to the first one if (! $nextItem) { return $playlistItems->first(); } return $nextItem; } }