mirror of
https://github.com/rmccorkl/TubeSage.git
synced 2026-07-22 06:45:31 +00:00
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 <noreply@anthropic.com>
This commit is contained in:
parent
65a17f83d5
commit
800bbee770
5 changed files with 3 additions and 131 deletions
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TranscriptSegment[]> {
|
||||
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
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue