Skip to content

Commit e44783a

Browse files
author
Garrett Downs
committed
add kaios helper class
1 parent 5dc1e35 commit e44783a

7 files changed

Lines changed: 155 additions & 107 deletions

File tree

src/contexts/playerContext.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
NotificationAction,
88
NotificationType,
99
} from '../models';
10-
import { getFileAsUrl } from '../services/files';
1110
import { useToast } from './ToastProvider';
1211
import { useEffect } from 'react';
1312
import { useSettings } from './SettingsProvider';
@@ -79,7 +78,8 @@ export function PlayerProvider(props: ComponentBaseProps): VNode {
7978

8079
(audioRef as any).mozAudioChannelType = 'content';
8180
if (data.isDownloaded && data.localFileUrl) {
82-
await getFileAsUrl(data.localFileUrl)
81+
await KaiOS.storage
82+
.getAsFileUrl('sdcard', data.localFileUrl)
8383
.then((url) => (audioRef.src = url))
8484
.catch(() => {
8585
showToast('File missing! Streaming instead.');
@@ -150,7 +150,7 @@ export function PlayerProvider(props: ComponentBaseProps): VNode {
150150
useEffect(() => {
151151
const onClick = (): void => {
152152
if (settings.notificationAction === NotificationAction.ViewPlayer) {
153-
KaiOS.getSelfApp().then((app) => {
153+
KaiOS.app.getSelf().then((app) => {
154154
app.launch();
155155
setTimeout(() => {
156156
route('/player');

src/models/FileDownload.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/models/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ export * from './Option';
44
export * from './OpmlFeed';
55
export * from './OpmlFile';
66
export * from './StorageFile';
7-
export * from './FileDownload';
87
export * from './Download';

src/routes/Podcasts.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Podcast } from 'foxcasts-core/lib/types';
1212
import { Core } from '../services/core';
1313
import { OPML } from '../services/opml';
1414
import { useToast } from '../contexts/ToastProvider';
15+
import { KaiOS } from '../services/kaios';
1516

1617
interface Props {
1718
selectedItemId?: string;
@@ -78,7 +79,7 @@ export default function Podcasts({ selectedItemId }: Props): VNode {
7879
async function exportFeeds(): Promise<void> {
7980
if (!podcasts) return;
8081

81-
const { storageName } = (navigator as any).getDeviceStorage('sdcard');
82+
const storageName = KaiOS.storage.getActualStorageName('sdcard');
8283
const feeds: OpmlFeed[] = podcasts.map((a, i) => ({
8384
id: i.toString(),
8485
type: 'rss',

src/services/download.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import { Subject } from 'rxjs';
33
import { Dexie } from 'dexie';
44
import 'dexie-observable';
5-
import { appendFile, deleteFile, getStorageName, saveFile } from './files';
65
import { EpisodeExtended } from 'foxcasts-core/lib/types';
76
import { Download, DownloadStatus } from '../models';
87
import { Core } from './core';
8+
import { KaiOS } from './kaios';
99

1010
type Chunk = {
1111
downloadId: number;
@@ -297,7 +297,7 @@ export class DownloadManager {
297297
const download = await this.db.getDownloadByEpisodeId(episode.id);
298298

299299
if (!download) {
300-
const storageName = getStorageName();
300+
const storageName = KaiOS.storage.getActualStorageName('sdcard');
301301
if (!storageName) {
302302
throw new Error('Failed to get storage name');
303303
}
@@ -367,11 +367,15 @@ export class DownloadManager {
367367
}
368368

369369
if (chunk.part === 1) {
370-
await deleteFile(download.localFileUrl);
371-
await saveFile(download.localFileUrl, new Blob());
370+
await KaiOS.storage.delete('sdcard', download.localFileUrl);
371+
await KaiOS.storage.addNamed('sdcard', new Blob(), download.localFileUrl);
372372
}
373373

374-
await appendFile(download.localFileUrl, new Blob([chunk.data]));
374+
await KaiOS.storage.appendNamed(
375+
'sdcard',
376+
new Blob([chunk.data]),
377+
download.localFileUrl
378+
);
375379

376380
const data: Partial<Download> = {
377381
currentBytes: chunk.startBytes + chunk.bytes,

src/services/files.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/services/kaios.ts

Lines changed: 141 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,119 @@
1-
const mozNavigator = navigator as any;
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
23

3-
type Manifest = {};
4+
export class KaiOS {
5+
static navigator: MozNavigator = navigator as MozNavigator;
6+
7+
static app = {
8+
getSelf: (): Promise<DomApplication> => {
9+
return new Promise((resolve, reject) => {
10+
const request = this.navigator.mozApps.getSelf();
11+
request.onsuccess = () => resolve(request.result);
12+
request.onerror = () => reject(request.error);
13+
});
14+
},
15+
getManifest: (): Promise<Manifest> => {
16+
return new Promise((resolve, reject) => {
17+
const request = this.navigator.mozApps.getSelf();
18+
request.onsuccess = () => resolve(request.result.manifest);
19+
request.onerror = () => reject(request.error);
20+
});
21+
},
22+
};
23+
24+
static storage = {
25+
get: (storageName: StorageName, filePath: string): Promise<File> => {
26+
return new Promise((resolve, reject) => {
27+
const storage = this.navigator.getDeviceStorage(storageName);
28+
const request = storage.get(filePath);
29+
request.onsuccess = () => resolve(request.result);
30+
request.onerror = () => reject(request.error);
31+
});
32+
},
33+
getAsFileUrl: (
34+
storageName: StorageName,
35+
filePathAndName: string
36+
): Promise<string> => {
37+
return new Promise((resolve, reject) => {
38+
const storage = this.navigator.getDeviceStorage(storageName);
39+
const request = storage.get(filePathAndName);
40+
request.onsuccess = () => resolve(URL.createObjectURL(request.result));
41+
request.onerror = () => reject(request.error);
42+
});
43+
},
44+
addNamed: (
45+
storageName: StorageName,
46+
file: Blob | File,
47+
filePathAndName: string
48+
): Promise<File> => {
49+
return new Promise((resolve, reject) => {
50+
const storage = this.navigator.getDeviceStorage(storageName);
51+
const request = storage.addNamed(file, filePathAndName);
52+
request.onsuccess = () => resolve(request.result);
53+
request.onerror = () => reject(request.error);
54+
});
55+
},
56+
appendNamed: (
57+
storageName: StorageName,
58+
file: Blob | File,
59+
filePathAndName: string
60+
): Promise<File> => {
61+
return new Promise((resolve, reject) => {
62+
const storage = this.navigator.getDeviceStorage(storageName);
63+
const request = storage.appendNamed(file, filePathAndName);
64+
request.onsuccess = () => resolve(request.result);
65+
request.onerror = () => reject(request.error);
66+
});
67+
},
68+
delete: (
69+
storageName: StorageName,
70+
filePathAndName: string
71+
): Promise<void> => {
72+
return new Promise((resolve, reject) => {
73+
const storage = this.navigator.getDeviceStorage(storageName);
74+
const request = storage.delete(filePathAndName);
75+
request.onsuccess = () => resolve();
76+
request.onerror = () => reject(request.error);
77+
});
78+
},
79+
search: (regex: RegExp): Promise<FileSearchResult[]> => {
80+
return new Promise((resolve, reject) => {
81+
const files: FileSearchResult[] = [];
82+
const sdcard = this.navigator.getDeviceStorage('sdcard');
83+
const cursor = sdcard.enumerate();
84+
85+
cursor.onsuccess = function (): void {
86+
if (!this.result) {
87+
resolve(files);
88+
return;
89+
}
90+
91+
console.log('file result', this.result);
92+
const match = this.result.name.match(regex);
93+
if (match) {
94+
files.push({
95+
name: this.result.name,
96+
size: this.result.size,
97+
type: this.result.type,
98+
lastModified: this.result.lastModified,
99+
lastModifiedDate: this.result.lastModifiedDate,
100+
});
101+
}
102+
103+
this.continue();
104+
};
105+
106+
cursor.onerror = function (): void {
107+
reject(this.error);
108+
};
109+
});
110+
},
111+
getActualStorageName: (storageName: StorageName): string =>
112+
this.navigator.getDeviceStorage(storageName)?.storageName,
113+
};
114+
}
115+
116+
type Manifest = any;
4117
type DomApplication = {
5118
manifest: Manifest;
6119
updateManifest: null;
@@ -16,27 +129,33 @@ type DomApplication = {
16129
launch: () => void;
17130
};
18131

19-
type StorageName = 'music' | 'pictures' | 'sdcard' | 'videos';
20-
type StorageRequest = {
21-
result?: File;
132+
type FileSearchResult = {
133+
name: string;
134+
size: number;
135+
type: string;
136+
lastModified: string;
137+
lastModifiedDate: Date;
138+
};
139+
140+
type Request<T> = {
141+
error?: Error;
142+
result: T;
22143
onsuccess: () => void;
23144
onerror: () => void;
24145
};
25-
type DeviceStorage = {
26-
storageName: StorageName;
27-
get: (filePath: string) => StorageRequest;
28-
};
29146

30-
export class KaiOS {
31-
static getSelfApp(): Promise<DomApplication> {
32-
return new Promise((resolve) => {
33-
mozNavigator.mozApps.getSelf().onsuccess = function (): void {
34-
resolve(this.result);
35-
};
36-
});
37-
}
38-
39-
static getDeviceStorage(name: StorageName): DeviceStorage {
40-
return mozNavigator.getDeviceStorage(name);
41-
}
42-
}
147+
type StorageName = 'music' | 'pictures' | 'sdcard' | 'videos' | 'apps';
148+
149+
type MozNavigator = Navigator & {
150+
mozApps: {
151+
getSelf: () => Request<DomApplication>;
152+
};
153+
getDeviceStorage: (name: StorageName) => {
154+
storageName: string;
155+
get: (filePath: string) => Request<File>;
156+
addNamed: (file: File | Blob, filePath: string) => Request<File>;
157+
appendNamed: (file: File | Blob, filePath: string) => Request<File>;
158+
delete: (filePath: string) => Request<void>;
159+
enumerate: any;
160+
};
161+
};

0 commit comments

Comments
 (0)