diff --git a/Core/Core/Domain/Model/CourseBlockModel.swift b/Core/Core/Domain/Model/CourseBlockModel.swift index c9e24441..21c8984e 100644 --- a/Core/Core/Domain/Model/CourseBlockModel.swift +++ b/Core/Core/Domain/Model/CourseBlockModel.swift @@ -379,7 +379,7 @@ public struct CourseBlockEncodedVideo: Sendable { public func video(downloadQuality: DownloadQuality) -> CourseBlockVideo? { switch downloadQuality { case .auto: - [mobileLow, mobileHigh, desktopMP4, fallback, hls] + [hls, mobileLow, mobileHigh, desktopMP4, fallback] .first(where: { $0?.isDownloadable == true })? .flatMap { $0 } case .high: @@ -400,44 +400,50 @@ public struct CourseBlockEncodedVideo: Sendable { public func video(streamingQuality: StreamingQuality) -> CourseBlockVideo? { switch streamingQuality { case .auto: - [mobileLow, mobileHigh, desktopMP4, fallback, hls] + [hls, mobileLow, mobileHigh, desktopMP4, fallback, youtube] .compactMap { $0 } .sorted(by: { ($0?.streamPriority ?? 0) < ($1?.streamPriority ?? 0) }) .first? .flatMap { $0 } case .high: - [desktopMP4, mobileHigh, mobileLow, fallback, hls] + [desktopMP4, mobileHigh, mobileLow, hls, youtube, fallback] .compactMap { $0 } .first? .flatMap { $0 } case .medium: - [mobileHigh, mobileLow, desktopMP4, fallback, hls] + [mobileHigh, mobileLow, desktopMP4, hls, youtube, fallback] .compactMap { $0 } .first? .flatMap { $0 } case .low: - [mobileLow, mobileHigh, desktopMP4, fallback, hls] + [mobileLow, mobileHigh, desktopMP4, hls, youtube, fallback] .compactMap { $0 } .first(where: { $0?.isDownloadable == true })? .flatMap { $0 } } } +} - public var youtubeVideoUrl: String? { - youtube?.url - } - +public enum CourseBlockVideoEncoding: Sendable { + case mobileLow, mobileHigh, desktopMP4, fallback, hls, youtube } public struct CourseBlockVideo: Equatable, Sendable { public let url: String? public let fileSize: Int? public let streamPriority: Int? + public let type: CourseBlockVideoEncoding? - public init(url: String?, fileSize: Int?, streamPriority: Int?) { + public init( + url: String?, + fileSize: Int?, + streamPriority: Int?, + type: CourseBlockVideoEncoding? + ) { self.url = url self.fileSize = fileSize self.streamPriority = streamPriority + self.type = type } public var isVideoURL: Bool { diff --git a/Core/CoreTests/DownloadManager/DownloadManagerTests.swift b/Core/CoreTests/DownloadManager/DownloadManagerTests.swift index 5c1b2ec5..c1b732ab 100644 --- a/Core/CoreTests/DownloadManager/DownloadManagerTests.swift +++ b/Core/CoreTests/DownloadManager/DownloadManagerTests.swift @@ -319,7 +319,8 @@ final class DownloadManagerTests: XCTestCase { fallback: CourseBlockVideo( url: "https://test.com/video.mp4", fileSize: videoSize, - streamPriority: 1 + streamPriority: 1, + type: .desktopMP4 ), youtube: nil, desktopMP4: nil, diff --git a/Course/Course/Data/CourseRepository.swift b/Course/Course/Data/CourseRepository.swift index abf19ebe..dd78e1ad 100644 --- a/Course/Course/Data/CourseRepository.swift +++ b/Course/Course/Data/CourseRepository.swift @@ -41,7 +41,7 @@ public actor CourseRepository: CourseRepositoryProtocol { self.config = config self.persistence = persistence } - + public func getCourseBlocks(courseID: String) async throws -> CourseStructure { let course = try await api.requestData( CourseEndpoint.getCourseBlocks(courseID: courseID, userName: coreStorage.user?.username ?? "") @@ -245,26 +245,48 @@ public actor CourseRepository: CourseRepositoryProtocol { webUrl: block.webUrl, subtitles: subtitles, encodedVideo: .init( - fallback: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.fallback), - youtube: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.youTube), - desktopMP4: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.desktopMP4), - mobileHigh: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.mobileHigh), - mobileLow: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.mobileLow), - hls: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.hls) + fallback: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.fallback, + type: .fallback + ), + youtube: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.youTube, + type: .youtube + ), + desktopMP4: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.desktopMP4, + type: .desktopMP4 + ), + mobileHigh: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.mobileHigh, + type: .mobileHigh + ), + mobileLow: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.mobileLow, + type: .mobileLow + ), + hls: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.hls, + type: .hls + ) ), multiDevice: block.multiDevice, offlineDownload: offlineDownload ) } - private func parseVideo(encodedVideo: DataLayer.EncodedVideoData?) -> CourseBlockVideo? { + private func parseVideo( + encodedVideo: DataLayer.EncodedVideoData?, + type: CourseBlockVideoEncoding + ) -> CourseBlockVideo? { guard let encodedVideo, encodedVideo.url?.isEmpty == false else { return nil } return .init( url: encodedVideo.url, fileSize: encodedVideo.fileSize, - streamPriority: encodedVideo.streamPriority + streamPriority: encodedVideo.streamPriority, + type: type ) } } @@ -482,26 +504,46 @@ And there are various ways of describing it-- call it oral poetry or webUrl: block.webUrl, subtitles: subtitles, encodedVideo: .init( - fallback: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.fallback), - youtube: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.youTube), - desktopMP4: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.desktopMP4), - mobileHigh: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.mobileHigh), - mobileLow: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.mobileLow), - hls: parseVideo(encodedVideo: block.userViewData?.encodedVideo?.hls) + fallback: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.fallback, + type: .fallback + ), + youtube: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.youTube, + type: .youtube + ), + desktopMP4: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.desktopMP4, + type: .desktopMP4 + ), + mobileHigh: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.mobileHigh, + type: .mobileHigh + ), + mobileLow: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.mobileLow, type: .mobileLow), + hls: parseVideo( + encodedVideo: block.userViewData?.encodedVideo?.hls, + type: .hls + ) ), multiDevice: block.multiDevice, offlineDownload: offlineDownload ) } - private func parseVideo(encodedVideo: DataLayer.EncodedVideoData?) -> CourseBlockVideo? { + private func parseVideo( + encodedVideo: DataLayer.EncodedVideoData?, + type: CourseBlockVideoEncoding + ) -> CourseBlockVideo? { guard let encodedVideo else { return nil } return .init( url: encodedVideo.url, fileSize: encodedVideo.fileSize, - streamPriority: encodedVideo.streamPriority + streamPriority: encodedVideo.streamPriority, + type: type ) } } diff --git a/Course/Course/Presentation/Unit/CourseUnitViewModel.swift b/Course/Course/Presentation/Unit/CourseUnitViewModel.swift index b2623310..1074ad0a 100644 --- a/Course/Course/Presentation/Unit/CourseUnitViewModel.swift +++ b/Course/Course/Presentation/Unit/CourseUnitViewModel.swift @@ -41,15 +41,15 @@ public enum LessonType: Equatable { case .discussion: return .discussion(block.topicId ?? "", block.id, block.displayName) case .video: - if block.encodedVideo?.youtubeVideoUrl != nil, - let encodedVideo = block.encodedVideo?.video(streamingQuality: streamingQuality)?.url { - return .video(videoUrl: encodedVideo, blockId: block.id) - } else if let youtubeVideoUrl = block.encodedVideo?.youtubeVideoUrl { - return .youtube(youtubeVideoUrl: youtubeVideoUrl, blockId: block.id) - } else if let encodedVideo = block.encodedVideo?.video(streamingQuality: streamingQuality)?.url { - return .video(videoUrl: encodedVideo, blockId: block.id) - } else if let encodedVideo = block.encodedVideo?.video(downloadQuality: DownloadQuality.auto)?.url { - return .video(videoUrl: encodedVideo, blockId: block.id) + if let encodedVideo = block.encodedVideo?.video(streamingQuality: streamingQuality), + let videoURL = encodedVideo.url { + if encodedVideo.type == .youtube { + return .youtube(youtubeVideoUrl: videoURL, blockId: block.id) + } else if encodedVideo.isVideoURL { + return .video(videoUrl: videoURL, blockId: block.id) + } else { + return .unknown(block.studentUrl) + } } else { return .unknown(block.studentUrl) } diff --git a/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift b/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift index 278faf66..3f2e8f82 100644 --- a/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift +++ b/Course/CourseTests/Presentation/Container/CourseContainerViewModelTests.swift @@ -391,7 +391,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type: .desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -535,7 +535,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type: .desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -662,7 +662,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type: .desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -790,7 +790,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type:.desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -911,7 +911,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type:.desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -1044,7 +1044,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type:.desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -1177,7 +1177,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type:.desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil @@ -1200,7 +1200,7 @@ final class CourseContainerViewModelTests: XCTestCase { encodedVideo: .init( fallback: nil, youtube: nil, - desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1), + desktopMP4: .init(url: "test.mp4", fileSize: 1000, streamPriority: 1, type:.desktopMP4), mobileHigh: nil, mobileLow: nil, hls: nil