Files
akmon/utils/mediaCacheService.uts
2026-01-20 08:04:15 +08:00

159 lines
4.4 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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