import UIKit import UniformTypeIdentifiers final class ShareViewController: UIViewController { private let statusLabel = UILabel() override func viewDidLoad() { super.viewDidLoad() setupUI() Task { await handleIncomingShare() } } private func setupUI() { view.backgroundColor = .systemBackground statusLabel.translatesAutoresizingMaskIntoConstraints = false statusLabel.textAlignment = .center statusLabel.numberOfLines = 0 statusLabel.text = "Paylaşılan bağlantı alınıyor..." view.addSubview(statusLabel) NSLayoutConstraint.activate([ statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), statusLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } @MainActor private func updateStatus(_ text: String) { statusLabel.text = text } private func handleIncomingShare() async { guard let item = extensionContext?.inputItems.first as? NSExtensionItem, let providers = item.attachments else { updateStatus("Paylaşılan içerik okunamadı.") return } for provider in providers { if let extracted = await extractURL(from: provider), isSupportedStreamingURL(extracted) { SharedPayloadStore.saveIncomingURL(extracted.absoluteString) updateStatus("Bağlantı alındı, uygulama açılıyor...") openHostApp() return } } updateStatus("Geçerli bir Netflix/Prime Video linki bulunamadı.") } private func extractURL(from provider: NSItemProvider) async -> URL? { if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) { return await withCheckedContinuation { continuation in provider.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) { item, _ in continuation.resume(returning: item as? URL) } } } if provider.hasItemConformingToTypeIdentifier(UTType.text.identifier) { return await withCheckedContinuation { continuation in provider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil) { item, _ in if let raw = item as? String, let url = URL(string: raw.trimmingCharacters(in: .whitespacesAndNewlines)) { continuation.resume(returning: url) return } continuation.resume(returning: nil) } } } return nil } private func isSupportedStreamingURL(_ url: URL) -> Bool { let host = url.host?.lowercased() ?? "" let netflixHosts = ["www.netflix.com", "netflix.com", "www.netflix.com.tr", "netflix.com.tr"] let primeHosts = ["www.primevideo.com", "primevideo.com", "www.amazon.com", "amazon.com"] let isNetflix = netflixHosts.contains(host) let isPrime = primeHosts.contains(host) guard isNetflix || isPrime else { return false } let path = url.path.lowercased() if path.contains("/title/") || path.contains("/watch/") || path.contains("/detail/") { return true } // Some share links can be shortened/redirect style without a canonical path. return !path.isEmpty && path != "/" } private func openHostApp() { guard let url = URL(string: "\(SharedConfig.appURLScheme)://ingest") else { extensionContext?.completeRequest(returningItems: nil) return } extensionContext?.open(url) { success in // If opening succeeded, the system should transition to the host app. // Completing the extension request immediately can bounce back to the source app. guard !success else { return } self.extensionContext?.completeRequest(returningItems: nil) } } }