YoutubeDL-iOS icon indicating copy to clipboard operation
YoutubeDL-iOS copied to clipboard

Calling YoutubeDL.extractInfo(url:) results in EXC_BAD_ACCESS

Open levitatingpineapple opened this issue 1 year ago • 9 comments

Hello 👋

Thanks for maintaining these repositories!

I'm experiencing a crash, when trying to extract info from a video. The following test is also failing with 🛑 EXC_BAD_ACCESS The crash appears to be originating from FFmpeg-iOS-Support dependency.

Test

The following test has been crashing as well: https://github.com/kewlbear/YoutubeDL-iOS/blob/6621fd127d373b42fff86e2ba2d472f7a7e48a20/Tests/YoutubeDL_iOSTests/YoutubeDLTests.swift#L35-L41

Workaround

Although I was not able to determine the cause of the crash, I currently have a workaround for extracting info by making a direct call:

// ✅ Passing
func testDirectExtractInfo() async throws {
    let youtubeDL: PythonObject = try await YtDlp().yt_dlp.YoutubeDL(["nocheckcertificate": true])
    let info = try PythonDecoder()
        .decode(
            Info.self,
            from: youtubeDL
                .extract_info
                .throwing
                .dynamicallyCall(withKeywordArguments: ["": "WdFj7fUnmC0", "download": false])
        )
    XCTAssertEqual(info.title, "YoutubeDL iOS app demo")
}

levitatingpineapple avatar May 03 '23 12:05 levitatingpineapple

+1

leonx98 avatar May 25 '23 15:05 leonx98

@levitatingpineapple i am having same issue. i do not want to download the video but only extract the info. Using the provided work-around does not work reliably with all videos. For example if you apply it to this url: https://video.kenh14.vn/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn it will crash because there is no formats key from the response which makes the decode to Info fail.

{
    "id":"si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-1685943258732976645813",
    "title":"Sĩ tử Hà Nội nô nức đến Văn Miếu cầu may trước kỳ thi vào lớp 10",
    "timestamp":"None",
    "description":"VOV.VN - Kỳ thi tuyển sinh lớp 10 THPT công lập năm nay sẽ được tổ chức trong thời gian 2 ngày từ 10-11/6 gồm 3 môn Toán, Ngữ văn, Ngoại ngữ. Những ngày này, rất đông sĩ tử và phụ huynh tới Văn Miếu - Quốc Tử Giám thắp hương, cầu may mắn.",
    "thumbnail":"https://kenh14cdn.com/203336854389633024/2023/6/5/.si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-1685943258732976645813.mp4.jpg",
    "age_limit":0,
    "uploader":"video.kenh14.vn",
    "http_headers":{
       "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.115 Safari/537.36",
       "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
       "Accept-Language":"en-us,en;q=0.5",
       "Sec-Fetch-Mode":"navigate",
       "Referer":"https://video.kenh14.vn/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn"
    },
    "url":"https://kenh14cdn.com/203336854389633024/2023/6/5/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-1685943258732976645813.mp4",
    "webpage_url":"https://video.kenh14.vn/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn",
    "original_url":"https://video.kenh14.vn/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn",
    "webpage_url_basename":"si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn",
    "webpage_url_domain":"video.kenh14.vn",
    "extractor":"generic",
    "extractor_key":"Generic",
    "playlist":"None",
    "playlist_index":"None",
    "thumbnails":[
       {
          "url":"https://kenh14cdn.com/203336854389633024/2023/6/5/.si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-1685943258732976645813.mp4.jpg",
          "id":"0"
       }
    ],
    "display_id":"si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-1685943258732976645813",
    "fulltitle":"Sĩ tử Hà Nội nô nức đến Văn Miếu cầu may trước kỳ thi vào lớp 10",
    "requested_subtitles":"None",
    "_has_drm":"None",
    "ext":"mp4",
    "protocol":"https",
    "resolution":"None",
    "dynamic_range":"SDR",
    "aspect_ratio":"None",
    "video_ext":"mp4",
    "audio_ext":"none",
    "format_id":"0",
    "format":"0 - unknown"
 }

Screenshot 2023-06-05 at 12 57 48

Here is the ios log:

[generic] Extracting URL: https://video.kenh14.vn/si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053.chn
[generic] si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] si-tu-ha-noi-no-nuc-den-van-mieu-cau-may-truoc-ky-thi-vao-lop-10-326053: Extracting information
YoutubeDL/PythonDecoder.swift:112: Fatal error: Unexpectedly found nil while unwrapping an Optional value
2023-06-05 12:57:37.342825+0400 Y[2360:275756] YoutubeDL/PythonDecoder.swift:112: Fatal error: Unexpectedly found nil while unwrapping an Optional value

If i use the yt-dlp directly from command line on my mac, it does not crash and download the file successfully.

f0enix avatar Jun 05 '23 09:06 f0enix

I'm having this same problem, but the work around doesn't work at all

scriptprojectsdev avatar Feb 15 '24 03:02 scriptprojectsdev

I found a workaround to the issue until it's fixed permanently. It seems that the last commit broke things. You can bypass it by following these steps:

  1. Click on your project name in the file explorer (Project navigator)
  2. Select your project name (above targets)
  3. Click on package dependencies
  4. Find YoutubeDL-iOS and change the dependency rule to commit
  5. Enter this commit 7eaa8312ffc33fe55912b5b6f5a2acdda283086e in the box to the right and press enter
  6. Things should work

scriptprojectsdev avatar Feb 15 '24 05:02 scriptprojectsdev

@scriptprojectsdev @kewlbear Even with that commit (0.0.8) we still have a pretty high percentage of crashes. Does your app run stably? Doesn't it crash? 스크린샷 2024-04-18 오후 2 03 38

dolphinysaru avatar Apr 18 '24 05:04 dolphinysaru

are the code is working fine run debug mood. but when I create a release it is crashing on.

try await yt_dlp(argv: argv) { dict in info = dict["info_dict"]

        let status = String(dict["status"]!)
        
        self.progress.localizedDescription = nil
        
        switch status {
            case "downloading":
                self.progress.kind = .file
                self.progress.fileOperationKind = .downloading
                if #available(iOS 16.0, *) {
                    self.progress.fileURL = URL(filePath: String(dict["tmpfilename"]!)!)
                } else {
                    // Fallback on earlier versions
                }
                self.progress.completedUnitCount = Int64(dict["downloaded_bytes"]!) ?? -1
                self.progress.totalUnitCount = Int64(Double(dict["total_bytes"] ?? dict["total_bytes_estimate"] ?? Python.None) ?? -1)
                self.progress.throughput = Int(dict["speed"]!)
                self.progress.estimatedTimeRemaining = TimeInterval(dict["eta"]!)
            case "finished":
                print(#function, dict["filename"] ?? "no filename")
                files.append(String(dict["filename"]!)!)
                formats.append(info!)
                
                // Reset progress indicators or perform any necessary actions when downloading is complete
                self.progress.kind = nil
                self.progress.completedUnitCount = 0
                self.progress.totalUnitCount = 0
                self.progress.throughput = 0
                self.progress.estimatedTimeRemaining = 0
            default:
                print(#function, dict)
        }
    } log: { level, message in
        print(#function, level, message)
        
        if level == "error" || message.hasSuffix("has already been downloaded") {
            error = message
        }
    } makeTranscodeProgressBlock: {
            self.progress.localizedDescription = NSLocalizedString("Transcoding...", comment: "Progress description")
            self.progress.completedUnitCount = 0
            self.progress.totalUnitCount = 100

            let t0 = ProcessInfo.processInfo.systemUptime

            return { (progress: Double) in
                print(#function, "transcode:", progress)
                let elapsed = ProcessInfo.processInfo.systemUptime - t0
                let speed = progress / elapsed
                let ETA = (1 - progress) / speed

                guard ETA.isFinite else { return }

                self.progress.completedUnitCount = Int64(progress * 100)
                self.progress.estimatedTimeRemaining = ETA
       }
    }
    if let error {
        throw NSError(domain: "App", code: 1, userInfo: [NSLocalizedDescriptionKey: error])
    }
    return (info, files, formats)
}

HamstyDeveloper avatar Apr 19 '24 07:04 HamstyDeveloper

issue is. here in this file func loadPythonModule(downloadPythonModule: Bool = true) async throws -> PythonObject { if Py_IsInitialized() == 0 { PythonSupport.initialize() }

    if !FileManager.default.fileExists(atPath: Self.pythonModuleURL.path) {
        guard downloadPythonModule else {
            throw YoutubeDLError.noPythonModule
        }
        try await Self.downloadPythonModule()
    }
    
    let sys = try Python.attemptImport("sys")
    if !(Array(sys.path) ?? []).contains(Self.pythonModuleURL.path) {
        injectFakePopen(handler: popenHandler)
        
        sys.path.insert(1, Self.pythonModuleURL.path)
    }
    
    let pythonModule = try Python.attemptImport("yt_dlp")
    version = String(pythonModule.version.__version__)
    return pythonModule
}

HamstyDeveloper avatar Apr 19 '24 07:04 HamstyDeveloper

are the code is working fine run debug mood. but when I create a release it is crashing on.

try await yt_dlp(argv: argv) { dict in info = dict["info_dict"]

        let status = String(dict["status"]!)
        
        self.progress.localizedDescription = nil
        
        switch status {
            case "downloading":
                self.progress.kind = .file
                self.progress.fileOperationKind = .downloading
                if #available(iOS 16.0, *) {
                    self.progress.fileURL = URL(filePath: String(dict["tmpfilename"]!)!)
                } else {
                    // Fallback on earlier versions
                }
                self.progress.completedUnitCount = Int64(dict["downloaded_bytes"]!) ?? -1
                self.progress.totalUnitCount = Int64(Double(dict["total_bytes"] ?? dict["total_bytes_estimate"] ?? Python.None) ?? -1)
                self.progress.throughput = Int(dict["speed"]!)
                self.progress.estimatedTimeRemaining = TimeInterval(dict["eta"]!)
            case "finished":
                print(#function, dict["filename"] ?? "no filename")
                files.append(String(dict["filename"]!)!)
                formats.append(info!)
                
                // Reset progress indicators or perform any necessary actions when downloading is complete
                self.progress.kind = nil
                self.progress.completedUnitCount = 0
                self.progress.totalUnitCount = 0
                self.progress.throughput = 0
                self.progress.estimatedTimeRemaining = 0
            default:
                print(#function, dict)
        }
    } log: { level, message in
        print(#function, level, message)
        
        if level == "error" || message.hasSuffix("has already been downloaded") {
            error = message
        }
    } makeTranscodeProgressBlock: {
            self.progress.localizedDescription = NSLocalizedString("Transcoding...", comment: "Progress description")
            self.progress.completedUnitCount = 0
            self.progress.totalUnitCount = 100

            let t0 = ProcessInfo.processInfo.systemUptime

            return { (progress: Double) in
                print(#function, "transcode:", progress)
                let elapsed = ProcessInfo.processInfo.systemUptime - t0
                let speed = progress / elapsed
                let ETA = (1 - progress) / speed

                guard ETA.isFinite else { return }

                self.progress.completedUnitCount = Int64(progress * 100)
                self.progress.estimatedTimeRemaining = ETA
       }
    }
    if let error {
        throw NSError(domain: "App", code: 1, userInfo: [NSLocalizedDescriptionKey: error])
    }
    return (info, files, formats)
}

Did you check #14?

kewlbear avatar Apr 19 '24 08:04 kewlbear

I changed the Strip style to Debugging and additionally changed the Enable Testability value to Yes. Thank you 스크린샷 2024-02-06 오후 2 13 47

Originally posted by @dolphinysaru in https://github.com/kewlbear/YoutubeDL-iOS/issues/14#issuecomment-1928799420

HamstyDeveloper avatar Apr 19 '24 12:04 HamstyDeveloper