sudo apt install ffmpeg        # Linux
brew install ffmpeg            # macOS
choco install ffmpeg           # Windows
videos_to_csv.py
import os
import csv
import subprocess
import re
from pathlib import Path
import tkinter as tk
from tkinter import filedialog

# ================= CONFIG =================
CDN_BASE = "https://cdn.pmaal.com"
THUMB_FOLDER = "IMG"
VIDEO_EXTENSIONS = (".mp4", ".mkv", ".avi", ".mov")
# ==========================================

def pick_root_folder():
    root = tk.Tk()
    root.withdraw()
    folder = filedialog.askdirectory(title="Select OTT Root Folder")
    return folder

def get_duration_minutes(video_path):
    try:
        cmd = [
            "ffprobe", "-v", "error",
            "-show_entries", "format=duration",
            "-of", "default=noprint_wrappers=1:nokey=1",
            video_path
        ]
        duration = float(subprocess.check_output(cmd).decode().strip())
        return round(duration / 60)
    except:
        return ""

def is_episode(filename):
    return re.search(r"(episode\s*\d+)", filename, re.IGNORECASE)

def extract_episode_number(filename):
    match = re.search(r"episode\s*(\d+)", filename, re.IGNORECASE)
    return match.group(1) if match else ""

def extract_series_name(filename):
    return re.sub(r"episode\s*\d+.*", "", filename, flags=re.IGNORECASE).strip()

def normalize_and_trim(text, max_len=4):
    clean = re.sub(r"[^a-z0-9]", "", text.lower())
    return clean[:max_len]

def generate_id(ott, title, series, episode_no, duration):
    ott_part = normalize_and_trim(ott)

    if series and episode_no:
        series_part = normalize_and_trim(series)
        return f"{ott_part}{series_part}{episode_no}{duration}"
    else:
        title_part = normalize_and_trim(title)
        return f"{ott_part}{title_part}{duration}"

def make_csv_name(ott_name):
    safe_name = re.sub(r"[^\w\s-]", "", ott_name).strip()
    return f"{safe_name}.csv"

def main():
    root_folder = pick_root_folder()
    if not root_folder:
        print("❌ No folder selected. Exiting.")
        return

    root = Path(root_folder)
    ott_name = root.name
    rows = []

    # Ensure IMG folder exists
    (root / THUMB_FOLDER).mkdir(exist_ok=True)

    for file in list(root.iterdir()):
        if file.is_file() and file.suffix.lower() in VIDEO_EXTENSIONS:
            title = file.stem
            duration = get_duration_minutes(str(file))
            episode_no = ""

            # EPISODE FILE
            if is_episode(title):
                episode_no = extract_episode_number(title)
                series = extract_series_name(title)

                series_folder = root / series
                series_folder.mkdir(exist_ok=True)

                new_path = series_folder / file.name
                if not new_path.exists():
                    file.rename(new_path)

                video_url = f"{CDN_BASE}/{ott_name}/{series}/{file.name}"
                image_url = f"{CDN_BASE}/{ott_name}/{THUMB_FOLDER}/{title}.webp"

            # SINGLE VIDEO
            else:
                series = ""
                video_url = f"{CDN_BASE}/{ott_name}/{file.name}"
                image_url = f"{CDN_BASE}/{ott_name}/{THUMB_FOLDER}/{title}.webp"

            video_id = generate_id(
                ott=ott_name,
                title=title,
                series=series,
                episode_no=episode_no,
                duration=duration
            )

            rows.append([
                video_id,
                title,
                series,
                ott_name,
                duration,
                video_url,
                image_url,
                "",
                "",
                "pending"
            ])

    output_csv = root / make_csv_name(ott_name)

    with open(output_csv, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([
            "ID",
            "Title",
            "Series",
            "OTT",
            "duration",
            "video_url",
            "image_url",
            "Models",
            "Year",
            "Status"
        ])
        writer.writerows(rows)

    print("✅ File organization complete")
    print(f"✅ CSV generated at: {output_csv}")

if __name__ == "__main__":
    main()
python videos_to_csv.py
Netflix/
├── Betaal/
│   ├── Betaal Episode 1.mp4
│   ├── Betaal Episode 2.mp4
│   └── Betaal Episode 3.mp4
├── Mama Ki Jai.mp4
├── Youga.mp4
├── IMG/
└── videos.csv

Get all File names with

C:\Users\User>dir "F:\OTT\Netflix\Series Thumb" /b /a-d | clip

Get all Folder names with

C:\Users\User>dir "F:\OTT\Netflix" /b /ad | clip

Leave a Comment