iOS: export/import stem playlists and sound settings
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9646b4c010
commit
4e2816673d
3 files changed
+144
No files matched your search
@@ -0,0 +1,84 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
/// What an export file holds: stem playlists (with each song's mix) and the non-secret sound settings.
|
||||
/// Plex and stem server tokens and URLs are never included.
|
||||
struct StemifyExport: Codable {
|
||||
static let format = "stemify-export"
|
||||
static let version = 1
|
||||
|
||||
struct Prefs: Codable {
|
||||
var stemQuality: String?
|
||||
var keepStemMix: Bool?
|
||||
var karaokeVocals: Int?
|
||||
var karaokeSoftDb: Int?
|
||||
var playbackSpeed: Double?
|
||||
var downloadsWifiOnly: Bool?
|
||||
}
|
||||
|
||||
var format = StemifyExport.format
|
||||
var version = StemifyExport.version
|
||||
var exported = Date()
|
||||
var playlists: [StemPlaylist]
|
||||
var prefs: Prefs
|
||||
|
||||
@MainActor
|
||||
static func capture(_ lists: StemPlaylists, _ s: Settings) -> StemifyExport {
|
||||
StemifyExport(playlists: lists.lists, prefs: Prefs(
|
||||
stemQuality: s.stemQuality.rawValue, keepStemMix: s.keepStemMix, karaokeVocals: s.karaokeVocals,
|
||||
karaokeSoftDb: s.karaokeSoftDb, playbackSpeed: s.playbackSpeed, downloadsWifiOnly: s.downloadsWifiOnly))
|
||||
}
|
||||
|
||||
func encoded() throws -> Data {
|
||||
let e = JSONEncoder()
|
||||
e.outputFormatting = [.prettyPrinted, .sortedKeys]
|
||||
e.dateEncodingStrategy = .iso8601
|
||||
return try e.encode(self)
|
||||
}
|
||||
|
||||
static func decode(_ data: Data) throws -> StemifyExport {
|
||||
let d = JSONDecoder()
|
||||
d.dateDecodingStrategy = .iso8601
|
||||
let x = try d.decode(StemifyExport.self, from: data)
|
||||
guard x.format == Self.format else { throw BackupError.notAnExport }
|
||||
guard x.version <= Self.version else { throw BackupError.newerVersion }
|
||||
return x
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func apply(to s: Settings) {
|
||||
if let v = prefs.stemQuality.flatMap(StemQuality.init(rawValue:)) { s.stemQuality = v }
|
||||
if let v = prefs.keepStemMix { s.keepStemMix = v }
|
||||
if let v = prefs.karaokeVocals { s.karaokeVocals = v }
|
||||
if let v = prefs.karaokeSoftDb { s.karaokeSoftDb = v }
|
||||
if let v = prefs.playbackSpeed { s.playbackSpeed = v }
|
||||
if let v = prefs.downloadsWifiOnly { s.downloadsWifiOnly = v }
|
||||
}
|
||||
}
|
||||
|
||||
enum BackupError: LocalizedError {
|
||||
case notAnExport, newerVersion
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .notAnExport: "That file isn't a Stemify export."
|
||||
case .newerVersion: "That export is from a newer version of Stemify."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Where an export goes and comes from. The Files sheet covers local storage and iCloud Drive;
|
||||
/// a direct iCloud (ubiquity container / CloudKit) backend would be another conformer.
|
||||
protocol BackupDestination {
|
||||
func write(_ data: Data, name: String) async throws
|
||||
func read() async throws -> Data
|
||||
}
|
||||
|
||||
/// The export as a document for fileExporter, which also reaches iCloud Drive through Files.
|
||||
struct ExportDocument: FileDocument {
|
||||
static var readableContentTypes: [UTType] { [.json] }
|
||||
var data: Data
|
||||
init(data: Data = Data()) { self.data = data }
|
||||
init(configuration: ReadConfiguration) throws { data = configuration.file.regularFileContents ?? Data() }
|
||||
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { FileWrapper(regularFileWithContents: data) }
|
||||
}
|
||||
Reference in new issue
Block a user