str-native-video-player 1.0.0
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/Package.swift +28 -0
- package/README.md +232 -0
- package/StrNativeVideoPlayer.podspec +17 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/strtv/app/STRTV.java +430 -0
- package/android/src/main/java/com/strtv/app/STRTVPlugin.java +236 -0
- package/android/src/main/java/com/strtv/app/VideoPlayer.java +163 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +202 -0
- package/dist/esm/IndexedDBInterface.d.ts +48 -0
- package/dist/esm/IndexedDBInterface.js +215 -0
- package/dist/esm/IndexedDBInterface.js.map +1 -0
- package/dist/esm/VideoCacheCoordinator.d.ts +21 -0
- package/dist/esm/VideoCacheCoordinator.js +74 -0
- package/dist/esm/VideoCacheCoordinator.js.map +1 -0
- package/dist/esm/definitions.d.ts +116 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +72 -0
- package/dist/esm/web.js +110 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +411 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +414 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/STRTVPlugin/STRTV.swift +8 -0
- package/ios/Sources/STRTVPlugin/STRTVPlugin.swift +23 -0
- package/ios/Tests/STRTVPluginTests/STRTVPluginTests.swift +15 -0
- package/package.json +80 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// video-cache-coordinator.ts
|
|
2
|
+
import { indexedDB_interface } from './IndexedDBInterface';
|
|
3
|
+
export class VideoCacheCoordinator {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.maxCacheSizeBytes = 1000000000; // default 1 GB
|
|
6
|
+
this.db = new indexedDB_interface('videoCache');
|
|
7
|
+
}
|
|
8
|
+
setMaxCacheSize(bytes) {
|
|
9
|
+
this.maxCacheSizeBytes = bytes;
|
|
10
|
+
}
|
|
11
|
+
getMaxCacheSize() {
|
|
12
|
+
return this.maxCacheSizeBytes;
|
|
13
|
+
}
|
|
14
|
+
metadataKey(uuid) {
|
|
15
|
+
return `${uuid}_meta`;
|
|
16
|
+
}
|
|
17
|
+
blobKey(uuid) {
|
|
18
|
+
return `${uuid}_blob`;
|
|
19
|
+
}
|
|
20
|
+
async storeVideo(uuid, blob, url) {
|
|
21
|
+
const metadata = {
|
|
22
|
+
uuid,
|
|
23
|
+
sizeBytes: blob.size,
|
|
24
|
+
lastAccessed: Date.now(),
|
|
25
|
+
url,
|
|
26
|
+
};
|
|
27
|
+
// Store metadata and blob
|
|
28
|
+
await this.db.storeInIndexedDB(this.metadataKey(uuid), metadata);
|
|
29
|
+
await this.db.storeInIndexedDB(this.blobKey(uuid), blob);
|
|
30
|
+
await this.evictIfNeeded();
|
|
31
|
+
}
|
|
32
|
+
async getVideo(uuid) {
|
|
33
|
+
const metadata = await this.db.getFromIndexedDB(this.metadataKey(uuid));
|
|
34
|
+
if (!metadata)
|
|
35
|
+
return null;
|
|
36
|
+
// Update last accessed
|
|
37
|
+
metadata.lastAccessed = Date.now();
|
|
38
|
+
await this.db.storeInIndexedDB(this.metadataKey(uuid), metadata);
|
|
39
|
+
return this.db.getFromIndexedDB(this.blobKey(uuid));
|
|
40
|
+
}
|
|
41
|
+
async listVideos() {
|
|
42
|
+
// IndexedDB wrapper doesn’t give a `getAllKeys` method, so we can store metadata as key = uuid_meta
|
|
43
|
+
// For simplicity, scan all entries in the store
|
|
44
|
+
const allEntries = await this.db.listEntries();
|
|
45
|
+
// Filter for metadata entries
|
|
46
|
+
const videoMetas = allEntries
|
|
47
|
+
.filter((entry) => entry.key.endsWith('_meta'))
|
|
48
|
+
.map((entry) => entry.data);
|
|
49
|
+
return videoMetas;
|
|
50
|
+
}
|
|
51
|
+
async removeVideo(uuid) {
|
|
52
|
+
await this.db.removeFromIndexedDB(this.metadataKey(uuid));
|
|
53
|
+
await this.db.removeFromIndexedDB(this.blobKey(uuid));
|
|
54
|
+
}
|
|
55
|
+
async evictIfNeeded() {
|
|
56
|
+
const videos = await this.listVideos();
|
|
57
|
+
let totalSize = videos.reduce((acc, v) => acc + v.sizeBytes, 0);
|
|
58
|
+
if (totalSize <= this.maxCacheSizeBytes)
|
|
59
|
+
return;
|
|
60
|
+
// Evict LRU
|
|
61
|
+
videos.sort((a, b) => a.lastAccessed - b.lastAccessed);
|
|
62
|
+
for (const video of videos) {
|
|
63
|
+
await this.removeVideo(video.uuid);
|
|
64
|
+
totalSize -= video.sizeBytes;
|
|
65
|
+
if (totalSize <= this.maxCacheSizeBytes)
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async isCached(uuid) {
|
|
70
|
+
const metadata = await this.db.getFromIndexedDB(this.metadataKey(uuid));
|
|
71
|
+
return !!metadata;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=VideoCacheCoordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VideoCacheCoordinator.js","sourceRoot":"","sources":["../../src/VideoCacheCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["// video-cache-coordinator.ts\r\nimport { indexedDB_interface } from './IndexedDBInterface';\r\n\r\nexport interface VideoMetadata {\r\n uuid: string;\r\n sizeBytes: number;\r\n lastAccessed: number;\r\n url?: string; // optional original URL\r\n}\r\n\r\nexport class VideoCacheCoordinator {\r\n private db: indexedDB_interface;\r\n private maxCacheSizeBytes = 1_000_000_000; // default 1 GB\r\n\r\n constructor() {\r\n this.db = new indexedDB_interface('videoCache');\r\n }\r\n\r\n setMaxCacheSize(bytes: number): void {\r\n this.maxCacheSizeBytes = bytes;\r\n }\r\n\r\n getMaxCacheSize(): number {\r\n return this.maxCacheSizeBytes;\r\n }\r\n\r\n private metadataKey(uuid: string) {\r\n return `${uuid}_meta`;\r\n }\r\n\r\n private blobKey(uuid: string) {\r\n return `${uuid}_blob`;\r\n }\r\n\r\n async storeVideo(uuid: string, blob: Blob, url?: string): Promise<void> {\r\n const metadata: VideoMetadata = {\r\n uuid,\r\n sizeBytes: blob.size,\r\n lastAccessed: Date.now(),\r\n url,\r\n };\r\n\r\n // Store metadata and blob\r\n await this.db.storeInIndexedDB(this.metadataKey(uuid), metadata);\r\n await this.db.storeInIndexedDB(this.blobKey(uuid), blob);\r\n\r\n await this.evictIfNeeded();\r\n }\r\n\r\n async getVideo(uuid: string): Promise<Blob | null> {\r\n const metadata = await this.db.getFromIndexedDB<VideoMetadata>(this.metadataKey(uuid));\r\n if (!metadata) return null;\r\n\r\n // Update last accessed\r\n metadata.lastAccessed = Date.now();\r\n await this.db.storeInIndexedDB(this.metadataKey(uuid), metadata);\r\n\r\n return this.db.getFromIndexedDB<Blob>(this.blobKey(uuid));\r\n }\r\n\r\n async listVideos(): Promise<VideoMetadata[]> {\r\n // IndexedDB wrapper doesn’t give a `getAllKeys` method, so we can store metadata as key = uuid_meta\r\n // For simplicity, scan all entries in the store\r\n const allEntries = await this.db.listEntries();\r\n // Filter for metadata entries\r\n const videoMetas = allEntries\r\n .filter((entry) => entry.key.endsWith('_meta'))\r\n .map((entry) => entry.data as VideoMetadata);\r\n\r\n return videoMetas;\r\n }\r\n\r\n async removeVideo(uuid: string): Promise<void> {\r\n await this.db.removeFromIndexedDB(this.metadataKey(uuid));\r\n await this.db.removeFromIndexedDB(this.blobKey(uuid));\r\n }\r\n\r\n private async evictIfNeeded() {\r\n const videos = await this.listVideos();\r\n let totalSize = videos.reduce((acc, v) => acc + v.sizeBytes, 0);\r\n\r\n if (totalSize <= this.maxCacheSizeBytes) return;\r\n\r\n // Evict LRU\r\n videos.sort((a, b) => a.lastAccessed - b.lastAccessed);\r\n for (const video of videos) {\r\n await this.removeVideo(video.uuid);\r\n totalSize -= video.sizeBytes;\r\n if (totalSize <= this.maxCacheSizeBytes) break;\r\n }\r\n }\r\n\r\n async isCached(uuid: string): Promise<boolean> {\r\n const metadata = await this.db.getFromIndexedDB<VideoMetadata>(this.metadataKey(uuid));\r\n return !!metadata;\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export interface STRTVPlugin {
|
|
2
|
+
/**
|
|
3
|
+
* Simple echo for testing connectivity.
|
|
4
|
+
*/
|
|
5
|
+
echo(options: {
|
|
6
|
+
value: string;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
value: string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Core video playback method.
|
|
12
|
+
*
|
|
13
|
+
* Plays a video identified by `uuid`. If it is not cached locally, it will stream from `url`
|
|
14
|
+
* while simultaneously caching it for future playback.
|
|
15
|
+
*
|
|
16
|
+
* @param uuid - Unique identifier for the video (used in caching)
|
|
17
|
+
* @param url - URL to stream the video from if it is not cached
|
|
18
|
+
* @param loop - Whether the video should loop (default: false)
|
|
19
|
+
*/
|
|
20
|
+
play_video(options: {
|
|
21
|
+
uuid: string;
|
|
22
|
+
url?: string;
|
|
23
|
+
loop?: boolean;
|
|
24
|
+
video_player?: any;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
success: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Pauses the currently playing video.
|
|
30
|
+
*/
|
|
31
|
+
pause_video(options: {
|
|
32
|
+
video_player?: any;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Resumes the currently playing video.
|
|
38
|
+
*/
|
|
39
|
+
resume_video(options: {
|
|
40
|
+
video_player?: any;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
success: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Stops the currently playing video.
|
|
46
|
+
*/
|
|
47
|
+
stop_video(options: {
|
|
48
|
+
video_player?: any;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
success: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Seeks the currently playing video to a specific position in milliseconds.
|
|
54
|
+
*/
|
|
55
|
+
seek_video(options: {
|
|
56
|
+
position_ms: number;
|
|
57
|
+
video_player?: any;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
success: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* Returns whether a video is currently playing.
|
|
63
|
+
*/
|
|
64
|
+
is_video_playing(): Promise<{
|
|
65
|
+
playing: boolean;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* Preload a video into local storage (without playing).
|
|
69
|
+
* Will fetch and cache the video to speed up future playback.
|
|
70
|
+
*
|
|
71
|
+
* Optional: should respect max cache size and apply LRU eviction.
|
|
72
|
+
*/
|
|
73
|
+
preload_video(options: {
|
|
74
|
+
uuid: string;
|
|
75
|
+
url: string;
|
|
76
|
+
}): Promise<{
|
|
77
|
+
success: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* List all currently cached videos with metadata.
|
|
81
|
+
*/
|
|
82
|
+
list_cached_videos(): Promise<{
|
|
83
|
+
value: {
|
|
84
|
+
uuid: string;
|
|
85
|
+
url: string;
|
|
86
|
+
size_bytes: number;
|
|
87
|
+
last_accessed: number;
|
|
88
|
+
}[];
|
|
89
|
+
}>;
|
|
90
|
+
/**
|
|
91
|
+
* Evict specific videos from cache manually.
|
|
92
|
+
*/
|
|
93
|
+
evict_videos(options: {
|
|
94
|
+
uuids: string[];
|
|
95
|
+
}): Promise<{
|
|
96
|
+
success: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
/**
|
|
99
|
+
* Get cache/storage statistics.
|
|
100
|
+
*/
|
|
101
|
+
get_storage_stats(): Promise<{
|
|
102
|
+
available_bytes: number;
|
|
103
|
+
total_bytes: number;
|
|
104
|
+
used_bytes_videos: number;
|
|
105
|
+
used_bytes_app: number;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Set maximum cache size for videos.
|
|
109
|
+
* When exceeded, LRU eviction should occur automatically.
|
|
110
|
+
*/
|
|
111
|
+
set_max_cache_size(options: {
|
|
112
|
+
max_bytes: number;
|
|
113
|
+
}): Promise<{
|
|
114
|
+
success: boolean;
|
|
115
|
+
}>;
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface STRTVPlugin {\n /**\n * Simple echo for testing connectivity.\n */\n echo(options: { value: string }): Promise<{ value: string }>;\n\n /**\n * Core video playback method.\n *\n * Plays a video identified by `uuid`. If it is not cached locally, it will stream from `url`\n * while simultaneously caching it for future playback.\n *\n * @param uuid - Unique identifier for the video (used in caching)\n * @param url - URL to stream the video from if it is not cached\n * @param loop - Whether the video should loop (default: false)\n */\n play_video(options: {\n uuid: string;\n url?: string;\n loop?: boolean;\n video_player?: any;\n }): Promise<{ success: boolean }>;\n\n /**\n * Pauses the currently playing video.\n */\n pause_video(options: { video_player?: any }): Promise<{ success: boolean }>;\n\n /**\n * Resumes the currently playing video.\n */\n resume_video(options: { video_player?: any }): Promise<{ success: boolean }>;\n\n /**\n * Stops the currently playing video.\n */\n stop_video(options: { video_player?: any }): Promise<{ success: boolean }>;\n\n /**\n * Seeks the currently playing video to a specific position in milliseconds.\n */\n seek_video(options: { position_ms: number; video_player?: any }): Promise<{ success: boolean }>;\n\n /**\n * Returns whether a video is currently playing.\n */\n is_video_playing(): Promise<{ playing: boolean }>;\n\n /**\n * Preload a video into local storage (without playing).\n * Will fetch and cache the video to speed up future playback.\n *\n * Optional: should respect max cache size and apply LRU eviction.\n */\n preload_video(options: { uuid: string; url: string }): Promise<{ success: boolean }>;\n\n /**\n * List all currently cached videos with metadata.\n */\n list_cached_videos(): Promise<{ value: { uuid: string; url: string; size_bytes: number; last_accessed: number }[] }>;\n\n /**\n * Evict specific videos from cache manually.\n */\n evict_videos(options: { uuids: string[] }): Promise<{ success: boolean }>;\n\n /**\n * Get cache/storage statistics.\n */\n get_storage_stats(): Promise<{\n available_bytes: number;\n total_bytes: number;\n used_bytes_videos: number;\n used_bytes_app: number;\n }>;\n\n /**\n * Set maximum cache size for videos.\n * When exceeded, LRU eviction should occur automatically.\n */\n set_max_cache_size(options: { max_bytes: number }): Promise<{ success: boolean }>;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,KAAK,GAAG,cAAc,CAAc,OAAO,EAAE;IACjD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;CACzD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { STRTVPlugin } from './definitions';\n\nconst STRTV = registerPlugin<STRTVPlugin>('STRTV', {\n web: () => import('./web').then((m) => new m.STRTVWeb()),\n});\n\nexport * from './definitions';\nexport { STRTV };\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { STRTVPlugin } from './definitions';
|
|
3
|
+
export declare class STRTVWeb extends WebPlugin implements STRTVPlugin {
|
|
4
|
+
private cache_coord;
|
|
5
|
+
echo(options: {
|
|
6
|
+
value: string;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
value: string;
|
|
9
|
+
}>;
|
|
10
|
+
play_video(options: {
|
|
11
|
+
uuid: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
loop?: boolean;
|
|
14
|
+
video_player?: any;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
success: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
pause_video(options: {
|
|
19
|
+
video_player?: any;
|
|
20
|
+
}): Promise<{
|
|
21
|
+
success: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
stop_video(options: {
|
|
24
|
+
video_player?: any;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
success: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
resume_video(options: {
|
|
29
|
+
video_player?: any;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
success: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
seek_video(options: {
|
|
34
|
+
position_ms: number;
|
|
35
|
+
video_player?: any;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
success: boolean;
|
|
38
|
+
}>;
|
|
39
|
+
is_video_playing(): Promise<{
|
|
40
|
+
playing: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
preload_video(options: {
|
|
43
|
+
uuid: string;
|
|
44
|
+
url: string;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
success: boolean;
|
|
47
|
+
}>;
|
|
48
|
+
list_cached_videos(): Promise<{
|
|
49
|
+
value: {
|
|
50
|
+
uuid: string;
|
|
51
|
+
url: string;
|
|
52
|
+
size_bytes: number;
|
|
53
|
+
last_accessed: number;
|
|
54
|
+
}[];
|
|
55
|
+
}>;
|
|
56
|
+
evict_videos(options: {
|
|
57
|
+
uuids: string[];
|
|
58
|
+
}): Promise<{
|
|
59
|
+
success: boolean;
|
|
60
|
+
}>;
|
|
61
|
+
get_storage_stats(): Promise<{
|
|
62
|
+
available_bytes: number;
|
|
63
|
+
total_bytes: number;
|
|
64
|
+
used_bytes_videos: number;
|
|
65
|
+
used_bytes_app: number;
|
|
66
|
+
}>;
|
|
67
|
+
set_max_cache_size(options: {
|
|
68
|
+
max_bytes: number;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
success: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import { VideoCacheCoordinator } from './VideoCacheCoordinator';
|
|
3
|
+
export class STRTVWeb extends WebPlugin {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this.cache_coord = new VideoCacheCoordinator();
|
|
7
|
+
}
|
|
8
|
+
async echo(options) {
|
|
9
|
+
console.log('ECHO', options);
|
|
10
|
+
return options;
|
|
11
|
+
}
|
|
12
|
+
async play_video(options) {
|
|
13
|
+
if (!options.video_player)
|
|
14
|
+
return { success: false };
|
|
15
|
+
const video_player = options.video_player;
|
|
16
|
+
// Try to get video from cache
|
|
17
|
+
const blob = await this.cache_coord.getVideo(options.uuid);
|
|
18
|
+
let url = options.url;
|
|
19
|
+
if (blob)
|
|
20
|
+
url = URL.createObjectURL(blob); // updating url with local cache url
|
|
21
|
+
video_player.src = url;
|
|
22
|
+
video_player.loop = !!options.loop;
|
|
23
|
+
await video_player.play();
|
|
24
|
+
// if (!blob && options.url) {
|
|
25
|
+
// this.preload_video({ uuid: options.uuid, url: options.url });
|
|
26
|
+
// }
|
|
27
|
+
return { success: true };
|
|
28
|
+
}
|
|
29
|
+
async pause_video(options) {
|
|
30
|
+
if (!options.video_player)
|
|
31
|
+
return { success: false };
|
|
32
|
+
options.video_player.pause();
|
|
33
|
+
return { success: true };
|
|
34
|
+
}
|
|
35
|
+
async stop_video(options) {
|
|
36
|
+
if (!options.video_player)
|
|
37
|
+
return { success: false };
|
|
38
|
+
options.video_player.src = '';
|
|
39
|
+
options.video_player.load();
|
|
40
|
+
options.video_player.pause();
|
|
41
|
+
return { success: true };
|
|
42
|
+
}
|
|
43
|
+
async resume_video(options) {
|
|
44
|
+
if (!options.video_player)
|
|
45
|
+
return { success: false };
|
|
46
|
+
options.video_player.play();
|
|
47
|
+
return { success: true };
|
|
48
|
+
}
|
|
49
|
+
async seek_video(options) {
|
|
50
|
+
if (!options.video_player)
|
|
51
|
+
return { success: false };
|
|
52
|
+
options.video_player.currentTime = options.position_ms / 1000;
|
|
53
|
+
return { success: true };
|
|
54
|
+
}
|
|
55
|
+
async is_video_playing() {
|
|
56
|
+
return { playing: false };
|
|
57
|
+
}
|
|
58
|
+
async preload_video(options) {
|
|
59
|
+
try {
|
|
60
|
+
if (await this.cache_coord.isCached(options.uuid))
|
|
61
|
+
return { success: true };
|
|
62
|
+
const resp = await fetch(options.url);
|
|
63
|
+
const blob = await resp.blob();
|
|
64
|
+
await this.cache_coord.storeVideo(options.uuid, blob, options.url);
|
|
65
|
+
return { success: true };
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error('Preload failed', err);
|
|
69
|
+
return { success: false };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async list_cached_videos() {
|
|
73
|
+
const videos = await this.cache_coord.listVideos();
|
|
74
|
+
return {
|
|
75
|
+
value: videos.map((v) => ({
|
|
76
|
+
uuid: v.uuid,
|
|
77
|
+
url: v.url || '',
|
|
78
|
+
size_bytes: v.sizeBytes,
|
|
79
|
+
last_accessed: v.lastAccessed,
|
|
80
|
+
})),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async evict_videos(options) {
|
|
84
|
+
try {
|
|
85
|
+
for (const uuid of options.uuids) {
|
|
86
|
+
await this.cache_coord.removeVideo(uuid);
|
|
87
|
+
}
|
|
88
|
+
return { success: true };
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.error('Eviction failed', err);
|
|
92
|
+
return { success: false };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async get_storage_stats() {
|
|
96
|
+
const videos = await this.cache_coord.listVideos();
|
|
97
|
+
const used_bytes_videos = videos.reduce((acc, v) => acc + v.sizeBytes, 0);
|
|
98
|
+
return {
|
|
99
|
+
available_bytes: this.cache_coord.getMaxCacheSize() - used_bytes_videos,
|
|
100
|
+
total_bytes: this.cache_coord.getMaxCacheSize(),
|
|
101
|
+
used_bytes_videos,
|
|
102
|
+
used_bytes_app: 0,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async set_max_cache_size(options) {
|
|
106
|
+
this.cache_coord.setMaxCacheSize(options.max_bytes);
|
|
107
|
+
return { success: false };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport { VideoCacheCoordinator } from './VideoCacheCoordinator';\nimport type { STRTVPlugin } from './definitions';\n\nexport class STRTVWeb extends WebPlugin implements STRTVPlugin {\n private cache_coord = new VideoCacheCoordinator();\n\n async echo(options: { value: string }): Promise<{ value: string }> {\n console.log('ECHO', options);\n return options;\n }\n\n async play_video(options: {\n uuid: string;\n url?: string;\n loop?: boolean;\n video_player?: any;\n }): Promise<{ success: boolean }> {\n if (!options.video_player) return { success: false };\n const video_player = options.video_player;\n\n // Try to get video from cache\n const blob = await this.cache_coord.getVideo(options.uuid);\n\n let url = options.url;\n if (blob) url = URL.createObjectURL(blob); // updating url with local cache url\n\n video_player.src = url;\n video_player.loop = !!options.loop;\n await video_player.play();\n\n // if (!blob && options.url) {\n // this.preload_video({ uuid: options.uuid, url: options.url });\n // }\n\n return { success: true };\n }\n\n async pause_video(options: { video_player?: any }): Promise<{ success: boolean }> {\n if (!options.video_player) return { success: false };\n options.video_player.pause();\n return { success: true };\n }\n\n async stop_video(options: { video_player?: any }): Promise<{ success: boolean }> {\n if (!options.video_player) return { success: false };\n options.video_player.src = '';\n options.video_player.load();\n options.video_player.pause();\n return { success: true };\n }\n\n async resume_video(options: { video_player?: any }): Promise<{ success: boolean }> {\n if (!options.video_player) return { success: false };\n options.video_player.play();\n return { success: true };\n }\n\n async seek_video(options: { position_ms: number; video_player?: any }): Promise<{ success: boolean }> {\n if (!options.video_player) return { success: false };\n options.video_player.currentTime = options.position_ms / 1000;\n return { success: true };\n }\n\n async is_video_playing(): Promise<{ playing: boolean }> {\n return { playing: false };\n }\n\n async preload_video(options: { uuid: string; url: string }): Promise<{ success: boolean }> {\n try {\n if (await this.cache_coord.isCached(options.uuid)) return { success: true };\n const resp = await fetch(options.url);\n const blob = await resp.blob();\n await this.cache_coord.storeVideo(options.uuid, blob, options.url);\n\n return { success: true };\n } catch (err) {\n console.error('Preload failed', err);\n return { success: false };\n }\n }\n\n async list_cached_videos(): Promise<{\n value: { uuid: string; url: string; size_bytes: number; last_accessed: number }[];\n }> {\n const videos = await this.cache_coord.listVideos();\n return {\n value: videos.map((v) => ({\n uuid: v.uuid,\n url: v.url || '',\n size_bytes: v.sizeBytes,\n last_accessed: v.lastAccessed,\n })),\n };\n }\n\n async evict_videos(options: { uuids: string[] }): Promise<{ success: boolean }> {\n try {\n for (const uuid of options.uuids) {\n await this.cache_coord.removeVideo(uuid);\n }\n return { success: true };\n } catch (err) {\n console.error('Eviction failed', err);\n return { success: false };\n }\n }\n\n async get_storage_stats(): Promise<{\n available_bytes: number;\n total_bytes: number;\n used_bytes_videos: number;\n used_bytes_app: number;\n }> {\n const videos = await this.cache_coord.listVideos();\n const used_bytes_videos = videos.reduce((acc, v) => acc + v.sizeBytes, 0);\n\n return {\n available_bytes: this.cache_coord.getMaxCacheSize() - used_bytes_videos,\n total_bytes: this.cache_coord.getMaxCacheSize(),\n used_bytes_videos,\n used_bytes_app: 0, // optional: could track app storage separately\n };\n }\n\n async set_max_cache_size(options: { max_bytes: number }): Promise<{ success: boolean }> {\n this.cache_coord.setMaxCacheSize(options.max_bytes);\n return { success: false };\n }\n}\n"]}
|