From 800bbee770442ca005f419d8ea5f66378b7d22b5 Mon Sep 17 00:00:00 2001 From: Richard McCorkle Date: Sun, 17 May 2026 20:20:37 +0200 Subject: [PATCH] refactor: remove dead class members flagged by fallow Fallow dead-code analysis flagged 13 issues. Removed the 10 that are genuinely unreferenced: - LLMFactory.getBestProvider, LLMFactory.updateSettings - GeminiClient.isAvailable, OllamaClient.isAvailable - ProcessingSpinner.setLabel, plus the now-dead callCount field and its '#N' suffix in the spinner text (setLabel was callCount's only writer, so the counter had been stuck at 0 already) - YouTubeTranscriptExtractor.fetchTranscriptSegments, combineTranscript, clearConfigCache, parseJsonCaptions - dropped the unused 'export' on the CaptionTrack interface (still used locally in the file, just never imported elsewhere) Kept OllamaClient.validateConnection and createChatCompletion: fallow flagged them, but transcript-summarizer.ts calls them via a loosely typed 'client' variable that fallow cannot statically resolve. Build and lint pass clean. Co-Authored-By: Claude Opus 4.7 --- src/llm/gemini-client.ts | 8 --- src/llm/llm-factory.ts | 10 ---- src/llm/ollama-client.ts | 10 ---- src/utils/processing-spinner.ts | 13 +---- src/youtube-transcript.ts | 93 +-------------------------------- 5 files changed, 3 insertions(+), 131 deletions(-) diff --git a/src/llm/gemini-client.ts b/src/llm/gemini-client.ts index 5687571..f986270 100644 --- a/src/llm/gemini-client.ts +++ b/src/llm/gemini-client.ts @@ -32,14 +32,6 @@ export class GeminiClient { logger.debug('Creating Gemini client'); } - /** - * Check if the client can be used on the current platform - */ - isAvailable(): boolean { - // Gemini should work on all platforms through our fetch shim - return true; - } - /** * Generate content using a Gemini model * diff --git a/src/llm/llm-factory.ts b/src/llm/llm-factory.ts index e787e2d..d20b717 100644 --- a/src/llm/llm-factory.ts +++ b/src/llm/llm-factory.ts @@ -25,10 +25,6 @@ export class LLMFactory { logger.debug('Created LLM Factory'); } - getBestProvider(): string { - return this.settings.selectedLLM; - } - getOllamaClient(): OllamaClient { if (!this.ollamaClient) { const baseUrl = this.settings.apiKeys['ollama'] || 'http://localhost:11434'; @@ -36,10 +32,4 @@ export class LLMFactory { } return this.ollamaClient; } - - updateSettings(settings: LLMSettings): void { - this.settings = settings; - this.ollamaClient = null; - logger.debug('LLM Factory settings updated'); - } } diff --git a/src/llm/ollama-client.ts b/src/llm/ollama-client.ts index d848024..5c3876e 100644 --- a/src/llm/ollama-client.ts +++ b/src/llm/ollama-client.ts @@ -41,16 +41,6 @@ export class OllamaClient { logger.debug('Ollama client created with base URL:', baseUrl); } - /** - * Check if Ollama can be used on the current platform - */ - isAvailable(): boolean { - // Ollama should work on all platforms with the unified fetch shim - // However, users need to ensure their Ollama server is accessible - // from their device (typically via localhost on same network) - return true; - } - /** * Validate that the Ollama server is accessible */ diff --git a/src/utils/processing-spinner.ts b/src/utils/processing-spinner.ts index 113501d..51a10e0 100644 --- a/src/utils/processing-spinner.ts +++ b/src/utils/processing-spinner.ts @@ -13,14 +13,12 @@ const SPINNER_INTERVAL_MS = 100; * Mobile: Obsidian has no status bar, so it renders a text element inside * the supplied modal content element instead. Same Braille frames either way. * - * Lifecycle: `start()` mounts and animates; `setLabel(text)` updates the - * per-step label and bumps the call counter; `stop()` removes the spinner + * Lifecycle: `start()` mounts and animates; `stop()` removes the spinner * and clears the interval. Safe to call `stop()` more than once. */ export class ProcessingSpinner { private statusBarItem: HTMLElement | null = null; private modalSpinnerEl: HTMLElement | null = null; - private callCount = 0; private currentLabel: string; private spinnerFrame = 0; private spinnerHandle: number | null = null; @@ -48,13 +46,6 @@ export class ProcessingSpinner { }, SPINNER_INTERVAL_MS); } - /** Update the per-step label and bump the call counter. */ - setLabel(label: string): void { - if (label) this.currentLabel = label; - this.callCount += 1; - this.render(); - } - /** Removes the spinner and stops the animation. Safe to call more than once. */ stop(): void { if (this.spinnerHandle !== null) { @@ -73,7 +64,7 @@ export class ProcessingSpinner { private render(): void { const spinner = SPINNER_FRAMES[this.spinnerFrame]; - const text = `${spinner} ${this.prefix} · ${this.currentLabel} · #${this.callCount}`; + const text = `${spinner} ${this.prefix} · ${this.currentLabel}`; if (this.statusBarItem) this.statusBarItem.setText(text); if (this.modalSpinnerEl) this.modalSpinnerEl.setText(text); } diff --git a/src/youtube-transcript.ts b/src/youtube-transcript.ts index c8d6836..846cf05 100644 --- a/src/youtube-transcript.ts +++ b/src/youtube-transcript.ts @@ -22,7 +22,7 @@ const isString = (value: unknown): value is string => typeof value === 'string'; /** * Interface for YouTube caption tracks */ -export interface CaptionTrack { +interface CaptionTrack { languageCode: string; kind?: string; // "asr" for auto-generated baseUrl?: string; @@ -240,18 +240,6 @@ export class YouTubeTranscriptExtractor { } } - /** - * Extracts only transcript segments from a YouTube video (backward compatibility) - * @param videoId YouTube video ID - * @param options Optional language and country settings - * @returns Promise with transcript segments only - */ - static async fetchTranscriptSegments(videoId: string, options: TranscriptOptions = {}): Promise { - const result = await this.fetchTranscript(videoId, options); - return result.segments; - } - - /** * Get video metadata from the player response * @param videoId YouTube video ID @@ -292,15 +280,6 @@ export class YouTubeTranscriptExtractor { } } - /** - * Combines transcript segments into a single text - * @param segments Array of transcript segments - * @returns Combined transcript text - */ - static combineTranscript(segments: TranscriptSegment[]): string { - return segments.map(segment => segment.text).join(' '); - } - /** * Extracts video ID from a YouTube URL * @param url YouTube video URL @@ -614,15 +593,6 @@ export class YouTubeTranscriptExtractor { return response.text(); } - /** - * Clear the cached YouTube config (useful for testing or after errors) - */ - static clearConfigCache(): void { - this.cachedConfig = null; - this.cachedVideoId = null; - transcriptLogger.debug('YouTube config cache cleared'); - } - /** * Select the best caption track for a requested language. * Priority: manual+exact → manual+base → auto+exact → auto+base @@ -1545,65 +1515,4 @@ export class YouTubeTranscriptExtractor { } } - /** - * Parses YouTube captions in JSON format - * @param jsonText The JSON content of captions - * @param videoId Video ID for reference - * @returns Parsed transcript segments - */ - static parseJsonCaptions(jsonText: string, videoId: string): TranscriptSegment[] { - transcriptLogger.debug(`Parsing JSON captions for video ${videoId}`); - - try { - const transcriptJson = JSON.parse(jsonText) as { events?: unknown[] }; - const events = Array.isArray(transcriptJson.events) ? transcriptJson.events : []; - - // Convert events to our TranscriptSegment format - const segments: TranscriptSegment[] = []; - - events - .filter((event): event is { segs?: Array<{ utf8?: string }>; tStartMs?: string; dDurationMs?: string } => { - return isRecord(event) && Array.isArray(event.segs); - }) - .forEach((event) => { - const startMs = event.tStartMs ? parseInt(event.tStartMs) : 0; - const durationMs = event.dDurationMs ? parseInt(event.dDurationMs) : 0; - - // Combine all segments in this event - const text = (event.segs ?? []) - .map((seg) => seg.utf8 || '') - .join('') - .replace(/[\u200B-\u200D\uFEFF]/g, ''); // Remove special chars - - const trimmedText = text.trim(); - if (trimmedText) { - segments.push({ - text: trimmedText, - start: startMs / 1000, // Convert to seconds - duration: durationMs / 1000 // Convert to seconds - }); - } - }); - - if (segments.length === 0) { - throw new Error(`No transcript segments found in JSON data. Video ID: ${videoId}`); - } - - return segments; - - } catch (e) { - const errorMessage = getSafeErrorMessage(e); - transcriptLogger.error("Error parsing JSON captions:", errorMessage); - - // Return a basic error segment - return [ - { - text: `Failed to parse YouTube JSON captions for video ${videoId}. Error: ${errorMessage}`, - start: 0, - duration: 0 - } - ]; - } - } - }