1+ import type { MediaItem , MediaCacheAdapter , CacheProgress } from '../types/cache'
2+
3+ const CACHE_NAME = 'screenlite-media-cache-v1'
4+ const METADATA_KEY = 'screenlite-media-metadata'
5+
6+ interface CacheMetadata {
7+ [ url : string ] : {
8+ type : 'image' | 'video'
9+ contentType : string
10+ size : number
11+ cachedAt : number
12+ }
13+ }
14+
15+ export class BrowserMediaCacheAdapter implements MediaCacheAdapter {
16+ private async getMetadata ( ) : Promise < CacheMetadata > {
17+ const data = localStorage . getItem ( METADATA_KEY )
18+ return data ? JSON . parse ( data ) : { }
19+ }
20+
21+ private async setMetadata ( metadata : CacheMetadata ) : Promise < void > {
22+ localStorage . setItem ( METADATA_KEY , JSON . stringify ( metadata ) )
23+ }
24+
25+ private async updateMetadata ( url : string , data : CacheMetadata [ string ] ) : Promise < void > {
26+ const metadata = await this . getMetadata ( )
27+ metadata [ url ] = data
28+ await this . setMetadata ( metadata )
29+ }
30+
31+ async cacheItem ( item : MediaItem ) : Promise < void > {
32+ const cache = await caches . open ( CACHE_NAME )
33+
34+ // First check if we already have this item
35+ if ( await this . hasItem ( item . url ) ) {
36+ return
37+ }
38+
39+ try {
40+ const response = await fetch ( item . url )
41+ if ( ! response . ok ) throw new Error ( `HTTP error! status: ${ response . status } ` )
42+
43+ const contentType = response . headers . get ( 'content-type' ) || item . contentType || 'application/octet-stream'
44+ const size = parseInt ( response . headers . get ( 'content-length' ) || '0' , 10 )
45+
46+ // Store the response in the cache
47+ await cache . put ( item . url , response . clone ( ) )
48+
49+ // Store metadata
50+ await this . updateMetadata ( item . url , {
51+ type : item . type ,
52+ contentType,
53+ size,
54+ cachedAt : Date . now ( )
55+ } )
56+ } catch ( error ) {
57+ console . error ( `Failed to cache item: ${ item . url } ` , error )
58+ throw error
59+ }
60+ }
61+
62+ async cacheItems ( items : MediaItem [ ] , onProgress ?: ( progress : CacheProgress ) => void ) : Promise < void > {
63+ const total = items . length
64+ let completed = 0
65+
66+ for ( const item of items ) {
67+ try {
68+ onProgress ?.( {
69+ url : item . url ,
70+ progress : ( completed / total ) * 100 ,
71+ status : 'downloading'
72+ } )
73+
74+ await this . cacheItem ( item )
75+ completed ++
76+
77+ onProgress ?.( {
78+ url : item . url ,
79+ progress : ( completed / total ) * 100 ,
80+ status : 'completed'
81+ } )
82+ } catch ( error ) {
83+ onProgress ?.( {
84+ url : item . url ,
85+ progress : ( completed / total ) * 100 ,
86+ status : 'error' ,
87+ error : error instanceof Error ? error . message : 'Unknown error'
88+ } )
89+ }
90+ }
91+ }
92+
93+ async getItem ( url : string ) : Promise < string | null > {
94+ const cache = await caches . open ( CACHE_NAME )
95+ const response = await cache . match ( url )
96+
97+ if ( ! response ) return null
98+
99+ // For browsers that support it, create a blob URL
100+ if ( window . URL && response . blob ) {
101+ const blob = await response . blob ( )
102+ return URL . createObjectURL ( blob )
103+ }
104+
105+ // Fallback to the original URL if we can't create a blob URL
106+ return url
107+ }
108+
109+ async hasItem ( url : string ) : Promise < boolean > {
110+ const cache = await caches . open ( CACHE_NAME )
111+ const response = await cache . match ( url )
112+ return ! ! response
113+ }
114+
115+ async removeItem ( url : string ) : Promise < void > {
116+ const cache = await caches . open ( CACHE_NAME )
117+ await cache . delete ( url )
118+
119+ // Remove metadata
120+ const metadata = await this . getMetadata ( )
121+ delete metadata [ url ]
122+ await this . setMetadata ( metadata )
123+ }
124+
125+ async clear ( ) : Promise < void > {
126+ await caches . delete ( CACHE_NAME )
127+ localStorage . removeItem ( METADATA_KEY )
128+ }
129+
130+ async getSize ( ) : Promise < number > {
131+ const metadata = await this . getMetadata ( )
132+ return Object . values ( metadata ) . reduce ( ( total , item ) => total + item . size , 0 )
133+ }
134+ }
0 commit comments