removed unwanted bar now with waveforms, major updates and enhancements
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user