feature/share-libs
ts 169 lines 4.52 KB
Raw
1 import Dexie, { Table } from "dexie";
2 import User from "../models/user";
3 import axios from "@/lib/axios"; // Move to rust
4 import { Logger } from "tslog";
5 import { AudioFile } from "@/models/audio-file";
6 import { ModeDemucs } from "@/models/mode";
7 import { Mode } from "fs";
8 import { Result } from "@/models/result";
9
10 // Legacy Spleeter result file
11 export interface AudioFiles {
12 id?: number;
13 audioFileId: string;
14 type: Mode;
15 file: Blob;
16 }
17
18 export enum CurrentUserType {
19 MAIN,
20 GUEST,
21 }
22
23 export interface CurrentUser {
24 accessToken: string;
25 type: CurrentUserType;
26 mode: Mode;
27 user: User;
28 }
29
30 // Splitfire result file
31 interface ResultFile {
32 id?: number;
33 audioFileId: number;
34 type: ModeDemucs;
35 buffer: ArrayBuffer;
36 blobType: string;
37 }
38
39 export interface BlobFile {
40 file: Blob;
41 mode: ModeDemucs;
42 }
43
44 export class SplitfireDB extends Dexie {
45 audioFiles!: Table<AudioFiles>;
46 resultFiles!: Table<ResultFile>;
47 currentUser!: Table<CurrentUser>;
48
49 log = new Logger({
50 name: "SplitfireDB",
51 type: "json",
52 });
53
54 constructor() {
55 super("splitfireDB");
56 this.version(10).stores({
57 audioFiles: "++id, [audioFileId+type]", // This is when I was using Spleeter
58 resultFiles: "++id, [audioFileId+type]", // This is when I was using Demucs
59 currentUser: "++id, [userId+type], type",
60 });
61 }
62
63 // The public interface to get the blob result files.
64 // It takes the audio file and then compute the modes from the results field.
65 async getResultFiles(audioFile: AudioFile): Promise<BlobFile[]> {
66 return new Promise(async (resolve, reject) => {
67 try {
68 // Check modes of results
69 const modes: ModeDemucs[] = audioFile.results.map(
70 (result) => result.filename.split("-").shift() as ModeDemucs
71 );
72
73 this.log.error("modes", modes);
74 let resultFiles: BlobFile[] = [];
75 // Check if we have result file in the db
76 for (const mode of modes) {
77 const result = await this._getResultFile(audioFile, mode);
78 resultFiles.push(result);
79 }
80 this.log.debug("resultFiles", resultFiles);
81 resolve(resultFiles);
82 } catch (error) {
83 this.log.error(error);
84 reject(error);
85 }
86 });
87 }
88
89 async _getResultFile(
90 audioFile: AudioFile,
91 mode: ModeDemucs
92 ): Promise<BlobFile> {
93 return new Promise(async (resolve, reject) => {
94 try {
95 // Check if we have result file in the db
96 const result = await db.resultFiles.get({
97 audioFileId: audioFile.id,
98 type: mode,
99 });
100 // if we do, then return it
101 this.log.debug("_getResultFile", result);
102 if (result?.buffer) {
103 const blob = new Blob([result.buffer], { type: result.blobType });
104 resolve({ file: blob, mode });
105 } else {
106 // otherwise, download the file and return it
107 const file = await this._downloadFile(audioFile, mode);
108 resolve({ file, mode });
109 }
110 } catch (error) {
111 reject(error);
112 }
113 });
114 }
115
116 async _downloadFile(audioFile: AudioFile, type: ModeDemucs): Promise<Blob> {
117 this.log.debug("_downloadFile", type);
118 let result: Result | undefined;
119 switch (type) {
120 case ModeDemucs.Vocals:
121 result = audioFile.results.find((obj) => {
122 return obj.filename.startsWith("vocals");
123 });
124 break;
125 case ModeDemucs.Bass:
126 result = audioFile?.results.find((obj) => {
127 return obj.filename.startsWith("bass");
128 });
129 break;
130 case ModeDemucs.Drums:
131 result = audioFile?.results.find((obj) => {
132 return obj.filename.startsWith("drums");
133 });
134 break;
135 case ModeDemucs.Other:
136 result = audioFile?.results.find((obj) => {
137 return obj.filename.startsWith("other");
138 });
139 break;
140 }
141
142 this.log.debug("Download url", result?.source_file);
143
144 return new Promise(async (resolve, reject) => {
145 try {
146 const response = await axios({
147 url: result?.source_file,
148 method: "GET",
149 responseType: "blob",
150 });
151 const blob = new Blob([response.data], { type: "audio/mp3" });
152 const buffer = await blob.arrayBuffer();
153 const item: ResultFile = {
154 audioFileId: audioFile.id,
155 type: type,
156 buffer: buffer,
157 blobType: blob.type,
158 };
159 db.resultFiles.add(item);
160 resolve(blob);
161 } catch (error) {
162 this.log.error(error);
163 reject(error);
164 }
165 });
166 }
167 }
168
169 export const db = new SplitfireDB();