From 23e69d0b7704972b8ff2529b2f2677897b2543af Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 15 May 2026 18:10:00 +0200 Subject: [PATCH] refactor(01-06): delete inline copy-offscreen plugin and orphan offscreen/ directory - Delete vite.config.ts inline copy-offscreen plugin (lines 13-216): the 174-line plugin that emitFile'd both offscreen HTML and a stringified JS module wired to tabCapture-era chromeMediaSource + IndexedDB pipeline (audit P0 #1 root cause; D-08 deletion target) - Delete vite.config.ts misplaced publicDir/copyPublicDir (no public/ dir exists; audit P2 #17) and the manualChunks=undefined shape - Rewrite vite.config.ts to RESEARCH.md Example B form: crx() + a single rollupOptions.input.offscreen pointing at src/offscreen/index.html (the crxjs-managed entry Plan 03 created); 21 lines total - Delete orphan offscreen/index.ts (audit P2 #18 dead-code, D-08) - Delete orphan offscreen/index.html (replaced by src/offscreen/index.html per D-07; runtime URL semantics preserved through crxjs entry binding) - T-1-NEW-06-01 grep gate green (this.emitFile = 0) - T-1-NEW-06-02 grep gate green (offscreen/ directory absent) - tsc --noEmit clean; 9/9 vitest tests still green Co-Authored-By: Claude Opus 4.7 (1M context) --- offscreen/index.html | 10 -- offscreen/index.ts | 60 ------------ vite.config.ts | 222 ++----------------------------------------- 3 files changed, 8 insertions(+), 284 deletions(-) delete mode 100644 offscreen/index.html delete mode 100644 offscreen/index.ts diff --git a/offscreen/index.html b/offscreen/index.html deleted file mode 100644 index f0d3d66..0000000 --- a/offscreen/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Offscreen Page - - - - - \ No newline at end of file diff --git a/offscreen/index.ts b/offscreen/index.ts deleted file mode 100644 index 0621aa2..0000000 --- a/offscreen/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -let mediaRecorder: MediaRecorder | null = null; -let videoChunks: Blob[] = []; - -// Запись видео -async function startRecording(streamId: string) { - const stream = await navigator.mediaDevices.getUserMedia({ - video: { - mandatory: { - chromeMediaSource: 'tab', - chromeMediaSourceId: streamId - } - } as any, - audio: false - }); - - mediaRecorder = new MediaRecorder(stream); - - mediaRecorder.ondataavailable = (event) => { - if (event.data && event.data.size > 0) { - videoChunks.push(event.data); - chrome.runtime.sendMessage({ - type: 'VIDEO_CHUNK', - data: event.data, - timestamp: Date.now() - }); - } - }; - - mediaRecorder.start(1000); -} - -// Остановка записи -function stopRecording() { - if (mediaRecorder && mediaRecorder.state !== 'inactive') { - mediaRecorder.stop(); - } -} - -// Получение чанков -function getChunks(): Blob[] { - return videoChunks; -} - -// Обработка сообщений -chrome.runtime.onMessage.addListener((message) => { - switch (message.type) { - case 'START_RECORDING': - startRecording(message.streamId); - break; - case 'STOP_RECORDING': - stopRecording(); - break; - case 'GET_CHUNKS': - chrome.runtime.sendMessage({ - type: 'CHUNKS_RESPONSE', - chunks: getChunks() - }); - break; - } -}); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 4c94919..a41d252 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,6 @@ -import { defineConfig } from 'vite' -import { crx } from '@crxjs/vite-plugin' -import manifest from './manifest.json' +import { defineConfig } from 'vite'; +import { crx } from '@crxjs/vite-plugin'; +import manifest from './manifest.json'; export default defineConfig({ plugins: [ @@ -10,218 +10,12 @@ export default defineConfig({ injectCss: false, }, }), - { - name: 'copy-offscreen', - generateBundle() { - this.emitFile({ - type: 'asset', - fileName: 'offscreen/index.html', - source: ` - - - - - Offscreen Page - - - - - -` - }); - this.emitFile({ - type: 'asset', - fileName: 'assets/offscreen.js', - source: ` -let mediaRecorder = null; -let videoChunks = []; -let chunkCount = 0; - -// IndexedDB для хранения видеочанков -let db = null; - -function openIndexedDB() { - return new Promise((resolve, reject) => { - const request = indexedDB.open('VideoRecorderDB', 1); - - request.onerror = () => reject(request.error); - request.onsuccess = () => { - db = request.result; - resolve(db); - }; - - request.onupgradeneeded = (event) => { - const db = event.target.result; - if (!db.objectStoreNames.contains('chunks')) { - db.createObjectStore('chunks', { keyPath: 'id' }); - } - }; - }); -} - -async function saveChunkToIndexedDB(blob, chunkId) { - if (!db) { - await openIndexedDB(); - } - - return new Promise((resolve, reject) => { - const transaction = db.transaction(['chunks'], 'readwrite'); - const store = transaction.objectStore('chunks'); - - const request = store.put({ - id: chunkId, - data: blob, - timestamp: Date.now() - }); - - request.onerror = () => reject(request.error); - request.onsuccess = () => { - console.log('[Offscreen] Chunk', chunkId, 'saved to IndexedDB, size:', blob.size); - // Отправляем уведомление в Service Worker - chrome.runtime.sendMessage({ - type: 'VIDEO_CHUNK_SAVED', - chunkId: chunkId, - size: blob.size - }); - resolve(); - }; - }); -} - -async function clearOldChunks() { - if (!db) { - await openIndexedDB(); - } - - return new Promise((resolve, reject) => { - const transaction = db.transaction(['chunks'], 'readwrite'); - const store = transaction.objectStore('chunks'); - const request = store.clear(); - - request.onerror = () => reject(request.error); - request.onsuccess = () => { - console.log('[Offscreen] Cleared old chunks from IndexedDB'); - resolve(); - }; - }); -} - -chrome.runtime.onMessage.addListener((message) => { - console.log('[Offscreen] Received message:', message.type); - switch (message.type) { - case 'START_RECORDING': - startRecording(message.streamId); - break; - case 'STOP_RECORDING': - stopRecording(); - break; - } -}); - -async function startRecording(streamId) { - console.log('[Offscreen] Starting recording with streamId:', streamId); - - // Инициализируем IndexedDB - await openIndexedDB(); - console.log('[Offscreen] IndexedDB initialized'); - - // Очищаем старые чанки - await clearOldChunks(); - - try { - const stream = await navigator.mediaDevices.getUserMedia({ - video: { - mandatory: { - chromeMediaSource: 'tab', - chromeMediaSourceId: streamId - } - }, - audio: false - }); - - console.log('[Offscreen] Stream created, tracks:', stream.getTracks().length); - const videoTrack = stream.getVideoTracks()[0]; - if (videoTrack) { - console.log('[Offscreen] Video track settings:', videoTrack.getSettings()); - console.log('[Offscreen] Video track readyState:', videoTrack.readyState); - console.log('[Offscreen] Video track enabled:', videoTrack.enabled); - } - - // Пробуем разные кодеки - const codecs = [ - 'video/webm; codecs=vp9', - 'video/webm; codecs=vp8', - 'video/webm; codecs=h264', - 'video/webm' - ]; - - let mediaRecorder = null; - for (const codec of codecs) { - try { - mediaRecorder = new MediaRecorder(stream, { mimeType: codec }); - console.log('[Offscreen] MediaRecorder created with codec:', codec, 'state:', mediaRecorder.state); - break; - } catch (e) { - console.log('[Offscreen] Codec', codec, 'not supported:', e.message); - } - } - - if (!mediaRecorder) { - mediaRecorder = new MediaRecorder(stream); - console.log('[Offscreen] Using default MediaRecorder'); - } - - mediaRecorder.ondataavailable = (event) => { - console.log('[Offscreen] Data available:', event.data.size, 'bytes, type:', event.data.type); - if (event.data && event.data.size > 0) { - chunkCount++; - console.log('[Offscreen] Sending chunk', chunkCount, 'to background, size:', event.data.size); - - // Сохраняем в indexedDB вместо передачи через сообщения - saveChunkToIndexedDB(event.data, chunkCount); - } else { - console.log('[Offscreen] Data available but size is 0, skipping'); - } - }; - - mediaRecorder.onerror = (event) => { - console.error('[Offscreen] MediaRecorder error:', event); - }; - - mediaRecorder.onstart = () => { - console.log('[Offscreen] MediaRecorder started, state:', mediaRecorder.state); - }; - - mediaRecorder.onstop = () => { - console.log('[Offscreen] MediaRecorder stopped, state:', mediaRecorder.state, 'total chunks:', chunkCount); - }; - - // Используем интервал 200мс для более частого получения чанков с ключевыми кадрами - mediaRecorder.start(200); - console.log('[Offscreen] Recording started with interval 200ms'); - } catch (error) { - console.error('[Offscreen] Error starting recording:', error); - } -} - -function stopRecording() { - if (mediaRecorder && mediaRecorder.state !== 'inactive') { - mediaRecorder.stop(); - console.log('[Offscreen] Recording stopped'); - } -} -` - }); - } - } ], build: { rollupOptions: { - output: { - manualChunks: undefined - } + input: { + offscreen: 'src/offscreen/index.html', + }, }, - copyPublicDir: true, - publicDir: 'public', - } -}) \ No newline at end of file + }, +});