Skip to content

Commit

Permalink
Also uses watch page html to extract additional source of streams
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeichhorn committed Dec 13, 2023
1 parent 2c47048 commit 7d5c7f6
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
6 changes: 6 additions & 0 deletions Sources/YouTubeKit/Extraction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ class Extraction {
throw YouTubeKitError.regexMatchError
}

/// Tries to find video info in watch html directly
class func getVideoInfo(fromHTML html: String) throws -> InnerTube.VideoInfo {
let pattern = NSRegularExpression(#"ytInitialPlayerResponse\s*=\s*"#)
return try parseForObject(InnerTube.VideoInfo.self, html: html, precedingRegex: pattern)
}

/// Return the playability status and status explanation of the video
/// For example, a video may have a status of LOGIN\_REQUIRED, and an explanation
/// of "This is a private video. Please sign in to verify that you may see it."
Expand Down
25 changes: 24 additions & 1 deletion Sources/YouTubeKit/YouTube.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import os.log

@available(iOS 13.0, watchOS 6.0, tvOS 13.0, macOS 10.15, *)
public class YouTube {
Expand Down Expand Up @@ -43,6 +44,10 @@ public class YouTube {
URL(string: "https://youtube.com/watch?v=\(videoID)")!
}

private var extendedWatchURL: URL {
URL(string: "https://youtube.com/watch?v=\(videoID)&bpctr=9999999999&has_verified=1")!
}

var embedURL: URL {
URL(string: "https://www.youtube.com/embed/\(videoID)")!
}
Expand All @@ -58,6 +63,8 @@ public class YouTube {

let methods: [ExtractionMethod]

private let log = OSLog(YouTube.self)

/// - parameter methods: Methods used to extract streams from the video - ordered by priority (Default: only local)
public init(videoID: String, proxies: [String: URL] = [:], useOAuth: Bool = false, allowOAuthCache: Bool = false, methods: [ExtractionMethod] = [.local]) {
self.videoID = videoID
Expand All @@ -84,7 +91,7 @@ public class YouTube {
if let cached = _watchHTML {
return cached
}
var request = URLRequest(url: watchURL)
var request = URLRequest(url: extendedWatchURL)
request.setValue("Mozilla/5.0", forHTTPHeaderField: "User-Agent")
request.setValue("en-US,en", forHTTPHeaderField: "accept-language")
let (data, _) = try await URLSession.shared.data(for: request)
Expand Down Expand Up @@ -218,6 +225,7 @@ public class YouTube {
// make sure only one stream per itag exists
for stream in newStreams {
if existingITags.insert(stream.itag.itag).inserted {
print(stream)
streams.append(stream)
}
}
Expand Down Expand Up @@ -285,6 +293,16 @@ public class YouTube {
return cached
}

// try extracting video infos from watch html directly as well
let watchVideoInfoTask = Task<InnerTube.VideoInfo?, Never> {
do {
return try await Extraction.getVideoInfo(fromHTML: watchHTML)
} catch let error {
os_log("Couldn't extract video info from main watch html: %{public}@", log: log, type: .debug, error.localizedDescription)
return nil
}
}

let innertubeClients: [InnerTube.ClientType] = [.ios, .android]

let results: [Result<InnerTube.VideoInfo, Error>] = await innertubeClients.concurrentMap { [videoID, useOAuth, allowOAuthCache] client in
Expand All @@ -310,6 +328,11 @@ public class YouTube {
}
}

// append potentially extracted video info (with least priority)
if let watchVideoInfo = await watchVideoInfoTask.value {
videoInfos.append(watchVideoInfo)
}

if videoInfos.isEmpty {
throw errors.first ?? YouTubeKitError.extractError
}
Expand Down

0 comments on commit 7d5c7f6

Please sign in to comment.