Skip to content

Commit 6b64751

Browse files
committed
feat: add support for non-playable videos in some special cases and test for member-only videos
1 parent 86d69f4 commit 6b64751

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

‎Sources/YouTubeKit/YouTubeResponseTypes/VideoInfos/VideoInfosResponse.swift‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ public struct VideoInfosResponse: YouTubeResponse {
136136
guard json["playabilityStatus", "status"].string != "LOGIN_REQUIRED" else {
137137
throw ResponseExtractionError(reponseType: self.self, stepDescription: "Login is required to get access to the video streaming info.")
138138
}
139+
guard json["playabilityStatus", "status"].string != "UNPLAYABLE" else {
140+
throw ResponseExtractionError(reponseType: self.self, stepDescription: json["playabilityStatus", "reason"].string ?? "Unkown error")
141+
}
139142

140143
/// Extract the dictionnaries that contains the video details and streaming data.
141144
let videoDetailsJSON = json["videoDetails"]

‎Tests/YouTubeKitTests/YouTubeKitTests.swift‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,26 @@ final class YouTubeKitTests: XCTestCase {
728728
XCTAssertNotEqual(requestResult.autoCompletionEntries.count, 0, TEST_NAME + "Checking if requestResult.autoCompletionEntries is empty")
729729
}
730730

731+
func testMemberOnlyVideo() async throws {
732+
if YTM.visitorData == "" {
733+
guard let visitorData = try await SearchResponse.sendThrowingRequest(youtubeModel: YTM, data: [.query: "home"]).visitorData else { XCTFail("VisitorData is not present in SearchResponse."); return }
734+
YTM.visitorData = visitorData
735+
}
736+
737+
self.YTM.alwaysUseCookies = false
738+
let testMemberOnlyVideoChannel = YTChannel(channelId: "UCXuqSBlHAE6Xw-yeJA0Tunw")
739+
740+
let memberOnlyTestChannel = try await testMemberOnlyVideoChannel.fetchInfosThrowing(youtubeModel: YTM)
741+
let memberOnlyVideos = try await memberOnlyTestChannel.getChannelContentThrowing(forType: .videos, youtubeModel: YTM)
742+
let memberOnlyVideo = (memberOnlyVideos.currentContent as? ChannelInfosResponse.Videos)?.items.first(where: {($0 as? YTVideo)?.memberOnly == true}) as? YTVideo
743+
guard let memberOnlyVideo = memberOnlyVideo else { return }
744+
do {
745+
_ = try await VideoInfosResponse.sendThrowingRequest(youtubeModel: YTM, data: [.query: memberOnlyVideo.videoId])
746+
XCTFail("Video should not be able to be played")
747+
} catch {}
748+
self.YTM.alwaysUseCookies = true
749+
}
750+
731751
func testChannelInfosResponse() async throws {
732752
let TEST_NAME = "Test: testChannelInfosResponse() -> "
733753

0 commit comments

Comments
 (0)