removed unwanted bar now with waveforms, major updates and enhancements

This commit is contained in:
Mark Gregory
2026-11-06 15:21:41 +00:00
parent c39c2bd757
commit bb136ee202
15 changed files with 239 additions and 437 deletions
+30 -2
View File
@@ -246,8 +246,8 @@ struct Importer {
graphics = target.path
}
imported += 1
let metadata = AVURLAsset(url:audio).commonMetadata
func tag(_ key: AVMetadataKey) -> String { metadata.first { $0.commonKey == key }?.stringValue ?? "" }
let metadata = try audioMetadata(audio,cancelled:cancelled)
func tag(_ key: AVMetadataKey) -> String { metadata[key] ?? "" }
let taggedTitle = tag(.commonKeyTitle)
let id = try library.add(title:taggedTitle.isEmpty ? audio.deletingPathExtension().lastPathComponent : taggedTitle,audio:dest.path,cdg:graphics,artist:tag(.commonKeyArtist),album:tag(.commonKeyAlbumName),label:tag(.commonKeyPublisher),duration:audioDuration(audio),fingerprint:hash,preferIncomingFile:copy)
songIDs.insert(id)
@@ -280,6 +280,27 @@ struct Importer {
while let data = try file.read(upToCount:1_048_576),!data.isEmpty { if cancelled() { throw CancellationError() };hasher.update(data:data) }
return hasher.finalize().map { String(format:"%02x",$0) }.joined()
}
/// The importer runs on its worker queue. Bridge asynchronous tag loading here
/// so the existing synchronous transaction can retain its cancellation semantics.
private func audioMetadata(_ url: URL,cancelled: () -> Bool) throws -> [AVMetadataKey:String] {
let result = ImportMetadataResult(),ready = DispatchSemaphore(value:0)
let task = Task.detached(priority:.utility) {
var tags = [AVMetadataKey:String]()
let items = (try? await AVURLAsset(url:url).load(.commonMetadata)) ?? []
for item in items {
if Task.isCancelled { break }
guard let key = item.commonKey,[AVMetadataKey.commonKeyTitle,.commonKeyArtist,.commonKeyAlbumName,.commonKeyPublisher].contains(key),tags[key] == nil else { continue }
if let value = try? await item.load(.stringValue) { tags[key] = value }
}
result.set(tags);ready.signal()
}
defer { task.cancel() }
while ready.wait(timeout:.now()+0.05) == .timedOut {
if cancelled() { throw CancellationError() }
}
if cancelled() { throw CancellationError() }
return result.get()
}
private func audioDuration(_ url: URL) -> Double {
guard let file = try? AVAudioFile(forReading:url) else { return 0 }
return Double(file.length)/file.processingFormat.sampleRate
@@ -669,3 +690,10 @@ enum DJLibraryMaintenance {
} catch { try? db.execute("ROLLBACK");throw error }
}
}
private final class ImportMetadataResult: @unchecked Sendable {
private let lock = NSLock()
private var tags = [AVMetadataKey:String]()
func set(_ value: [AVMetadataKey:String]) { lock.lock();tags = value;lock.unlock() }
func get() -> [AVMetadataKey:String] { lock.lock();defer { lock.unlock() };return tags }
}