mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-28 13:00:10 +00:00
feat: accumulate track sizes to present a unified overall progress bar
- Removed track-specific status messages in favor of a simpler generic message. - Passed initial `sizeBytes` estimation into the progress parser. - YTDLPProgressParser now accumulates sizes across multiple sequential downloads (like video then audio). - The progress fraction and displayed size are correctly computed relative to the overall expected size, preventing the progress bar from resetting to 0% mid-download.
This commit is contained in:
@@ -98,7 +98,7 @@ final class MediaDownloadEngine: @unchecked Sendable {
|
||||
process.standardOutput = outputPipe
|
||||
process.standardError = errorPipe
|
||||
|
||||
let parser = YTDLPProgressParser()
|
||||
let parser = YTDLPProgressParser(totalExpectedBytes: item.sizeBytes)
|
||||
let errorBuffer = LockedDataBuffer()
|
||||
let outputPathTracker = YTDLPOutputPathTracker()
|
||||
let completionGate = CompletionGate(completion)
|
||||
@@ -309,14 +309,7 @@ final class YTDLPOutputHandler: @unchecked Sendable {
|
||||
return "YouTube challenge solver unavailable"
|
||||
}
|
||||
if line.contains("Destination:") {
|
||||
trackCount += 1
|
||||
if trackCount == 1 {
|
||||
return "Downloading Video Track"
|
||||
} else if trackCount == 2 {
|
||||
return "Downloading Audio Track"
|
||||
} else {
|
||||
return "Downloading Track \(trackCount)"
|
||||
}
|
||||
return "Downloading Media"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -389,6 +382,62 @@ final class YTDLPProgressParser: @unchecked Sendable {
|
||||
private let etaRegex = try? NSRegularExpression(pattern: #"ETA\s+([^\s]+)"#)
|
||||
private let sizeRegex = try? NSRegularExpression(pattern: #"of\s+~?([0-9.]+[a-zA-Z]+)"#)
|
||||
|
||||
private let totalExpectedBytes: Int64?
|
||||
private var accumulatedBytes: Int64 = 0
|
||||
private var currentFileBytes: Int64 = 0
|
||||
private var lastFraction: Double = 0
|
||||
|
||||
init(totalExpectedBytes: Int64?) {
|
||||
self.totalExpectedBytes = totalExpectedBytes
|
||||
}
|
||||
|
||||
private func processCumulativeProgress(
|
||||
fraction: Double,
|
||||
parsedSize: Int64,
|
||||
sizeStr: String
|
||||
) -> (overallFraction: Double, displaySizeStr: String) {
|
||||
if fraction < lastFraction && lastFraction > 0.95 {
|
||||
accumulatedBytes += currentFileBytes
|
||||
}
|
||||
|
||||
currentFileBytes = parsedSize
|
||||
lastFraction = fraction
|
||||
|
||||
let totalDownloadedBytes = accumulatedBytes + Int64(Double(parsedSize) * fraction)
|
||||
let overallTotalBytes = max(totalExpectedBytes ?? 0, accumulatedBytes + parsedSize)
|
||||
|
||||
var overallFraction = fraction
|
||||
var displaySizeStr = sizeStr
|
||||
|
||||
if overallTotalBytes > 0 {
|
||||
overallFraction = Double(totalDownloadedBytes) / Double(overallTotalBytes)
|
||||
displaySizeStr = ByteFormatter.string(overallTotalBytes)
|
||||
}
|
||||
|
||||
return (overallFraction, displaySizeStr)
|
||||
}
|
||||
|
||||
private func parseBytes(_ sizeStr: String) -> Int64 {
|
||||
let clean = sizeStr.replacingOccurrences(of: "~", with: "").trimmingCharacters(in: .whitespaces)
|
||||
guard let regex = try? NSRegularExpression(pattern: #"^([0-9.]+)([a-zA-Z]+)$"#) else { return 0 }
|
||||
let nsString = clean as NSString
|
||||
guard let match = regex.firstMatch(in: clean, range: NSRange(location: 0, length: clean.count)),
|
||||
match.numberOfRanges == 3 else { return 0 }
|
||||
|
||||
let numStr = nsString.substring(with: match.range(at: 1))
|
||||
let unitStr = nsString.substring(with: match.range(at: 2)).lowercased()
|
||||
|
||||
guard let value = Double(numStr) else { return 0 }
|
||||
|
||||
switch unitStr {
|
||||
case "b": return Int64(value)
|
||||
case "k", "kb", "kib": return Int64(value * 1024)
|
||||
case "m", "mb", "mib": return Int64(value * 1024 * 1024)
|
||||
case "g", "gb", "gib": return Int64(value * 1024 * 1024 * 1024)
|
||||
default: return Int64(value)
|
||||
}
|
||||
}
|
||||
|
||||
func parse(_ line: String) -> DownloadProgress? {
|
||||
if line.contains("[download]") && line.contains("%") {
|
||||
let fraction = (Double(firstCapture(in: line, regex: percentageRegex) ?? "0") ?? 0) / 100.0
|
||||
@@ -396,9 +445,12 @@ final class YTDLPProgressParser: @unchecked Sendable {
|
||||
let eta = firstCapture(in: line, regex: etaRegex) ?? "-"
|
||||
let size = firstCapture(in: line, regex: sizeRegex) ?? "-"
|
||||
|
||||
let parsedSize = parseBytes(size)
|
||||
let cumulative = processCumulativeProgress(fraction: fraction, parsedSize: parsedSize, sizeStr: size)
|
||||
|
||||
return DownloadProgress(
|
||||
fraction: min(max(fraction, 0), 1),
|
||||
bytesText: size,
|
||||
fraction: min(max(cumulative.overallFraction, 0), 1),
|
||||
bytesText: cumulative.displaySizeStr,
|
||||
speedText: speed,
|
||||
etaText: eta,
|
||||
connectionCount: 1
|
||||
@@ -410,9 +462,12 @@ final class YTDLPProgressParser: @unchecked Sendable {
|
||||
let size = firstCapture(in: line, regex: try? NSRegularExpression(pattern: #"/([^\s\(]+)\("#)) ?? "-"
|
||||
let cn = Int(firstCapture(in: line, regex: try? NSRegularExpression(pattern: #"CN:(\d+)"#)) ?? "1") ?? 1
|
||||
|
||||
let parsedSize = parseBytes(size)
|
||||
let cumulative = processCumulativeProgress(fraction: fraction, parsedSize: parsedSize, sizeStr: size)
|
||||
|
||||
return DownloadProgress(
|
||||
fraction: min(max(fraction, 0), 1),
|
||||
bytesText: size,
|
||||
fraction: min(max(cumulative.overallFraction, 0), 1),
|
||||
bytesText: cumulative.displaySizeStr,
|
||||
speedText: speed,
|
||||
etaText: eta,
|
||||
connectionCount: cn
|
||||
|
||||
Reference in New Issue
Block a user