Small FastAPI app for uploading, downloading, and deleting files in a local directory.
Storage location
Files are stored in ~/upload/files (resolved from the running user's home directory).
Run
Install:
pip install "fastapi[standard]"Optional (Twitter/X article extraction):
npm installProduction-style:
fastapi run server.py --host 0.0.0.0 --port 8000Dev mode with reload:
fastapi dev server.py --host 0.0.0.0 --port 8000Endpoints
GET /- Chunked HTML upload form (loads
index.html).
- Chunked HTML upload form (loads
GET /help- Returns this README as plain text.
GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD /header- Returns the received request headers as JSON.
- If the request includes an
Originheader, the response mirrors it in CORS headers so browser requests from that site can read the result.
POST /check/chunk- JSON body:
filename,block_id,block_md5,block_size, optionaltotal_size. - Response:
{ "exists": true|false }based on MD5 match at the expected offset.
- JSON body:
POST /upload/chunk- Multipart form fields:
filename,block_id,block_md5,block_size, optionaltotal_size, plusfile(chunk bytes). - Writes chunk into
filename.partand renames to the final filename when the last chunk is received.
- Multipart form fields:
POST /upload/url- JSON body:
url, optionalfilename. - Server downloads the URL (defaults to
https://if no scheme is provided) and saves it into~/upload/files. - Follows HTTP redirects.
- Download starts in the background and returns immediately with a relative
url. - Accessing the file while downloading returns
202 File is downloading. - Auto-rewrite helpers:
- arXiv
https://arxiv.org/abs/...orhttps://arxiv.org/html/...are downloaded ashttps://arxiv.org/pdf/...with a.pdffilename. - GitHub repo
https://github.com/{owner}/{repo}is downloaded as.../archive/refs/heads/master.zip(or.../tree/{branch}to the branch zip). - GitHub file
https://github.com/{owner}/{repo}/blob/{branch}/pathis downloaded as.../raw/refs/heads/{branch}/path. - Twitter/X articles
https://twitter.com/i/article...,https://twitter.com/i/articles/..., orhttps://x.com/{user}/article/...are downloaded as a.mdfile extracted from the article title and body. - Twitter/X status URLs are supported; if the tweet links to an article, the article content is used.
- arXiv
- JSON body:
GET /url_status/{filename}- Returns JSON status for a URL download:
status,downloaded,total,url.
- Returns JSON status for a URL download:
GET /speed_test/download- Query:
size(bytes, default 10 MB, max 200 MB). Returns a stream for download speed tests.
- Query:
POST /speed_test/upload- Raw body upload for speed tests (max 200 MB). Returns bytes received.
GET /{filename}- Download a file from
~/upload/files. - Text-like types (
text/*, JSON, XML, JS) are served inline; others download as attachments.
- Download a file from
GET /rm/{pattern}- Deletes files matching a glob pattern in
~/upload/files. - Example:
GET /rm/*.txtdeletes all.txtfiles. - Only basename patterns are allowed (no path separators).
- Deletes files matching a glob pattern in
Notes
- Upload and delete operations only affect files in
~/upload/files. - Directory traversal is blocked by requiring the path to be a basename.
- Chunked uploads use 1,000,000-byte blocks and can resume by checking existing blocks.
- Before each upload (multipart, chunk, or URL), the server ensures at least 5 GB free space.
- If free space is below 5 GB, the largest file in
~/upload/filesis deleted.
- If free space is below 5 GB, the largest file in
- Twitter/X article extraction uses a Node script powered by
@the-convocation/twitter-scraper.- The script extracts the tweet/article id from the URL and uses
Scraper.getTweet. - If articles require auth, set
TWITTER_COOKIES(orTWITTER_COOKIE) for the Node fetcher. - If
nodeis not on PATH, setTWITTER_NODE_PATHto the Node binary.
- The script extracts the tweet/article id from the URL and uses
Examples
The URL upload endpoint includes built-in URL normalization for common sources (arXiv and GitHub) so you can paste a share link and still download the actual file.
Twitter Article Upload
Twitter/X article and status URLs are fetched via the Node scraper and saved as Markdown. Re-uploading the same URL will refresh the file (it replaces the previous download).
- arXiv
https://arxiv.org/abs/2512.01457v4→https://arxiv.org/pdf/2512.01457v4https://arxiv.org/html/2512.01457v4→https://arxiv.org/pdf/2512.01457v4
- GitHub repo
https://github.com/moonshotai/attention-residuals→https://github.com/moonshotai/attention-residuals/archive/refs/heads/master.zip
- GitHub file
https://github.com/MoonshotAI/Attention-Residuals/blob/master/Attention_Residuals.pdf→https://github.com/MoonshotAI/Attention-Residuals/raw/refs/heads/master/Attention_Residuals.pdf
- Twitter/X article
https://twitter.com/i/article/1234567890→twitter-article-1234567890.mdhttps://twitter.com/i/articles/1234567890→twitter-article-1234567890.mdhttps://x.com/RayDalio/article/1234567890→twitter-article-1234567890.md
- Twitter/X status
https://x.com/user/status/1234567890→twitter-article-1234567890.md