Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
b1325bd
docs: add the OpenMedia design spec
ttncode Sep 13, 2026
d067951
docs: add the OpenMedia implementation plan
ttncode Sep 13, 2026
5af3991
feat(api): add settings, error model and runtime readiness checks
ttncode Sep 13, 2026
2b0b50c
feat(api): validate download input and block private network targets
ttncode Sep 13, 2026
ffc45e2
chore: ignore python caches
ttncode Sep 13, 2026
3bdf13b
feat(api): build yt-dlp commands, parse progress and map extraction e…
ttncode Sep 13, 2026
41f2046
feat(api): add the download job engine with retention and storage limits
ttncode Sep 13, 2026
36660be
fix(api): keep the job queue alive on unexpected errors and early can…
ttncode Sep 13, 2026
927b0b1
feat(api): add cookie storage, cross-site guard, rate limiting and op…
ttncode Sep 13, 2026
5d57298
fix(api): harden cookie parsing, session revocation and private file …
ttncode Sep 13, 2026
2430c1e
feat(api): expose the media API with reclip-compatible routes
ttncode Sep 13, 2026
c9fa036
build(api): ship ffmpeg, deno and a data volume in the API image
ttncode Sep 13, 2026
238c6d6
feat(web): add the API proxy, typed client, i18n dictionaries and des…
ttncode Sep 13, 2026
3024d62
fix(web): track the env example and silence the vitest config warning
ttncode Sep 13, 2026
54d8a4b
feat(web): add client state, persistence, API commands and job polling
ttncode Sep 13, 2026
6144a2a
fix(web): read live state in commands and keep polling steady
ttncode Sep 13, 2026
dcc4ec0
feat(web): add Apple-style controls, sheets, alerts and the notice is…
ttncode Sep 13, 2026
46f71be
fix(web): filter undefined capsule classes, close alerts on Escape, c…
ttncode Sep 14, 2026
fd7b900
feat(web): add the download queue and the options inspector with trim…
ttncode Sep 14, 2026
1bc664c
refactor(web): drop duplicated artwork styles from the inspector
ttncode Sep 14, 2026
b143a47
feat(web): add history, settings, password sign-in and installable PW…
ttncode Sep 14, 2026
2cbb75d
fix(web): reject unknown PWA icon sizes and keep history rows non-int…
ttncode Sep 14, 2026
798610f
feat(web): assemble the OpenMedia shell with sidebar, toolbar, tab ba…
ttncode Sep 14, 2026
16bb15a
fix(web): scope Enter to non-buttons, gate shortcuts on overlays, wir…
ttncode Sep 14, 2026
749f2f0
docs: add README, licensing, operator guides and architecture decisions
ttncode Sep 14, 2026
f99a430
docs: fix install command shell, video format wording, cross-site gua…
ttncode Sep 14, 2026
20858e9
fix: name the compose projects and install folder openmedia
ttncode Sep 14, 2026
83c2c98
fix(api): accept any source video height as quality_height
ttncode Sep 14, 2026
b60b21d
fix(api): remux single-file video sources into the chosen container
ttncode Sep 14, 2026
26acab0
fix(web): announce fetched info only for links that became ready
ttncode Sep 14, 2026
d5cac54
fix: add each entry of links that resolve to a playlist or album
ttncode Sep 14, 2026
10818a0
fix(web): use singular English nouns for a count of one
ttncode Sep 14, 2026
bdcae06
fix(web): leave out unknown speed and time left on downloading rows
ttncode Sep 14, 2026
5faca1e
fix(web): refresh storage usage together with the job list
ttncode Sep 14, 2026
016ef6a
fix(web): show the trim length between the start and end fields
ttncode Sep 14, 2026
44ecc2b
fix(web): pin the phone sheet footer to the bottom in a row layout
ttncode Sep 14, 2026
16f1442
docs: add screenshots from the running stack
ttncode Sep 14, 2026
bf68e01
fix(web): expand playlists one level and flag nested playlist entries
ttncode Sep 14, 2026
b73a609
fix(web): keep an error row for playlists without entries
ttncode Sep 14, 2026
d3df4af
fix(web): keep job sync and the last storage value when storage polli…
ttncode Sep 14, 2026
8cf08d7
fix: raise the default request rate limit to 120 per minute
ttncode Sep 14, 2026
fe6f734
fix: report ffmpeg conversion failures with a hint to choose MKV
ttncode Sep 14, 2026
f5b89df
fix(web): say items instead of videos when a playlist is added
ttncode Sep 14, 2026
c2a2974
fix(web): show Ctrl instead of Command in the shortcuts panel off App…
ttncode Sep 14, 2026
bdbfbd0
fix(web): focus the password field on the sign-in screen
ttncode Sep 14, 2026
5a6aaee
fix(docs): explain that playlist links expand even with the single scope
ttncode Sep 14, 2026
9781d91
fix(api): cap sign-in attempts across all clients and evict idle rate…
ttncode Sep 14, 2026
cda129d
fix(api): read forwarded host and proto from the web proxy hop only
ttncode Sep 14, 2026
313de0c
fix(api): report too_large when yt-dlp aborts an oversized file with …
ttncode Sep 14, 2026
c2732c1
fix(api): drop stale yt-dlp copies and wait for the update in the hea…
ttncode Sep 14, 2026
9924a6d
fix: refuse the changeme placeholder password and print the generated…
ttncode Sep 14, 2026
4b5d73a
fix(api): cap concurrent info and playlist lookups at four
ttncode Sep 14, 2026
c6b03a8
fix(api): strip control characters from download file names
ttncode Sep 14, 2026
ba941f7
fix(api): report storage_full when the disk runs out of space
ttncode Sep 14, 2026
d9d5e3e
fix(api): kill the whole process group when a lookup times out
ttncode Sep 14, 2026
cca7403
fix(api): kill a stopped download that ignores SIGTERM after a grace …
ttncode Sep 14, 2026
dfb50f2
fix(compose): keep .env secrets out of the web container
ttncode Sep 14, 2026
2f69985
fix(docs): say deno comes from the yt-dlp deno extra
ttncode Sep 14, 2026
f928175
fix(web): cap proxied request bodies at the API limit and forward abo…
ttncode Sep 14, 2026
b9b1972
fix(web): let the sheet Done button receive its click on touch devices
ttncode Sep 14, 2026
490a80c
fix(web): record history only when a job turns done so clearing it st…
ttncode Sep 14, 2026
3a45bc3
fix(web): show sign in on expired sessions, report outages once and k…
ttncode Sep 14, 2026
144771a
fix(web): snap the trim end to a fractional duration so a full range …
ttncode Sep 14, 2026
be0ef59
fix(web): select queue rows through a button beside the row actions
ttncode Sep 14, 2026
65d88e0
fix(web): fetch at most three links or playlist entries at once
ttncode Sep 14, 2026
878aa9a
fix(web): announce a history entry as added again only after its fetc…
ttncode Sep 14, 2026
570b869
fix(web): validate stored preferences and drop malformed stored entries
ttncode Sep 14, 2026
944d362
fix(web): announce download status changes without reading speed ever…
ttncode Sep 14, 2026
d5dab07
fix(web): escape the thumbnail url in the trim filmstrip
ttncode Sep 14, 2026
331ade6
fix(web): update the toolbar theme icon when the system scheme changes
ttncode Sep 14, 2026
019a12e
fix(web): keep the closed tablet sidebar out of tab order and close i…
ttncode Sep 14, 2026
e344914
fix(web): fall back to solid glass without backdrop blur or with redu…
ttncode Sep 14, 2026
4d0e144
fix(web): stack the alert and shortcuts panels above their scrim so t…
ttncode Sep 14, 2026
79ba5be
fix(web): give the drop overlay a solid fallback without glass
ttncode Sep 14, 2026
2c63e96
fix(web): time out hung polls so job progress keeps updating
ttncode Sep 14, 2026
018e5db
fix(web): translate oversized request errors and drop the pointer cur…
ttncode Sep 14, 2026
a691ed9
fix(api): accept the same true values for yt-dlp auto-update as the a…
ttncode Sep 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ coverage/

.DS_Store
*.swp

__pycache__/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.venv/
apps/api/data/
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Contributing

```bash
mise install # exact toolchain versions, from mise.lock
lefthook install # formatting, secret scan, commit-message check
mise run dev # the compose stack
mise install # exact toolchain versions, from mise.lock
lefthook install # formatting, secret scan, commit-message check
mise run //apps/api:dev # the API
mise run //apps/web:dev # the web UI
```

Before opening a pull request, run `mise run checklist`. It runs exactly what
Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 OpenMedia contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
29 changes: 29 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
OpenMedia
Copyright (c) 2026 OpenMedia contributors

This product is a rebuild of ReClip (https://github.com/averygan/reclip),
released under the MIT License:

MIT License
Copyright (c) 2026 ReClip authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Third-party tools used at runtime: yt-dlp (Unlicense), FFmpeg (LGPL/GPL),
Deno (MIT), Next.js (MIT), Flask (BSD-3-Clause), Phosphor Icons (MIT).
162 changes: 109 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,128 @@
# Openmedia
<div align="center">
<img src="docs/public/logo.svg" alt="OpenMedia" width="96" />
<h1>OpenMedia</h1>
<p>Download videos from almost any website. Lightweight, self-hosted media downloader with a clean web UI.</p>
<p>
<a href="https://github.com/ttncode/openmedia/actions/workflows/ci.yml"><img src="https://github.com/ttncode/openmedia/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<a href="https://github.com/ttncode/openmedia/releases"><img src="https://img.shields.io/github/v/release/ttncode/openmedia?color=12939c" alt="Release" /></a>
<a href="https://github.com/ttncode/openmedia/stargazers"><img src="https://img.shields.io/github/stars/ttncode/openmedia?style=flat&color=12939c" alt="Stars" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-12939c" alt="MIT license" /></a>
</p>
<p>English | <a href="README.vi.md">Tiếng Việt</a></p>
</div>

## Features

- Downloads from 1000+ sites through yt-dlp
- MP4 and MKV video with a quality picker
- MP3, M4A, Opus, FLAC and WAV audio
- Trimming to a time range
- Subtitles, embedded or as a separate SRT file
- Cover art, metadata and chapters embedded in the file
- A queue with live progress, cancel and a concurrency limit
- Bulk links and playlists
- Cookies for age-restricted or bot-checked videos
- Optional password, rate limiting and private-network blocking
- History, drag and drop, paste anywhere, keyboard shortcuts
- Installable PWA with a share target
- Light and dark themes with seven accent colors
- English and Vietnamese

<div align="center">
<img src="docs/public/screenshots/desktop-light.png" alt="OpenMedia desktop, light theme" width="70%" />
<img src="docs/public/screenshots/phone-dark.png" alt="OpenMedia on a phone, dark theme" width="20%" />
</div>

## Installation

### Docker Compose

Download `compose.yaml` and `example.env` from the
[latest release](https://github.com/ttncode/openmedia/releases/latest), then
copy the example settings:

A monorepo generated by [scaffold](https://github.com/ttncode/scaffold). Every
application in it implements the same task contract, so one command works the
same way in every config root and CI never has to learn a language.
```bash
cp example.env .env
```

## Start here
Edit `.env` and set `OPENMEDIA_PASSWORD` to a password of your own. The API
refuses to start while it is still `changeme`; leave it empty only for a
private local instance. Then start the stack:

```bash
mise install # the exact toolchain in mise.lock
lefthook install # formatting, secret scan, commit-message check
mise run dev # the local services this project was generated against
docker compose up -d
```

`mise run dev` starts `compose.dev.yaml` — throwaway local copies of whichever
database and cache this project selected, published on loopback only. A project
generated with neither has nothing to start. See
[docs/getting-started](docs/getting-started.md).
Open `http://localhost:8080`.

## The task contract
### Installer script

Every config root — each `apps/*`, `packages/*` and `docs` — answers the same
nine tasks:
```bash
curl -fsSL https://github.com/ttncode/openmedia/releases/latest/download/install.sh | bash
```

| Task | What it does |
| --------------------- | ------------------------------------------ |
| `install` | install dependencies from the lockfile |
| `format`/`format-fix` | report / repair formatting |
| `lint` | report lint failures |
| `check` | type-check |
| `test` | run the tests |
| `build` | produce the build output |
| `ci-unit` | what CI runs on a pull request |
| `checklist` | `ci-unit` plus `build` — the pre-push gate |
The installer generates a random password and prints it with the address when
it finishes.

Run one for a single root with `mise run //apps/api:ci-unit`, or `mise run
checklist` from the project root to run every root at once. That is exactly
what CI runs, so a green checklist locally means a green pull request.
### From source

## Layout
```bash
git clone https://github.com/ttncode/openmedia.git
cd openmedia
mise install
mise run //apps/api:dev
mise run //apps/web:dev
```

| Path | What lives there |
| ------------------ | --------------------------------------------------- |
| `apps/` | the applications, one config root each |
| `packages/` | code shared between them |
| `docs/` | the documentation site, and `docs/decisions` |
| `compose.yaml` | the stack a client runs, attached to every release |
| `compose.dev.yaml` | throwaway local services, started by `mise run dev` |
| `install.sh` | what an operator runs on the target host |
Open `http://localhost:3000`.

## Releasing and installing
## Documentation

Commits are [Conventional Commits](https://www.conventionalcommits.org);
Release Please turns `feat:` and `fix:` on `main` into a release, and the
release publishes a container image and attaches `compose.yaml`, `example.env`
and `install.sh` to it.
- [Getting started](docs/getting-started.md)
- [Usage](docs/usage.md)
- [Configuration](docs/configuration.md)
- [Deployment](docs/deployment.md)
- [Troubleshooting](docs/troubleshooting.md)
- [Security](docs/security.md)

An operator installs a release with:
## For Developers

```bash
curl -fsSL https://github.com/ttncode/openmedia/releases/latest/download/install.sh | bash
```
Every config root (`apps/api`, `apps/web`, `docs`) answers the same task
contract: `install`, `format`/`format-fix`, `lint`, `check`, `test`, `build`,
`ci-unit`, `checklist`. Run one root's checks with `mise run
//apps/api:ci-unit`, or `mise run checklist` from the project root to run
every root, which is exactly what CI runs.

| Path | What lives there |
| ---------- | --------------------------------- |
| `apps/api` | Flask backend, yt-dlp integration |
| `apps/web` | Next.js web UI |
| `docs` | This documentation site |

See [CONTRIBUTING.md](CONTRIBUTING.md) for the branch and commit conventions.

## Get Help

- [Troubleshooting guide](docs/troubleshooting.md)
- [Report a problem](https://github.com/ttncode/openmedia/issues)
- [Security policy](SECURITY.md)

## Acknowledgments

- [ReClip](https://github.com/averygan/reclip), the project OpenMedia is built on
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
- [FFmpeg](https://ffmpeg.org)
- [Deno](https://deno.com)
- [Next.js](https://nextjs.org)
- [Flask](https://flask.palletsprojects.com)
- [Phosphor Icons](https://phosphoricons.com)
- The [scaffold](https://github.com/ttncode/scaffold) toolbox this project was generated with

## Disclaimer

A private project needs a `GITHUB_TOKEN` carrying `repo` and `read:packages` —
see [docs/deployment](docs/deployment.md) for why one scope is not enough.
OpenMedia is for personal use. Respect copyright law and the terms of service
of the sites you download from.

## Contributing
## License

[CONTRIBUTING.md](CONTRIBUTING.md) covers the branch and commit conventions.
Architecture decisions live in [docs/decisions](docs/decisions); read the
relevant one before changing behaviour it covers, and add one when you make a
decision the next reader would otherwise have to reconstruct.
MIT, see [LICENSE](LICENSE) and [NOTICE](NOTICE).
128 changes: 128 additions & 0 deletions README.vi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<div align="center">
<img src="docs/public/logo.svg" alt="OpenMedia" width="96" />
<h1>OpenMedia</h1>
<p>Tải video từ hầu hết mọi trang web. Công cụ tải media gọn nhẹ, tự lưu trữ, với giao diện web rõ ràng.</p>
<p>
<a href="https://github.com/ttncode/openmedia/actions/workflows/ci.yml"><img src="https://github.com/ttncode/openmedia/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<a href="https://github.com/ttncode/openmedia/releases"><img src="https://img.shields.io/github/v/release/ttncode/openmedia?color=12939c" alt="Release" /></a>
<a href="https://github.com/ttncode/openmedia/stargazers"><img src="https://img.shields.io/github/stars/ttncode/openmedia?style=flat&color=12939c" alt="Stars" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-12939c" alt="MIT license" /></a>
</p>
<p><a href="README.md">English</a> | Tiếng Việt</p>
</div>

## Tính năng

- Tải từ hơn 1000 trang web thông qua yt-dlp
- Video MP4 và MKV với bộ chọn chất lượng
- Âm thanh MP3, M4A, Opus, FLAC và WAV
- Cắt theo khoảng thời gian
- Phụ đề, nhúng vào video hoặc tách riêng dưới dạng SRT
- Nhúng ảnh bìa, metadata và chương vào tệp
- Hàng đợi hiển thị tiến độ trực tiếp, có thể hủy và giới hạn số lượng tải cùng lúc
- Dán nhiều liên kết cùng lúc và tải playlist
- Cookie cho video giới hạn độ tuổi hoặc bị chặn kiểm tra bot
- Mật khẩu tùy chọn, giới hạn tốc độ yêu cầu và chặn địa chỉ mạng nội bộ
- Lịch sử, kéo thả, dán bất kỳ đâu, phím tắt
- Cài đặt được như một PWA với share target
- Giao diện sáng và tối với bảy màu nhấn
- Tiếng Anh và tiếng Việt

<div align="center">
<img src="docs/public/screenshots/desktop-light.png" alt="OpenMedia trên desktop, giao diện sáng" width="70%" />
<img src="docs/public/screenshots/phone-dark.png" alt="OpenMedia trên điện thoại, giao diện tối" width="20%" />
</div>

## Cài đặt

### Docker Compose

Tải `compose.yaml` và `example.env` từ
[bản phát hành mới nhất](https://github.com/ttncode/openmedia/releases/latest), sau đó
sao chép tệp cấu hình mẫu:

```bash
cp example.env .env
```

Sửa `.env` và đặt `OPENMEDIA_PASSWORD` thành mật khẩu của riêng bạn. API sẽ
không khởi động khi giá trị vẫn là `changeme`; chỉ để trống khi chạy riêng trên
máy hoặc mạng cục bộ của bạn. Sau đó khởi động:

```bash
docker compose up -d
```

Mở `http://localhost:8080`.

### Script cài đặt

```bash
curl -fsSL https://github.com/ttncode/openmedia/releases/latest/download/install.sh | bash
```

Script tạo một mật khẩu ngẫu nhiên và in mật khẩu cùng địa chỉ truy cập khi
hoàn tất.

### Từ mã nguồn

```bash
git clone https://github.com/ttncode/openmedia.git
cd openmedia
mise install
mise run //apps/api:dev
mise run //apps/web:dev
```

Mở `http://localhost:3000`.

## Tài liệu

- [Bắt đầu](docs/getting-started.md)
- [Sử dụng](docs/usage.md)
- [Cấu hình](docs/configuration.md)
- [Triển khai](docs/deployment.md)
- [Xử lý sự cố](docs/troubleshooting.md)
- [Bảo mật](docs/security.md)

## Dành cho lập trình viên

Mỗi thư mục gốc cấu hình (`apps/api`, `apps/web`, `docs`) trả lời cùng một hợp
đồng tác vụ: `install`, `format`/`format-fix`, `lint`, `check`, `test`,
`build`, `ci-unit`, `checklist`. Chạy kiểm tra của một thư mục bằng `mise run
//apps/api:ci-unit`, hoặc `mise run checklist` từ thư mục gốc dự án để chạy
tất cả, đúng như những gì CI thực hiện.

| Đường dẫn | Nội dung |
| ---------- | ------------------------------ |
| `apps/api` | Backend Flask, tích hợp yt-dlp |
| `apps/web` | Giao diện web Next.js |
| `docs` | Trang tài liệu này |

Xem [CONTRIBUTING.md](CONTRIBUTING.md) để biết quy ước nhánh và commit.

## Cần trợ giúp

- [Hướng dẫn xử lý sự cố](docs/troubleshooting.md)
- [Báo cáo vấn đề](https://github.com/ttncode/openmedia/issues)
- [Chính sách bảo mật](SECURITY.md)

## Lời cảm ơn

- [ReClip](https://github.com/averygan/reclip), dự án mà OpenMedia được xây dựng dựa trên
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
- [FFmpeg](https://ffmpeg.org)
- [Deno](https://deno.com)
- [Next.js](https://nextjs.org)
- [Flask](https://flask.palletsprojects.com)
- [Phosphor Icons](https://phosphoricons.com)
- Bộ công cụ [scaffold](https://github.com/ttncode/scaffold) đã tạo dự án này

## Miễn trừ trách nhiệm

OpenMedia dành cho mục đích cá nhân. Hãy tôn trọng luật bản quyền và điều
khoản dịch vụ của các trang bạn tải xuống.

## Giấy phép

MIT, xem [LICENSE](LICENSE) và [NOTICE](NOTICE).
1 change: 1 addition & 0 deletions apps/api/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ __pycache__
.env
.env.*
.git
data/
Loading