diff --git a/docs/YouTube-Processing.md b/docs/YouTube-Processing.md index b5626f71..b86929d8 100644 --- a/docs/YouTube-Processing.md +++ b/docs/YouTube-Processing.md @@ -215,6 +215,19 @@ fabric -y "https://www.youtube.com/watch?v=VIDEO_ID" --pattern write_blog_post - **Try without language specification** - let yt-dlp choose any available language - **Try English instead** - `fabric -g en` (English subtitles may be less rate-limited) +### Language Fallback Behavior + +When you specify a language (e.g., `-g es` for Spanish) but that language isn't available or fails to download: + +1. **Automatic fallback**: Fabric automatically retries without language specification +2. **Smart file detection**: If the fallback downloads a different language (e.g., English), Fabric will automatically detect and use it +3. **No manual intervention needed**: The process is transparent to the user + +```bash +# Even if Spanish isn't available, this will work with whatever language yt-dlp finds +fabric -g es -y "https://youtube.com/watch?v=VIDEO_ID" --pattern summarize +``` + ## Configuration ### YAML Configuration diff --git a/internal/tools/youtube/youtube.go b/internal/tools/youtube/youtube.go index 7ffa65bf..629d9f22 100644 --- a/internal/tools/youtube/youtube.go +++ b/internal/tools/youtube/youtube.go @@ -269,8 +269,10 @@ func (o *YouTube) tryMethodYtDlpInternal(videoId string, language string, additi return } } + // Find VTT files using cross-platform approach - vttFiles, err := o.findVTTFiles(tempDir, language) + // Try to find files with the requested language first, but fall back to any VTT file + vttFiles, err := o.findVTTFilesWithFallback(tempDir, language) if err != nil { return "", err } @@ -719,9 +721,11 @@ func (o *YouTube) findVTTFiles(dir, language string) ([]string, error) { } // Prefer files with the specified language - for _, file := range vttFiles { - if strings.Contains(file, "."+language+".vtt") { - return []string{file}, nil + if language != "" { + for _, file := range vttFiles { + if strings.Contains(file, "."+language+".vtt") { + return []string{file}, nil + } } } @@ -729,6 +733,56 @@ func (o *YouTube) findVTTFiles(dir, language string) ([]string, error) { return []string{vttFiles[0]}, nil } +// findVTTFilesWithFallback searches for VTT files, handling fallback scenarios +// where the requested language might not be available +func (o *YouTube) findVTTFilesWithFallback(dir, requestedLanguage string) ([]string, error) { + var vttFiles []string + + // Walk through the directory to find VTT files + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if !info.IsDir() && strings.HasSuffix(strings.ToLower(path), ".vtt") { + vttFiles = append(vttFiles, path) + } + return nil + }) + + if err != nil { + return nil, fmt.Errorf("failed to walk directory: %v", err) + } + + if len(vttFiles) == 0 { + return nil, fmt.Errorf("no VTT files found in directory") + } + + // If no specific language requested, return the first file + if requestedLanguage == "" { + return []string{vttFiles[0]}, nil + } + + // First, try to find files with the requested language + for _, file := range vttFiles { + if strings.Contains(file, "."+requestedLanguage+".vtt") { + return []string{file}, nil + } + } + + // If requested language not found, check if we have any language-specific files + // This handles the fallback case where yt-dlp downloaded a different language + for _, file := range vttFiles { + // Look for any language pattern (e.g., .en.vtt, .es.vtt, etc.) + if matched, _ := regexp.MatchString(`\.[a-z]{2}(-[A-Z]{2})?\.vtt$`, file); matched { + return []string{file}, nil + } + } + + // If no language-specific files found, return the first VTT file + return []string{vttFiles[0]}, nil +} + type VideoMeta struct { Id string Title string