@stepincto/expo-video 1.0.0 → 1.0.3
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.
|
@@ -17,6 +17,8 @@ class CachableRequest: Equatable, Hashable {
|
|
|
17
17
|
var response: URLResponse?
|
|
18
18
|
private(set) var receivedData = Data()
|
|
19
19
|
private let dataOffset: Int64
|
|
20
|
+
private static var fileLocks: [String: NSLock] = [:]
|
|
21
|
+
private static let fileLocksQueue = DispatchQueue(label: "expo-video-cache-file-locks")
|
|
20
22
|
|
|
21
23
|
init(loadingRequest: AVAssetResourceLoadingRequest, dataTask: URLSessionDataTask, dataRequest: AVAssetResourceLoadingDataRequest) {
|
|
22
24
|
self.loadingRequest = loadingRequest
|
|
@@ -30,8 +32,41 @@ class CachableRequest: Equatable, Hashable {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
func saveData(to cachedResource: CachedResource) {
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
+
// 1. Check if file is fully cached
|
|
36
|
+
if let mediaInfo = cachedResource.mediaInfo {
|
|
37
|
+
let expectedLength = Int(mediaInfo.expectedContentLength)
|
|
38
|
+
let ranges = mediaInfo.loadedDataRanges
|
|
39
|
+
if ranges.count == 1, ranges[0].0 == 0, ranges[0].1 == expectedLength - 1 {
|
|
40
|
+
// Already fully cached, do not write
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 2. Acquire per-file lock
|
|
46
|
+
let filePath = cachedResource.dataPath
|
|
47
|
+
let lock: NSLock = Self.fileLocksQueue.sync {
|
|
48
|
+
if let l = Self.fileLocks[filePath] { return l }
|
|
49
|
+
let l = NSLock()
|
|
50
|
+
Self.fileLocks[filePath] = l
|
|
51
|
+
return l
|
|
52
|
+
}
|
|
53
|
+
if !lock.try() {
|
|
54
|
+
// Another writer is active, skip this write
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
defer { lock.unlock() }
|
|
58
|
+
|
|
59
|
+
// 3. Write only missing data
|
|
60
|
+
let offset = dataOffset
|
|
61
|
+
let length = receivedData.count
|
|
62
|
+
let end = offset + Int64(length) - 1
|
|
63
|
+
if cachedResource.canRespondWithData(from: offset, to: end) {
|
|
64
|
+
// This range is already cached, skip
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
Task {
|
|
68
|
+
await cachedResource.writeData(data: receivedData, offset: offset)
|
|
69
|
+
}
|
|
35
70
|
}
|
|
36
71
|
|
|
37
72
|
static func == (lhs: CachableRequest, rhs: CachableRequest) -> Bool {
|
|
@@ -210,6 +210,15 @@ extension VideoCacheManager {
|
|
|
210
210
|
let fileUrl = URL(fileURLWithPath: saveFilePath)
|
|
211
211
|
let mediaInfoPath = saveFilePath + VideoCacheManager.mediaInfoSuffix
|
|
212
212
|
|
|
213
|
+
// Ensure parent directory exists before writing file
|
|
214
|
+
let parentDir = fileUrl.deletingLastPathComponent()
|
|
215
|
+
do {
|
|
216
|
+
try FileManager.default.createDirectory(at: parentDir, withIntermediateDirectories: true)
|
|
217
|
+
} catch {
|
|
218
|
+
print("[expo-video] Failed to create parent directory for cache file: \(error)")
|
|
219
|
+
throw error
|
|
220
|
+
}
|
|
221
|
+
|
|
213
222
|
let (data, response) = try await URLSession.shared.data(from: url)
|
|
214
223
|
try data.write(to: fileUrl, options: .atomic)
|
|
215
224
|
|
|
@@ -253,10 +262,13 @@ extension VideoCacheManager {
|
|
|
253
262
|
let fileUrl = URL(fileURLWithPath: saveFilePath)
|
|
254
263
|
let mediaInfoPath = saveFilePath + VideoCacheManager.mediaInfoSuffix
|
|
255
264
|
|
|
256
|
-
// Ensure
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
265
|
+
// Ensure parent directory exists before writing file
|
|
266
|
+
let parentDir = fileUrl.deletingLastPathComponent()
|
|
267
|
+
do {
|
|
268
|
+
try FileManager.default.createDirectory(at: parentDir, withIntermediateDirectories: true)
|
|
269
|
+
} catch {
|
|
270
|
+
print("[expo-video] Failed to create parent directory for cache file: \(error)")
|
|
271
|
+
throw error
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
// Ensure the file exists before opening for writing
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stepincto/expo-video",
|
|
3
3
|
"title": "Expo Video",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.3",
|
|
5
5
|
"originalUpstreamVersion": "2.2.2",
|
|
6
6
|
"description": "A cross-platform, performant video component for React Native and Expo with Web support",
|
|
7
7
|
"main": "build/index.js",
|