Skip to content

Commit 1f963c7

Browse files
committed
feat: add support for 360° format detection
1 parent 6cc2d07 commit 1f963c7

3 files changed

Lines changed: 14 additions & 1 deletion

File tree

Sources/YouTubeKit/YouTubeResponseTypes/VideoInfos/VideoInfosResponse.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public struct VideoInfosResponse: YouTubeResponse {
4040
/// }
4141
/// }
4242
/// ```
43+
///
44+
/// - Note: when putting this URL in an `AVURLAsset` to play it on macOS, you need to remove any potential VP9-format video from it, for example using a custom `AVAssetResourceLoaderDelegate`.
45+
/// - Note: to see whether the stream is 360°, you can check if the `YT-EXT-PROJECTION-TYPE="equirectangular"` parameter is set in the .m3u8 playlist.
4346
public var streamingURL: URL?
4447

4548
/// Array of thumbnails.

Sources/YouTubeKit/YouTubeResponseTypes/VideoInfos/VideoInfosWithDownloadFormatsResponse.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,10 +407,11 @@ public struct VideoInfosWithDownloadFormatsResponse: YouTubeResponse {
407407

408408
/// Struct representing a download format that contains the video and audio.
409409
public struct VideoDownloadFormat: DownloadFormat {
410-
public init(averageBitrate: Int? = nil, contentDuration: Int? = nil, contentLength: Int? = nil, isCopyrightedMedia: Bool? = nil, mimeType: String? = nil, codec: String? = nil, url: URL? = nil, width: Int? = nil, height: Int? = nil, quality: String? = nil, fps: Int? = nil) {
410+
public init(averageBitrate: Int? = nil, contentDuration: Int? = nil, contentLength: Int? = nil, is360: Bool? = nil, isCopyrightedMedia: Bool? = nil, mimeType: String? = nil, codec: String? = nil, url: URL? = nil, width: Int? = nil, height: Int? = nil, quality: String? = nil, fps: Int? = nil) {
411411
self.averageBitrate = averageBitrate
412412
self.contentDuration = contentDuration
413413
self.contentLength = contentLength
414+
self.is360 = is360
414415
self.isCopyrightedMedia = isCopyrightedMedia
415416
self.mimeType = mimeType
416417
self.codec = codec
@@ -430,6 +431,8 @@ public struct VideoInfosWithDownloadFormatsResponse: YouTubeResponse {
430431

431432
public var contentLength: Int?
432433

434+
public var is360: Bool?
435+
433436
public var isCopyrightedMedia: Bool?
434437

435438
public var mimeType: String?
@@ -545,6 +548,7 @@ public struct VideoInfosWithDownloadFormatsResponse: YouTubeResponse {
545548
return nil
546549
}
547550
}(),
551+
is360: json["projectionType"].string == "MESH",
548552
isCopyrightedMedia: json["signatureCipher"].string != nil,
549553
mimeType: json["mimeType"].string?.ytkFirstGroupMatch(for: "([^;]*)"),
550554
codec: json["mimeType"].string?.ytkFirstGroupMatch(for: #"codecs="([^\.]+)"#),

Tests/YouTubeKitTests/YouTubeKitTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,12 @@ final class YouTubeKitTests: XCTestCase {
689689
""",
690690
TEST_NAME + "Checking if testCaptionsResponse.getFormattedString(withFormat: .srt) is good."
691691
) // srt integrity checked with https://taoning2014.github.io/srt-validator-website/index.html
692+
693+
XCTAssertTrue(requestResult.downloadFormats.compactMap({$0 as? VideoInfosWithDownloadFormatsResponse.VideoDownloadFormat}).allSatisfy({$0.is360 == false}), TEST_NAME + "Checking if the is360 property is correctly set -> has to be false")
694+
695+
// test 360 video
696+
let video360result = try await YTVideo(videoId: "yVLfEHXQk08").fetchStreamingInfosThrowing(youtubeModel: YTM)
697+
XCTAssertTrue(video360result.downloadFormats.compactMap({$0 as? VideoInfosWithDownloadFormatsResponse.VideoDownloadFormat}).allSatisfy({$0.is360 == true}), TEST_NAME + "Checking if the is360 property is correctly set -> has to be true")
692698
}
693699

694700
func testVideoInfosWithDownloadFormatsResponse() async throws {

0 commit comments

Comments
 (0)