Camera YouTube Manager is a small Python service for keeping IP camera streams live on YouTube with as little manual intervention as possible.
It does two jobs together:
- It manages the YouTube side by creating and ending scheduled broadcasts.
- It manages the local streaming side by launching and supervising
ffmpeginsidescreensessions.
This is useful when you want a Raspberry Pi or other small Linux machine to keep one or more camera feeds online without having to constantly recreate broadcasts, restart stuck streams, or log into YouTube by hand.
Without this kind of manager, a camera-to-YouTube setup usually needs manual attention when:
- a scheduled broadcast does not exist
- a stream becomes unhealthy
- a machine reboot stops the local
ffmpegprocess - a broadcast needs recycling
- credentials expire and need refreshing
This project automates those repetitive tasks so the box running the stream can act more like a watchdog than a one-shot script.
For each enabled camera, the manager:
- loads the camera configuration from
settings.json - authenticates to the camera's YouTube account
- checks whether a scheduled broadcast already exists
- creates and binds a new broadcast if one is missing
- starts the local camera stream when a schedule is created
- checks the YouTube live stream health
- restarts the stream if the YouTube stream is unhealthy
- starts the stream if the broadcast exists but has not started yet
- recycles broadcasts at fixed times of day
- logs the main actions so you can see what happened
The local machine streams to YouTube by launching ffmpeg in a dedicated screen session per camera.
Session naming convention:
youtube_<camera_name>
That makes it possible to:
- leave streams running in the background
- stop and restart them cleanly
- check whether a given camera process is already active
This project has both Python dependencies and system/runtime dependencies.
These must be installed on the machine running the service:
- Linux or another Unix-like environment
- Python 3
pip- FFmpeg
- GNU Screen
- network access to each IP camera over RTSP
- network access to YouTube / Google APIs
Typical Raspberry Pi package installation:
sudo apt update
sudo apt install -y git python3 python3-pip ffmpeg screen logrotateInstalled from requirements.txt:
google-api-python-clientgoogle-authgoogle-auth-oauthlibpytestfor local testing
Install them with:
pip3 install -r requirements.txtBefore the service can run successfully, you also need:
- a Google Cloud project
- YouTube Data API access for that project
- an OAuth client downloaded as
client_secret.json - a YouTube channel enabled for live streaming
- remember that one YouTube channel can only run one live stream at a time
- one YouTube account/channel per camera if you want simultaneous camera streams
- a valid YouTube stream key for each camera/account
Place client_secret.json in the project root.
The project intentionally treats each configured camera as having a one-to-one relationship with a YouTube account/channel and its scheduled broadcast.
The main reason is URL persistence. A single scheduled broadcast gives viewers a stable YouTube URL for that camera. If a YouTube account has more than one live broadcast in rotation, the public URL changes between broadcasts, which makes it harder to publish an embeded camera link on a website.
At runtime, these files/directories matter:
client_secret.jsonsettings.jsontokens/
The tokens/ directory stores the per-camera OAuth token files generated after authentication.
Create it before first run:
mkdir -p tokensCreate a settings.json file in the project root.
Example:
{
"cameras": [
{
"name": "cam1",
"title": "Back Garden Live",
"description": "Live stream from the back garden camera",
"enabled": true,
"url": "user:[email protected]/ISAPI/Streaming/Channels/101/picture",
"key": "xxxx-xxxx-xxxx-xxxx-xxxx"
}
]
}nameUsed for logging and for the localscreensession name.titleUsed as the YouTube broadcast title.descriptionUsed as the YouTube broadcast description.enabledIffalse, the camera is skipped.urlThe RTSP target without the leadingrtsp://because the code adds that prefix.keyThe YouTube stream key for that camera's account. It must match the reusable YouTube live stream that you want broadcasts to bind to.
On the first run for each camera, the application will open the OAuth flow and ask you to authorise the relevant YouTube account.
In practice, that means:
- run
python3 source/main.pymanually before enabling cron - the script starts Google's installed-app OAuth flow on the local machine
- a browser window should open, or you will be given a local Google authorisation URL to open yourself
- sign in to the YouTube account/channel for that camera
- click
Allowwhen Google asks for permission - once Google redirects back to the local callback, the script saves the token file automatically
Once completed, it stores the token in:
tokens/<camera_name>_token.json
After that, future runs will reuse or refresh the saved credentials automatically.
If the Pi is headless, do this first run from a session where you can complete the browser sign-in on the Pi.
Run it directly with:
python3 source/main.pyWith no parameters, the manager runs the normal watchdog check for every enabled camera. This is the same mode used by cron.
You can also run targeted manual actions by passing an action and a camera name:
python3 source/main.py check --camera cam1
python3 source/main.py kill --camera cam1
python3 source/main.py restart --camera cam1
python3 source/main.py recycle --camera cam1Manual actions:
checkRuns the same watchdog logic as cron. Without--camera, it checks every enabled camera. With--camera, it checks only that camera.killStops the localscreen/ffmpegstream for the selected camera.restartStops the selected camera's local stream if it is running, then starts it again.recycleStops the selected camera's stream, ends its current YouTube broadcast, creates a new scheduled broadcast, and starts streaming again.
kill, restart, and recycle require --camera so an accidental manual run
does not operate on every configured stream.
The application logs the main operational events, for example:
- camera checks
- schedule creation
- stream starts
- stream stops
- unhealthy stream recovery
- YouTube API failures
By default logging runs at INFO.
To change the log level:
LOG_LEVEL=WARNING python3 source/main.pyRun the test suite locally with:
pytest -qTo see line coverage locally:
pytest -q --cov=source --cov-report=term-missingCurrent behaviour worth knowing:
- broadcasts are recycled once during the
02:00,08:00, and20:00hours - the script is designed to be run repeatedly, for example from cron or a service/timer
- each camera should use its own YouTube account
This project is a good fit for a Raspberry Pi that:
- stays powered on continuously
- has a stable network connection
- can reach both the cameras and YouTube
- runs this script on a schedule
The steps below assume the service will run as your normal Pi user and that the repository lives at ~/camera-youtube-manager. That keeps the cron entry simple and makes it obvious where settings.json, client_secret.json, and the saved OAuth tokens live.
Install the system packages first:
sudo apt update
sudo apt install -y git python3 python3-pip ffmpeg screen logrotateThen install the Python packages used by this project:
cd ~
git clone https://github.com/r0w4n/camera-youtube-manager.git
cd ~/camera-youtube-manager
pip3 install -r requirements.txt
mkdir -p ~/camera-youtube-manager/tokensIf you already have the repository on the Pi and just want to update it:
cd ~/camera-youtube-manager
git pull
pip3 install -r requirements.txtThe cron example later in this guide expects the code to be in:
~/camera-youtube-manager
That means the main script path will be:
~/camera-youtube-manager/source/main.py
If you install it somewhere else, update the cron command and any notes below to match your chosen location.
Copy the OAuth client downloaded from Google Cloud into the project root:
~/camera-youtube-manager/client_secret.json
Create ~/camera-youtube-manager/settings.json using the example earlier in this README.
Important points when filling it in:
nameshould be short and unique because it is used in log messages and in thescreensession nameurlmust not include the leadingrtsp://because the code adds that part itselfkeymust be the YouTube stream key for the channel that camera should stream toenabledlets you temporarily disable a camera without deleting its configuration
Before you automate the Pi, make sure the YouTube side is ready:
- enable live streaming on the YouTube channel
- create or retrieve the correct stream key for each camera
- remember that a single YouTube channel can only have one live stream at a time
- if you want multiple cameras live at the same time, give each one its own YouTube account/channel and its own stream key
This project already assumes separate YouTube credentials per camera by saving tokens as:
tokens/<camera_name>_token.json
Do one interactive run before setting up cron so the OAuth flow can complete and create the token files:
cd ~/camera-youtube-manager
python3 source/main.pyDuring this run, approve the Google/YouTube access request in the browser for each camera account as prompted.
When approval succeeds, the script writes the saved credentials to:
~/camera-youtube-manager/tokens/<camera_name>_token.json
If you want to use the home-directory log file from the cron example below, create it once:
touch ~/youtube-camera.logOpen your user crontab:
crontab -eAdd this line:
*/5 * * * * python3 ~/camera-youtube-manager/source/main.py >> ~/youtube-camera.log 2>&1That runs the manager every five minutes, which fits the way this project is designed to keep checking schedules, stream health, and inactive broadcasts.
Manual commands use the same script but should not be put in cron. For example, to recycle one camera on demand:
cd ~/camera-youtube-manager
python3 source/main.py recycle --camera cam1Create /etc/logrotate.d/camera-youtube-manager with contents like this:
/home/pi/youtube-camera.log {
daily
rotate 0
missingok
notifempty
copytruncate
}
Replace /home/pi/youtube-camera.log with the real home-directory path for the user running the cron job.
Because the cron job appends to the file as your normal user, copytruncate keeps rotation simple without needing root to recreate the file with specific ownership.
rotate 0 means old log files are not kept. The current log is discarded each day rather than keeping dated archives.
Do this only after:
- the repository is in place
settings.jsonis correctclient_secret.jsonis present- the first OAuth run has completed successfully
Then enable the overlay filesystem from raspi-config:
sudo raspi-configIn the menu, go to Advanced Options and then Overlay File System, enable it, and reboot when prompted.
Reasons to do this:
- it reduces SD card wear on a Pi that is writing logs and temporary data regularly
- it makes the box more resilient to sudden power loss
- it helps the Pi behave more like a small appliance once the setup is stable
Important trade-off:
- when the overlay filesystem is enabled, changes made to the root filesystem do not persist across reboot unless you disable the overlay first
- that means future
git pullupdates, package installs, changes tosettings.json, and re-authorisation work should be done with the overlay temporarily turned off
Camera YouTube Manager acts as the glue between your IP cameras, local streaming process, and YouTube Live.
Its main benefit is operational reliability:
- it reduces manual setup
- it recovers from common streaming problems
- it keeps the YouTube broadcast state aligned with the local stream state
- it gives you enough logging to understand what it is doing