Fetch transcripts with timestamps

YouTube exposes caption tracks through an unofficial API. The Python library youtube-transcript-api wraps it nicely. We get back a list of snippets, and each snippet carries text, a start time in seconds, and a duration. That timestamp data is gold: it is what lets us cite a specific second later.

transcript.py
python
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api._errors import (
    NoTranscriptFound, TranscriptsDisabled, VideoUnavailable,
    CouldNotRetrieveTranscript,
)


def fetch_transcript(video_id: str) -> list[dict]:
    """Fetch transcript. Returns list of {text, start, duration} dicts."""
    api = YouTubeTranscriptApi()

    # Try English first
    try:
        fetched = api.fetch(video_id, languages=["en"])
        return [{"text": s.text, "start": s.start, "duration": s.duration}
                for s in fetched]
    except TranscriptsDisabled:
        raise ValueError("Transcripts are disabled for this video.")
    except VideoUnavailable:
        raise ValueError("Video is unavailable or private.")
    except (NoTranscriptFound, CouldNotRetrieveTranscript):
        pass  # Fall through to language discovery

Start with English because most of our test videos are English. Catch the three hard errors (disabled, unavailable, not found) and fall through to a discovery path if English is missing.

transcript.py
python
    # Fallback: discover all available languages, use the first one
    try:
        transcript_list = api.list(video_id)
        available = [t.language_code for t in transcript_list]
        if not available:
            raise ValueError("No transcripts available for this video.")
        fetched = api.fetch(video_id, languages=available)
        return [{"text": s.text, "start": s.start, "duration": s.duration}
                for s in fetched]
    except TranscriptsDisabled:
        raise ValueError("Transcripts are disabled for this video.")
    except VideoUnavailable:
        raise ValueError("Video is unavailable or private.")
    except ValueError:
        raise
    except Exception as e:
        raise ValueError(f"Could not fetch transcript: {str(e)}")

When English is missing, list what is available and take the first language. This gracefully handles videos uploaded in other languages.

Not directly. This workshop depends on YouTube captions. If the creator disabled captions and YouTube did not auto-generate any, fetch_transcript raises ValueError and the UI shows a clean error. A natural extension is to plug in Whisper and transcribe the audio yourself when captions are missing.

transcript shape
python
# Example of what fetch_transcript returns
[
    {"text": "Welcome to the deep learning crash course.", "start": 0.0, "duration": 3.2},
    {"text": "Today we are going to cover gradient descent.", "start": 3.2, "duration": 2.9},
    {"text": "This is the algorithm that powers almost every", "start": 6.1, "duration": 2.7},
    {"text": "neural network you have ever used.", "start": 8.8, "duration": 2.4},
]

Three fields per snippet. Text is the caption line. Start is seconds from the beginning of the video. Duration is how long that snippet plays before the next line appears.

Quiz: Quiz

Loading practice…