@opendaw/studio-core 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AudioOfflineRenderer.d.ts +1 -2
- package/dist/AudioOfflineRenderer.d.ts.map +1 -1
- package/dist/AudioOfflineRenderer.js +10 -3
- package/dist/EffectBox.d.ts +2 -2
- package/dist/EffectBox.d.ts.map +1 -1
- package/dist/EffectFactories.d.ts +9 -0
- package/dist/EffectFactories.d.ts.map +1 -1
- package/dist/EffectFactories.js +41 -24
- package/dist/EffectFactory.d.ts +1 -1
- package/dist/EffectFactory.d.ts.map +1 -1
- package/dist/EffectParameterDefaults.d.ts +5 -0
- package/dist/EffectParameterDefaults.d.ts.map +1 -0
- package/dist/EffectParameterDefaults.js +27 -0
- package/dist/Engine.d.ts +1 -1
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +1 -1
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +1 -1
- package/dist/EngineWorklet.d.ts +1 -1
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +3 -2
- package/dist/Preferences.d.ts +20 -0
- package/dist/Preferences.d.ts.map +1 -0
- package/dist/Preferences.js +46 -0
- package/dist/capture/CaptureDevices.d.ts +1 -1
- package/dist/capture/CaptureDevices.d.ts.map +1 -1
- package/dist/capture/CaptureDevices.js +22 -11
- package/dist/capture/CaptureMidi.js +1 -1
- package/dist/capture/RecordTrack.d.ts +2 -2
- package/dist/capture/RecordTrack.d.ts.map +1 -1
- package/dist/capture/Recording.d.ts +1 -1
- package/dist/capture/Recording.d.ts.map +1 -1
- package/dist/capture/Recording.js +1 -1
- package/dist/dawproject/BuiltinDevices.d.ts.map +1 -1
- package/dist/dawproject/BuiltinDevices.js +3 -2
- package/dist/dawproject/{DawProjectImport.d.ts → DawProjectImporter.d.ts} +1 -1
- package/dist/dawproject/DawProjectImporter.d.ts.map +1 -0
- package/dist/dawproject/{DawProjectImport.js → DawProjectImporter.js} +17 -5
- package/dist/dawproject/DawProjectImporter.test.d.ts +2 -0
- package/dist/dawproject/DawProjectImporter.test.d.ts.map +1 -0
- package/dist/dawproject/{DawProjectImport.test.js → DawProjectImporter.test.js} +1 -1
- package/dist/dawproject/DawProjectService.js +1 -1
- package/dist/dawproject/index.d.ts +1 -1
- package/dist/dawproject/index.d.ts.map +1 -1
- package/dist/dawproject/index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/midi/MIDILearning.d.ts +1 -1
- package/dist/midi/MIDILearning.d.ts.map +1 -1
- package/dist/midi/MIDILearning.js +22 -3
- package/dist/processors.js +7 -7
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts +12 -7
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +60 -33
- package/dist/project/ProjectMigration.d.ts.map +1 -1
- package/dist/project/ProjectMigration.js +10 -1
- package/dist/project/Recovery.d.ts +9 -0
- package/dist/project/Recovery.d.ts.map +1 -0
- package/dist/project/Recovery.js +49 -0
- package/dist/project/index.d.ts +1 -0
- package/dist/project/index.d.ts.map +1 -1
- package/dist/project/index.js +1 -0
- package/dist/workers-main.js +2 -2
- package/dist/workers-main.js.map +4 -4
- package/dist/ysync/YService.d.ts.map +1 -1
- package/dist/ysync/YService.js +19 -8
- package/dist/ysync/YSync.d.ts +4 -4
- package/dist/ysync/YSync.d.ts.map +1 -1
- package/dist/ysync/YSync.js +29 -26
- package/package.json +49 -49
- package/dist/dawproject/DawProjectImport.d.ts.map +0 -1
- package/dist/dawproject/DawProjectImport.test.d.ts +0 -2
- package/dist/dawproject/DawProjectImport.test.d.ts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Procedure, Terminable, TerminableOwner, Terminator } from "@opendaw/lib-std";
|
|
2
|
-
import {
|
|
1
|
+
import { Func, Procedure, Terminable, TerminableOwner, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
3
|
import { AudioBusBox, AudioUnitBox, BoxIO, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { BoxAdapters, BoxAdaptersContext, ClipSequencing, ParameterFieldAdapters, ProcessorOptions, ProjectSkeleton, RootBoxAdapter, SampleLoaderManager, SoundfontLoaderManager, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamBroadcaster, LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
@@ -11,23 +11,26 @@ import { EngineFacade } from "../EngineFacade";
|
|
|
11
11
|
import { EngineWorklet } from "../EngineWorklet";
|
|
12
12
|
import { MIDILearning } from "../midi";
|
|
13
13
|
export type RestartWorklet = {
|
|
14
|
-
unload:
|
|
14
|
+
unload: Func<unknown, Promise<unknown>>;
|
|
15
15
|
load: Procedure<EngineWorklet>;
|
|
16
16
|
};
|
|
17
|
+
export type ProjectCreateOptions = {
|
|
18
|
+
noDefaultUser?: boolean;
|
|
19
|
+
};
|
|
17
20
|
export declare class Project implements BoxAdaptersContext, Terminable, TerminableOwner {
|
|
18
21
|
#private;
|
|
19
|
-
static new(env: ProjectEnv): Project;
|
|
22
|
+
static new(env: ProjectEnv, options?: ProjectCreateOptions): Project;
|
|
20
23
|
static load(env: ProjectEnv, arrayBuffer: ArrayBuffer): Project;
|
|
21
|
-
static skeleton(env: ProjectEnv, skeleton: ProjectSkeleton): Project;
|
|
24
|
+
static skeleton(env: ProjectEnv, skeleton: ProjectSkeleton, followFirstUser?: boolean): Project;
|
|
22
25
|
readonly boxGraph: BoxGraph<BoxIO.TypeMap>;
|
|
23
26
|
readonly rootBox: RootBox;
|
|
24
|
-
readonly
|
|
27
|
+
readonly userInterfaceBoxes: ReadonlyArray<UserInterfaceBox>;
|
|
25
28
|
readonly masterBusBox: AudioBusBox;
|
|
26
29
|
readonly masterAudioUnit: AudioUnitBox;
|
|
27
30
|
readonly timelineBox: TimelineBox;
|
|
28
31
|
readonly api: ProjectApi;
|
|
29
32
|
readonly captureDevices: CaptureDevices;
|
|
30
|
-
readonly editing:
|
|
33
|
+
readonly editing: BoxEditing;
|
|
31
34
|
readonly selection: VertexSelection;
|
|
32
35
|
readonly boxAdapters: BoxAdapters;
|
|
33
36
|
readonly userEditingManager: UserEditingManager;
|
|
@@ -39,6 +42,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
39
42
|
private constructor();
|
|
40
43
|
startAudioWorklet(restart?: RestartWorklet, options?: ProcessorOptions): EngineWorklet;
|
|
41
44
|
startRecording(countIn?: boolean): void;
|
|
45
|
+
follow(box: UserInterfaceBox): void;
|
|
42
46
|
own<T extends Terminable>(terminable: T): T;
|
|
43
47
|
ownAll<T extends Terminable>(...terminables: Array<T>): void;
|
|
44
48
|
spawn(): Terminator;
|
|
@@ -53,6 +57,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
53
57
|
get isMainThread(): boolean;
|
|
54
58
|
get liveStreamBroadcaster(): LiveStreamBroadcaster;
|
|
55
59
|
get skeleton(): ProjectSkeleton;
|
|
60
|
+
collectSampleUUIDs(): ReadonlyArray<UUID.Bytes>;
|
|
56
61
|
toArrayBuffer(): ArrayBufferLike;
|
|
57
62
|
copy(env?: Partial<ProjectEnv>): Project;
|
|
58
63
|
invalid(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
|
package/dist/project/Project.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Arrays, ByteArrayOutput, Option, panic, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
|
-
import {
|
|
3
|
-
import { AudioBusBox, AudioUnitBox, BoxIO, GrooveShuffleBox, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
2
|
+
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
|
+
import { AudioBusBox, AudioUnitBox, BoxIO, CompressorDeviceBox, GrooveShuffleBox, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { BoxAdapters, IconSymbol, ParameterFieldAdapters, ProjectDecoder, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
6
6
|
import { AudioUnitType } from "@opendaw/studio-enums";
|
|
@@ -11,9 +11,10 @@ import { CaptureDevices, Recording } from "../capture";
|
|
|
11
11
|
import { EngineFacade } from "../EngineFacade";
|
|
12
12
|
import { MIDILearning } from "../midi";
|
|
13
13
|
import { ProjectValidation } from "./ProjectValidation";
|
|
14
|
+
import { Preferences } from "../Preferences";
|
|
14
15
|
// Main Entry Point for a Project
|
|
15
16
|
export class Project {
|
|
16
|
-
static new(env) {
|
|
17
|
+
static new(env, options) {
|
|
17
18
|
const boxGraph = new BoxGraph(Option.wrap(BoxIO.create));
|
|
18
19
|
const isoString = new Date().toISOString();
|
|
19
20
|
console.debug(`New Project created on ${isoString}`);
|
|
@@ -25,45 +26,67 @@ export class Project {
|
|
|
25
26
|
box.groove.refer(grooveShuffleBox);
|
|
26
27
|
box.created.setValue(isoString);
|
|
27
28
|
});
|
|
28
|
-
const
|
|
29
|
-
const masterBusBox = AudioBusBox.create(boxGraph, UUID.generate(), box => {
|
|
29
|
+
const primaryAudioBus = AudioBusBox.create(boxGraph, UUID.generate(), box => {
|
|
30
30
|
box.collection.refer(rootBox.audioBusses);
|
|
31
31
|
box.label.setValue("Output");
|
|
32
32
|
box.icon.setValue(IconSymbol.toName(IconSymbol.SpeakerHeadphone));
|
|
33
33
|
box.color.setValue(/*Colors.blue*/ "hsl(189, 100%, 65%)"); // TODO
|
|
34
34
|
});
|
|
35
|
-
const
|
|
35
|
+
const primaryAudioOutputUnit = AudioUnitBox.create(boxGraph, UUID.generate(), box => {
|
|
36
36
|
box.type.setValue(AudioUnitType.Output);
|
|
37
37
|
box.collection.refer(rootBox.audioUnits);
|
|
38
38
|
box.output.refer(rootBox.outputDevice);
|
|
39
39
|
box.index.setValue(0);
|
|
40
40
|
});
|
|
41
|
+
if (Preferences.values["auto-create-output-compressor"]) {
|
|
42
|
+
CompressorDeviceBox.create(boxGraph, UUID.generate(), box => {
|
|
43
|
+
box.label.setValue("Compressor");
|
|
44
|
+
box.index.setValue(0);
|
|
45
|
+
box.host.refer(primaryAudioOutputUnit.audioEffects);
|
|
46
|
+
box.threshold.setValue(0);
|
|
47
|
+
box.ratio.setValue(24);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
41
50
|
const timelineBox = TimelineBox.create(boxGraph, UUID.generate());
|
|
42
51
|
rootBox.timeline.refer(timelineBox.root);
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
primaryAudioBus.output.refer(primaryAudioOutputUnit.input);
|
|
53
|
+
const userInterfaceBoxes = [];
|
|
54
|
+
const createDefaultUser = options?.noDefaultUser !== true;
|
|
55
|
+
if (createDefaultUser) {
|
|
56
|
+
const userInterfaceBox = UserInterfaceBox.create(boxGraph, UUID.generate());
|
|
57
|
+
userInterfaceBox.root.refer(rootBox.users);
|
|
58
|
+
userInterfaceBoxes.push(userInterfaceBox);
|
|
59
|
+
}
|
|
45
60
|
boxGraph.endTransaction();
|
|
46
|
-
|
|
61
|
+
const project = new Project(env, boxGraph, {
|
|
47
62
|
rootBox,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
primaryAudioBus,
|
|
64
|
+
primaryAudioOutputUnit,
|
|
65
|
+
userInterfaceBoxes,
|
|
51
66
|
timelineBox
|
|
52
67
|
});
|
|
68
|
+
if (createDefaultUser) {
|
|
69
|
+
project.follow(userInterfaceBoxes[0]);
|
|
70
|
+
}
|
|
71
|
+
return project;
|
|
53
72
|
}
|
|
54
73
|
static load(env, arrayBuffer) {
|
|
55
74
|
return this.skeleton(env, ProjectDecoder.decode(arrayBuffer));
|
|
56
75
|
}
|
|
57
|
-
static skeleton(env, skeleton) {
|
|
76
|
+
static skeleton(env, skeleton, followFirstUser = true) {
|
|
58
77
|
ProjectMigration.migrate(skeleton);
|
|
59
78
|
ProjectValidation.validate(skeleton);
|
|
60
|
-
|
|
79
|
+
const project = new Project(env, skeleton.boxGraph, skeleton.mandatoryBoxes);
|
|
80
|
+
if (followFirstUser) {
|
|
81
|
+
project.follow(project.userInterfaceBoxes[0]);
|
|
82
|
+
}
|
|
83
|
+
return project;
|
|
61
84
|
}
|
|
62
85
|
#terminator = new Terminator();
|
|
63
86
|
#env;
|
|
64
87
|
boxGraph;
|
|
65
88
|
rootBox;
|
|
66
|
-
|
|
89
|
+
userInterfaceBoxes;
|
|
67
90
|
masterBusBox;
|
|
68
91
|
masterAudioUnit;
|
|
69
92
|
timelineBox;
|
|
@@ -78,26 +101,28 @@ export class Project {
|
|
|
78
101
|
midiLearning;
|
|
79
102
|
mixer;
|
|
80
103
|
engine = new EngineFacade();
|
|
81
|
-
constructor(env, boxGraph, { rootBox,
|
|
104
|
+
constructor(env, boxGraph, { rootBox, userInterfaceBoxes, primaryAudioBus, primaryAudioOutputUnit, timelineBox }) {
|
|
82
105
|
this.#env = env;
|
|
83
106
|
this.boxGraph = boxGraph;
|
|
84
107
|
this.rootBox = rootBox;
|
|
85
|
-
this.
|
|
86
|
-
this.masterBusBox =
|
|
87
|
-
this.masterAudioUnit =
|
|
108
|
+
this.userInterfaceBoxes = userInterfaceBoxes;
|
|
109
|
+
this.masterBusBox = primaryAudioBus;
|
|
110
|
+
this.masterAudioUnit = primaryAudioOutputUnit;
|
|
88
111
|
this.timelineBox = timelineBox;
|
|
89
112
|
this.api = new ProjectApi(this);
|
|
90
|
-
this.editing = new
|
|
113
|
+
this.editing = new BoxEditing(this.boxGraph);
|
|
91
114
|
this.selection = new VertexSelection(this.editing, this.boxGraph);
|
|
92
115
|
this.parameterFieldAdapters = new ParameterFieldAdapters();
|
|
93
116
|
this.boxAdapters = this.#terminator.own(new BoxAdapters(this));
|
|
94
117
|
this.userEditingManager = new UserEditingManager(this.editing);
|
|
95
|
-
this.userEditingManager.follow(this.userInterfaceBox);
|
|
96
|
-
this.selection.switch(this.userInterfaceBox.selection);
|
|
97
118
|
this.liveStreamReceiver = this.#terminator.own(new LiveStreamReceiver());
|
|
98
119
|
this.midiLearning = this.#terminator.own(new MIDILearning(this));
|
|
99
120
|
this.captureDevices = this.#terminator.own(new CaptureDevices(this));
|
|
100
121
|
this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
|
|
122
|
+
// TODO We are probably doing that from the outside
|
|
123
|
+
if (this.userInterfaceBoxes.length === 1) {
|
|
124
|
+
this.follow(this.userInterfaceBoxes[0]);
|
|
125
|
+
}
|
|
101
126
|
console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
|
|
102
127
|
}
|
|
103
128
|
startAudioWorklet(restart, options) {
|
|
@@ -109,8 +134,8 @@ export class Project {
|
|
|
109
134
|
// we will only accept the first error
|
|
110
135
|
engine.removeEventListener("error", handler);
|
|
111
136
|
engine.removeEventListener("processorerror", handler);
|
|
112
|
-
safeExecute(restart?.unload, event);
|
|
113
137
|
lifecycle.terminate();
|
|
138
|
+
await safeExecute(restart?.unload, event);
|
|
114
139
|
safeExecute(restart?.load, this.startAudioWorklet(restart));
|
|
115
140
|
};
|
|
116
141
|
engine.addEventListener("error", handler);
|
|
@@ -126,6 +151,10 @@ export class Project {
|
|
|
126
151
|
}
|
|
127
152
|
Recording.start(this, countIn).finally();
|
|
128
153
|
}
|
|
154
|
+
follow(box) {
|
|
155
|
+
this.userEditingManager.follow(box);
|
|
156
|
+
this.selection.switch(box.selection);
|
|
157
|
+
}
|
|
129
158
|
own(terminable) { return this.#terminator.own(terminable); }
|
|
130
159
|
ownAll(...terminables) { return this.#terminator.ownAll(...terminables); }
|
|
131
160
|
spawn() { return this.#terminator.spawn(); }
|
|
@@ -145,26 +174,24 @@ export class Project {
|
|
|
145
174
|
mandatoryBoxes: {
|
|
146
175
|
rootBox: this.rootBox,
|
|
147
176
|
timelineBox: this.timelineBox,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
primaryAudioBus: this.masterBusBox,
|
|
178
|
+
primaryAudioOutputUnit: this.masterAudioUnit,
|
|
179
|
+
userInterfaceBoxes: this.userInterfaceBoxes
|
|
151
180
|
}
|
|
152
181
|
};
|
|
153
182
|
}
|
|
183
|
+
collectSampleUUIDs() {
|
|
184
|
+
return this.boxGraph.boxes()
|
|
185
|
+
.filter(box => box.accept({ visitAudioFileBox: (_box) => true }))
|
|
186
|
+
.map(box => box.address.uuid);
|
|
187
|
+
}
|
|
154
188
|
toArrayBuffer() {
|
|
155
189
|
const output = ByteArrayOutput.create();
|
|
156
190
|
output.writeInt(ProjectDecoder.MAGIC_HEADER_OPEN);
|
|
157
191
|
output.writeInt(ProjectDecoder.FORMAT_VERSION);
|
|
158
|
-
// store all boxes
|
|
159
192
|
const boxGraphChunk = this.boxGraph.toArrayBuffer();
|
|
160
193
|
output.writeInt(boxGraphChunk.byteLength);
|
|
161
194
|
output.writeBytes(new Int8Array(boxGraphChunk));
|
|
162
|
-
// store mandatory boxes' addresses
|
|
163
|
-
UUID.toDataOutput(output, this.rootBox.address.uuid);
|
|
164
|
-
UUID.toDataOutput(output, this.userInterfaceBox.address.uuid);
|
|
165
|
-
UUID.toDataOutput(output, this.masterBusBox.address.uuid);
|
|
166
|
-
UUID.toDataOutput(output, this.masterAudioUnit.address.uuid);
|
|
167
|
-
UUID.toDataOutput(output, this.timelineBox.address.uuid);
|
|
168
195
|
return output.toArrayBuffer();
|
|
169
196
|
}
|
|
170
197
|
copy(env) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ProjectMigration.d.ts","sourceRoot":"","sources":["../../src/project/ProjectMigration.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,eAAe,EAAC,MAAM,0BAA0B,CAAA;AAExD,qBAAa,gBAAgB;IACzB,MAAM,CAAC,OAAO,CAAC,EAAC,QAAQ,EAAE,cAAc,EAAC,EAAE,eAAe,GAAG,IAAI;CA4EpE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, ValueEventCurveBox } from "@opendaw/studio-boxes";
|
|
2
|
-
import { asDefined, asInstanceOf, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { asDefined, asInstanceOf, clamp, UUID } from "@opendaw/lib-std";
|
|
3
3
|
import { AudioUnitType } from "@opendaw/studio-enums";
|
|
4
4
|
export class ProjectMigration {
|
|
5
5
|
static migrate({ boxGraph, mandatoryBoxes }) {
|
|
@@ -70,6 +70,15 @@ export class ProjectMigration {
|
|
|
70
70
|
}));
|
|
71
71
|
box.capture.refer(captureBox);
|
|
72
72
|
boxGraph.endTransaction();
|
|
73
|
+
},
|
|
74
|
+
visitRevampDeviceBox: (box) => {
|
|
75
|
+
// Clamp order in RevampDeviceBox to 0-3
|
|
76
|
+
// The older version stored the actual order,
|
|
77
|
+
// but the new version only stores indices, so 4 is not valid anymore
|
|
78
|
+
boxGraph.beginTransaction();
|
|
79
|
+
box.lowPass.order.setValue(clamp(box.lowPass.order.getValue(), 0, 3));
|
|
80
|
+
box.highPass.order.setValue(clamp(box.highPass.order.getValue(), 0, 3));
|
|
81
|
+
boxGraph.endTransaction();
|
|
73
82
|
}
|
|
74
83
|
}));
|
|
75
84
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Option, Provider } from "@opendaw/lib-std";
|
|
2
|
+
import { ProjectEnv, ProjectProfile } from "../";
|
|
3
|
+
export declare class Recovery {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(projectProfileService: Provider<Option<ProjectProfile>>, env: ProjectEnv);
|
|
6
|
+
restoreProfile(): Promise<Option<ProjectProfile>>;
|
|
7
|
+
createBackupCommand(): Option<Provider<Promise<void>>>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=Recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Recovery.d.ts","sourceRoot":"","sources":["../../src/project/Recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAO,MAAM,kBAAkB,CAAA;AAEvD,OAAO,EAAU,UAAU,EAAe,cAAc,EAAU,MAAM,KAAK,CAAA;AAE7E,qBAAa,QAAQ;;gBAML,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU;IAK9E,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAsBvD,mBAAmB,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CAgBzD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Option, UUID } from "@opendaw/lib-std";
|
|
2
|
+
import { Promises } from "@opendaw/lib-runtime";
|
|
3
|
+
import { Project, ProjectProfile, Workers } from "../";
|
|
4
|
+
export class Recovery {
|
|
5
|
+
static #RESTORE_FILE_PATH = ".backup";
|
|
6
|
+
#projectProfileProvider;
|
|
7
|
+
#env;
|
|
8
|
+
constructor(projectProfileService, env) {
|
|
9
|
+
this.#projectProfileProvider = projectProfileService;
|
|
10
|
+
this.#env = env;
|
|
11
|
+
}
|
|
12
|
+
async restoreProfile() {
|
|
13
|
+
const backupResult = await Promises.tryCatch(Workers.Opfs.list(Recovery.#RESTORE_FILE_PATH));
|
|
14
|
+
if (backupResult.status === "rejected" || backupResult.value.length === 0) {
|
|
15
|
+
return Option.None;
|
|
16
|
+
}
|
|
17
|
+
const readResult = await Promises.tryCatch(Promise.all([
|
|
18
|
+
Workers.Opfs.read(`${Recovery.#RESTORE_FILE_PATH}/uuid`)
|
|
19
|
+
.then(x => UUID.validateBytes(x)),
|
|
20
|
+
Workers.Opfs.read(`${Recovery.#RESTORE_FILE_PATH}/project.od`)
|
|
21
|
+
.then(x => Project.load(this.#env, x.buffer)),
|
|
22
|
+
Workers.Opfs.read(`${Recovery.#RESTORE_FILE_PATH}/meta.json`)
|
|
23
|
+
.then(x => JSON.parse(new TextDecoder().decode(x.buffer))),
|
|
24
|
+
Workers.Opfs.read(`${Recovery.#RESTORE_FILE_PATH}/saved`)
|
|
25
|
+
.then(x => x.at(0) === 1)
|
|
26
|
+
]));
|
|
27
|
+
const deleteResult = await Promises.tryCatch(Workers.Opfs.delete(Recovery.#RESTORE_FILE_PATH));
|
|
28
|
+
console.debug(`delete backup: "${deleteResult.status}"`);
|
|
29
|
+
if (readResult.status === "rejected") {
|
|
30
|
+
return Option.None;
|
|
31
|
+
}
|
|
32
|
+
const [uuid, project, meta, saved] = readResult.value;
|
|
33
|
+
const profile = new ProjectProfile(uuid, project, meta, Option.None, saved);
|
|
34
|
+
console.debug(`restore ${profile}, saved: ${saved}`);
|
|
35
|
+
return Option.wrap(profile);
|
|
36
|
+
}
|
|
37
|
+
createBackupCommand() {
|
|
38
|
+
return this.#projectProfileProvider().map((profile) => async () => {
|
|
39
|
+
console.debug("backup project");
|
|
40
|
+
const { project, meta, uuid } = profile;
|
|
41
|
+
return Promises.tryCatch(Promise.all([
|
|
42
|
+
Workers.Opfs.write(`${Recovery.#RESTORE_FILE_PATH}/uuid`, uuid),
|
|
43
|
+
Workers.Opfs.write(`${Recovery.#RESTORE_FILE_PATH}/project.od`, new Uint8Array(project.toArrayBuffer())),
|
|
44
|
+
Workers.Opfs.write(`${Recovery.#RESTORE_FILE_PATH}/meta.json`, new TextEncoder().encode(JSON.stringify(meta))),
|
|
45
|
+
Workers.Opfs.write(`${Recovery.#RESTORE_FILE_PATH}/saved`, new Uint8Array([profile.saved() ? 1 : 0]))
|
|
46
|
+
])).then(result => console.debug(`backup result: ${result.status}`));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
package/dist/project/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/project/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/project/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA"}
|
package/dist/project/index.js
CHANGED