yefees-recorder
Cross-platform screen recorder CLI for Windows, Linux and macOS. It drives ffmpeg and adds the parts ffmpeg does not have: picking a source, pausing, mixing system audio with a microphone at sane levels, finishing the file when the terminal goes away, and a settings menu so none of it needs flags.
| Platform | Screen | System audio | Microphone |
|---|---|---|---|
| Windows | ddagrab on the GPU, encoded by NVENC when there is one | WASAPI loopback, no virtual cable needed | WASAPI |
| Linux / X11 | x11grab | PulseAudio / PipeWire sink monitor | PulseAudio source |
| Linux / Wayland | wf-recorder (wlroots only — not GNOME/KDE) | sink monitor | one source only |
| macOS | avfoundation | BlackHole or another virtual device, via CoreAudio | CoreAudio |
What has actually been tested
Worth knowing before you rely on it:
| Screen | Audio | |
|---|---|---|
| Windows | recorded on real hardware | recorded on real hardware |
| macOS | recorded on real hardware (14.5) | rewritten since, not yet re-tested |
| Linux / X11 | recorded in CI, on a virtual display only | not tested |
| Linux / Wayland | never run at all | never run at all |
Nobody working on this has a Linux machine. The Linux backends are written and covered by unit tests, and CI runs the X11 capture test against a virtual display: it paints the screen red, records it, and checks the frames really are red — a broken recorder here produces a perfectly valid file full of black frames and no error at all. That passes, but a virtual display is not a desktop, and nobody has heard Linux audio. Until someone runs it on a real Linux desktop, treat Linux as unproven.
Bug reports from a real Linux session are very welcome, and the most useful ones
say what yefees-recorder doctor printed and whether the recorded file is black.
Installing
1. ffmpeg
ffmpeg is not bundled — it is large and its licensing is its own — so install it first:
winget install Gyan.FFmpeg # Windows
brew install ffmpeg # macOS
sudo apt install ffmpeg # Debian / Ubuntu
sudo pacman -S ffmpeg # Arch
On Wayland you also need wf-recorder, because ffmpeg cannot capture a Wayland
screen at all:
sudo apt install wf-recorder
2. The recorder
pip install yefees-recorder
or, if you use uv, which puts it on your PATH in its own isolated environment:
uv tool install yefees-recorder
There is one package for every platform — it is pure Python, so there is no
Windows build or Linux build to choose between. The one platform-specific
dependency (pyaudiowpatch, for Windows loopback audio) is marked as such and
is only downloaded on Windows.
3. Check it
yefees-recorder doctor
It reports whether ffmpeg is on your PATH, and on macOS whether Screen Recording permission has been granted. Fix anything it complains about before recording.
Running from a clone
If you cloned the repository instead of installing the package:
git clone https://github.com/Yefee8/yefees-recorder.git
cd yefees-recorder
uv sync
uv run yefees-recorder doctor
uv sync creates .venv and installs the dependencies pinned in uv.lock;
uv run then executes inside it, so nothing is installed system-wide. Every
command below works the same way — put uv run in front:
uv run yefees-recorder record -d 10 -o clip.mp4
uv run pytest
Don't have uv? Install it, or use the standard library:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
yefees-recorder doctor
Python 3.10 or newer is required.
Usage
yefees-recorder doctor # check ffmpeg is installed
yefees-recorder sources # list displays, windows and audio devices
yefees-recorder record # record until you press q
yefees-recorder record -d 30 -o clip.mp4
yefees-recorder record --no-audio --fps 60
Choosing what to record
sources prints the exact flag for each thing it finds:
yefees-recorder record --display 1 # one monitor
yefees-recorder record --window "Firefox" # one window
yefees-recorder record --region 0,0,1280x720 # an area, as x,y,WIDTHxHEIGHT
yefees-recorder record --audio-device "Speakers" # a specific audio source
yefees-recorder record --mic # add the microphone
yefees-recorder record --mic --no-audio # microphone only
yefees-recorder record --mic-device "Headset" # a specific microphone
yefees-recorder record --mic-gain 4 # mics are quiet; turn it up
yefees-recorder record -q high # low | balanced | high
yefees-recorder record --pick # choose from a menu instead
--display, --window and --region are mutually exclusive — only one thing
can be recorded at a time. Recording the whole desktop is the default, which on
a multi-monitor machine means every monitor side by side; use --display for
one of them. On Windows that matters for speed too: one monitor is captured on
the GPU, every monitor at once only through the much slower GDI.
Window capture is not available everywhere: Windows does it natively, X11 needs
wmctrl installed, and macOS cannot do it at all.
While recording
Press p (or space) to pause and resume, q to stop. Ctrl+C also stops cleanly, and so does closing the terminal window, logging out or shutting down: the recording is finalised rather than left truncated. Paused time is cut out of the finished file rather than appearing as a frozen frame.
The one way to lose a recording is killing the process outright (Task Manager's
End Task, kill -9); the operating system gives no program a chance to react to
that.
Audio
System audio and the microphone are independent — record either, both or neither. With both on they are mixed into a single track at their original levels, so adding a microphone does not make the system audio quieter.
Microphones are usually far quieter than system audio, so a voice can be
buried under a game or video even though it is being recorded. Raise it with
--mic-gain (a multiplier: 2 is +6 dB, 4 is +12 dB) or set mic_gain in
the config.
If audio ends up slightly ahead of or behind the video on your machine, nudge it
with --audio-offset 0.2.
Recording one application's audio
yefees-recorder record --app-audio "Firefox"
Only Linux can do this directly, by routing that application through a capture
sink with pactl and putting it back when the recording ends. On Windows and
macOS the operating system offers no way for ffmpeg to capture a single
application, so the command explains the alternative instead: send the app to
its own output device (Windows: Settings > System > Sound > Volume mixer;
macOS: a virtual device such as BlackHole) and record that device with
--audio-device.
sources lists every audio device separately as audio (what the machine is
playing) and mic (what it can hear). On a machine with several outputs —
a monitor's speakers and a headset, say — each one is its own audio entry,
so --audio-device picks which one is recorded.
Presets
yefees-recorder record --save-preset gameplay --display 1 --fps 60 -q high
yefees-recorder record --preset gameplay
yefees-recorder config # lists saved presets
Presets are appended to the config file as [presets.NAME] blocks, so you can
also write them by hand. A flag still overrides a preset.
Shell completion
yefees-recorder --install-completion
Platform notes
Windows
A monitor, or an area inside one, is copied on the GPU with Desktop
Duplication (ffmpeg's ddagrab, ffmpeg 6 or newer) and, on an NVIDIA card,
encoded there by NVENC, so a game keeps the CPU. Measured at 1080p60 on a GTX
1660 Ti: the old GDI path managed 35 fps on 1.7 CPU cores, this one 55-60 fps on
under 5% of one. Without NVENC the frame is handed to x264 instead. A window,
or an area spanning monitors, still goes through GDI.
Which of these a machine can do is tested with a one-frame recording when recording starts, which costs about half a second.
macOS
Grant Screen Recording to your terminal in System Settings > Privacy &
Security, then restart it — macOS only applies the change to newly launched
processes. Without the grant avfoundation never delivers a single frame and
ffmpeg waits for one forever, so doctor checks the permission before anything
starts and record refuses rather than hanging.
Audio needs Microphone permission too, in System Settings > Privacy &
Security > Microphone, for the same terminal. macOS asks for it before handing
over any audio input, virtual devices like BlackHole included, and without it
hands over silence instead — so record checks the permission first and says
so, rather than leaving you with a silent recording to discover later.
Audio is recorded through CoreAudio rather than ffmpeg: ffmpeg 8.1's avfoundation drops audio buffers, which came out as stuttering sound.
System audio needs a loopback device, because macOS has no way to record its own output:
brew install blackhole-2ch
Then open Audio MIDI Setup, create a Multi-Output Device containing both BlackHole and your speakers, and select it as the system output. Without the multi-output you record the sound but stop hearing it. With no loopback device at all you get video only, which the command says at the time.
--region is in pixels, not points. avfoundation captures at the display's
backing resolution, so on a Retina screen --region 0,0,1280x720 covers the
640x360 points you actually see. Double the numbers you read off Screenshot.
--window is not available: avfoundation exposes whole screens and nothing
smaller. Use --region for the area a window occupies.
Linux
X11 sessions use x11grab for video and the PulseAudio/PipeWire sink monitor
for system audio. --window needs wmctrl installed.
This path is untested on real hardware — see the table at the top.
Wayland
ffmpeg cannot capture the screen there — access is only available through
xdg-desktop-portal/PipeWire — so wf-recorder is required. It supports wlroots
compositors (Sway, Hyprland, river). On GNOME or KDE, use your desktop's own
recorder or run an X11 session.
Wayland also asks you to pick the screen or window in its own dialog; that
choice is an operating-system security boundary and cannot be automated, so
--display and --window are unavailable there.
Configuration
Settings come from three places, and the first one that has an answer wins:
a flag on the command line → the config file → the built-in default
So the config file holds what you want most of the time, and a flag overrides it for one recording without changing anything.
yefees-recorder config # where the file lives and what is in effect
yefees-recorder config --edit # change settings from a menu, no flags needed
yefees-recorder config --init # write a commented starter file
config prints every setting, its current value, and whether that value came
from the file or the default — which is the quickest way to find out why a
recording did something you did not ask for.
Where the file lives
| Path | |
|---|---|
| Windows | %LOCALAPPDATA%\yefees-recorder\config.toml |
| macOS | ~/Library/Application Support/yefees-recorder/config.toml |
| Linux | ~/.config/yefees-recorder/config.toml |
Set YEFEES_RECORDER_CONFIG to a path to use a different file — useful for
keeping a separate profile, or for trying something without touching your real
settings:
YEFEES_RECORDER_CONFIG=./test.toml yefees-recorder config --edit
A broken or misspelled setting is reported as a warning and skipped; it never stops a recording.
The settings editor
yefees-recorder config --edit
opens an arrow-key menu — no flags, no editing TOML by hand, and nothing is written until you choose Save.
| Key | What it does |
|---|---|
| ↑ ↓ | move between rows |
| Enter, → or space | open a page, or choose the highlighted value |
| ← | go back one page (ignored on the top page) |
| Esc, Backspace or q | go back, and from the top page, quit |
On a slider:
| Key | What it does |
|---|---|
| ← → | nudge the value |
| ↑ ↓ | bigger steps |
| t | type an exact value the steps cannot land on |
| Enter | accept |
| Backspace | leave it as it was |
Each row on the top page shows what it currently holds:
- Video source — whole desktop, a monitor, a window, or an area. This is one choice rather than three settings, because only one of them can be recorded: picking a window clears the monitor and the area automatically.
- Audio — system audio on/off and its device and level, the microphone on/off and its device and level, one application's audio, and the A/V offset.
- Output and quality — where recordings are saved, the frame rate, and the
quality preset (
lowsmallest files,balancedthe default,highbest looking). - Menu colour — the accent the menus are built from.
- Save and exit / Quit without saving — the row tells you whether there is anything to save.
Device settings (monitor, window, audio device, microphone) offer what this machine actually has as a list, so you pick a real device instead of typing its name and hoping. Scanning happens once when a page first needs it, and each list has a Rescan row for when you plug something in while the menu is open.
Audio levels are edited in decibels and stored as multipliers. dB is the
scale the numbers mean something on; ffmpeg wants the multiplier. So +6 dB in
the menu and mic_gain = 2.0 in the file are the same thing. The slider turns
yellow past +6 dB and red past +14 dB, where clipping starts.
The menus are built from a single accent colour, indigo by default. The text colour on a highlighted row is worked out from that colour's brightness, so a pale accent gets black text and a dark one gets white — you cannot pick a colour that makes the selection unreadable.
When you save, only the settings you changed are written, your comments and layout survive, and the editor re-reads the file afterwards and shows you what it actually holds rather than what it believes it wrote.
Every setting
# Where recordings go. Unset means the current directory.
output_dir = "~/Videos"
fps = 30 # capture frame rate
quality = "balanced" # low | balanced | high
accent = "#5A4FCF" # menu colour: a hex value or a name like "blue_violet"
audio = true # record what the machine plays
audio_device = "Speakers" # unset = let the recorder choose
audio_gain = 1.0 # multiplier; 2.0 is +6 dB
mic = false # also record the microphone
mic_device = "Headset"
mic_gain = 4.0 # mics need boosting more often than not
app_audio = "Firefox" # one application's audio (Linux only)
audio_offset = 0.0 # seconds; nudge if audio drifts from the video
# Only one of these three may be set — they are mutually exclusive.
display = 0 # monitor index, as `sources` prints it
window = "Firefox" # window title
region = "0,0,1280x720" # x,y,WIDTHxHEIGHT
| Setting | Type | Default | Notes |
|---|---|---|---|
output_dir |
string | current directory | ~ is expanded |
fps |
integer | 30 |
|
quality |
string | "balanced" |
low, balanced or high |
accent |
string | indigo #5A4FCF |
hex, or a colour name |
audio |
boolean | true |
system audio |
audio_device |
string | chosen for you | see sources |
audio_gain |
number | 1.0 |
multiplier, not dB |
mic |
boolean | false |
|
mic_device |
string | chosen for you | see sources |
mic_gain |
number | 1.0 |
multiplier, not dB |
app_audio |
string | unset | Linux only |
audio_offset |
number | 0.0 |
seconds |
display |
integer | unset | mutually exclusive with the two below |
window |
string | unset | |
region |
string | unset | x,y,WIDTHxHEIGHT |
Presets live in the same file and override the top-level values when selected:
[presets.gameplay]
display = 1
fps = 60
quality = "high"
mic = true
mic_gain = 4.0
Development
uv sync
uv run yefees-recorder --help
uv run pytest
The test suite runs anywhere: the capture lifecycle is exercised against
ffmpeg's synthetic lavfi source rather than a real screen, and the tests that
genuinely need a platform skip themselves elsewhere. CI runs it on Linux (3.10
and 3.13), macOS and Windows.
License
GPL-3.0-or-later. See LICENSE.
ffmpeg is invoked as an external program and is not bundled or linked, so its own licensing is independent of this package's.
Metadata
Release files for yefees-recorder 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| yefees_recorder-0.2.0.tar.gz | 68.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yefees_recorder-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 138.3 kB
Release files / yefees_recorder-0.2.0.tar.gz
| Download URL | yefees_recorder-0.2.0.tar.gz |
|---|---|
| Size | 68.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ad8f5fc838f94b752524c0c0625397058ca043445d288fb54b03482842995684
|
|
BLAKE2b-256 checksum How to use checksums |
aecc6fcef6b9e37f827c96831c6cd0b330b890ecbed1115f57d231d9b0ad95e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / yefees_recorder-0.2.0-py3-none-any.whl
| Download URL | yefees_recorder-0.2.0-py3-none-any.whl |
|---|---|
| Size | 69.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3515b12610e40b36d0f2e386107ad4df8d9f213e4dff9bd233f9926fa213abc
|
|
BLAKE2b-256 checksum How to use checksums |
09ad873d2ae6a9ad2dfc43c05ce31156ccae4618462bec0a5c471886a593304c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|