YouTube Downloader

Download one authorized YouTube video or audio file to a folder you choose.

6 steps · runs code · uses 2 tools

6 stepsRuns codeUses a tool4 reach outside
choice is "video"choice is "audio"

What's new in version 1: Built and tested single-URL YouTube downloads with per-run video/audio selection, folder choice, safe URL handling, MP4 merging, and overwrite support.

What you provide

Osaurus asks for these each time the workflow runs.

YouTube linkstringrequired

Paste the URL of one YouTube video.

Download typechoicerequired

Choose whether to save video or audio.

One of: video, audio

Destination folderstringrequired

Choose where the downloaded file should be saved.

What it does

Every step in the order it runs. Code steps show their full source so you can read exactly what runs on your Mac.

  1. Step 1: Prepare safe download

    Runs codejavascript Show in graph

    Safely encode the URL and select the requested download branch.

    No network access. · Times out after 30s

    async function run(input, ctx) {
      const bytes = [];
      for (const ch of input.url.trim()) {
        const cp = ch.codePointAt(0);
        if (cp <= 0x7f) bytes.push(cp);
        else if (cp <= 0x7ff) bytes.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));
        else if (cp <= 0xffff) bytes.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
        else bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));
      }
      const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      let out = '';
      for (let i = 0; i < bytes.length; i += 3) {
        const a = bytes[i];
        const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
        const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
        const n = (a << 16) | (b << 8) | c;
        out += alphabet[(n >> 18) & 63] + alphabet[(n >> 12) & 63];
        out += i + 1 < bytes.length ? alphabet[(n >> 6) & 63] : '=';
        out += i + 2 < bytes.length ? alphabet[n & 63] : '=';
      }
      return { choice: input.choice, url_b64: out, overwrite: true };
    }
    Data passed to this step
    {
      "url": "{{input.youtube_url}}",
      "choice": "{{input.download_type}}"
    }
  2. Step 2: Download video

    Uses a toolshell_run Show in graph

    Download the best directly available MP4 video with audio.

    Runs only when Prepare safe download reports choice is "video".

    Data passed to this step
    {
      "command": "URL_B64='{{nodes.prepare.output.url_b64}}'; URL=$(printf '%s' \"$URL_B64\" | base64 -d); rm -f youtube-download.mp4 youtube-download.f*; yt-dlp --js-runtimes node --no-playlist --format 'bv*[ext=mp4]+ba[ext=m4a]/bv*+ba/b' --merge-output-format mp4 --output youtube-download.mp4 \"$URL\""
    }
  3. Step 3: Download audio

    Uses a toolshell_run Show in graph

    Download the best directly available M4A audio stream.

    Runs only when Prepare safe download reports choice is "audio".

    Data passed to this step
    {
      "command": "URL_B64='{{nodes.prepare.output.url_b64}}'; URL=$(printf '%s' \"$URL_B64\" | base64 -d); rm -f youtube-download.m4a; yt-dlp --js-runtimes node --no-playlist --format 'bestaudio[ext=m4a]' --output youtube-download.m4a \"$URL\""
    }
  4. Step 4: Save video

    Uses a toolfile_copy Show in graph

    Copy the completed MP4 file to the chosen folder.

    Data passed to this step
    {
      "source": "youtube-download.mp4",
      "overwrite": "{{nodes.prepare.output.overwrite}}",
      "destination": "{{input.destination_folder}}/youtube-download.mp4"
    }
  5. Step 5: Save audio

    Uses a toolfile_copy Show in graph

    Copy the completed M4A file to the chosen folder.

    Data passed to this step
    {
      "source": "youtube-download.m4a",
      "overwrite": "{{nodes.prepare.output.overwrite}}",
      "destination": "{{input.destination_folder}}/youtube-download.m4a"
    }
  6. Step 6: Report saved file

    Runs codejavascript Show in graph

    Return the path and type of the file that was saved.

    No network access. · Times out after 30s

    async function run(input, ctx) {
      const folder = input.folder.replace(/\/$/, '');
      const filename = input.media_type === 'video' ? 'youtube-download.mp4' : 'youtube-download.m4a';
      return {
        file_path: folder + '/' + filename,
        media_type: input.media_type,
        note: 'Download completed. Only save content you are authorized to download.'
      };
    }
    Data passed to this step
    {
      "folder": "{{input.destination_folder}}",
      "media_type": "{{input.download_type}}"
    }

What it can access

Read from the workflow's steps, not only what the author declared. Osaurus shows this again before you add the workflow.

Network
Code steps have no network access.
Secrets
Doesn't ask for any API keys or passwords.
Tools
Uses shell_run, file_copy.
Code
Runs JavaScript in Osaurus's sandbox. The full source is shown above.
Models
Uses your default model.
Your input
Runs start to finish without stopping.

What you get back

Resultstringrequired

note

Saved filestringrequired

file_path

Download typechoicerequired

One of: video, audio

Examples

Sample inputs the author included.

Download one YouTube audio file
{
  "youtube_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
  "download_type": "audio",
  "destination_folder": "tmp"
}
Download one YouTube video
{
  "youtube_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
  "download_type": "video",
  "destination_folder": "tmp"
}

The signed file

This is the exact template Osaurus imports. Its hash and signature were checked when it was uploaded.

Show template JSON (10.7 KB)
{
  "id": "BC20B98D-1B93-4A74-A971-C8F77F56CABB",
  "kind": "workflow",
  "name": "YouTube Downloader",
  "author": {
    "name": "tpae",
    "address": "0xc820da3Ce55C600A6282D2B21083Fe5Aa7E51F3D",
    "signature": "27f68ec2c07bcd9c49624e8dd711ac25bfda95dab336965409cf91cc7bd48db50557742740b0c71c65c040aa4ecb0d3869569d548d623cb194600755d080114c1c"
  },
  "format": "osaurus.template",
  "summary": "Download one authorized YouTube video or audio file to a folder you choose.",
  "version": 1,
  "workflow": {
    "edges": [
      {
        "to": "download_video",
        "from": "prepare",
        "when": {
          "op": "equals",
          "path": "choice",
          "value": "video"
        }
      },
      {
        "to": "download_audio",
        "from": "prepare",
        "when": {
          "op": "equals",
          "path": "choice",
          "value": "audio"
        }
      },
      {
        "to": "copy_video",
        "from": "download_video"
      },
      {
        "to": "copy_audio",
        "from": "download_audio"
      },
      {
        "to": "finish",
        "from": "copy_video"
      },
      {
        "to": "finish",
        "from": "copy_audio"
      }
    ],
    "nodes": [
      {
        "id": "prepare",
        "code": {
          "source": "async function run(input, ctx) {\n  const bytes = [];\n  for (const ch of input.url.trim()) {\n    const cp = ch.codePointAt(0);\n    if (cp <= 0x7f) bytes.push(cp);\n    else if (cp <= 0x7ff) bytes.push(0xc0 | (cp >> 6), 0x80 | (cp & 0x3f));\n    else if (cp <= 0xffff) bytes.push(0xe0 | (cp >> 12), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));\n    else bytes.push(0xf0 | (cp >> 18), 0x80 | ((cp >> 12) & 0x3f), 0x80 | ((cp >> 6) & 0x3f), 0x80 | (cp & 0x3f));\n  }\n  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n  let out = '';\n  for (let i = 0; i < bytes.length; i += 3) {\n    const a = bytes[i];\n    const b = i + 1 < bytes.length ? bytes[i + 1] : 0;\n    const c = i + 2 < bytes.length ? bytes[i + 2] : 0;\n    const n = (a << 16) | (b << 8) | c;\n    out += alphabet[(n >> 18) & 63] + alphabet[(n >> 12) & 63];\n    out += i + 1 < bytes.length ? alphabet[(n >> 6) & 63] : '=';\n    out += i + 2 < bytes.length ? alphabet[n & 63] : '=';\n  }\n  return { choice: input.choice, url_b64: out, overwrite: true };\n}",
          "network": [],
          "secrets": [],
          "timeout": 30
        },
        "kind": "code",
        "name": "Prepare safe download",
        "input": {
          "url": "{{input.youtube_url}}",
          "choice": "{{input.download_type}}"
        },
        "retry": {
          "max_attempts": 1,
          "backoff_seconds": 1
        },
        "intent": "Safely encode the URL and select the requested download branch.",
        "timeout": 120,
        "output_schema": {
          "type": "object",
          "required": [
            "choice",
            "url_b64",
            "overwrite"
          ],
          "properties": {
            "choice": {
              "enum": [
                "video",
                "audio"
              ],
              "type": "string"
            },
            "url_b64": {
              "type": "string"
            },
            "overwrite": {
              "type": "boolean"
            }
          },
          "additionalProperties": false
        }
      },
      {
        "id": "download_video",
        "kind": "tool",
        "name": "Download video",
        "tool": {
          "name": "shell_run"
        },
        "input": {
          "command": "URL_B64='{{nodes.prepare.output.url_b64}}'; URL=$(printf '%s' \"$URL_B64\" | base64 -d); rm -f youtube-download.mp4 youtube-download.f*; yt-dlp --js-runtimes node --no-playlist --format 'bv*[ext=mp4]+ba[ext=m4a]/bv*+ba/b' --merge-output-format mp4 --output youtube-download.mp4 \"$URL\""
        },
        "retry": {
          "max_attempts": 2,
          "backoff_seconds": 2
        },
        "intent": "Download the best directly available MP4 video with audio.",
        "timeout": 300,
        "output_schema": {}
      },
      {
        "id": "download_audio",
        "kind": "tool",
        "name": "Download audio",
        "tool": {
          "name": "shell_run"
        },
        "input": {
          "command": "URL_B64='{{nodes.prepare.output.url_b64}}'; URL=$(printf '%s' \"$URL_B64\" | base64 -d); rm -f youtube-download.m4a; yt-dlp --js-runtimes node --no-playlist --format 'bestaudio[ext=m4a]' --output youtube-download.m4a \"$URL\""
        },
        "retry": {
          "max_attempts": 2,
          "backoff_seconds": 2
        },
        "intent": "Download the best directly available M4A audio stream.",
        "timeout": 180,
        "output_schema": {}
      },
      {
        "id": "copy_video",
        "kind": "tool",
        "name": "Save video",
        "tool": {
          "name": "file_copy"
        },
        "input": {
          "source": "youtube-download.mp4",
          "overwrite": "{{nodes.prepare.output.overwrite}}",
          "destination": "{{input.destination_folder}}/youtube-download.mp4"
        },
        "retry": {
          "max_attempts": 1,
          "backoff_seconds": 1
        },
        "intent": "Copy the completed MP4 file to the chosen folder.",
        "timeout": 120,
        "output_schema": {}
      },
      {
        "id": "copy_audio",
        "kind": "tool",
        "name": "Save audio",
        "tool": {
          "name": "file_copy"
        },
        "input": {
          "source": "youtube-download.m4a",
          "overwrite": "{{nodes.prepare.output.overwrite}}",
          "destination": "{{input.destination_folder}}/youtube-download.m4a"
        },
        "retry": {
          "max_attempts": 1,
          "backoff_seconds": 1
        },
        "intent": "Copy the completed M4A file to the chosen folder.",
        "timeout": 120,
        "output_schema": {}
      },
      {
        "id": "finish",
        "code": {
          "source": "async function run(input, ctx) {\n  const folder = input.folder.replace(/\\/$/, '');\n  const filename = input.media_type === 'video' ? 'youtube-download.mp4' : 'youtube-download.m4a';\n  return {\n    file_path: folder + '/' + filename,\n    media_type: input.media_type,\n    note: 'Download completed. Only save content you are authorized to download.'\n  };\n}",
          "network": [],
          "secrets": [],
          "timeout": 30
        },
        "kind": "code",
        "name": "Report saved file",
        "input": {
          "folder": "{{input.destination_folder}}",
          "media_type": "{{input.download_type}}"
        },
        "retry": {
          "max_attempts": 1,
          "backoff_seconds": 1
        },
        "intent": "Return the path and type of the file that was saved.",
        "timeout": 120,
        "output_schema": {
          "type": "object",
          "required": [
            "file_path",
            "media_type",
            "note"
          ],
          "properties": {
            "note": {
              "type": "string"
            },
            "file_path": {
              "type": "string"
            },
            "media_type": {
              "enum": [
                "video",
                "audio"
              ],
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      }
    ],
    "output": {
      "note": "{{nodes.finish.output.note}}",
      "file_path": "{{nodes.finish.output.file_path}}",
      "media_type": "{{nodes.finish.output.media_type}}"
    },
    "secrets": [],
    "examples": [
      {
        "name": "Download one YouTube audio file",
        "input": {
          "youtube_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
          "download_type": "audio",
          "destination_folder": "tmp"
        }
      },
      {
        "name": "Download one YouTube video",
        "input": {
          "youtube_url": "https://www.youtube.com/watch?v=jNQXAC9IVRw",
          "download_type": "video",
          "destination_folder": "tmp"
        }
      }
    ],
    "model_slots": [],
    "dependencies": [
      {
        "manager": "pip",
        "binaries": [
          "yt-dlp"
        ],
        "packages": [
          "yt-dlp"
        ]
      },
      {
        "manager": "apk",
        "binaries": [
          "ffmpeg"
        ],
        "packages": [
          "ffmpeg"
        ]
      }
    ],
    "input_schema": {
      "type": "object",
      "x-order": [
        "youtube_url",
        "download_type",
        "destination_folder"
      ],
      "required": [
        "youtube_url",
        "download_type",
        "destination_folder"
      ],
      "properties": {
        "youtube_url": {
          "type": "string",
          "title": "YouTube link",
          "description": "Paste the URL of one YouTube video."
        },
        "download_type": {
          "enum": [
            "video",
            "audio"
          ],
          "type": "string",
          "title": "Download type",
          "description": "Choose whether to save video or audio."
        },
        "destination_folder": {
          "type": "string",
          "title": "Destination folder",
          "format": "folder",
          "description": "Choose where the downloaded file should be saved."
        }
      },
      "additionalProperties": false
    },
    "output_schema": {
      "type": "object",
      "required": [
        "file_path",
        "media_type",
        "note"
      ],
      "properties": {
        "note": {
          "type": "string",
          "title": "Result"
        },
        "file_path": {
          "type": "string",
          "title": "Saved file"
        },
        "media_type": {
          "enum": [
            "video",
            "audio"
          ],
          "type": "string",
          "title": "Download type"
        }
      },
      "additionalProperties": false
    },
    "requirement_notes": {}
  },
  "changelog": "Built and tested single-URL YouTube downloads with per-run video/audio selection, folder choice, safe URL handling, MP4 merging, and overwrite support.",
  "created_at": "2026-10-07T19:23:31Z",
  "content_hash": "sha256:70a717b3d59e59d8bfd5652543db60bcf6cbe46e3a80f8ffc0e6dcabf7dbb2b0",
  "requirements": {
    "notes": {},
    "tools": [
      "shell_run",
      "file_copy"
    ],
    "models": [],
    "network": [],
    "plugins": [],
    "secrets": [],
    "knowledge": [],
    "mcp_servers": [],
    "permissions": [],
    "dependencies": [
      {
        "manager": "pip",
        "binaries": [
          "yt-dlp"
        ],
        "packages": [
          "yt-dlp"
        ]
      },
      {
        "manager": "apk",
        "binaries": [
          "ffmpeg"
        ],
        "packages": [
          "ffmpeg"
        ]
      }
    ]
  },
  "format_version": 1,
  "available_to_orchestrator": true
}

Open raw template