Files
run/RunPlus/LocalTrack.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
)
}
}