fetchforge 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fetchforge-2.0.0/LICENSE +21 -0
- fetchforge-2.0.0/MANIFEST.in +3 -0
- fetchforge-2.0.0/PKG-INFO +131 -0
- fetchforge-2.0.0/README.md +115 -0
- fetchforge-2.0.0/fetchforge/__init__.py +3 -0
- fetchforge-2.0.0/fetchforge/__main__.py +4 -0
- fetchforge-2.0.0/fetchforge/cli.py +27 -0
- fetchforge-2.0.0/fetchforge/index.html +2978 -0
- fetchforge-2.0.0/fetchforge/provision.py +116 -0
- fetchforge-2.0.0/fetchforge/server.py +2198 -0
- fetchforge-2.0.0/fetchforge.egg-info/PKG-INFO +131 -0
- fetchforge-2.0.0/fetchforge.egg-info/SOURCES.txt +24 -0
- fetchforge-2.0.0/fetchforge.egg-info/dependency_links.txt +1 -0
- fetchforge-2.0.0/fetchforge.egg-info/entry_points.txt +2 -0
- fetchforge-2.0.0/fetchforge.egg-info/requires.txt +4 -0
- fetchforge-2.0.0/fetchforge.egg-info/top_level.txt +1 -0
- fetchforge-2.0.0/pyproject.toml +33 -0
- fetchforge-2.0.0/setup.cfg +4 -0
- fetchforge-2.0.0/tests/test_batch_pipeline.py +163 -0
- fetchforge-2.0.0/tests/test_cli.py +43 -0
- fetchforge-2.0.0/tests/test_encode.py +106 -0
- fetchforge-2.0.0/tests/test_history.py +42 -0
- fetchforge-2.0.0/tests/test_pipeline_sim.py +153 -0
- fetchforge-2.0.0/tests/test_provision.py +131 -0
- fetchforge-2.0.0/tests/test_server.py +142 -0
- fetchforge-2.0.0/tests/test_tool_resolution.py +27 -0
fetchforge-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Petur Bjarnason
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fetchforge
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Download YouTube videos and transcode to H.265/HEVC with NVIDIA NVENC — a localhost web app.
|
|
5
|
+
Author: Petur Bjarnason
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/prekabreki/fetchforge
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: fastapi
|
|
12
|
+
Requires-Dist: uvicorn
|
|
13
|
+
Requires-Dist: python-multipart
|
|
14
|
+
Requires-Dist: yt-dlp[default]
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# FetchForge
|
|
18
|
+
|
|
19
|
+
> **Requires an NVIDIA GPU with NVENC.** The H.265 transcode uses hardware
|
|
20
|
+
> `hevc_nvenc` and has no CPU-encode fallback — without an NVIDIA card the
|
|
21
|
+
> transcode path cannot run (download + audio-extract still work). macOS has no
|
|
22
|
+
> NVIDIA GPUs, so the transcode is Windows/Linux only.
|
|
23
|
+
|
|
24
|
+
FetchForge is a localhost web app that downloads YouTube videos and playlists
|
|
25
|
+
and transcodes them to H.265/HEVC using NVIDIA NVENC hardware encoding. Single
|
|
26
|
+
videos, full playlists with pipeline mode, and local-file conversion. Smart
|
|
27
|
+
auto-analysis picks CQ, maxrate, and preset from the source.
|
|
28
|
+
|
|
29
|
+
## Install & launch
|
|
30
|
+
|
|
31
|
+
**With pip (recommended):**
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pip install fetchforge
|
|
35
|
+
fetchforge
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The browser opens automatically at `http://localhost:8765`. On Windows, if an
|
|
39
|
+
NVENC-capable ffmpeg isn't already present, FetchForge downloads one on first
|
|
40
|
+
run. On Linux, install ffmpeg from your package manager first
|
|
41
|
+
(`sudo dnf install ffmpeg` / `sudo apt install ffmpeg`) and make sure the NVIDIA
|
|
42
|
+
driver is loaded. macOS has no NVIDIA GPU, so the H.265 transcode can't run
|
|
43
|
+
there, but download and audio-extract still work and just need ffmpeg
|
|
44
|
+
(`brew install ffmpeg`).
|
|
45
|
+
|
|
46
|
+
**Output files land in the current directory** — run `fetchforge` from wherever
|
|
47
|
+
you want `downloads/` to appear.
|
|
48
|
+
|
|
49
|
+
**From source (clone):**
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
git clone https://github.com/prekabreki/fetchforge
|
|
53
|
+
cd fetchforge
|
|
54
|
+
./launch.sh # Windows: launch.bat
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> "Update yt-dlp" in the UI is a no-op for pip installs — update with
|
|
58
|
+
> `pip install -U fetchforge` (or `pip install -U "yt-dlp[default]"`).
|
|
59
|
+
|
|
60
|
+
## Stack
|
|
61
|
+
|
|
62
|
+
- **Backend** — `fetchforge/server.py` (FastAPI + uvicorn, fully async)
|
|
63
|
+
- **Frontend** — `fetchforge/index.html` (single file, vanilla JS + SSE, no build step)
|
|
64
|
+
- **CLI entry point** — `fetchforge/cli.py`, exposed as the `fetchforge` console script (also runnable as `python -m fetchforge`)
|
|
65
|
+
- **Downloader** — `yt-dlp[default]`, a regular dependency (pulled in by pip, not bundled)
|
|
66
|
+
- **Encoder** — ffmpeg + `hevc_nvenc` (NVENC); auto-downloaded to a per-user cache on Windows, expected on `PATH` on Linux
|
|
67
|
+
- **Packaging** — `pyproject.toml`; `pip install fetchforge` for the package, `pip install -e .` for an editable clone
|
|
68
|
+
- **Launchers** — `launch.bat` (Windows) / `launch.sh` (Linux/macOS) for the clone workflow: create/reuse a venv, `pip install -e .`, open the browser, run `python -m fetchforge`
|
|
69
|
+
|
|
70
|
+
## What's NOT in the repo (gitignored)
|
|
71
|
+
|
|
72
|
+
These are restored locally — they're either rebuildable, regenerable, or sensitive.
|
|
73
|
+
|
|
74
|
+
| Path | Why ignored |
|
|
75
|
+
|------|-------------|
|
|
76
|
+
| `_internal/` | Optional manual ffmpeg override for a source clone on Windows — pip installs auto-provision ffmpeg into `%LOCALAPPDATA%\FetchForge\ffmpeg` instead |
|
|
77
|
+
| `yt-dlp.exe` | Optional manual override; the normal path gets yt-dlp as a pip dependency, updated via `pip install -U`, not a dropped binary |
|
|
78
|
+
| `cookies.txt` | YouTube auth cookies (sensitive — never commit) |
|
|
79
|
+
| `history.json` | Last 50 downloaded URLs (per-machine state) |
|
|
80
|
+
| `logs/` | Runtime logs |
|
|
81
|
+
| `downloads/` | Output MP4s |
|
|
82
|
+
|
|
83
|
+
`cookies.txt`, `history.json`, `logs/`, and `downloads/` are runtime state and
|
|
84
|
+
live under the current working directory you launch `fetchforge` from.
|
|
85
|
+
`_internal/` and `yt-dlp.exe` are the two exceptions: they're optional manual
|
|
86
|
+
overrides FetchForge looks for next to the installed package itself, not the
|
|
87
|
+
cwd — the normal pip install path never needs them.
|
|
88
|
+
|
|
89
|
+
## First-run setup on a new machine
|
|
90
|
+
|
|
91
|
+
1. `pip install fetchforge`.
|
|
92
|
+
2. Run `fetchforge`. On Windows it downloads an NVENC-capable ffmpeg build automatically the first time it's needed. On Linux, install `ffmpeg` from your package manager first and confirm the NVIDIA driver is loaded — FetchForge won't fetch a build for you there.
|
|
93
|
+
3. (Optional) Upload a `cookies.txt` via the **Authentication** card if you need age-restricted, private, or members-only content — see [Cookies](#cookies) below for how to get one.
|
|
94
|
+
|
|
95
|
+
Working from a clone instead: run `./launch.sh` (or `launch.bat` on Windows) — it sets up a `.venv`, installs the package in editable mode, and starts the server the same way.
|
|
96
|
+
|
|
97
|
+
## Cookies
|
|
98
|
+
|
|
99
|
+
Public videos need no cookies. Cookies are only necessary for age-restricted,
|
|
100
|
+
private, or members-only videos, which require a logged-in YouTube session.
|
|
101
|
+
|
|
102
|
+
To get a `cookies.txt`:
|
|
103
|
+
|
|
104
|
+
1. Install a cookies-export browser extension — **Get cookies.txt LOCALLY**
|
|
105
|
+
for Chrome/Edge, or **cookies.txt** for Firefox.
|
|
106
|
+
2. Log in to YouTube in that browser.
|
|
107
|
+
3. Open the extension on a `youtube.com` tab and export in **Netscape**
|
|
108
|
+
format — that's your `cookies.txt`.
|
|
109
|
+
4. Upload the file via the **Authentication** card in the FetchForge UI.
|
|
110
|
+
|
|
111
|
+
The file grants access to your YouTube account, so treat it as a secret: it's
|
|
112
|
+
gitignored and stays on your machine — don't share or commit it. Re-export it
|
|
113
|
+
if it stops working; YouTube rotates cookies periodically.
|
|
114
|
+
|
|
115
|
+
## Features
|
|
116
|
+
|
|
117
|
+
- **Sequential or pipelined playlist processing** — pipeline mode runs download and encode concurrently with a `maxsize=1` queue (downloader stays at most one video ahead of the encoder)
|
|
118
|
+
- **Smart pre-download skip** — checks for existing `<title>_h265.mp4` before downloading, skips if ≥85% of expected size
|
|
119
|
+
- **Two encode tunes** — `uhq` (Smart Auto, archival quality) and `hq` (NLE-friendly, ~4–6× speed, capped at source bitrate)
|
|
120
|
+
- **HDR / 10-bit passthrough** — auto-detected; outputs `yuv420p10le` + `main10`
|
|
121
|
+
- **Wake-lock during jobs** — ref-counted; Windows `SetThreadExecutionState` re-asserted every 30s, Linux holds a `systemd-inhibit` process
|
|
122
|
+
- **Post-job shutdown** — UI countdown with cancel button; `shutdown /s /t 0` (Windows) / `systemctl poweroff` (Linux) if not cancelled
|
|
123
|
+
- **Local conversion mode** — point at files or folders, batch-encode without downloading
|
|
124
|
+
|
|
125
|
+
## Repository conventions
|
|
126
|
+
|
|
127
|
+
- **Issue tracking**: GitHub Issues. Run `python tools/issue-ready.py` for available work (open issues, dependencies satisfied), or `gh issue list`.
|
|
128
|
+
- **Personal-use only** — no auth, no multi-user, no cloud deploy.
|
|
129
|
+
- **Per-user runtime state is gitignored** (see table above) and preserved locally, never pushed.
|
|
130
|
+
|
|
131
|
+
See `CLAUDE.md` for full architecture: endpoint table, SSE event types, encode parameter logic, and the Python <3.12 f-string gotcha that bit this codebase.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# FetchForge
|
|
2
|
+
|
|
3
|
+
> **Requires an NVIDIA GPU with NVENC.** The H.265 transcode uses hardware
|
|
4
|
+
> `hevc_nvenc` and has no CPU-encode fallback — without an NVIDIA card the
|
|
5
|
+
> transcode path cannot run (download + audio-extract still work). macOS has no
|
|
6
|
+
> NVIDIA GPUs, so the transcode is Windows/Linux only.
|
|
7
|
+
|
|
8
|
+
FetchForge is a localhost web app that downloads YouTube videos and playlists
|
|
9
|
+
and transcodes them to H.265/HEVC using NVIDIA NVENC hardware encoding. Single
|
|
10
|
+
videos, full playlists with pipeline mode, and local-file conversion. Smart
|
|
11
|
+
auto-analysis picks CQ, maxrate, and preset from the source.
|
|
12
|
+
|
|
13
|
+
## Install & launch
|
|
14
|
+
|
|
15
|
+
**With pip (recommended):**
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
pip install fetchforge
|
|
19
|
+
fetchforge
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The browser opens automatically at `http://localhost:8765`. On Windows, if an
|
|
23
|
+
NVENC-capable ffmpeg isn't already present, FetchForge downloads one on first
|
|
24
|
+
run. On Linux, install ffmpeg from your package manager first
|
|
25
|
+
(`sudo dnf install ffmpeg` / `sudo apt install ffmpeg`) and make sure the NVIDIA
|
|
26
|
+
driver is loaded. macOS has no NVIDIA GPU, so the H.265 transcode can't run
|
|
27
|
+
there, but download and audio-extract still work and just need ffmpeg
|
|
28
|
+
(`brew install ffmpeg`).
|
|
29
|
+
|
|
30
|
+
**Output files land in the current directory** — run `fetchforge` from wherever
|
|
31
|
+
you want `downloads/` to appear.
|
|
32
|
+
|
|
33
|
+
**From source (clone):**
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
git clone https://github.com/prekabreki/fetchforge
|
|
37
|
+
cd fetchforge
|
|
38
|
+
./launch.sh # Windows: launch.bat
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> "Update yt-dlp" in the UI is a no-op for pip installs — update with
|
|
42
|
+
> `pip install -U fetchforge` (or `pip install -U "yt-dlp[default]"`).
|
|
43
|
+
|
|
44
|
+
## Stack
|
|
45
|
+
|
|
46
|
+
- **Backend** — `fetchforge/server.py` (FastAPI + uvicorn, fully async)
|
|
47
|
+
- **Frontend** — `fetchforge/index.html` (single file, vanilla JS + SSE, no build step)
|
|
48
|
+
- **CLI entry point** — `fetchforge/cli.py`, exposed as the `fetchforge` console script (also runnable as `python -m fetchforge`)
|
|
49
|
+
- **Downloader** — `yt-dlp[default]`, a regular dependency (pulled in by pip, not bundled)
|
|
50
|
+
- **Encoder** — ffmpeg + `hevc_nvenc` (NVENC); auto-downloaded to a per-user cache on Windows, expected on `PATH` on Linux
|
|
51
|
+
- **Packaging** — `pyproject.toml`; `pip install fetchforge` for the package, `pip install -e .` for an editable clone
|
|
52
|
+
- **Launchers** — `launch.bat` (Windows) / `launch.sh` (Linux/macOS) for the clone workflow: create/reuse a venv, `pip install -e .`, open the browser, run `python -m fetchforge`
|
|
53
|
+
|
|
54
|
+
## What's NOT in the repo (gitignored)
|
|
55
|
+
|
|
56
|
+
These are restored locally — they're either rebuildable, regenerable, or sensitive.
|
|
57
|
+
|
|
58
|
+
| Path | Why ignored |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `_internal/` | Optional manual ffmpeg override for a source clone on Windows — pip installs auto-provision ffmpeg into `%LOCALAPPDATA%\FetchForge\ffmpeg` instead |
|
|
61
|
+
| `yt-dlp.exe` | Optional manual override; the normal path gets yt-dlp as a pip dependency, updated via `pip install -U`, not a dropped binary |
|
|
62
|
+
| `cookies.txt` | YouTube auth cookies (sensitive — never commit) |
|
|
63
|
+
| `history.json` | Last 50 downloaded URLs (per-machine state) |
|
|
64
|
+
| `logs/` | Runtime logs |
|
|
65
|
+
| `downloads/` | Output MP4s |
|
|
66
|
+
|
|
67
|
+
`cookies.txt`, `history.json`, `logs/`, and `downloads/` are runtime state and
|
|
68
|
+
live under the current working directory you launch `fetchforge` from.
|
|
69
|
+
`_internal/` and `yt-dlp.exe` are the two exceptions: they're optional manual
|
|
70
|
+
overrides FetchForge looks for next to the installed package itself, not the
|
|
71
|
+
cwd — the normal pip install path never needs them.
|
|
72
|
+
|
|
73
|
+
## First-run setup on a new machine
|
|
74
|
+
|
|
75
|
+
1. `pip install fetchforge`.
|
|
76
|
+
2. Run `fetchforge`. On Windows it downloads an NVENC-capable ffmpeg build automatically the first time it's needed. On Linux, install `ffmpeg` from your package manager first and confirm the NVIDIA driver is loaded — FetchForge won't fetch a build for you there.
|
|
77
|
+
3. (Optional) Upload a `cookies.txt` via the **Authentication** card if you need age-restricted, private, or members-only content — see [Cookies](#cookies) below for how to get one.
|
|
78
|
+
|
|
79
|
+
Working from a clone instead: run `./launch.sh` (or `launch.bat` on Windows) — it sets up a `.venv`, installs the package in editable mode, and starts the server the same way.
|
|
80
|
+
|
|
81
|
+
## Cookies
|
|
82
|
+
|
|
83
|
+
Public videos need no cookies. Cookies are only necessary for age-restricted,
|
|
84
|
+
private, or members-only videos, which require a logged-in YouTube session.
|
|
85
|
+
|
|
86
|
+
To get a `cookies.txt`:
|
|
87
|
+
|
|
88
|
+
1. Install a cookies-export browser extension — **Get cookies.txt LOCALLY**
|
|
89
|
+
for Chrome/Edge, or **cookies.txt** for Firefox.
|
|
90
|
+
2. Log in to YouTube in that browser.
|
|
91
|
+
3. Open the extension on a `youtube.com` tab and export in **Netscape**
|
|
92
|
+
format — that's your `cookies.txt`.
|
|
93
|
+
4. Upload the file via the **Authentication** card in the FetchForge UI.
|
|
94
|
+
|
|
95
|
+
The file grants access to your YouTube account, so treat it as a secret: it's
|
|
96
|
+
gitignored and stays on your machine — don't share or commit it. Re-export it
|
|
97
|
+
if it stops working; YouTube rotates cookies periodically.
|
|
98
|
+
|
|
99
|
+
## Features
|
|
100
|
+
|
|
101
|
+
- **Sequential or pipelined playlist processing** — pipeline mode runs download and encode concurrently with a `maxsize=1` queue (downloader stays at most one video ahead of the encoder)
|
|
102
|
+
- **Smart pre-download skip** — checks for existing `<title>_h265.mp4` before downloading, skips if ≥85% of expected size
|
|
103
|
+
- **Two encode tunes** — `uhq` (Smart Auto, archival quality) and `hq` (NLE-friendly, ~4–6× speed, capped at source bitrate)
|
|
104
|
+
- **HDR / 10-bit passthrough** — auto-detected; outputs `yuv420p10le` + `main10`
|
|
105
|
+
- **Wake-lock during jobs** — ref-counted; Windows `SetThreadExecutionState` re-asserted every 30s, Linux holds a `systemd-inhibit` process
|
|
106
|
+
- **Post-job shutdown** — UI countdown with cancel button; `shutdown /s /t 0` (Windows) / `systemctl poweroff` (Linux) if not cancelled
|
|
107
|
+
- **Local conversion mode** — point at files or folders, batch-encode without downloading
|
|
108
|
+
|
|
109
|
+
## Repository conventions
|
|
110
|
+
|
|
111
|
+
- **Issue tracking**: GitHub Issues. Run `python tools/issue-ready.py` for available work (open issues, dependencies satisfied), or `gh issue list`.
|
|
112
|
+
- **Personal-use only** — no auth, no multi-user, no cloud deploy.
|
|
113
|
+
- **Per-user runtime state is gitignored** (see table above) and preserved locally, never pushed.
|
|
114
|
+
|
|
115
|
+
See `CLAUDE.md` for full architecture: endpoint table, SSE event types, encode parameter logic, and the Python <3.12 f-string gotcha that bit this codebase.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""`fetchforge` console entry point: preflight ffmpeg/NVENC, then run the app."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from fetchforge import provision
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main(argv: list[str] | None = None) -> int:
|
|
11
|
+
try:
|
|
12
|
+
provision.ensure_ffmpeg()
|
|
13
|
+
except provision.ProvisionError as e:
|
|
14
|
+
if shutil.which("ffmpeg"):
|
|
15
|
+
print(
|
|
16
|
+
f"WARNING: {e}\n\nStarting without NVENC — YouTube download and "
|
|
17
|
+
"audio-extract work, but the H.265 transcode needs an NVENC-capable "
|
|
18
|
+
"ffmpeg + NVIDIA GPU.\n",
|
|
19
|
+
file=sys.stderr,
|
|
20
|
+
)
|
|
21
|
+
else:
|
|
22
|
+
print(f"FetchForge cannot start:\n\n{e}\n", file=sys.stderr)
|
|
23
|
+
return 1
|
|
24
|
+
# Import after preflight so tool resolution sees a provisioned ffmpeg on PATH.
|
|
25
|
+
from fetchforge import server
|
|
26
|
+
server.run_server(open_browser=True)
|
|
27
|
+
return 0
|