A portable, offline media server powered by the ESP32-S3 in a thumbdrive form factor.
Stream movies, music, books, and shows anywhere — no internet required.
The following library and core versions are confirmed to compile and run correctly with Nomad:
- ArduinoJson by Benoit Blanchon — 7.4.2
- ESP Async WebServer by ESP32Async — 3.8.0
- AsyncTCP by ESP32Async — 3.4.7
- LVGL by kisvegabor — 8.4.0
(Nomad UI is built with SquareLine Studio for LVGL 8; LVGL 9.x requires major code changes) - Arduino_GFX_Library — 1.6.1
- ESP32 Core (esp32 by Espressif Systems) — 3.3.0
- Arduino IDE — 2.3.6
These versions represent a stable, tested baseline. Future updates may work, but for reliability stick to the versions above unless you’re actively migrating.
The make_posters.py script scans your media folders for video files and creates a matching .jpg poster for each file using TMDb. It supports both Movies and TV episodes, and is designed to be a drop-in tool.
- Scans recursively for video files:
.mp4,.mkv,.avi,.m4v - Creates a poster next to each video with the same base name and
.jpgextension - Fetches real posters from TMDb using your API key:
- Movies:
Title (YYYY).extorTitle [YYYY].ext - TV episodes:
Show.Name.S01E02.ext,Show Name - S01E02.ext, etc. (series poster is applied to episodes)
- Movies:
- Strips non-year tags like
[Extended],(Director's Cut)before searching TMDb - Never generates placeholders — real posters only
- Works as dry-run without a key; real runs require a TMDb key
- Python 3.x
- Dependencies (install with pip):
python -m pip install pillow requests
Create a make_posters.json file next to make_posters.py with your TMDb API key:
{
"TMDB_API_KEY": "your_api_key_here"
}Without this file, dry-run still works, but real runs will exit with instructions.
From the root of your media (or pass a path):
# Scan current folder
python make_posters.py
# Scan a specific folder
python make_posters.py Movies
# Preview only (no files written)
python make_posters.py Movies --dry-run
# Overwrite existing JPGs
python make_posters.py Movies --overwrite
# Include/Exclude top-level folders
python make_posters.py . --only-folders Movies,Shows
python make_posters.py . --exclude-folders Samples,Extras
# Set language for TMDb results
python make_posters.py Movies --lang en-US-
Movies:
Title (2010).mp4Title [2010].mkv- Or place files in a folder that contains
(2010)or[2010]in its name
-
TV Episodes:
Show.Name.S01E02.extShow Name - S01E02.ext- Flexible separators supported
Generate all movie posters:
cd SD_Card_Template
python make_posters.py MoviesGenerate episode posters for one show:
python make_posters.py "SD_Card_Template/Shows/Girls Last Tour/Season 01"One-shot pass for Movies + Shows:
python make_posters.py SD_Card_Template --only-folders Movies,ShowsSanity check before running:
python make_posters.py SD_Card_Template --dry-run-
Missing dependencies:
Install withpython -m pip install pillow requests -
Config error (no API key):
Ensuremake_posters.jsonexists with your key -
No match errors:
Ensure filenames include a year or are placed in a folder with(YYYY)or[YYYY]
A compatibility guide for supported media types, streaming expectations, and additional notes on performance.
| Category | Supported Formats | Notes |
|---|---|---|
| Video | .mp4, .mov, .mkv, .webm, .avi, .m4v |
.avi files may not play reliably in all browsers. |
| Audio | .mp3, .flac, .wav, .ogg |
Other audio formats are not supported by the built-in player. |
| Books / Docs | .pdf (recommended), .epub (download only) |
.pdf files can be opened and read directly in the browser. .epub files are downloadable but cannot be viewed in the built-in reader. |
| Images | .jpg, .png |
Used for covers, gallery images, and folder artwork. |
Important: Nomad uses FAT32 storage by default, which limits individual file sizes to under 4 GB.
The following stream counts are based on a high endurance Grade 10 microSD card under ideal conditions:
| Resolution | Typical Concurrent Streams |
|---|---|
| 480p | 6–8 streams |
| 720p | 3–5 streams |
| 1080p | 2–3 streams |
| Ultra-HD / High bitrate | ~1 stream |
Disclaimer: Actual streaming performance varies depending on:
- File encoding and bitrate
- Network conditions
- Client device capabilities
- Number of simultaneous users
Encoding video files using H.264 video codec and AAC audio codec tends to improve streaming performance and allow more concurrent streams.
Kept these links intact from original repo: https://github.com/Jstudner/jcorp-nomad
You can now buy your own Nomad Dev Kit and get started immediately!
The product is open source, but this saves you time and effort on assembly.
Promo Video:
https://www.youtube.com/shorts/k8XJGTmbzzc
Demo Video
https://www.youtube.com/watch?v=zEjgI8bhxzk&t=2s
Official Website:
https://nomad.jcorptech.net
Jcorp Nomad is an open-source offline media server built for travel, remote work, classrooms, camping, and more. It runs entirely on an ESP32-S3 dev board, creates a local Wi-Fi hotspot, and serves media through a browser-accessible interface. It does not require internet access and works similarly to in-flight entertainment systems. It also allows multiple users watching separate media streams at the same time.
This project is designed to be compact, simple, and easily modifiable. It includes optional 3D-printable hardware and a fully open source firmware and web interface.
This project was originally cloned from the hard work of: https://github.com/Jstudner/jcorp-nomad
- Creates a local Wi-Fi hotspot with captive portal
- Serves HTML media interface to any connected device
- Streams content directly from a FAT32-formatted microSD card
- Supports simultaneous connections (tested with up to 4 video streams)
- No app or internet connection required
- Open source firmware and UI
- Customizable web interface / Features
- Arduino IDE or PlatformIO (to flash firmware)
- Python 3.x (to run
media.py) - SquareLine Studio (optional, for screen UI editing)
All software used is free and available on Windows, macOS, and Linux.
- Flash the ESP32-S3 with the firmware in the
/firmware/directory. - Format your SD card as FAT32 and copy the web files from
/SD_Card_Template/. - Place your media files into the appropriate folders (see structure below).
- Run
media.pyto generatemedia.jsonautomatically. - Insert the SD card and power the device.
- Connect to the Wi-Fi network named
NomadServer. - Your browser will be redirected to the offline media interface.
/Movies/
Interstellar.mp4
Interstellar.jpg
/Shows/
The Office/
S01E01 - Pilot.mp4
S01E02 - Diversity Day.mp4
The Office.jpg
/Books/
The Martian.pdf
The Martian.jpg
/Music/
track01.mp3
index.html
appleindex.html
menu.html
movies.html
shows.html
books.html
music.html
media.py
media.json
placeholder.jpg
Logo.png
favicon.ico
- Video:
.mp4,.mov,.mkv,.webm,.avi(may not play reliably),.m4v - Audio:
.mp3,.wav,.flac,.ogg - Books:
.pdf,.epub - Images:
.jpg,.png
Ensure all images and media files use matching names for proper display.
- Wi-Fi name and password can be changed in
firmware/Nomad.ino - Branding (logo, favicon) can be replaced in
/SD_Card_Template/ - Sections (Movies, Music, etc.) can be removed from
menu.html - Web interface can be edited using any text editor
- The screen UI can be edited with SquareLine Studio (the free version is fine)
/firmware/– Arduino firmware for ESP32-S3/SD_Card_Template/– Web UI, HTML files, andmedia.py/case/– STL files for optional 3D-printed enclosure/docs/– Logos, screenshots, and design files
Common issues and their solutions are detailed in the Troubleshooting section on instructibles.
Topics covered include:
- SD card read errors
- Captive portal issues on some phones
- Video playback and seeking bugs
- UI glitches or screen failure
Looking for a step-by-step tutorial?
Check out the full build guide on Instructables for detailed instructions, photos, and tips on setting up Jcorp Nomad.
👉 Read the Instructables Guide
Kept from: https://github.com/Jstudner/jcorp-nomad
- Move TMDb key into
config/settings.json(managed via admin screen) - Add admin UI controls to run poster scans
- Optionally generate
folder.jpgper season/show for Plex/Jellyfin compatibility
This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You may remix, adapt, and share this project for non-commercial use, as long as you give credit and share under the same terms.
For commercial licensing, please contact the author.
Developed by Jackson Studner (Jcorp Tech).
Branch updates by RakaMaru.
Inspired by open-source offline projects like Backcountry Beacon.
If you build, remix, or improve this project, please consider submitting a pull request or tagging the project.
