Skip to main content

Extract video URLs from web pages and generate curl download commands

Project description

vidurl

A more powerful, cleverer yt-dlp. Given any web page — a single-video page, a thumbnail-grid listing, or something obscure yt-dlp doesn't know about — vidurl downloads the videos.

License: AGPL v3 Python 3.13+

How it works

Three-tier escalation per URL, cheapest first:

  1. yt-dlp handles whatever it can natively (thousands of sites, including playlists/channels).
  2. Playwright loads the page and sniffs the rendered DOM, JS, network responses, and embedded iframes for a video URL — then downloads with curl. For listing pages, vidurl scrapes the DOM for video-page links and recurses.
  3. LLM (optional, opt-in) — when the heuristics fail, vidurl can ask a large language model (via scrapegraphai) to identify the video URL or video-page links on the rendered DOM.

Installation

uv sync
uv run playwright install chromium

yt-dlp and playwright are installed automatically. The LLM tier is optional:

uv sync --extra llm           # pulls in scrapegraphai

Also requires curl in PATH.

Usage

# yt-dlp does the work
vidurl https://www.youtube.com/watch?v=dQw4w9WgXcQ

# Site yt-dlp doesn't know — Playwright finds the video
vidurl https://example.com/embedded-video-page

# Listing of videos — vidurl visits each link
vidurl https://example.com/gallery
vidurl https://example.com/gallery --listing --link-selector "a.video-card"

# Don't download, just print the commands
vidurl https://example.com/page --dry-run

# Enable LLM fallback
vidurl https://example.com/weird-page \
    --llm-provider anthropic --llm-model claude-haiku-4-5

Flags

Flag Purpose
--output-dir / -o DIR Where to save files (default: cwd)
--dry-run Print the yt-dlp / curl commands instead of executing
--no-ytdlp Skip the yt-dlp tier; go straight to Playwright
--ytdlp-args 'STR' Extra args appended to the yt-dlp invocation
--listing Force listing mode (skip per-page video extraction)
--no-listing Never recurse into links
--link-selector CSS Use this CSS selector to find video-page links
--link-pattern REGEX Only follow links whose absolute URL matches
--min-links N Minimum links for listing auto-detect (default 3)
--max-pages N Max listing pages to walk (default 10)
--no-paginate Disable pagination — process only the first listing page
--next-selector CSS CSS selector for the next-page link
--next-pattern REGEX Regex; treat as next-page link only if URL matches
--page-url-template URL URL template with {n}; vidurl walks 2..max-pages
--llm-provider P anthropic, openai, groq, google, ollama, ...
--llm-model M Model id
--no-llm Disable the LLM tier even if provider/model are set
--no-headless Show the browser window
--timeout S Page load timeout (default 15s)
--verbose / --quiet Logging

LLM tier

The LLM tier is off by default. To enable, pass both --llm-provider and --llm-model (or set them in config.json). API keys are read from environment first, then from gnome-keyring via secret-tool under service=env, key=<PROVIDER_KEY>. If a key is present but provider/model are not set, vidurl logs a hint and stays off — no silent spend.

Pagination

When a listing page is detected, vidurl walks subsequent pages automatically (capped by --max-pages, default 10). Next-page discovery tries, in order:

  1. <link rel="next"> or <a rel="next">.
  2. Anchor text or aria-label matching Next, , , », More (filtered to avoid "next video" navigation).
  3. URL-template inference (?page=N, /page/N/, &offset=N, trailing /N), validated with a HEAD/GET probe.
  4. LLM fallback (if the LLM tier is enabled).

Override with --next-selector, --next-pattern, or --page-url-template URL (e.g. https://example.com/list?page={n}). Disable with --no-paginate.

What's intentionally not (yet) supported

  • "Load more" buttons and infinite scroll — these need click-and-wait logic without a URL change.
  • Parallel downloads of multiple listing-page videos — sequential for now.

Configuration

Pass a JSON file via --config path/to/config.json. See config.example.json for all fields.

Development

uv sync --extra dev
uv run pytest        # no tests yet

License

AGPL-3.0-or-later. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vidurl-0.3.0.tar.gz (35.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vidurl-0.3.0-py3-none-any.whl (36.6 kB view details)

Uploaded Python 3

File details

Details for the file vidurl-0.3.0.tar.gz.

File metadata

  • Download URL: vidurl-0.3.0.tar.gz
  • Upload date:
  • Size: 35.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vidurl-0.3.0.tar.gz
Algorithm Hash digest
SHA256 d12306a77b8a7fb810dd7f3b834a70642a92a5dde339a0f9efac34a457bfe850
MD5 1a28474e9b1d0c7db5a9e3457d2863e5
BLAKE2b-256 441d9163cbca617ff11e6998f0522ac17d3327ef1c77b2cb10f4f93c81fcbc7a

See more details on using hashes here.

File details

Details for the file vidurl-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: vidurl-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 36.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vidurl-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f7e569f5b6ce7a4695509ec29b2e6c420a74e8d02c182bd833957d333aba5d59
MD5 a0242a33b7f1f6af63667cec04ecd202
BLAKE2b-256 687c238a20b83348cc4d5a8b6b85c5a4b49fb09c8df1c1c914ec48f699f13787

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page