RTSDA-iOS/ViewModels/MessagesViewModel.swift
2025-02-03 16:15:57 -05:00

250 lines
9.6 KiB
Swift

import Foundation
@MainActor
class MessagesViewModel: ObservableObject {
@Published var messages: [Message] = []
@Published var filteredMessages: [Message] = []
@Published var livestream: Message?
@Published var isLoading = false
@Published var error: Error?
@Published var availableYears: [String] = []
@Published var availableMonths: [String] = []
@Published var currentMediaType: JellyfinService.MediaType = .sermons
private let jellyfinService = JellyfinService.shared
private let owncastService = OwnCastService.shared
private var currentTask: Task<Void, Never>?
private var autoRefreshTask: Task<Void, Never>?
init() {
Task {
await loadContent()
startAutoRefresh()
}
}
deinit {
autoRefreshTask?.cancel()
}
private func startAutoRefresh() {
// Cancel any existing auto-refresh task
autoRefreshTask?.cancel()
// Create new auto-refresh task
autoRefreshTask = Task {
while !Task.isCancelled {
// Wait for 5 seconds
try? await Task.sleep(nanoseconds: 5 * 1_000_000_000)
// Check only livestream status
let streamStatus = try? await owncastService.getStreamStatus()
print("📺 Stream status: \(String(describing: streamStatus))")
if let status = streamStatus, status.online {
print("📺 Stream is online! Creating livestream message")
self.livestream = owncastService.createLivestreamMessage(from: status)
print("📺 Livestream message created: \(String(describing: self.livestream))")
} else {
print("📺 Stream is offline or status check failed")
self.livestream = nil
}
}
}
}
func loadContent(mediaType: JellyfinService.MediaType = .sermons) async {
currentMediaType = mediaType
guard !isLoading else { return }
isLoading = true
error = nil
// Cancel any existing task
currentTask?.cancel()
// Create a new task for content loading
currentTask = Task {
do {
// Check OwnCast stream status
if !Task.isCancelled {
let streamStatus = try? await owncastService.getStreamStatus()
print("📺 Initial stream status: \(String(describing: streamStatus))")
if let status = streamStatus, status.online {
print("📺 Stream is online on initial load! Creating livestream message")
self.livestream = owncastService.createLivestreamMessage(from: status)
print("📺 Initial livestream message created: \(String(describing: self.livestream))")
} else {
print("📺 Stream is offline on initial load")
self.livestream = nil
}
}
// Set media type and fetch content
if !Task.isCancelled {
jellyfinService.setType(mediaType)
let sermons = try await jellyfinService.fetchSermons(type: mediaType == .sermons ? .sermon : .liveArchive)
// Create simple date formatter
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.timeZone = TimeZone(identifier: "America/New_York")
// Convert sermons to messages
self.messages = sermons.map { sermon in
Message(
id: sermon.id,
title: sermon.title,
description: sermon.description,
speaker: sermon.speaker,
videoUrl: sermon.videoUrl ?? "",
thumbnailUrl: sermon.thumbnail ?? "",
duration: 0,
isLiveStream: sermon.type == .liveArchive,
isPublished: true,
isDeleted: false,
liveBroadcastStatus: sermon.type == .liveArchive ? "live" : "none",
date: formatter.string(from: sermon.date)
)
}
.sorted { $0.date > $1.date }
// Update available years and months
updateAvailableFilters()
// Initialize filtered messages with all messages
self.filteredMessages = self.messages
// Only show error if both content and livestream failed
if self.messages.isEmpty && self.livestream == nil {
self.error = JellyfinService.JellyfinError.noVideosFound
}
}
} catch {
if !Task.isCancelled {
self.error = error
print("Error loading content: \(error.localizedDescription)")
}
}
if !Task.isCancelled {
isLoading = false
}
}
// Wait for the task to complete
await currentTask?.value
}
func refreshContent() async {
// Check stream status first
let streamStatus = try? await owncastService.getStreamStatus()
if let status = streamStatus, status.online {
self.livestream = owncastService.createLivestreamMessage(from: status)
} else {
self.livestream = nil
}
// Then load the rest of the content
await loadContent(mediaType: currentMediaType)
}
private func updateAvailableFilters() {
// Get messages for current media type
let currentMessages = messages.filter { message in
message.isLiveStream == (currentMediaType == .livestreams)
}
// Create date formatter
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
// Get unique years first
var years = Set<String>()
var monthsByYear: [String: Set<String>] = [:]
for message in currentMessages {
if let date = formatter.date(from: message.date) {
let calendar = Calendar.current
let year = String(calendar.component(.year, from: date))
let month = String(format: "%02d", calendar.component(.month, from: date))
years.insert(year)
// Group months by year
if monthsByYear[year] == nil {
monthsByYear[year] = Set<String>()
}
monthsByYear[year]?.insert(month)
}
}
// Sort years descending (newest first)
availableYears = Array(years).sorted(by: >)
// Get months only for selected year (first year by default)
if let selectedYear = availableYears.first,
let monthsForYear = monthsByYear[selectedYear] {
availableMonths = Array(monthsForYear).sorted()
} else {
availableMonths = []
}
}
// Add a method to update months when year changes
func updateMonthsForYear(_ year: String) {
// Get messages for current media type and year
let currentMessages = messages.filter { message in
message.isLiveStream == (currentMediaType == .livestreams) &&
message.date.hasPrefix(year)
}
// Create date formatter
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
// Get months for the selected year
var months = Set<String>()
for message in currentMessages {
if let date = formatter.date(from: message.date) {
let calendar = Calendar.current
let month = String(format: "%02d", calendar.component(.month, from: date))
months.insert(month)
}
}
// Sort months ascending (Jan to Dec)
availableMonths = Array(months).sorted()
}
func filterContent(year: String? = nil, month: String? = nil) {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
// Filter by type first
let typeFiltered = messages.filter { message in
message.isLiveStream == (currentMediaType == .livestreams)
}
// Then filter by date components
let dateFiltered = typeFiltered.filter { message in
guard let date = formatter.date(from: message.date) else { return false }
let calendar = Calendar.current
if let year = year {
let messageYear = String(calendar.component(.year, from: date))
if messageYear != year { return false }
}
if let month = month {
let messageMonth = String(format: "%02d", calendar.component(.month, from: date))
if messageMonth != month { return false }
}
return true
}
// Sort by date, newest first
filteredMessages = dateFiltered.sorted { $0.date > $1.date }
}
}