# YouTube Timestamp Generator > Format YouTube chapter timestamps, check ordering, and copy a ready-to-paste description block. ## Tool Identity - Site: CleanUtils Business Tools - Tool ID: youtube-timestamp-generator - Canonical page: https://cleanutils.com/business-tools/youtube-timestamp-generator/ - LLM schema URL: https://cleanutils.com/business-tools/youtube-timestamp-generator/llms.txt - Primary keyword: youtube timestamp generator - Input mode: textarea - Output profile: line-check ## What This Tool Does Format YouTube chapter timestamps, check ordering, and copy a ready-to-paste description block. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input string in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `788428119230c8f425cffc49bc8bfe8140d1a81cd4df223a8d617cc27a7a139e` Expected command shape: `node run-tool.mjs < input.txt` The runner must: 1. load only the JavaScript in this document, 2. call `runCleanUtilsTool(inputText)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "YouTube Timestamp Generator input", "type": "string", "description": "Video chapters. 0:00 Intro\n1:24 Setup\n3:10 Results", "examples": [ "0:00 Intro\n1:24 Setup\n3:10 Cleaning the CSV\n6:45 Export results" ] } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const severityRank = { error: 0, warning: 1, info: 2 }; const sortIssues = (issues) => [...issues].sort((a, b) => { const severity = severityRank[a.severity] - severityRank[b.severity]; if (severity !== 0) return severity; return (a.line ?? a.row ?? 0) - (b.line ?? b.row ?? 0); }); const summarizeIssues = (issues) => { const errors = issues.filter((issue) => issue.severity === "error").length; const warnings = issues.filter((issue) => issue.severity === "warning").length; const infos = issues.filter((issue) => issue.severity === "info").length; const parts = []; if (errors) parts.push(`${errors} error${errors === 1 ? "" : "s"}`); if (warnings) parts.push(`${warnings} warning${warnings === 1 ? "" : "s"}`); if (infos) parts.push(`${infos} note${infos === 1 ? "" : "s"}`); return parts.length ? parts.join(", ") : "No issues found"; }; const parseFlexibleTime = (value) => { const parts = value.trim().split(":").map(Number); if (parts.some((part) => !Number.isFinite(part))) return Number.NaN; if (parts.length === 2) return parts[0] * 60 + parts[1]; if (parts.length === 3) return parts[0] * 3600 + parts[1] * 60 + parts[2]; return Number.NaN; }; const formatYoutubeTime = (seconds) => { const whole = Math.max(0, Math.floor(seconds)); const h = Math.floor(whole / 3600); const m = Math.floor((whole % 3600) / 60); const s = whole % 60; return h ? `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}` : `${m}:${String(s).padStart(2, "0")}`; }; const generateYoutubeTimestamps = (input) => { const issues = []; let previous = -1; const rows = input.split(/\r?\n/).map((line, index) => { const match = line.trim().match(/^(\d{1,2}:\d{2}(?::\d{2})?)\s+(.+)$/); if (!match) { issues.push({ severity: "error", line: index + 1, message: "Line should start with mm:ss or hh:mm:ss followed by a chapter title." }); return ""; } const seconds = parseFlexibleTime(match[1]); if (seconds <= previous) issues.push({ severity: "warning", line: index + 1, message: "Timestamp is not later than the previous chapter." }); previous = seconds; return `${formatYoutubeTime(seconds)} ${match[2].trim()}`; }).filter(Boolean); if (rows.length && !rows[0].startsWith("0:00")) issues.push({ severity: "info", message: "YouTube chapters usually need the first timestamp to start at 0:00." }); return { summary: `${rows.length} YouTube timestamp${rows.length === 1 ? "" : "s"} formatted. ${summarizeIssues(issues)}.`, issues: sortIssues(issues), output: rows.join("\n"), exportFilename: "youtube-timestamps.txt", stats: { chapters: rows.length } }; }; const __userInput = userInput == null ? "" : userInput; const __run = generateYoutubeTimestamps; const __input = __userInput && typeof __userInput === "object" && "input" in __userInput ? __userInput.input : __userInput; return __run(__input == null ? "" : String(__input)); } ``` ## Checks - Timestamp format: Lines must start with mm:ss or hh:mm:ss followed by a chapter title. - Ascending order: Each timestamp is compared with the previous chapter so out-of-order markers are visible. - 0:00 starting note: The tool reminds you when the first chapter does not start at 0:00. - Consistent output: Chapter times are reformatted into a clean YouTube-ready style. - Description-only scope: The generator does not upload to YouTube or validate channel-specific chapter behavior. ## Related Tools - [SRT Subtitle Line Length Checker](/business-tools/srt-subtitle-line-length-checker/): Check SRT captions for long lines, too many text rows, and readability issues before publishing.