diff options
author | Hailey <me@haileyok.com> | 2024-08-15 11:23:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-15 11:23:48 -0700 |
commit | 11061b628ef5b5805c6435155ca2a571001e4643 (patch) | |
tree | d1e3c672d225592af7e1341332c6c6aeb979f216 /modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift | |
parent | b9975697e22ef729e60b9111883127961258445b (diff) | |
download | voidsky-11061b628ef5b5805c6435155ca2a571001e4643.tar.zst |
[Video] Download videos (#4886)
Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>
Diffstat (limited to 'modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift')
-rw-r--r-- | modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift b/modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift new file mode 100644 index 000000000..591c09335 --- /dev/null +++ b/modules/expo-bluesky-swiss-army/ios/HLSDownload/HLSDownloadView.swift @@ -0,0 +1,148 @@ +import ExpoModulesCore +import WebKit + +class HLSDownloadView: ExpoView, WKScriptMessageHandler, WKNavigationDelegate, WKDownloadDelegate { + var webView: WKWebView! + var downloaderUrl: URL? + + private var onStart = EventDispatcher() + private var onError = EventDispatcher() + private var onProgress = EventDispatcher() + private var onSuccess = EventDispatcher() + + private var outputUrl: URL? + + public required init(appContext: AppContext? = nil) { + super.init(appContext: appContext) + + // controller for post message api + let contentController = WKUserContentController() + contentController.add(self, name: "onMessage") + let configuration = WKWebViewConfiguration() + configuration.userContentController = contentController + + // create webview + let webView = WKWebView(frame: .zero, configuration: configuration) + + // Use these for debugging, to see the webview itself + webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + webView.layer.masksToBounds = false + webView.backgroundColor = .clear + webView.contentMode = .scaleToFill + + webView.navigationDelegate = self + + self.addSubview(webView) + self.webView = webView + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - view functions + + func startDownload(sourceUrl: URL) { + guard let downloaderUrl = self.downloaderUrl, + let url = URL(string: "\(downloaderUrl.absoluteString)?videoUrl=\(sourceUrl.absoluteString)") else { + self.onError([ + "message": "Downloader URL is not set." + ]) + return + } + + self.onStart() + self.webView.load(URLRequest(url: url)) + } + + // webview message handling + + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + guard let response = message.body as? String, + let data = response.data(using: .utf8), + let payload = try? JSONDecoder().decode(WebViewActionPayload.self, from: data) else { + self.onError([ + "message": "Failed to decode JSON post message." + ]) + return + } + + switch payload.action { + case .progress: + guard let progress = payload.messageFloat else { + self.onError([ + "message": "Failed to decode JSON post message." + ]) + return + } + self.onProgress([ + "progress": progress + ]) + case .error: + guard let messageStr = payload.messageStr else { + self.onError([ + "message": "Failed to decode JSON post message." + ]) + return + } + self.onError([ + "message": messageStr + ]) + } + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy { + guard #available(iOS 14.5, *) else { + return .cancel + } + + if navigationAction.shouldPerformDownload { + return .download + } else { + return .allow + } + } + + // MARK: - wkdownloaddelegate + + @available(iOS 14.5, *) + func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) { + download.delegate = self + } + + @available(iOS 14.5, *) + func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) { + download.delegate = self + } + + @available(iOS 14.5, *) + func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) { + let directory = NSTemporaryDirectory() + let fileName = "\(NSUUID().uuidString).mp4" + let url = NSURL.fileURL(withPathComponents: [directory, fileName]) + + self.outputUrl = url + completionHandler(url) + } + + @available(iOS 14.5, *) + func downloadDidFinish(_ download: WKDownload) { + guard let url = self.outputUrl else { + return + } + self.onSuccess([ + "uri": url.absoluteString + ]) + self.outputUrl = nil + } +} + +struct WebViewActionPayload: Decodable { + enum Action: String, Decodable { + case progress, error + } + + let action: Action + let messageStr: String? + let messageFloat: Float? +} |