In [1]:
# Install required packages
!apt-get install -y ffmpeg
!pip install git+https://github.com/openai/whisper.git
!pip install pytubefix
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
ffmpeg is already the newest version (7:4.4.2-0ubuntu0.22.04.1).
0 upgraded, 0 newly installed, 0 to remove and 62 not upgraded.
Collecting git+https://github.com/openai/whisper.git
  Cloning https://github.com/openai/whisper.git to /tmp/pip-req-build-3k5vlxpu
  Running command git clone --filter=blob:none --quiet https://github.com/openai/whisper.git /tmp/pip-req-build-3k5vlxpu
  Resolved https://github.com/openai/whisper.git to commit 517a43ecd132a2089d85f4ebc044728a71d49f6e
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: more-itertools in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (10.5.0)
Requirement already satisfied: numba in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (0.60.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (1.26.4)
Requirement already satisfied: tiktoken in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (0.8.0)
Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (2.5.1+cu121)
Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (4.67.1)
Requirement already satisfied: triton>=2 in /usr/local/lib/python3.10/dist-packages (from openai-whisper==20240930) (3.2.0)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.10/dist-packages (from numba->openai-whisper==20240930) (0.43.0)
Requirement already satisfied: mkl_fft in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (1.3.8)
Requirement already satisfied: mkl_random in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (1.2.4)
Requirement already satisfied: mkl_umath in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (0.1.1)
Requirement already satisfied: mkl in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (2025.0.1)
Requirement already satisfied: tbb4py in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (2022.0.0)
Requirement already satisfied: mkl-service in /usr/local/lib/python3.10/dist-packages (from numpy->openai-whisper==20240930) (2.4.1)
Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.10/dist-packages (from tiktoken->openai-whisper==20240930) (2024.11.6)
Requirement already satisfied: requests>=2.26.0 in /usr/local/lib/python3.10/dist-packages (from tiktoken->openai-whisper==20240930) (2.32.3)
Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (3.16.1)
Requirement already satisfied: typing-extensions>=4.8.0 in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (4.12.2)
Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (3.4.2)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (3.1.4)
Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (2024.9.0)
Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.10/dist-packages (from torch->openai-whisper==20240930) (1.13.1)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy==1.13.1->torch->openai-whisper==20240930) (1.3.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.26.0->tiktoken->openai-whisper==20240930) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.26.0->tiktoken->openai-whisper==20240930) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.26.0->tiktoken->openai-whisper==20240930) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.26.0->tiktoken->openai-whisper==20240930) (2024.12.14)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch->openai-whisper==20240930) (3.0.2)
Requirement already satisfied: intel-openmp>=2024 in /usr/local/lib/python3.10/dist-packages (from mkl->numpy->openai-whisper==20240930) (2024.2.0)
Requirement already satisfied: tbb==2022.* in /usr/local/lib/python3.10/dist-packages (from mkl->numpy->openai-whisper==20240930) (2022.0.0)
Requirement already satisfied: tcmlib==1.* in /usr/local/lib/python3.10/dist-packages (from tbb==2022.*->mkl->numpy->openai-whisper==20240930) (1.2.0)
Requirement already satisfied: intel-cmplr-lib-rt in /usr/local/lib/python3.10/dist-packages (from mkl_umath->numpy->openai-whisper==20240930) (2024.2.0)
Requirement already satisfied: intel-cmplr-lib-ur==2024.2.0 in /usr/local/lib/python3.10/dist-packages (from intel-openmp>=2024->mkl->numpy->openai-whisper==20240930) (2024.2.0)
Requirement already satisfied: pytubefix in /usr/local/lib/python3.10/dist-packages (8.12.1)
In [2]:
# Import libraries
import math
import os
import re
import warnings
from pytubefix import YouTube, Playlist
import whisper

warnings.filterwarnings("ignore")
In [3]:
# Configuration
MODEL_NAME = "large-v3"
DOWNLOAD_DIR = "/kaggle/working/Downloads"
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
In [4]:
# Blacklist - List of titles (Regex Supported)
BLACKLIST_PATTERNS = [r"Welcome Video", r"Lecture 01:", r"Lecture 02:", r"Lecture 03:", r"Lecture 04:", r"Lecture 05:", r"Lecture 06:", r"Lecture 07:"]

def is_blacklisted(title):
    """Check if the video title matches any blacklist pattern."""
    return any(re.search(pattern, title, re.IGNORECASE) for pattern in BLACKLIST_PATTERNS)

def sanitize_filename(filename):
    """Remove invalid characters from filenames"""
    return re.sub(r'[\\/*?:"<>|]', "", filename)

def get_video_urls(input_url):
    """Extract video URLs from playlist or single video, logging all titles before filtering."""
    video_urls = []
    if "playlist?list=" in input_url:
        playlist = Playlist(input_url)
        for video in playlist.videos:
            print(f"Found Video: {video.title}")
            if not is_blacklisted(video.title):
                video_urls.append(video.watch_url)
    else:
        yt = YouTube(input_url)
        print(f"Found Video: {yt.title}")
        if not is_blacklisted(yt.title):
            video_urls.append(input_url)
    
    return video_urls

def download_video(video_url):
    """Download the video from the given URL and return the file path."""
    yt = YouTube(video_url)
    video_title = sanitize_filename(yt.title)
    stream = yt.streams.filter(progressive=True).order_by('resolution').desc().first()
    output_path = os.path.join(DOWNLOAD_DIR, f"{video_title}.mp4")
    stream.download(output_path=DOWNLOAD_DIR, filename=f"{video_title}.mp4")
    return output_path

def format_timestamp(seconds: float):
    """
    format time in srt-file expected format
    """
    assert seconds >= 0, "non-negative timestamp expected"
    milliseconds = round(seconds * 1000.0)

    hours = milliseconds // 3_600_000
    milliseconds -= hours * 3_600_000

    minutes = milliseconds // 60_000
    milliseconds -= minutes * 60_000

    seconds = milliseconds // 1_000
    milliseconds -= seconds * 1_000

    return (f"{hours}:" if hours > 0 else "00:") + f"{minutes:02d}:{seconds:02d},{milliseconds:03d}"

def generate_srt(transcription, filter_duration=None):
    """
    Format transcription into srt file format
    """
    segment_lines = []
    for idx, segment in enumerate(transcription):
        timestamp = (segment["start"], segment["end"])
        # for the case where the model could not predict an ending timestamp, which can happen if audio is cut off in the middle of a word.
        if segment["end"] == -1:
            timestamp[1] = filter_duration

        if filter_duration is not None and (timestamp[0] >= math.floor(filter_duration) or timestamp[1] > math.ceil(filter_duration) + 1):
            break
        segment_lines.append(str(idx + 1) + "\n")
        time_start = format_timestamp(timestamp[0])
        time_end = format_timestamp(timestamp[1])
        time_str = f"{time_start} --> {time_end}\n"
        segment_lines.append(time_str)
        segment_lines.append(segment["text"] + "\n\n")
    return segment_lines
In [5]:
# Main processing function
def process_videos(input_url, language="English", include_video=False):
    # Load model once
    model = whisper.load_model(MODEL_NAME)
    
    # Get video URLs
    video_urls = get_video_urls(input_url)
    
    for video_url in video_urls:
        try:
            # Create YouTube object
            yt = YouTube(video_url)
            safe_title = sanitize_filename(yt.title)
            print(f"\nProcessing: {safe_title}")

            stream = None
            if include_video:
                stream = yt.streams.filter(progressive=True).order_by('resolution').desc().first() # highest resolution
            else: 
                stream = yt.streams.filter(only_audio=True).order_by('abr').desc().first() # Download best audio stream
            
            if not stream:
                raise Exception("No stream found")
                
            # Download file
            file_path = stream.download(
                output_path=DOWNLOAD_DIR,
                filename=f"{safe_title}.mp4"
            )
            print(f"Downloaded to: {file_path}")
            
            # Transcribe
            print("Starting transcription...")
            result = model.transcribe(file_path, verbose=False, word_timestamps=False, language=language)
            print("Transcription completed!")
            
            # Generate SRT
            srt_path = os.path.join(DOWNLOAD_DIR, f"{safe_title}.srt")
            srt_content = generate_srt(result["segments"])
            
            with open(srt_path, "w", encoding="utf-8") as f:
                f.writelines(srt_content)
            
            print(f"SRT saved to: {srt_path}\n")
            
        except Exception as e:
            print(f"Error processing {video_url}: {str(e)}")
            continue

    print("All processing completed!")
In [6]:
# Example usage - replace with your playlist/video URL
INPUT_URL = "https://youtube.com/playlist?list=PL9_jI1bdZmz2emSh0UQ5iOdT2xRHFHL7E&si=7Y5O9LQ45ec2oOGZ"

# Start processing
process_videos(INPUT_URL)
Found Video: Computer Graphics (CMU 15-462/662): Welcome Video
Found Video: Lecture 01: Course Overview (CMU 15-462/662)
Found Video: Lecture 02: Linear Algebra (P)Review (CMU 15-462/662)
Found Video: Lecture 03: Vector Calculus (P)Review (CMU 15-462/662)
Found Video: Lecture 04: Drawing a Triangle and an Intro to Sampling (CMU 15-462/662)
Found Video: Lecture 05: Spatial Transformations (CMU 15-462/662)
Found Video: Lecture 06: 3D Rotations and Complex Representations (CMU 15-462/662)
Found Video: Lecture 07: Perspective Projection and Texture Mapping (CMU 15-462/662)
Found Video: Lecture 08: Depth and Transparency (CMU 15-462/662)
Found Video: Lecture 09: Introduction to Geometry (CMU 15-462/662)
Found Video: Lecture 10: Meshes and Manifolds (CMU 15-462/662)
Found Video: Lecture 11: Digital Geometry Processing (CMU 15-462/662)
Found Video: Lecture 12: Geometric Queries (CMU 15-462/662)
Found Video: Lecture 13: Spatial Data Structures (CMU 15-462/662)
Found Video: Lecture 14: Color (CMU 15-462/662)
Found Video: Lecture 15: Radiometry (CMU 15-462/662)
Found Video: Lecture 16: The Rendering Equation (CMU 15-462/662)
Found Video: Lecture 17: Numerical Integration (CMU 15-462/662)
Found Video: Lecture 18: Monte Carlo Rendering (CMU 15-462/662)
Found Video: Lecture 19: Variance Reduction (CMU 15-462/662)
Found Video: Lecture 20: Introduction to Animation (CMU 15-462/662)
Found Video: Lecture 21: Dynamics and Time Integration (CMU 15-462/662)
Found Video: Lecture 22: Optimization (CMU 15-462/662)
Found Video: Lecture 23: Physically Based Animation and PDEs (CMU 15-462/662)
Found Video: Computer Graphics - Student Creations! (CMU 15-462/662)

Processing: Lecture 08 Depth and Transparency (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 08 Depth and Transparency (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 316623/316623 [15:52<00:00, 332.50frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 08 Depth and Transparency (CMU 15-462662).srt


Processing: Lecture 09 Introduction to Geometry (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 09 Introduction to Geometry (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 448147/448147 [20:44<00:00, 360.02frames/s] 
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 09 Introduction to Geometry (CMU 15-462662).srt


Processing: Lecture 10 Meshes and Manifolds (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 10 Meshes and Manifolds (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 407131/407131 [19:16<00:00, 352.11frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 10 Meshes and Manifolds (CMU 15-462662).srt


Processing: Lecture 11 Digital Geometry Processing (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 11 Digital Geometry Processing (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 473923/473923 [23:39<00:00, 333.88frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 11 Digital Geometry Processing (CMU 15-462662).srt


Processing: Lecture 12 Geometric Queries (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 12 Geometric Queries (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 418706/418706 [21:26<00:00, 325.37frames/s] 
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 12 Geometric Queries (CMU 15-462662).srt


Processing: Lecture 13 Spatial Data Structures (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 13 Spatial Data Structures (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 489430/489430 [26:39<00:00, 305.90frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 13 Spatial Data Structures (CMU 15-462662).srt


Processing: Lecture 14 Color (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 14 Color (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 485370/485370 [22:46<00:00, 355.25frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 14 Color (CMU 15-462662).srt


Processing: Lecture 15 Radiometry (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 15 Radiometry (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 402177/402177 [16:43<00:00, 400.64frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 15 Radiometry (CMU 15-462662).srt


Processing: Lecture 16 The Rendering Equation (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 16 The Rendering Equation (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 273164/273164 [15:37<00:00, 291.49frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 16 The Rendering Equation (CMU 15-462662).srt


Processing: Lecture 17 Numerical Integration (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 17 Numerical Integration (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 453137/453137 [25:53<00:00, 291.78frames/s] 
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 18 Monte Carlo Rendering (CMU 15-462662).srt


Processing: Lecture 19 Variance Reduction (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 19 Variance Reduction (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 564871/564871 [22:25<00:00, 419.72frames/s]  
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 19 Variance Reduction (CMU 15-462662).srt


Processing: Lecture 20 Introduction to Animation (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 20 Introduction to Animation (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 410983/410983 [19:36<00:00, 349.24frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 20 Introduction to Animation (CMU 15-462662).srt


Processing: Lecture 21 Dynamics and Time Integration (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 21 Dynamics and Time Integration (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 600621/600621 [28:08<00:00, 355.80frames/s]  
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 21 Dynamics and Time Integration (CMU 15-462662).srt


Processing: Lecture 22 Optimization (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 22 Optimization (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 574740/574740 [27:00<00:00, 354.68frames/s] 
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 22 Optimization (CMU 15-462662).srt


Processing: Lecture 23 Physically Based Animation and PDEs (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Lecture 23 Physically Based Animation and PDEs (CMU 15-462662).mp4
Starting transcription...
100%|██████████| 427124/427124 [25:06<00:00, 283.46frames/s]
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Lecture 23 Physically Based Animation and PDEs (CMU 15-462662).srt


Processing: Computer Graphics - Student Creations! (CMU 15-462662)
Downloaded to: /kaggle/working/Downloads/Computer Graphics - Student Creations! (CMU 15-462662).mp4
Starting transcription...
 81%|████████  | 37173/46173 [01:10<00:17, 527.21frames/s] 
Transcription completed!
SRT saved to: /kaggle/working/Downloads/Computer Graphics - Student Creations! (CMU 15-462662).srt

All processing completed!