mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(desktop): stop reading whole voice backgrounds to classify them (#1839)
This commit is contained in:
1 parent
c8ff177f85
commit
7ec155eac1
6 files changed
+58
-28
No files matched your search
@@ -319,7 +319,6 @@ export interface ElectronAPI {
|
||||
clearThemeLocalFiles: () => Promise<void>;
|
||||
importThemeDirectory: () => Promise<Array<ThemeDirectoryCssFile>>;
|
||||
cacheVoiceBackgroundMedia: (options: VoiceBackgroundMediaCacheRequest) => Promise<VoiceBackgroundMediaCacheResult>;
|
||||
resolveVoiceBackgroundMedia: (id: string) => Promise<VoiceBackgroundMediaCacheResult | null>;
|
||||
readVoiceBackgroundMedia: (id: string) => Promise<VoiceBackgroundMediaReadResult | null>;
|
||||
deleteVoiceBackgroundMedia: (id: string) => Promise<void>;
|
||||
onUpdaterEvent: (callback: (event: UpdaterEvent) => void) => () => void;
|
||||
|
||||
Vendored
-1
@@ -377,7 +377,6 @@ export interface ElectronAPI {
|
||||
clearThemeLocalFiles?(): Promise<void>;
|
||||
importThemeDirectory?(): Promise<Array<ThemeDirectoryCssFile>>;
|
||||
cacheVoiceBackgroundMedia?(options: VoiceBackgroundMediaCacheRequest): Promise<VoiceBackgroundMediaCacheResult>;
|
||||
resolveVoiceBackgroundMedia?(id: string): Promise<VoiceBackgroundMediaCacheResult | null>;
|
||||
readVoiceBackgroundMedia?(id: string): Promise<VoiceBackgroundMediaReadResult | null>;
|
||||
deleteVoiceBackgroundMedia?(id: string): Promise<void>;
|
||||
getDesktopTroubleshootingSettings?(): Promise<DesktopTroubleshootingSettings>;
|
||||
|
||||
@@ -656,7 +656,6 @@ export interface ElectronAPI {
|
||||
clearThemeLocalFiles: () => Promise<void>;
|
||||
importThemeDirectory: () => Promise<Array<ThemeDirectoryCssFile>>;
|
||||
cacheVoiceBackgroundMedia: (options: VoiceBackgroundMediaCacheRequest) => Promise<VoiceBackgroundMediaCacheResult>;
|
||||
resolveVoiceBackgroundMedia: (id: string) => Promise<VoiceBackgroundMediaCacheResult | null>;
|
||||
readVoiceBackgroundMedia: (id: string) => Promise<VoiceBackgroundMediaReadResult | null>;
|
||||
deleteVoiceBackgroundMedia: (id: string) => Promise<void>;
|
||||
getDesktopTroubleshootingSettings: () => Promise<DesktopTroubleshootingSettings>;
|
||||
|
||||
@@ -87,3 +87,19 @@ describe('ChromiumRuntime Windows capture policy', () => {
|
||||
assert.deepEqual([...features], ['ExistingFeature']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ChromiumRuntime configured switch allowlist', () => {
|
||||
test('rejects settings-supplied switches that would disable or shrink the HTTP cache', () => {
|
||||
const {appendedSwitches, module} = loadChromiumRuntime('win32');
|
||||
|
||||
module.appendConfiguredChromiumSwitches([
|
||||
'disable-http-cache',
|
||||
'disk-cache-size',
|
||||
'disk-cache-dir',
|
||||
'disable-gpu-shader-disk-cache',
|
||||
'disable_metal',
|
||||
]);
|
||||
|
||||
assert.deepEqual(appendedSwitches, [{name: 'disable_metal', value: undefined}]);
|
||||
});
|
||||
});
|
||||
@@ -15,6 +15,8 @@ const CACHE_DIR_NAME = 'voice-background-media';
|
||||
const MAX_BACKGROUND_MEDIA_BYTES = 10 * 1024 * 1024;
|
||||
const MAX_BACKGROUND_MEDIA_CACHE_FILES = 16;
|
||||
const MAX_BACKGROUND_MEDIA_ID_LENGTH = 128;
|
||||
const MAX_BACKGROUND_MEDIA_TEMP_AGE_MS = 60 * 60 * 1000;
|
||||
const WEBP_HEADER_BYTES = 1024;
|
||||
|
||||
const MEDIA_TYPES = new Map<
|
||||
string,
|
||||
@@ -82,7 +84,7 @@ function isAnimatedWebp(data: Buffer): boolean {
|
||||
if (data.subarray(12, 16).toString('ascii') === 'VP8X') {
|
||||
return (data[20] & 0b0000_0010) !== 0;
|
||||
}
|
||||
return data.includes(Buffer.from('ANMF', 'ascii'));
|
||||
return data.subarray(0, WEBP_HEADER_BYTES).includes(Buffer.from('ANMF', 'ascii'));
|
||||
}
|
||||
|
||||
function classifyMediaKind(
|
||||
@@ -95,6 +97,20 @@ function classifyMediaKind(
|
||||
return mediaType.mediaKind;
|
||||
}
|
||||
|
||||
async function readMediaHeader(filePath: string, byteLength: number): Promise<Buffer | null> {
|
||||
const handle = await fs.open(filePath, 'r').catch(() => null);
|
||||
if (!handle) return null;
|
||||
try {
|
||||
const header = Buffer.alloc(byteLength);
|
||||
const {bytesRead} = await handle.read(header, 0, byteLength, 0);
|
||||
return header.subarray(0, bytesRead);
|
||||
} catch {
|
||||
return null;
|
||||
} finally {
|
||||
await handle.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
async function findCachedVoiceBackgroundMedia(
|
||||
id: string,
|
||||
): Promise<{path: string; mimeType: string; mediaKind: VoiceBackgroundMediaKind} | null> {
|
||||
@@ -110,9 +126,9 @@ async function findCachedVoiceBackgroundMedia(
|
||||
const filePath = path.join(cacheDir, entry.name);
|
||||
let mediaKind = mediaType.mediaKind;
|
||||
if (mediaType.extension === 'webp') {
|
||||
const data = await fs.readFile(filePath).catch(() => null);
|
||||
if (!data) continue;
|
||||
mediaKind = classifyMediaKind(mediaType, data);
|
||||
const header = await readMediaHeader(filePath, WEBP_HEADER_BYTES);
|
||||
if (!header) continue;
|
||||
mediaKind = classifyMediaKind(mediaType, header);
|
||||
}
|
||||
return {
|
||||
path: filePath,
|
||||
@@ -124,20 +140,29 @@ async function findCachedVoiceBackgroundMedia(
|
||||
}
|
||||
|
||||
async function trimVoiceBackgroundMediaCache(cacheDir: string): Promise<void> {
|
||||
const entries = await fs.readdir(cacheDir, {withFileTypes: true});
|
||||
const files = await Promise.all(
|
||||
entries
|
||||
.filter((entry) => entry.isFile())
|
||||
.map(async (entry) => {
|
||||
const filePath = path.join(cacheDir, entry.name);
|
||||
const stats = await fs.stat(filePath);
|
||||
return {filePath, mtimeMs: stats.mtimeMs};
|
||||
}),
|
||||
const entries = await fs.readdir(cacheDir, {withFileTypes: true}).catch(() => []);
|
||||
const now = Date.now();
|
||||
const cachedMedia: Array<{filePath: string; mtimeMs: number}> = [];
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile()) continue;
|
||||
const filePath = path.join(cacheDir, entry.name);
|
||||
const stats = await fs.stat(filePath).catch(() => null);
|
||||
if (!stats) continue;
|
||||
const extension = path.extname(entry.name).slice(1).toLowerCase();
|
||||
if (!MEDIA_TYPES_BY_EXTENSION.has(extension)) {
|
||||
if (now - stats.mtimeMs > MAX_BACKGROUND_MEDIA_TEMP_AGE_MS) {
|
||||
await fs.rm(filePath, {force: true}).catch(() => undefined);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
cachedMedia.push({filePath, mtimeMs: stats.mtimeMs});
|
||||
}
|
||||
if (cachedMedia.length <= MAX_BACKGROUND_MEDIA_CACHE_FILES) return;
|
||||
cachedMedia.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
||||
const deleteCount = cachedMedia.length - MAX_BACKGROUND_MEDIA_CACHE_FILES;
|
||||
await Promise.all(
|
||||
cachedMedia.slice(0, deleteCount).map(({filePath}) => fs.rm(filePath, {force: true}).catch(() => undefined)),
|
||||
);
|
||||
if (files.length <= MAX_BACKGROUND_MEDIA_CACHE_FILES) return;
|
||||
files.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
||||
const deleteCount = files.length - MAX_BACKGROUND_MEDIA_CACHE_FILES;
|
||||
await Promise.all(files.slice(0, deleteCount).map(({filePath}) => fs.rm(filePath, {force: true})));
|
||||
}
|
||||
|
||||
async function cacheVoiceBackgroundMedia(
|
||||
@@ -165,12 +190,6 @@ async function cacheVoiceBackgroundMedia(
|
||||
return {path: filePath, mediaKind};
|
||||
}
|
||||
|
||||
async function resolveVoiceBackgroundMedia(id: string): Promise<VoiceBackgroundMediaCacheResult | null> {
|
||||
const cached = await findCachedVoiceBackgroundMedia(id);
|
||||
if (!cached) return null;
|
||||
return {path: cached.path, mediaKind: cached.mediaKind};
|
||||
}
|
||||
|
||||
async function readVoiceBackgroundMedia(id: string): Promise<VoiceBackgroundMediaReadResult | null> {
|
||||
const cached = await findCachedVoiceBackgroundMedia(id);
|
||||
if (!cached) return null;
|
||||
@@ -200,7 +219,6 @@ export function registerVoiceBackgroundMediaCacheHandlers(): void {
|
||||
ipcMain.handle('voice-background-media-cache:write', (_event, options: VoiceBackgroundMediaCacheRequest) =>
|
||||
cacheVoiceBackgroundMedia(options),
|
||||
);
|
||||
ipcMain.handle('voice-background-media-cache:resolve', (_event, id: string) => resolveVoiceBackgroundMedia(id));
|
||||
ipcMain.handle('voice-background-media-cache:read', (_event, id: string) => readVoiceBackgroundMedia(id));
|
||||
ipcMain.handle('voice-background-media-cache:delete', (_event, id: string) => deleteVoiceBackgroundMedia(id));
|
||||
}
|
||||
@@ -357,7 +357,6 @@ const api: ElectronAPI = {
|
||||
clearThemeLocalFiles: () => ipcRenderer.invoke('theme-local-files-clear'),
|
||||
importThemeDirectory: () => ipcRenderer.invoke('theme-directory-import'),
|
||||
cacheVoiceBackgroundMedia: (options) => ipcRenderer.invoke('voice-background-media-cache:write', options),
|
||||
resolveVoiceBackgroundMedia: (id) => ipcRenderer.invoke('voice-background-media-cache:resolve', id),
|
||||
readVoiceBackgroundMedia: (id) => ipcRenderer.invoke('voice-background-media-cache:read', id),
|
||||
deleteVoiceBackgroundMedia: (id) => ipcRenderer.invoke('voice-background-media-cache:delete', id),
|
||||
getDesktopTroubleshootingSettings: (): Promise<DesktopTroubleshootingSettings> =>
|
||||
|
||||
Reference in new issue
Block a user