sudo apt install ffmpeg # Linux
brew install ffmpeg # macOS
choco install ffmpeg # Windowsvideos_to_csv.pyimport 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.pyNetflix/
├── Betaal/
│ ├── Betaal Episode 1.mp4
│ ├── Betaal Episode 2.mp4
│ └── Betaal Episode 3.mp4
├── Mama Ki Jai.mp4
├── Youga.mp4
├── IMG/
└── videos.csvGet all File names with
C:\Users\User>dir "F:\OTT\Netflix\Series Thumb" /b /a-d | clipGet all Folder names with
C:\Users\User>dir "F:\OTT\Netflix" /b /ad | clip