71 lines
2.7 KiB
Swift
71 lines
2.7 KiB
Swift
import Foundation
|
|
import AVFoundation
|
|
|
|
struct LocalTrack: Identifiable, Hashable {
|
|
let id: UUID
|
|
let url: URL
|
|
let displayName: String
|
|
let duration: TimeInterval
|
|
|
|
static func libraryDirectory() -> URL {
|
|
let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
|
|
let dir = docs.appendingPathComponent("RunPlus", isDirectory: true)
|
|
if !FileManager.default.fileExists(atPath: dir.path) {
|
|
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
|
}
|
|
return dir
|
|
}
|
|
|
|
static func loadLibrary() async -> [LocalTrack] {
|
|
let dir = libraryDirectory()
|
|
let urls = (try? FileManager.default.contentsOfDirectory(at: dir, includingPropertiesForKeys: nil)) ?? []
|
|
var tracks: [LocalTrack] = []
|
|
for url in urls {
|
|
let asset = AVURLAsset(url: url)
|
|
let duration = (try? await asset.load(.duration).seconds) ?? 0
|
|
let track = LocalTrack(
|
|
id: UUID(uuidString: url.deletingPathExtension().lastPathComponent) ?? UUID(),
|
|
url: url,
|
|
displayName: url.deletingPathExtension().lastPathComponent,
|
|
duration: duration
|
|
)
|
|
tracks.append(track)
|
|
}
|
|
return tracks.sorted { $0.displayName.lowercased() < $1.displayName.lowercased() }
|
|
}
|
|
|
|
static func importTrack(from url: URL) async throws -> LocalTrack {
|
|
let dir = libraryDirectory()
|
|
let id = UUID()
|
|
let dest = dir.appendingPathComponent("\(id.uuidString).mp3")
|
|
let didStart = url.startAccessingSecurityScopedResource()
|
|
defer {
|
|
if didStart { url.stopAccessingSecurityScopedResource() }
|
|
}
|
|
try FileManager.default.copyItem(at: url, to: dest)
|
|
let duration = (try? await AVURLAsset(url: dest).load(.duration).seconds) ?? 0
|
|
return LocalTrack(
|
|
id: id,
|
|
url: dest,
|
|
displayName: url.deletingPathExtension().lastPathComponent,
|
|
duration: duration
|
|
)
|
|
}
|
|
|
|
static func importReceivedTrack(from url: URL, trackID: String, displayName: String) async throws -> LocalTrack {
|
|
let dir = libraryDirectory()
|
|
let dest = dir.appendingPathComponent("\(trackID).mp3")
|
|
if FileManager.default.fileExists(atPath: dest.path) {
|
|
try FileManager.default.removeItem(at: dest)
|
|
}
|
|
try FileManager.default.moveItem(at: url, to: dest)
|
|
let duration = (try? await AVURLAsset(url: dest).load(.duration).seconds) ?? 0
|
|
return LocalTrack(
|
|
id: UUID(uuidString: trackID) ?? UUID(),
|
|
url: dest,
|
|
displayName: displayName,
|
|
duration: duration
|
|
)
|
|
}
|
|
}
|