From 28e4792b0121bea2b7dd05249b220df85a844948 Mon Sep 17 00:00:00 2001 From: Yonn Date: Fri, 26 Dec 2025 18:05:27 +0100 Subject: [PATCH 1/2] Make size property optional in MediathekShow and update related decoding logic --- Zapp/Models/MediathekShow.swift | 19 +++++--- Zapp/Networking/MediathekAPI.swift | 57 +++++++++++++++++++---- Zapp/Persistence/PersistenceManager.swift | 2 +- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Zapp/Models/MediathekShow.swift b/Zapp/Models/MediathekShow.swift index 91c8e91a..389edce6 100644 --- a/Zapp/Models/MediathekShow.swift +++ b/Zapp/Models/MediathekShow.swift @@ -7,7 +7,7 @@ struct MediathekShow: Identifiable, Codable { let description: String? let channel: String let timestamp: Int - let size: Int + let size: Int? let duration: Int? let filmlisteTimestamp: Int let url_website: String? @@ -38,7 +38,7 @@ struct MediathekShow: Identifiable, Codable { description: String?, channel: String, timestamp: Int, - size: Int, + size: Int?, duration: Int?, filmlisteTimestamp: Int, url_website: String?, @@ -69,7 +69,14 @@ struct MediathekShow: Identifiable, Codable { description = try container.decodeIfPresent(String.self, forKey: .description) channel = try container.decode(String.self, forKey: .channel) timestamp = try container.decode(Int.self, forKey: .timestamp) - size = try container.decode(Int.self, forKey: .size) + + if let numericSize = try? container.decodeIfPresent(Int.self, forKey: .size) { + size = numericSize + } else if let stringSize = try? container.decodeIfPresent(String.self, forKey: .size) { + size = Int(stringSize) + } else { + size = nil + } if let numericDuration = try? container.decodeIfPresent(Int.self, forKey: .duration) { duration = numericDuration @@ -94,7 +101,7 @@ struct MediathekShow: Identifiable, Codable { try container.encodeIfPresent(description, forKey: .description) try container.encode(channel, forKey: .channel) try container.encode(timestamp, forKey: .timestamp) - try container.encode(size, forKey: .size) + try container.encodeIfPresent(size, forKey: .size) try container.encodeIfPresent(duration, forKey: .duration) try container.encode(filmlisteTimestamp, forKey: .filmlisteTimestamp) try container.encodeIfPresent(url_website, forKey: .url_website) @@ -214,8 +221,8 @@ extension PersistedMediathekShow { if let expectedDownloadBytes, expectedDownloadBytes > 0 { return expectedDownloadBytes } - if show.size > 0 { - return Int64(show.size) + if let size = show.size, size > 0 { + return Int64(size) } return nil } diff --git a/Zapp/Networking/MediathekAPI.swift b/Zapp/Networking/MediathekAPI.swift index df89d1d4..3b3951c5 100644 --- a/Zapp/Networking/MediathekAPI.swift +++ b/Zapp/Networking/MediathekAPI.swift @@ -141,8 +141,14 @@ final class MediathekAPI { private let baseURL = URL(string: "https://mediathekviewweb.de/api/")! private let session: URLSession - init(session: URLSession = .shared) { - self.session = session + private init() { + let config = URLSessionConfiguration.default + config.urlCache = nil + config.requestCachePolicy = .reloadIgnoringLocalCacheData + config.timeoutIntervalForRequest = 30 + config.timeoutIntervalForResource = 60 + config.waitsForConnectivity = true + self.session = URLSession(configuration: config) } func search(request: MediathekQueryRequest) async throws -> MediathekAnswer { @@ -150,17 +156,50 @@ final class MediathekAPI { var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" urlRequest.setValue("text/plain", forHTTPHeaderField: "Content-Type") + urlRequest.cachePolicy = .reloadIgnoringLocalCacheData let encoder = JSONEncoder() urlRequest.httpBody = try encoder.encode(request) - let (data, response) = try await session.data(for: urlRequest) - guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else { - let status = (response as? HTTPURLResponse)?.statusCode - throw MediathekAPIError.requestFailed(statusCode: status) - } + #if DEBUG + print("🔍 MediathekAPI: Searching with query: \(request.queries.first?.query ?? "none")") + print("🔍 MediathekAPI: Cache policy: \(urlRequest.cachePolicy.rawValue)") + #endif - let decoder = JSONDecoder() - return try decoder.decode(MediathekAnswer.self, from: data) + do { + let (data, response) = try await session.data(for: urlRequest) + + #if DEBUG + print("📡 MediathekAPI: Response received, status: \((response as? HTTPURLResponse)?.statusCode ?? 0)") + #endif + + guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else { + let status = (response as? HTTPURLResponse)?.statusCode + #if DEBUG + print("❌ MediathekAPI: HTTP error - status code: \(status ?? -1)") + #endif + throw MediathekAPIError.requestFailed(statusCode: status) + } + + let decoder = JSONDecoder() + let answer = try decoder.decode(MediathekAnswer.self, from: data) + + #if DEBUG + print("✅ MediathekAPI: Received \(answer.result.results.count) results (total: \(answer.result.queryInfo.totalResults))") + #endif + + return answer + } catch let decodingError as DecodingError { + #if DEBUG + print("❌ MediathekAPI: Decoding error: \(decodingError)") + #endif + throw decodingError + } catch { + #if DEBUG + print("❌ MediathekAPI: Network error: \(error.localizedDescription)") + print("❌ MediathekAPI: Error details: \(error)") + #endif + throw error + } } } diff --git a/Zapp/Persistence/PersistenceManager.swift b/Zapp/Persistence/PersistenceManager.swift index 4b1b4432..a3ef2cf4 100644 --- a/Zapp/Persistence/PersistenceManager.swift +++ b/Zapp/Persistence/PersistenceManager.swift @@ -157,7 +157,7 @@ final class PersistenceManager { func startDownload(show: MediathekShow, quality: MediathekShow.Quality) { var downloads = loadDownloads() - let expectedBytes = show.size > 0 ? Int64(show.size) : nil + let expectedBytes = (show.size ?? 0) > 0 ? Int64(show.size!) : nil if let index = downloads.firstIndex(where: { $0.apiId == show.id }) { downloads[index].downloadStatus = .queued From 9a98647710879d51ae744a7c6781c1a8b1ac1919 Mon Sep 17 00:00:00 2001 From: Yonn Date: Fri, 26 Dec 2025 18:05:46 +0100 Subject: [PATCH 2/2] bump project version to 16 --- Zapp.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zapp.xcodeproj/project.pbxproj b/Zapp.xcodeproj/project.pbxproj index 52a49eac..114f876a 100644 --- a/Zapp.xcodeproj/project.pbxproj +++ b/Zapp.xcodeproj/project.pbxproj @@ -271,7 +271,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 15; + CURRENT_PROJECT_VERSION = 16; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Info.plist; @@ -307,7 +307,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 15; + CURRENT_PROJECT_VERSION = 16; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = Info.plist;