# All Url Uploader: a Telegram bot that turns a link into a file

> All Url Uploader is an aiogram bot that accepts a direct file URL or a supported media link, fetches it with the right tool, and sends the result back into Telegram with the correct media type, metadata and an optional custom thumbnail. It is a small, well-tooled Python project with CI, CodeQL, pylint, pytest and a one-command Docker image, and the interesting engineering is in how it handles four different link shapes.

**kalanakt/All-Url-Uploader** — A simple telegram Bot, Upload Media File| video To telegram using the direct download link. (youtube, Mediafire, google drive, mega drive, etc)

- Repository: https://github.com/kalanakt/All-Url-Uploader
- Website: https://urluploader.vercel.app
- Stars: 538 · Forks: 1,098
- Language: Python
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/kalanakt-all-url-uploader

## What the bot does

All Url Uploader is a Telegram bot that accepts direct file URLs and supported media links, downloads them with the right tool for the job, and sends the result back to Telegram with the correct media type, metadata, and optional custom thumbnail. The repository description puts it more bluntly: upload direct links and supported media sources back to Telegram.

The built with line is short and tells you the stack: aiogram for the Telegram framework, yt-dlp for the sources that need a dedicated extractor, and uv for a cleaner local workflow.

The primary language is Python, the licence is MIT, the default branch is main, and the homepage is urluploader.vercel.app. The recent releases are v3.0.0 from 2026-04-14, v2.1.0 from 2024-01-09 and v2.0.2 from 2022-08-26, and the last push was on 2026-10-20 with the project not archived. There is a gap of over two years between v2.1.0 and v3.0.0, and then a v3.0.0 in April 2026 followed by active work through the summer.

The topic list gives a sense of the intended sources, with youtube, youtube-downloader, yt-dlp, medifile, googledrive, megadrive, galaxy, directlink and download-manager among them, and also psa-rips, which is a term from the music scene release world and is the one tag worth pausing on.

The bot's scope is deliberately narrow and worth stating plainly. It moves files from a URL into a Telegram chat. It does not host them, it does not index them, and it does not search for them. What it does is remove the need to download something to your own machine before you can forward it, which is a small convenience that a lot of people want and few bots do cleanly.

The topic list also includes heroku-deployment and the README carries one-click deploy buttons for Railway, Koyeb and Heroku, so the intended deployment is a small always-on service on a PaaS rather than a machine you keep at home.

## The four link shapes it accepts

The What It Handles section lists the accepted input formats, and the list is the clearest statement of the design.

There is a plain direct file link. There is url|filename, which appends a chosen filename. There is url|filename|username|password, for links that need credentials. And there is url * filename, which uses a different separator for the case where the filename itself contains a pipe.

Four shapes, one of them with an escape hatch. The separator choice is the interesting bit, because a URL can legitimately contain a pipe character in a query string, and a naive split on the first pipe would truncate it. Offering both pipe and asterisk as separators lets the user pick one that cannot appear in their URL, and that is a small design decision with a real user-facing effect.

On top of that there are YouTube quick audio and quick video downloads, and format selection for supported yt-dlp sources. That is the part where yt-dlp comes in, and it is the part that has to be handled differently from a plain HTTP fetch, because a media page is not a file and the extractor has to run first to find out what the actual file is.

Then the two thumbnail commands, which are per-user. Custom per-user thumbnails can be set with /thumb and removed with /delthumb. Per-user rather than global matters in a multi-user bot, because a shared thumbnail would be one person's choice imposed on everybody else's uploads.

The command set is small and each command does one thing. /start gives a welcome message with shortcuts and usage guidance. /help lists the supported link formats and an overview of the flow. /about gives runtime details, a repository link and project notes. /thumb shows the currently saved custom thumbnail and /delthumb removes it.

The /help command including the flow overview is a thoughtful touch for a bot whose input format is not obvious from the description, and the whole point of the tool is that a user should be able to work out the syntax without reading the source.

## Setting it up, and the environment variables that matter

The Quick Start is four steps and the third one is where the interesting flag is.

Clone the repository and move into it:

```bash
git clone https://github.com/kalanakt/All-Url-Uploader.git
cd All-Url-Uploader
```

Then create a .env file in the project root:

```dotenv
BOT_TOKEN=
OWNER_ID=
AUTH_USERS=
DOWNLOAD_LOCATION=./DOWNLOADS
CHUNK_SIZE=128
HTTP_PROXY=
PROCESS_MAX_TIMEOUT=3700
```

Then install the dependencies:

```bash
uv sync --group dev
```

And start the bot:

```bash
uv run python bot.py
```

The .env file is eight lines and each one is worth reading, because the defaults are not all neutral.

BOT_TOKEN is the Telegram bot token and is required. OWNER_ID is the Telegram user id of the bot owner and is required, which tells you the bot has an owner concept rather than being open to anyone who finds the handle.

AUTH_USERS is an optional comma-separated list of user ids that bypass the cooldown. So there is a cooldown by default, and this is the opt-out list for people who should not be subject to it. A bot that downloads and re-uploads files on demand is expensive to serve per request, and a cooldown is the standard way to keep one user from consuming the quota for everyone else.

DOWNLOAD_LOCATION is an optional base directory for temporary downloads and uploads, defaulting to ./DOWNLOADS. The word temporary is doing real work here, because a bot that downloads a file has to put it somewhere on disk before it can upload it, and on a small PaaS container that disk is the constraint.

CHUNK_SIZE is an optional direct-download chunk size, and the documentation has a wrinkle worth noting: values below 1024 are treated as kilobytes for backward compatibility. That is a real migration hazard left in place rather than cleaned up, and the practical effect is that an old configuration file keeps working after an upgrade.

HTTP_PROXY is an optional proxy URL passed to network requests and to yt-dlp. And PROCESS_MAX_TIMEOUT is an optional process timeout in seconds for external tools, defaulting to 3700, which is a little over an hour, which is the right order of magnitude for a large media download over a slow link.

So the three settings that most affect how the bot behaves in practice are the cooldown and its bypass list, the proxy, and the download directory, and the first of those is the one to think about before putting the bot in front of other people.

## The packaging, and what the project layout says

The project layout section is short and gives a clear division.

The root runtime entrypoints are bot.py, app.py and config.py. The routers/ directory holds the Telegram handlers, services/ holds the business logic, utils/ holds shared helpers and models, tests/ holds the tests, and docs/ is the external documentation site.

The pyproject confirms that split in its packaging. The py-modules list names app and config as top-level modules, and the packages find directive includes routers, services and utils. The three names that are excluded from the packages find, the ones listed as py-modules, are exactly the two of the three root entrypoints that are not bot.py, which suggests bot.py is the executable rather than an importable module.

The dependency list is short and every entry has a reason:

```toml
    "aiogram>=3.21.0,<4",
    "aiohttp>=3.14.3,<4",
    "hachoir>=3.3.0,<4",
    "python-dotenv>=1.0.1,<2",
    "yt-dlp>=2026.7.4",
```

aiogram at 3.21 or newer but below 4 is the Telegram framework, and the upper bound is the kind of constraint worth respecting since aiogram has had breaking major versions. aiohttp is the async HTTP client. hachoir is the metadata analyser, and it is the reason the bot can report file metadata without knowing the format in advance, since hachoir inspects the file and works out what it is. python-dotenv reads the .env file. And yt-dlp is pinned to a 2026 release, which tells you the project tracks yt-dlp closely, which it has to, since extractor support is the whole point of using it.

The dev group is three packages:

```toml
dev = [
    "pylint>=3.3.0,<4",
    "pytest>=8.3.0,<9",
    "pytest-asyncio>=0.24.0,<1",
]
```

pylint for linting, pytest and pytest-asyncio for the tests, with asyncio_mode set to auto in the pytest configuration so that the async test cases do not each need a decorator. The testpaths setting points at tests, and the setup.cfg, .pylintrc and .hintrc files in the tree are the configuration for those tools.

The autopep8 configuration is also present, with a max line length of 150 and a set of ignored codes, and it runs in place and recursively, so formatting is applied to the tree rather than checked. That is a slightly older style of setup than the ruff-based configurations you see in newer Python projects, and it is a hint about the project's age.

There is a renovate.json for dependency updates, a uv.lock for reproducible installs, and a .pre-commit-config.yaml in the tree, so the dependency and hook automation is all in place.

## The Dockerfile and the checks

The Dockerfile is short and the ordering is the interesting part.

```dockerfile
FROM python:3.11-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

RUN apt-get update \
    && apt-get install -y --no-install-recommends curl ffmpeg \
    && rm -rf /var/lib/apt/lists/*

RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:${PATH}"

WORKDIR /app

COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project

COPY . .
RUN uv sync --frozen --no-dev

CMD ["uv", "run", "python", "bot.py"]
```

The base is python:3.11-slim, which matches the requires-python floor of >=3.11,<3.12 in the manifest, and the two environment variables are the standard pair: no bytecode writing and unbuffered output, so that logs appear promptly in a container.

The first apt-get installs curl and ffmpeg with --no-install-recommends, and then the apt lists are removed. ffmpeg is there for the yt-dlp paths, since extracting and re-muxing audio and video needs it, and curl is needed by the next step.

Then uv is installed by piping its official install script through a shell, and the PATH is extended to include /root/.local/bin. The workdir is /app.

The dependency layer is copied first on its own, pyproject.toml and uv.lock together, and uv sync --frozen --no-dev --no-install-project runs. The --frozen flag uses the lockfile exactly as it is, and --no-install-project installs the dependencies without installing the project itself, which is the standard uv trick to get a cached dependency layer. Then the source is copied and uv sync --frozen --no-dev runs again, this time installing the project too. The result is that a change to your source code does not invalidate the dependency layer, so rebuilds are fast.

The entrypoint is uv run python bot.py, which is the same command the Quick Start tells you to run locally, so the container and the local workflow behave identically.

The Checks section is where the project's own standard of quality is stated, and it says the same checks are used in GitHub Actions:

```bash
uv run pytest
uv run pylint $(git ls-files '*.py')
cd docs && npm run build
```

So there are three: pytest for the tests, pylint over every Python file tracked by git, and a build of the documentation site with npm. The pylint invocation uses git ls-files rather than a directory, so the lint covers exactly what is in the repository.

The badges tell the rest of the story. There is a CI badge and a CodeQL badge, and CodeQL is GitHub's security analysis, which on a project that downloads files from arbitrary URLs and executes an external process is not decoration. There is a Python 3.11 badge matching the pinned interpreter range, and a licence badge.

The SECURITY.md file at the root, alongside the CODE_OF_CONDUCT.md and CONTRIBUTING.md, completes the set of files a project maintains when it expects to be deployed by strangers.

## How to evaluate it, and what to check first

There are four things to consider, and the first one is about what you will use it for.

This is a file transfer tool. It moves content from a URL into a Telegram chat, and it can do it for YouTube and other yt-dlp sources, which means the content it moves may be something you have no right to redistribute, and the topic tags include psa-rips, which is a term from the music release scene. If you intend to run this for yourself, to move your own files around, that is straightforward. If you intend to run it as a public service, the legal exposure of hosting other people's media is the first thing to think about, and it is not a technical problem the code can solve.

Second, the operational side. A bot that downloads arbitrary files from arbitrary URLs and re-uploads them needs a temporary directory with real space in it, a network egress allowance, and a process timeout long enough for large media, and the defaults give you the shape of that: ./DOWNLOADS for the temporary space, a 3700 second process timeout and a proxy setting for outbound traffic.

Third, the access control, which is thinner than it might look. There is an owner id and an optional list of user ids that bypass the cooldown, but the documentation does not describe a general allow-list. The /start and /help behaviour and the cooldown are what stand between an anonymous user and your account's quota. On a shared or public bot, that is the part to read the source for rather than assume.

Fourth, the tooling, which is the strongest part of the project. Continuous integration, CodeQL, pytest with asyncio in auto mode, pylint over the tracked files, a documentation build in the same check set, renovate for dependency updates, a pre-commit configuration, and a Dockerfile with a properly cached dependency layer and a pinned interpreter range that matches the manifest. For a project of this size, that is more infrastructure than most, and it means a fork is a reasonable starting point rather than a mess.

What you get is a small, well-organised bot with a real installation story, four deploy buttons, and a code layout that separates Telegram handlers from business logic, so adapting it to your own sources or your own authentication model is a matter of editing services/ rather than rewriting the project.

## Conclusion

Adopt All Url Uploader if you want a Telegram bot that turns a link into a file with the metadata and a per-user thumbnail already attached, and you are deploying it for yourself or for a group you control, since the code separates Telegram handlers from the download services and the packaging is ready to fork. Do not run it as a public service for other people without thinking about the rights to the material it moves, because the bot will happily fetch and re-host whatever it is pointed at. Before you commit, change the default credentials by setting BOT_TOKEN and OWNER_ID, read the source for the general access control rather than assuming the cooldown is an allow-list, and make sure the container has temporary disk for the download directory and a process timeout long enough for the largest file you expect to move.

## FAQ

### What is All Url Uploader?

It is a Telegram bot that accepts direct file URLs and supported media links, downloads them with the right tool for the job, and sends the result back to Telegram with the correct media type, metadata and optional custom thumbnail. It is MIT licensed, written in Python with aiogram, yt-dlp and uv, and the last push to the repository was on 2026-10-20.

### What link formats does the All Url Uploader bot accept?

A plain direct file link, url|filename, url|filename|username|password for links needing credentials, and url * filename for cases where the filename contains a pipe. It also handles YouTube quick audio and quick video downloads and format selection for supported yt-dlp sources.

### How do I install and run All Url Uploader?

Clone the repository, create a .env file in the project root with the settings, run uv sync --group dev to install the dependencies, and then start the bot with uv run python bot.py. The required settings are BOT_TOKEN and OWNER_ID, with optional AUTH_USERS, DOWNLOAD_LOCATION, CHUNK_SIZE, HTTP_PROXY and PROCESS_MAX_TIMEOUT.

### What do the CHUNK_SIZE and PROCESS_MAX_TIMEOUT settings do?

CHUNK_SIZE is an optional direct-download chunk size, and values below 1024 are treated as kilobytes for backward compatibility, so an older configuration file keeps working after an upgrade. PROCESS_MAX_TIMEOUT is an optional timeout in seconds for external tools such as yt-dlp, and it defaults to 3700 seconds, which is the right order of magnitude for a large media download.

### How do I run All Url Uploader with Docker?

Build the image with docker build -t all-url-uploader . and run it with docker run --env-file .env all-url-uploader. The Dockerfile is based on python:3.11-slim, installs curl and ffmpeg, installs uv, and layers the dependencies from the lockfile before copying the source so that code changes do not invalidate the dependency layer. The entrypoint is uv run python bot.py.

## Sources

- [kalanakt/All-Url-Uploader on GitHub](https://github.com/kalanakt/All-Url-Uploader)
- [License: MIT](https://github.com/kalanakt/All-Url-Uploader/blob/main/LICENSE)
- [Project website](https://urluploader.vercel.app)
- [README](https://github.com/kalanakt/All-Url-Uploader/blob/main/README.md)
- [Releases](https://github.com/kalanakt/All-Url-Uploader/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kalanakt-all-url-uploader
