feat(main): main

This commit is contained in:
2026-03-10 08:39:28 -04:00
parent b1a93161c0
commit af3076342a
18 changed files with 826 additions and 38 deletions

View File

@@ -58,13 +58,26 @@ class AiringSchema(Schema):
ends_at: datetime
slot_kind: str
status: str
exact_playback_offset_seconds: float = 0.0
@staticmethod
def from_airing(airing) -> 'AiringSchema':
media_path = None
exact_offset = 0.0
# Calculate exactly how far into the video we should be right now
now = timezone.now()
# if the airing hasn't started yet, offset is 0
if now >= airing.starts_at:
exact_offset = (now - airing.starts_at).total_seconds()
if airing.media_item:
item = airing.media_item
# If the item has a known runtime, and we are looping it, modulo the offset
if item.runtime_seconds and item.runtime_seconds > 0:
exact_offset = exact_offset % item.runtime_seconds
# 1. Determine if this item is from a YouTube source
is_youtube = False
if item.media_source and item.media_source.source_type in ['youtube', 'youtube_channel', 'youtube_playlist']:
@@ -102,6 +115,7 @@ class AiringSchema(Schema):
ends_at=airing.ends_at,
slot_kind=airing.slot_kind,
status=airing.status,
exact_playback_offset_seconds=max(0.0, exact_offset)
)
@router.get("/", response=List[ChannelSchema])
@@ -112,7 +126,61 @@ def list_channels(request):
)
class ChannelStatusSchema(Schema):
total_upcoming_airings: int
total_cached_airings: int
percent_cached: float
missing_items: List[dict]
@router.get("/{channel_id}/status", response=ChannelStatusSchema)
def get_channel_status(request, channel_id: int):
channel = get_object_or_404(Channel, id=channel_id)
now = timezone.now()
window_end = now + timedelta(hours=24)
airings = Airing.objects.filter(
channel=channel,
ends_at__gt=now,
starts_at__lte=window_end
).select_related('media_item')
total = 0
cached = 0
missing = []
for a in airings:
total += 1
item = a.media_item
if item and item.cached_file_path:
# We don't do path.exists() here to keep it fast, but we could.
cached += 1
elif item:
missing.append({
"id": item.id,
"title": item.title,
"starts_at": a.starts_at.isoformat()
})
pct = (cached / total * 100.0) if total > 0 else 100.0
return {
"total_upcoming_airings": total,
"total_cached_airings": cached,
"percent_cached": pct,
"missing_items": missing
}
@router.post("/{channel_id}/download")
def trigger_channel_download(request, channel_id: int):
get_object_or_404(Channel, id=channel_id)
from core.services.cache import run_cache
# Run cache explicitly for this channel for the next 24 hours
result = run_cache(hours=24, prune_only=False, channel_id=channel_id)
return result
@router.get("/{channel_id}", response=ChannelSchema)
def get_channel(request, channel_id: int):
return get_object_or_404(Channel, id=channel_id)