159 lines
4.4 KiB
Plaintext
159 lines
4.4 KiB
Plaintext
export type MediaCacheIndex =UTSJSONObject
|
||
|
||
type DownloadFileResult = {
|
||
statusCode?: number
|
||
tempFilePath?: string
|
||
tempFilePathArray?: string[]
|
||
apFilePath?: string
|
||
// UTS不支持索引签名,已移除
|
||
}
|
||
export class MediaCacheService {
|
||
static STORAGE_KEY: string = 'media-cache-index'
|
||
static index: MediaCacheIndex | null = null
|
||
|
||
static async init(): Promise<void> {
|
||
if (this.index != null) return
|
||
try {
|
||
const res = await new Promise<UTSJSONObject | null>((resolve) => {
|
||
uni.getStorage({
|
||
key: this.STORAGE_KEY,
|
||
success: (result) => {
|
||
const json = result.data as UTSJSONObject
|
||
const data = json['data'] as UTSJSONObject | null
|
||
resolve(data)
|
||
},
|
||
fail: () => resolve(null)
|
||
})
|
||
})
|
||
if (res != null) {
|
||
this.index = res
|
||
} else {
|
||
this.index = {}
|
||
}
|
||
} catch (_) {
|
||
this.index = {}
|
||
}
|
||
}
|
||
|
||
static async persist(): Promise<void> {
|
||
try {
|
||
// @ts-ignore
|
||
await uni.setStorage({ key: this.STORAGE_KEY, data: this.index ?? {} })
|
||
} catch (_) {}
|
||
}
|
||
|
||
static async getCachedPath(url: string): Promise<string> {
|
||
await this.init()
|
||
if (this.index == null) return url
|
||
const index = this.index!
|
||
const existing = index[url] as string | null
|
||
if (existing != null && await this.fileExists(existing)) {
|
||
return existing
|
||
}
|
||
const saved = await this.downloadAndSave(url)
|
||
if (saved != null) {
|
||
this.index[url] = saved
|
||
await this.persist()
|
||
return saved
|
||
}
|
||
// fallback to remote url if save failed
|
||
return url
|
||
}
|
||
|
||
static async clear(url?: string): Promise<void> {
|
||
await this.init()
|
||
if (this.index == null) return
|
||
if (url != null && url != '') {
|
||
this.index[url] = null
|
||
} else {
|
||
this.index = {}
|
||
}
|
||
await this.persist()
|
||
}
|
||
|
||
private static async fileExists(filePath: string): Promise<boolean> {
|
||
return await new Promise<boolean>((resolve) => {
|
||
try {
|
||
const fs = uni.getFileSystemManager()
|
||
let settled = false
|
||
const finish = (value: boolean) => {
|
||
if (settled) {
|
||
return
|
||
}
|
||
settled = true
|
||
resolve(value)
|
||
}
|
||
fs.access({
|
||
path: filePath,
|
||
success: () => finish(true),
|
||
fail: () => finish(false)
|
||
})
|
||
} catch (_) {
|
||
resolve(false)
|
||
}
|
||
})
|
||
}
|
||
|
||
private static async downloadAndSave(url: string): Promise<string | null> {
|
||
const dlRes = await new Promise<DownloadFileResult | null>((resolve) => {
|
||
try {
|
||
uni.downloadFile({
|
||
url,
|
||
success: (res) => {
|
||
const result: DownloadFileResult = {
|
||
statusCode: res.statusCode,
|
||
tempFilePath: res['tempFilePath'] as string | null,
|
||
tempFilePathArray: res['tempFilePathArray'] as string[] | null,
|
||
apFilePath: res['apFilePath'] as string | null
|
||
}
|
||
resolve(result)
|
||
},
|
||
fail: () => resolve(null)
|
||
})
|
||
} catch (_) {
|
||
resolve(null)
|
||
}
|
||
})
|
||
const statusCode = dlRes?.statusCode
|
||
if (dlRes == null || statusCode == null || statusCode < 200 || statusCode >= 400) {
|
||
return null
|
||
}
|
||
const tempFilePath = dlRes.tempFilePath ?? (dlRes.tempFilePathArray != null ? dlRes.tempFilePathArray[0] : null) ?? dlRes.apFilePath ?? null
|
||
if (tempFilePath == null) return null
|
||
const savedPath = await new Promise<string | null>((resolve) => {
|
||
try {
|
||
const fs = uni.getFileSystemManager()
|
||
let settled = false
|
||
const finish = (value: string | null) => {
|
||
if (settled) {
|
||
return
|
||
}
|
||
settled = true
|
||
resolve(value)
|
||
}
|
||
const options: SaveFileOptions = {
|
||
tempFilePath: tempFilePath,
|
||
success: (res) => {
|
||
const savedPath = res.savedFilePath
|
||
if (savedPath != null && savedPath.length > 0) {
|
||
finish(savedPath)
|
||
return
|
||
}
|
||
finish(null)
|
||
},
|
||
fail: () => finish(null)
|
||
}
|
||
fs.saveFile(options as SaveFileOptions)
|
||
} catch (_) {
|
||
resolve(null)
|
||
}
|
||
})
|
||
if (savedPath != null && savedPath.length > 0) {
|
||
return savedPath
|
||
}
|
||
return null
|
||
}
|
||
}
|
||
|
||
export default MediaCacheService
|