You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测非.mp4结尾的视频URL并从间接链接提取下载视频

Got it, let's break down how to solve your two key challenges: handling indirect video URLs (like YouTube page links) and detecting video URLs that don’t end with .mp4. Here’s a practical, step-by-step approach tailored to your Swift codebase:

Indirect URLs point to webpages, not direct video files. To extract the underlying video source, you’ll need to fetch and parse the webpage’s content. Keep in mind: platforms like YouTube have anti-scraping measures and strict terms of service—always prioritize official APIs if available.

Core Workflow:

  • Fetch the webpage’s HTML content
  • Parse the HTML to locate embedded video sources
  • Validate and select a usable video URL

Example Implementation (with SwiftSoup for HTML parsing):

First, add SwiftSoup to your project (via CocoaPods or Swift Package Manager) for easier HTML parsing. Then update your code:

import UIKit
import SwiftSoup

class VideoDownloader: UIViewController {

    @IBAction func downloadButtonAction(_ sender: Any) {
        // Test with a YouTube page link or direct video URL
        let inputURLString = "https://www.youtube.com/watch?v=example"
        processInputURL(inputURLString)
    }

    // Route input URL to direct video handling or webpage extraction
    func processInputURL(_ urlString: String) {
        guard let inputURL = URL(string: urlString) else {
            print("Invalid URL provided")
            return
        }

        checkIfDirectVideo(inputURL) { isDirect, videoURL in
            if isDirect, let validVideoURL = videoURL {
                self.downloadVideoLinkAndCreateAsset(validVideoURL.absoluteString)
            } else {
                self.extractVideoFromWebpage(inputURL) { extractedURL in
                    guard let videoURL = extractedURL else {
                        print("Failed to pull video from webpage")
                        return
                    }
                    self.downloadVideoLinkAndCreateAsset(videoURL.absoluteString)
                }
            }
        }
    }

    // Check if URL points directly to a video (via HTTP HEAD request)
    func checkIfDirectVideo(_ url: URL, completion: @escaping (Bool, URL?) -> Void) {
        var request = URLRequest(url: url)
        request.httpMethod = "HEAD"

        URLSession.shared.dataTask(with: request) { _, response, error in
            guard let httpResponse = response as? HTTPURLResponse, error == nil else {
                completion(false, nil)
                return
            }

            if let contentType = httpResponse.allHeaderFields["Content-Type"] as? String {
                let isVideo = contentType.starts(with: "video/")
                completion(isVideo, isVideo ? url : nil)
            } else {
                completion(false, nil)
            }
        }.resume()
    }

    // Extract video source from webpage HTML
    func extractVideoFromWebpage(_ webpageURL: URL, completion: @escaping (URL?) -> Void) {
        URLSession.shared.dataTask(with: webpageURL) { data, _, error in
            guard let data = data, error == nil else {
                completion(nil)
                return
            }

            do {
                let htmlString = String(data: data, encoding: .utf8)!
                let doc = try SwiftSoup.parse(htmlString)

                // Look for direct video sources in <video> or <source> tags
                if let videoSrc = try doc.select("video").attr("src").nonEmpty {
                    completion(URL(string: videoSrc))
                } else if let sourceSrc = try doc.select("source[type^=video/]").attr("src").nonEmpty {
                    completion(URL(string: sourceSrc))
                } else {
                    // For dynamic sites (like YouTube), static parsing won't work—use official APIs instead
                    print("No static video source found. For platforms like YouTube, use their official Data API.")
                    completion(nil)
                }
            } catch {
                print("HTML parsing error: \(error.localizedDescription)")
                completion(nil)
            }
        }.resume()
    }

    // Your existing download function, updated to handle non-.mp4 formats
    func downloadVideoLinkAndCreateAsset(_ videoLink: String) {
        guard let videoURL = URL(string: videoLink) else { return }
        guard let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

        URLSession.shared.downloadTask(with: videoURL) { tempURL, response, error in
            guard let tempURL = tempURL, error == nil else {
                print("Download failed: \(error?.localizedDescription ?? "Unknown error")")
                return
            }

            do {
                // Set correct file extension based on content type
                let fileExt = self.getFileExtension(from: response)
                let finalURL = docsDir.appendingPathComponent("\(UUID().uuidString).\(fileExt)")
                try FileManager.default.moveItem(at: tempURL, to: finalURL)
                print("Video saved to: \(finalURL)")
            } catch {
                print("Failed to save video: \(error.localizedDescription)")
            }
        }.resume()
    }

    // Helper to get file extension from HTTP response content type
    func getFileExtension(from response: URLResponse?) -> String {
        guard let httpResponse = response as? HTTPURLResponse,
              let contentType = httpResponse.allHeaderFields["Content-Type"] as? String else {
            return "mp4" // Fallback
        }

        switch contentType {
        case "video/mp4": return "mp4"
        case "video/webm": return "webm"
        case "video/quicktime": return "mov"
        case "video/x-matroska": return "mkv"
        default: return "mp4"
        }
    }
}

// Small extension to check for non-empty strings
extension String {
    var nonEmpty: String? {
        let trimmed = self.trimmingCharacters(in: .whitespacesAndNewlines)
        return trimmed.isEmpty ? nil : trimmed
    }
}
2. Detecting Non-.mp4 Video URLs

Many video URLs don’t end with .mp4 (e.g., https://example.com/video?id=123 or streaming formats like .m3u8). Use these methods to validate them:

  • Check HTTP Content-Type: Send a HEAD request to verify the response’s Content-Type starts with video/
  • Parse URL patterns: Use regex to match common video extensions (even if hidden in query parameters)
  • Use response metadata: After fetching the resource, confirm it’s a video via its file signature or metadata

Key Notes:

  • For dynamic sites (like YouTube) that load videos via JavaScript, static HTML parsing won’t work. Use platform-specific APIs (e.g., YouTube Data API) to get legitimate video stream URLs.
  • Always comply with a website’s terms of service—unauthorized scraping can lead to legal issues or blocked access.

内容的提问来源于stack exchange,提问作者ThatMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:09:39