Automatically uploads OBS recordings to YouTube when recording finishes. The app watches a folder for new video files, waits until a file stops changing, then uploads it to your channel as a private video titled with the date and time. It can run as a command-line process, with a small Windows tray GUI, or in a Windows container.
- Python 3.7+
watchdogfor file system events- Google API client libraries (YouTube Data API v3, OAuth 2.0 desktop flow)
- PySide6 for the optional GUI (Windows)
- Docker (Windows containers) via
Dockerfileanddocker-compose.yml
- In the Google Cloud Console, create a project and enable YouTube Data API v3.
- Create an OAuth client ID of type Desktop app and note the client ID and secret.
- On the OAuth consent screen, add the scope
https://www.googleapis.com/auth/youtube.uploadand add yourself as a test user.
pip install -r requirements.txt
export YOUTUBE_CLIENT_ID='your-client-id'
export YOUTUBE_CLIENT_SECRET='your-client-secret'
export YOUTUBE_PROJECT_ID='your-project-id' # optionalOn Windows PowerShell use $env:YOUTUBE_CLIENT_ID="..." instead of export.
python main.py # command line
python main.py --gui # windowed / tray modeOn first run a browser window opens for Google sign-in. The resulting token is saved to token.json, which is gitignored and reused afterwards. If authentication goes wrong, delete token.json and sign in again.
See DOCKER.md. In short:
.\validate-docker-setup.ps1 # optional prerequisite check
docker-compose up --buildEdit the bind-mounted recordings folder in docker-compose.yml to match your machine.
watchdognotices a new file in the watched directory (theWATCH_DIRenvironment variable, otherwiseF:\Recordingsas coded inmain.py).- The handler polls the file on an interval (60 seconds by default). If the file was modified since the last check it waits another interval; otherwise it treats the recording as finished.
- The file is uploaded as a private video titled with the current date and time, and the status is logged. Change visibility later in YouTube Studio.
Only one file is tracked at a time. The GUI also remembers the last chosen directory in config.json (also gitignored).
YOUTUBE_CLIENT_ID,YOUTUBE_CLIENT_SECRET(required)YOUTUBE_PROJECT_ID(optional)WATCH_DIR- directory to watchDATA_DIR- whereconfig.jsonandtoken.jsonare stored (defaults to the current directory)
main.py- entry point; wires the watcher and uploader togetherfileHandler.py- detects finished recordings and triggers uploadsuploader.py- OAuth and YouTube upload logicgui.py- PySide6 window and system tray iconconfig.py- persists the chosen directorywatcher.py- file watching helper