|
@@ -15,6 +15,7 @@ import { formProvider, formBindingData } from '@kit.FormKit';
|
|
|
import { fileIo } from '@kit.CoreFileKit';
|
|
import { fileIo } from '@kit.CoreFileKit';
|
|
|
import { BusinessError } from '@kit.BasicServicesKit';
|
|
import { BusinessError } from '@kit.BasicServicesKit';
|
|
|
import { http } from '@kit.NetworkKit';
|
|
import { http } from '@kit.NetworkKit';
|
|
|
|
|
+import { util } from '@kit.ArkTS';
|
|
|
import json from '@ohos.util.json';
|
|
import json from '@ohos.util.json';
|
|
|
import MediaTable from '../util/MediaTable';
|
|
import MediaTable from '../util/MediaTable';
|
|
|
import { Utility } from '../util/Utility';
|
|
import { Utility } from '../util/Utility';
|
|
@@ -79,6 +80,15 @@ export interface WidgetTimeInfo {
|
|
|
progressPercentage: number;
|
|
progressPercentage: number;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 缓存文件信息接口
|
|
|
|
|
+ */
|
|
|
|
|
+export interface CacheFileInfo {
|
|
|
|
|
+ path: string;
|
|
|
|
|
+ size: number;
|
|
|
|
|
+ mtime: number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 卡片数据接口
|
|
* 卡片数据接口
|
|
|
*/
|
|
*/
|
|
@@ -302,6 +312,13 @@ export interface IPlayerService {
|
|
|
* 强制刷新收藏状态(用于收藏/取消收藏操作后)
|
|
* 强制刷新收藏状态(用于收藏/取消收藏操作后)
|
|
|
*/
|
|
*/
|
|
|
refreshFavoriteStatus(): Promise<void>;
|
|
refreshFavoriteStatus(): Promise<void>;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取收藏列表
|
|
|
|
|
+ * @returns 收藏列表
|
|
|
|
|
+ */
|
|
|
|
|
+ getFav(): Array<VideoItem>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -380,6 +397,11 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
private autoPlayDebounceMs: number = 1000; // 自动播放防抖间隔(毫秒)
|
|
private autoPlayDebounceMs: number = 1000; // 自动播放防抖间隔(毫秒)
|
|
|
private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换
|
|
private isManualSongChange: boolean = false; // 新增:是否正在进行手动歌曲切换
|
|
|
|
|
|
|
|
|
|
+ // 图片缓存相关属性
|
|
|
|
|
+ private imageCacheDir: string = ''; // 图片缓存目录
|
|
|
|
|
+ private readonly CACHE_EXPIRY_DAYS: number = 7; // 缓存有效期:7天
|
|
|
|
|
+ private readonly MAX_CACHE_SIZE_MB: number = 50; // 最大缓存大小:50MB
|
|
|
|
|
+
|
|
|
private constructor() {
|
|
private constructor() {
|
|
|
this.playerManager = PlayerManager.getInstance();
|
|
this.playerManager = PlayerManager.getInstance();
|
|
|
this.stateModel = new PlayerStateModel();
|
|
this.stateModel = new PlayerStateModel();
|
|
@@ -407,6 +429,9 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
console.log("Heanup2 UnifiedPlayerService: 开始快速初始化服务");
|
|
console.log("Heanup2 UnifiedPlayerService: 开始快速初始化服务");
|
|
|
this.context = context;
|
|
this.context = context;
|
|
|
|
|
|
|
|
|
|
+ // 初始化图片缓存目录
|
|
|
|
|
+ await this.initImageCacheDirectory();
|
|
|
|
|
+
|
|
|
// 快速初始化核心组件
|
|
// 快速初始化核心组件
|
|
|
this.playerManager.setStateCallback(this);
|
|
this.playerManager.setStateCallback(this);
|
|
|
|
|
|
|
@@ -580,7 +605,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
// 同步更新所有桌面卡片状态
|
|
// 同步更新所有桌面卡片状态
|
|
|
this.updateAllForms();
|
|
this.updateAllForms();
|
|
|
}
|
|
}
|
|
|
- public toggleFavorite() {
|
|
|
|
|
|
|
+ public async toggleFavorite(): Promise<void> {
|
|
|
|
|
|
|
|
let isFav = 0
|
|
let isFav = 0
|
|
|
let item=this.getCurrentSong() as VideoItem;
|
|
let item=this.getCurrentSong() as VideoItem;
|
|
@@ -589,13 +614,22 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
} else {
|
|
} else {
|
|
|
isFav = 1
|
|
isFav = 1
|
|
|
}
|
|
}
|
|
|
- this.getTable().updateIsFavByFilePath(item.filePath, isFav, async (result: boolean) => {
|
|
|
|
|
- if (result) {
|
|
|
|
|
- // 刷新UnifiedPlayerService的收藏状态,这会自动更新AVSession
|
|
|
|
|
- console.log("Heanup2 UnifiedPlayerService toggleFavorite: 收藏状态切换");
|
|
|
|
|
- await this.refreshFavoriteStatus();
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return new Promise<void>((resolve) => {
|
|
|
|
|
+ this.getTable().updateIsFavByFilePath(item.filePath, isFav, async (result: boolean) => {
|
|
|
|
|
+ if (result) {
|
|
|
|
|
+ // 刷新UnifiedPlayerService的收藏状态,这会自动更新AVSession
|
|
|
|
|
+ console.log("Heanup2 UnifiedPlayerService toggleFavorite: 收藏状态切换");
|
|
|
|
|
+ await this.refreshFavoriteStatus();
|
|
|
|
|
+
|
|
|
|
|
+ // 立即更新桌面卡片状态,确保收藏图标正确显示
|
|
|
|
|
+ await this.updateAllForms(true);
|
|
|
|
|
+
|
|
|
|
|
+ console.log("Heanup2 UnifiedPlayerService toggleFavorite: 收藏状态和卡片状态更新完成");
|
|
|
|
|
+ }
|
|
|
|
|
+ resolve();
|
|
|
|
|
+ })
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1077,7 +1111,11 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
// 清空缓存,强制重新加载
|
|
// 清空缓存,强制重新加载
|
|
|
this.favList = [];
|
|
this.favList = [];
|
|
|
await this.updateFavoriteList();
|
|
await this.updateFavoriteList();
|
|
|
- LogUtils.getInstance().LOGI('UnifiedPlayerService: Favorite status refreshed');
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 触发状态变化通知,确保LocalMusic UI能收到收藏状态变化
|
|
|
|
|
+ this.stateModel.forceNotifyStateChanged();
|
|
|
|
|
+
|
|
|
|
|
+ LogUtils.getInstance().LOGI('UnifiedPlayerService: Favorite status refreshed and state change notified');
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to refresh favorite status: ${error}`);
|
|
LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to refresh favorite status: ${error}`);
|
|
|
}
|
|
}
|
|
@@ -2771,44 +2809,43 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
|
|
|
|
|
// 判断是否为网络图片
|
|
// 判断是否为网络图片
|
|
|
if (formData.pixelMapPath.startsWith('http://') || formData.pixelMapPath.startsWith('https://')) {
|
|
if (formData.pixelMapPath.startsWith('http://') || formData.pixelMapPath.startsWith('https://')) {
|
|
|
- // 处理网络图片:下载到临时文件
|
|
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloading network image ${formData.pixelMapPath}`);
|
|
|
|
|
-
|
|
|
|
|
- const tempDir = this.context?.getApplicationContext().tempDir;
|
|
|
|
|
- if (!tempDir) {
|
|
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: No temp directory available for network image`);
|
|
|
|
|
- } else {
|
|
|
|
|
- const tempFileName = imgName + '.tmp';
|
|
|
|
|
- const tempFilePath = tempDir + '/' + tempFileName;
|
|
|
|
|
-
|
|
|
|
|
- // 创建HTTP请求下载图片
|
|
|
|
|
- const httpRequest = http.createHttp();
|
|
|
|
|
- try {
|
|
|
|
|
- const response = await httpRequest.request(formData.pixelMapPath, {
|
|
|
|
|
- method: http.RequestMethod.GET,
|
|
|
|
|
- connectTimeout: 5000, // 5秒超时,避免卡片更新被阻塞
|
|
|
|
|
- readTimeout: 5000
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (response.responseCode === http.ResponseCode.OK && response.result) {
|
|
|
|
|
- // 将下载的图片数据写入临时文件
|
|
|
|
|
- const tempFile = fileIo.openSync(tempFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
|
|
|
|
|
|
+ // 处理网络图片:使用缓存机制
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Processing network image ${formData.pixelMapPath}`);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.imageCacheDir) {
|
|
|
|
|
+ const cacheFileName = this.generateCacheFileName(formData.pixelMapPath);
|
|
|
|
|
+ const cacheFilePath = this.imageCacheDir + '/' + cacheFileName;
|
|
|
|
|
+
|
|
|
|
|
+ // 检查缓存是否存在且有效
|
|
|
|
|
+ if (await this.isCacheValid(cacheFilePath)) {
|
|
|
|
|
+ // 使用缓存文件
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Using cached image: ${cacheFilePath}`);
|
|
|
|
|
+ try {
|
|
|
|
|
+ const file = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_ONLY);
|
|
|
|
|
+ imgMap[imgName] = file.fd;
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Opened cached image with fd ${file.fd}, imgName: ${imgName}`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to open cached image: ${error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 下载到缓存
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloading image to cache: ${cacheFilePath}`);
|
|
|
|
|
+ const downloadSuccess = await this.downloadImageToCache(formData.pixelMapPath, cacheFilePath);
|
|
|
|
|
|
|
|
|
|
+ if (downloadSuccess) {
|
|
|
try {
|
|
try {
|
|
|
- await fileIo.write(tempFile.fd, response.result as ArrayBuffer);
|
|
|
|
|
- imgMap[imgName] = tempFile.fd;
|
|
|
|
|
-
|
|
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Downloaded and opened network image ${formData.pixelMapPath} to ${tempFilePath} with fd ${tempFile.fd}, imgName: ${imgName}`);
|
|
|
|
|
- } catch (writeError) {
|
|
|
|
|
- fileIo.closeSync(tempFile);
|
|
|
|
|
- // throw writeError;
|
|
|
|
|
|
|
+ const file = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_ONLY);
|
|
|
|
|
+ imgMap[imgName] = file.fd;
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Opened downloaded image with fd ${file.fd}, imgName: ${imgName}`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to open downloaded image: ${error}`);
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to download network image ${formData.pixelMapPath}: HTTP ${response.responseCode}`);
|
|
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to download network image ${formData.pixelMapPath}`);
|
|
|
}
|
|
}
|
|
|
- } finally {
|
|
|
|
|
- httpRequest.destroy();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Image cache directory not available`);
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
// 处理本地图片文件
|
|
// 处理本地图片文件
|
|
@@ -2922,21 +2959,8 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
const fd = imgMap[imgKey];
|
|
const fd = imgMap[imgKey];
|
|
|
if (typeof fd === 'number') {
|
|
if (typeof fd === 'number') {
|
|
|
// 关闭文件描述符
|
|
// 关闭文件描述符
|
|
|
- fileIo.closeSync( fd);
|
|
|
|
|
|
|
+ fileIo.closeSync(fd);
|
|
|
LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Closed image file descriptor ${fd} for ${imgKey}`);
|
|
LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Closed image file descriptor ${fd} for ${imgKey}`);
|
|
|
-
|
|
|
|
|
- // 如果是网络图片的临时文件,尝试删除
|
|
|
|
|
- if (tempDir && imgKey.startsWith('songCover_')) {
|
|
|
|
|
- try {
|
|
|
|
|
- const tempFilePath = tempDir + '/' + imgKey + '.tmp';
|
|
|
|
|
- if (fileIo.accessSync(tempFilePath)) {
|
|
|
|
|
- fileIo.unlinkSync(tempFilePath);
|
|
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Deleted temp file ${tempFilePath}`);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (deleteError) {
|
|
|
|
|
- LogUtils.getInstance().LOGI(`UnifiedPlayerService updateAllForms: Failed to delete temp file for ${imgKey}: ${deleteError}`);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
@@ -3266,5 +3290,182 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
|
|
|
|
|
// ==================== 辅助方法 ====================
|
|
// ==================== 辅助方法 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 初始化图片缓存目录
|
|
|
|
|
+ */
|
|
|
|
|
+ private async initImageCacheDirectory(): Promise<void> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (this.context) {
|
|
|
|
|
+ const cacheDir = this.context.getApplicationContext().cacheDir;
|
|
|
|
|
+ this.imageCacheDir = cacheDir + '/cover_images';
|
|
|
|
|
+
|
|
|
|
|
+ // 创建缓存目录
|
|
|
|
|
+ if (!fileIo.accessSync(this.imageCacheDir)) {
|
|
|
|
|
+ fileIo.mkdirSync(this.imageCacheDir);
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Created image cache directory: ${this.imageCacheDir}`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 清理过期缓存
|
|
|
|
|
+ await this.cleanExpiredCache();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to initialize image cache directory: ${error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 生成图片URL的哈希值作为缓存文件名
|
|
|
|
|
+ */
|
|
|
|
|
+ private generateCacheFileName(url: string): string {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const textEncoder = new util.TextEncoder();
|
|
|
|
|
+ const data = textEncoder.encodeInto(url);
|
|
|
|
|
+
|
|
|
|
|
+ // 使用URL的简单哈希算法
|
|
|
|
|
+ let hash = 0;
|
|
|
|
|
+ for (let i = 0; i < data.byteLength; i++) {
|
|
|
|
|
+ const char = data[i];
|
|
|
|
|
+ hash = ((hash << 5) - hash) + char;
|
|
|
|
|
+ hash = hash & hash; // 转换为32位整数
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Math.abs(hash).toString(16) + '.jpg';
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ // 如果哈希生成失败,使用URL的简单替换方案
|
|
|
|
|
+ return url.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 50) + '.jpg';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查缓存文件是否存在且未过期
|
|
|
|
|
+ */
|
|
|
|
|
+ private async isCacheValid(cacheFilePath: string): Promise<boolean> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (!fileIo.accessSync(cacheFilePath)) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const stat = fileIo.statSync(cacheFilePath);
|
|
|
|
|
+ const fileAge = Date.now() - stat.mtime;
|
|
|
|
|
+ const maxAge = this.CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000; // 转换为毫秒
|
|
|
|
|
+
|
|
|
|
|
+ return fileAge < maxAge;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to check cache validity: ${error}`);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 下载网络图片到缓存
|
|
|
|
|
+ */
|
|
|
|
|
+ private async downloadImageToCache(url: string, cacheFilePath: string): Promise<boolean> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const httpRequest = http.createHttp();
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await httpRequest.request(url, {
|
|
|
|
|
+ method: http.RequestMethod.GET,
|
|
|
|
|
+ connectTimeout: 10000, // 10秒超时
|
|
|
|
|
+ readTimeout: 10000
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (response.responseCode === http.ResponseCode.OK && response.result) {
|
|
|
|
|
+ const tempFile = fileIo.openSync(cacheFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await fileIo.write(tempFile.fd, response.result as ArrayBuffer);
|
|
|
|
|
+ fileIo.closeSync(tempFile.fd);
|
|
|
|
|
+
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Downloaded image to cache: ${cacheFilePath}`);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (writeError) {
|
|
|
|
|
+ fileIo.closeSync(tempFile.fd);
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Write error: ${writeError}`);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to download image ${url}: HTTP ${response.responseCode}`);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ httpRequest.destroy();
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Error downloading image to cache: ${error}`);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 清理过期缓存
|
|
|
|
|
+ */
|
|
|
|
|
+ private async cleanExpiredCache(): Promise<void> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (!this.imageCacheDir || !fileIo.accessSync(this.imageCacheDir)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const files = fileIo.listFileSync(this.imageCacheDir);
|
|
|
|
|
+ const maxAge = this.CACHE_EXPIRY_DAYS * 24 * 60 * 60 * 1000;
|
|
|
|
|
+ let totalSize = 0;
|
|
|
|
|
+ const fileInfos: Array<CacheFileInfo> = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 收集文件信息
|
|
|
|
|
+ for (const file of files) {
|
|
|
|
|
+ const filePath = this.imageCacheDir + '/' + file;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const stat = fileIo.statSync(filePath);
|
|
|
|
|
+ totalSize += stat.size;
|
|
|
|
|
+ const fileInfo: CacheFileInfo = {
|
|
|
|
|
+ path: filePath,
|
|
|
|
|
+ size: stat.size,
|
|
|
|
|
+ mtime: stat.mtime
|
|
|
|
|
+ };
|
|
|
|
|
+ fileInfos.push(fileInfo);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ // 忽略无法读取的文件
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除过期文件
|
|
|
|
|
+ const now = Date.now();
|
|
|
|
|
+ for (const fileInfo of fileInfos) {
|
|
|
|
|
+ if (now - fileInfo.mtime > maxAge) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ fileIo.unlinkSync(fileInfo.path);
|
|
|
|
|
+ totalSize -= fileInfo.size;
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Deleted expired cache file: ${fileInfo.path}`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to delete expired cache file: ${error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果缓存大小超限,删除最旧的文件
|
|
|
|
|
+ const maxSizeBytes = this.MAX_CACHE_SIZE_MB * 1024 * 1024;
|
|
|
|
|
+ if (totalSize > maxSizeBytes) {
|
|
|
|
|
+ const sortedFiles = fileInfos
|
|
|
|
|
+ .filter(f => fileIo.accessSync(f.path)) // 只保留仍存在的文件
|
|
|
|
|
+ .sort((a, b) => a.mtime - b.mtime); // 按修改时间排序,最旧的在前
|
|
|
|
|
+
|
|
|
|
|
+ for (const fileInfo of sortedFiles) {
|
|
|
|
|
+ if (totalSize <= maxSizeBytes) break;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ fileIo.unlinkSync(fileInfo.path);
|
|
|
|
|
+ totalSize -= fileInfo.size;
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Deleted cache file due to size limit: ${fileInfo.path}`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to delete cache file: ${error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Cache cleanup completed, total size: ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI(`UnifiedPlayerService: Failed to clean expired cache: ${error}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
|
|
|
}
|
|
}
|