importer chnges
This commit is contained in:
@@ -39,7 +39,35 @@ struct Importer {
|
||||
return siblingCache[directory]?[url.deletingPathExtension().lastPathComponent.lowercased()] ?? [:]
|
||||
}
|
||||
defer { state.total = max(state.total,state.completed);progress(state) }
|
||||
var files = urls
|
||||
// Discover before copying: overlapping selections must not import twice,
|
||||
// and a destination inside the selected tree must not feed itself back in.
|
||||
let keys: Set<URLResourceKey> = [.isDirectoryKey,.isRegularFileKey,.isSymbolicLinkKey,.isPackageKey]
|
||||
let supported = Set(["mp3","wav","m4a","mp4","m4v","mov","cdg","zip"])
|
||||
let managedRoot = media.resolvingSymlinksInPath().standardizedFileURL
|
||||
var visited = Set<URL>(),discovered = Set<URL>()
|
||||
func discover(_ input:URL) throws {
|
||||
if cancelled() { throw CancellationError() }
|
||||
let url = input.standardizedFileURL
|
||||
guard visited.insert(url).inserted else { return }
|
||||
do {
|
||||
let values = try url.resourceValues(forKeys:keys)
|
||||
// Do not follow directory symlinks (cycles or files outside the selection).
|
||||
guard values.isSymbolicLink != true else { return }
|
||||
if values.isDirectory == true {
|
||||
guard values.isPackage != true,url.resolvingSymlinksInPath().standardizedFileURL.path != managedRoot.path else { return }
|
||||
report("Scanning "+url.path)
|
||||
for child in try FileManager.default.contentsOfDirectory(at:url,includingPropertiesForKeys:Array(keys),options:[.skipsHiddenFiles]) {
|
||||
try discover(child)
|
||||
}
|
||||
} else if values.isRegularFile == true,supported.contains(url.pathExtension.lowercased()) {
|
||||
discovered.insert(url)
|
||||
}
|
||||
} catch is CancellationError { throw CancellationError() }
|
||||
catch { throw LibraryError.message("Could not scan \(url.path): \(error.localizedDescription)") }
|
||||
}
|
||||
report("Scanning selected files and folders…",force:true)
|
||||
for url in urls { try discover(url) }
|
||||
var files = discovered.sorted { $0.path < $1.path }
|
||||
var temporary = [URL]()
|
||||
defer { for url in temporary { try? FileManager.default.removeItem(at: url) } }
|
||||
var songIDs = Set<Int64>()
|
||||
@@ -57,7 +85,7 @@ struct Importer {
|
||||
if let archive = archiveForFile[audio.resolvingSymlinksInPath().path] { archiveSongIDs[archive,default:[]].append(id) }
|
||||
else { try library.rememberImport(path:audio.standardizedFileURL.path,signature:signature,songs:[id]) }
|
||||
}
|
||||
for zip in urls where zip.pathExtension.lowercased() == "zip" {
|
||||
for zip in files where zip.pathExtension.lowercased() == "zip" {
|
||||
if cancelled() { throw CancellationError() }
|
||||
let signature = try importSignature(zip)
|
||||
if let existing = try library.importedSongs(path:zip.standardizedFileURL.path,signature:signature) {
|
||||
@@ -125,7 +153,7 @@ struct Importer {
|
||||
if let audio = ["mp3","wav","m4a","mp4","m4v","mov"].compactMap({ matching[$0] }).first { files.append(audio) }
|
||||
}
|
||||
var imported = 0
|
||||
let audioFiles = Set(files).filter { ["mp3","wav","m4a","mp4","m4v","mov"].contains($0.pathExtension.lowercased()) }.sorted { $0.path < $1.path }
|
||||
let audioFiles = Set(files.map { $0.standardizedFileURL }).filter { ["mp3","wav","m4a","mp4","m4v","mov"].contains($0.pathExtension.lowercased()) }.sorted { $0.path < $1.path }
|
||||
state.total = audioFiles.count+state.completed
|
||||
report("Importing tracks…",force:true)
|
||||
for audio in audioFiles {
|
||||
|
||||
@@ -769,7 +769,7 @@ struct LibraryView: View {
|
||||
updateLibraryRows()
|
||||
if source == "Singer Songs",presentedSinger != singer { showSinger(singer,section:nil) }
|
||||
}
|
||||
.fileImporter(isPresented: $importing, allowedContentTypes: [.audio, .movie, .zip, UTType(filenameExtension: "cdg") ?? .data], allowsMultipleSelection: true) { result in
|
||||
.fileImporter(isPresented: $importing, allowedContentTypes: [.folder, .audio, .movie, .zip, UTType(filenameExtension: "cdg") ?? .data], allowsMultipleSelection: true) { result in
|
||||
switch result {
|
||||
case .success(let urls): model.importFiles(urls)
|
||||
case .failure(let error): model.error = error.localizedDescription
|
||||
@@ -1425,7 +1425,7 @@ private struct SingerSongsSheet: View {
|
||||
}.padding(24).frame(width:520).background(StudioTheme.frame)
|
||||
.disabled(model.importProgress != nil || model.storageProgress != nil)
|
||||
.overlay { if model.storageProgress != nil { ImportProgressDialog(model:model,storageMode:true) } else if model.importProgress != nil { ImportProgressDialog(model:model) } }
|
||||
.fileImporter(isPresented:$importing,allowedContentTypes:[.audio,.movie,.zip,UTType(filenameExtension:"cdg") ?? .data],allowsMultipleSelection:true) { result in
|
||||
.fileImporter(isPresented:$importing,allowedContentTypes:[.folder,.audio,.movie,.zip,UTType(filenameExtension:"cdg") ?? .data],allowsMultipleSelection:true) { result in
|
||||
switch result { case .success(let urls):model.importFiles(urls);case .failure(let error):model.error = error.localizedDescription }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user