2022-05-19 07:29:25 -06:00
import Foundation
import AVFoundation
import DVAssetLoaderDelegate
import Promises
class RCTVideoCachingHandler : NSObject , DVAssetLoaderDelegatesDelegate {
private var _videoCache : RCTVideoCache ! = RCTVideoCache . sharedInstance ( )
2023-11-17 07:09:28 -07:00
var playerItemPrepareText : ( ( AVAsset ? , NSDictionary ? , String ) -> AVPlayerItem ) ?
2022-05-19 07:29:25 -06:00
override init ( ) {
super . init ( )
}
func shouldCache ( source : VideoSource , textTracks : [ TextTrack ] ? ) -> Bool {
if source . isNetwork && source . shouldCache && ( ( textTracks = = nil ) || ( textTracks ! . count = = 0 ) ) {
/* T h e D V U R L A s s e t c r e a t e d b y c a c h e d o e s n ' t h a v e a t r a c k s W i t h M e d i a T y p e p r o p e r t y , s o t r y i n g
* to bring in the text track code will crash . I suspect this is because the asset hasn ' t fully loaded .
* Until this is fixed , we need to bypass caching when text tracks are specified .
*/
DebugLog ( " Caching is not supported for uri ' \( source . uri ) ' because text tracks are not compatible with the cache. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md " )
return true
}
return false
}
func playerItemForSourceUsingCache ( uri : String ! , assetOptions options : NSDictionary ! ) -> Promise < AVPlayerItem ? > {
let url = URL ( string : uri )
return getItemForUri ( uri )
. then { [ weak self ] ( videoCacheStatus : RCTVideoCacheStatus , cachedAsset : AVAsset ? ) -> AVPlayerItem in
guard let self = self , let playerItemPrepareText = self . playerItemPrepareText else { throw NSError ( domain : " " , code : 0 , userInfo : nil ) }
switch ( videoCacheStatus ) {
case . missingFileExtension :
DebugLog ( " Could not generate cache key for uri ' \( uri ) '. It is currently not supported to cache urls that do not include a file extension. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md " )
let asset : AVURLAsset ! = AVURLAsset ( url : url ! , options : options as ! [ String : Any ] )
2023-11-17 00:19:39 -07:00
return playerItemPrepareText ( asset , options , " " )
2022-05-19 07:29:25 -06:00
case . unsupportedFileExtension :
DebugLog ( " Could not generate cache key for uri ' \( uri ) '. The file extension of that uri is currently not supported. The video file will not be cached. Checkout https://github.com/react-native-community/react-native-video/blob/master/docs/caching.md " )
let asset : AVURLAsset ! = AVURLAsset ( url : url ! , options : options as ! [ String : Any ] )
2023-11-17 00:19:39 -07:00
return playerItemPrepareText ( asset , options , " " )
2022-05-19 07:29:25 -06:00
default :
if let cachedAsset = cachedAsset {
DebugLog ( " Playing back uri ' \( uri ) ' from cache " )
// S e e n o t e i n p l a y e r I t e m F o r S o u r c e a b o u t n o t b e i n g a b l e t o s u p p o r t t e x t t r a c k s & c a c h i n g
return AVPlayerItem ( asset : cachedAsset )
}
}
let asset : DVURLAsset ! = DVURLAsset ( url : url , options : options as ! [ String : Any ] , networkTimeout : 10000 )
asset . loaderDelegate = self
/* M o r e g r a n u l a r c o d e t o h a v e c o n t r o l o v e r t h e D V U R L A s s e t
let resourceLoaderDelegate = DVAssetLoaderDelegate ( url : url )
resourceLoaderDelegate . delegate = self
let components = NSURLComponents ( url : url , resolvingAgainstBaseURL : false )
components ? . scheme = DVAssetLoaderDelegate . scheme ( )
var asset : AVURLAsset ? = nil
if let url = components ? . url {
asset = AVURLAsset ( url : url , options : options )
}
asset ? . resourceLoader . setDelegate ( resourceLoaderDelegate , queue : DispatchQueue . main )
*/
return AVPlayerItem ( asset : asset )
}
}
func getItemForUri ( _ uri : String ) -> Promise < ( videoCacheStatus : RCTVideoCacheStatus , cachedAsset : AVAsset ? ) > {
return Promise < ( videoCacheStatus : RCTVideoCacheStatus , cachedAsset : AVAsset ? ) > { fulfill , reject in
self . _videoCache . getItemForUri ( uri , withCallback : { ( videoCacheStatus : RCTVideoCacheStatus , cachedAsset : AVAsset ? ) in
fulfill ( ( videoCacheStatus , cachedAsset ) )
} )
}
}
// MARK: - D V A s s e t L o a d e r D e l e g a t e
2023-11-16 14:13:53 -07:00
func dvAssetLoaderDelegate ( _ loaderDelegate : DVAssetLoaderDelegate ! , didLoad data : Data ! , for url : URL ! ) {
_videoCache . storeItem ( data as Data ? , forUri : url . absoluteString , withCallback : { ( success : Bool ) in
2022-05-19 07:29:25 -06:00
DebugLog ( " Cache data stored successfully 🎉 " )
} )
}
}