Open-source project
lossless1024/StreaMonitor avatar
lossless1024/StreaMonitor

StreaMonitor: one recorder for a dozen live stream sites

Adult live stream downloader for advanced people. I could have chosen a better name.

559 stars136 forksCSSGPL-3.0

At a glance

What is it?
StreaMonitor is a Python 3 application that monitors and records live streams from fifteen cam sites behind a single interface, with a console, a Flask web interface and a ZeroMQ control channel, and an adapter per site so that differences in resolution, usernames and crypto keys stay in one place.
Who is it for?
StreaMonitor suits someone who wants a single recording workflow across several cam sites rather than a separate tool per site, because the per-site quirks are isolated in adapters and the site list, the abbreviation table and the quirk column in the README tell you exactly which sites need attention.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 71 days ago.
What is it written in?
Mainly CSS, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Fifteen sites, and a column that tells you which ones are awkward

StreaMonitor is a Python 3 application for monitoring and saving, mostly adult, live streams from various websites, and it was inspired by Recordurbate.

The site table is the most useful part of the documentation, because it is not just a list. Each site has a name, a short abbreviation, an aliases field, a quirks column and a note on whether a selectable resolution is available.

The abbreviations are what you type at the command line, so Bongacams is BC, Cam4 is C4, Cams.com is CC, CamSoda is CS, Chaturbate is CB, DreamCam is DC, DreamCam VR is DCVR, FanslyLive is FL, Flirt4Free is F4F, MyFreeCams is MFC, SexChat.hu is SCHU, StreaMate is SM, StripChat is SC, StripChat VR is SCVR and XLoveCam is XLC.

The quirks column is where the engineering work shows. SexChat.hu needs the id used as the username. StripChat requires crypto keys to be added. The VR variants are for VR video. And StreaMate and StripChat have long alias lists, PornHubLive and PepperCams for the first and XHamsterLive for the second, which is how a site that rebrands gets covered without a new adapter.

Resolution support is also uneven, and the table is honest about it. Cams.com is currently limited to 360p. DreamCam, DreamCam VR, SexChat.hu, StripChat VR and XLoveCam have no selectable resolution. Everything else does.

There is also a list of sites that are not supported, each with a one line reason, and the reasons are technical rather than moral. Amateur.TV uses Widevine now, Cherry.tv and ManyVids Live switched to Agora, ImLive has too strict captcha protection for scraping, and LiveJasmin has no nudity in the free streams. The site that the author found hardest, ImLive, is the one that stopped him, not the one he chose to skip.

The table also notes that there are hundreds of clones of these sites, with a link explaining how the platforms relate to each other, which is the reason the alias column exists.

One adapter per site, and why the repo calls the primary language CSS

The repository layout is what tells you how the code is organised, and it is a plain Python application with a per-site package.

At the top level there is Downloader.py, which is the main process, and Controller.py, which is the remote control client. There is a streamonitor/ directory holding the application itself, a parameters.py for configuration, a config.json for the streamer list, a requirements.txt, a Dockerfile and a docker-compose.yml. And there is stripchat_mouflon_keys.json, the file the documentation says you have to fill in yourself.

The per-site structure is what keeps fifteen integrations manageable. Each site has its own quirks, its own URL format, its own stream discovery mechanism and sometimes its own crypto, and folding that into one module per site means a change to one site cannot break another. The StripChat crypto is the clearest example of why: it needs keys that have to be supplied, so that logic is isolated in the StripChat code path and nowhere else.

One thing in the repository is odd enough to mention. The primary language is recorded as CSS, which is almost certainly a detection artefact of a stylesheet in the web interface being the largest counted file type rather than a statement about what the project is. The application is Python, the manifest is Python, and the Dockerfile runs Python 3. If you are filtering repositories by language, this one will look like a CSS project.

The requirements file gives the shape of the implementation. requests, pycurl and pycurl-requests handle HTTP, with pycurl present because some of these sites need a real TLS stack with a browser-like fingerprint. fake-useragent is there to set a user agent string. beautifulsoup4 and m3u8 handle page parsing and the HLS playlist format, and websocket-client handles the sites that push updates over a socket rather than through polling. ffmpy is the FFmpeg wrapper, and the documentation lists FFmpeg itself as a requirement, so the recording is done by invoking the encoder. flask and terminaltables provide the web interface and the console status table, pyzmq provides the ZeroMQ channel, termcolor colours the console output, and django-environ handles the parameter file.

Three interfaces, and what the console actually offers

The application exposes a console, an external console over ZeroMQ described as sort of working, and a web interface, and the console is the most complete of them.

code
add <username> <site> - Add streamer to the list (also starts monitoring)
remove <username> [<site>] - Remove streamer from the list
start <username> [<site>] - Start monitoring streamer
start * - Start all
stop <username> [<site>] - Stop monitoring
stop * - stop all
status - Status display 
status2 - A slightly more readable status table
quit - Clean exit (Pressing CTRL-C also behaves like this)

Two conventions are worth picking up before you start typing. The wildcard form, start * and stop *, operates on everything at once, which is how you set the whole roster running. And status and status2 are the same information in two renderings, the second being the more readable table.

The add command also starts monitoring, so you do not add a streamer and then start it as a separate step. And the documentation is precise about the username, because this is where people get stuck: you usually have to enter the username as represented in the original URL of the room, and some sites are case-sensitive. The site argument is more forgiving, since you can use either the full or the short format and it is case-insensitive.

Starting the downloader itself is a single command, and the note in the documentation is that it does not fork yet, which means it runs in the foreground and does not daemonise itself:

code
python3 Downloader.py

It automatically imports all the streamers from the config file when it starts.

The remote controller is a separate script for the same configuration, and the documentation notes that adding or removing a streamer through it also saves the config file:

code
python3 Controller.py add <username> <website>
python3 Controller.py remove <username>
code
python3 Controller.py <start|stop> <username>
code
python3 Controller.py status

The web interface is on port 5000. The documentation is unusually blunt about the default credentials, since if you set a password in parameters.py the username is admin and the password is admin, and an empty password is also allowed. Setting the WEBSERVER_HOST also makes it reachable from other computers on the network, which is the point at which those defaults start to matter.

Docker, the compose file, and the settings it exposes

The container support is the recommended way to run this, and the compose file is where the real configuration surface lives.

code
services:
  streamonitor:
    image: ghcr.io/lossless1024/streamonitor:latest

    restart: unless-stopped
    environment:
      STRMNTR_HOST: '0.0.0.0'
      STRMNTR_CONFIRM_DEL: "MOBILE"
      STRMNTR_STATUS_FREQ: "5"
      STRMNTR_LIST_FREQ: "30"
    volumes:
      - ./downloads:/app/downloads
      - ./config.json:/app/config.json
      - ./stripchat_mouflon_keys.json:/app/stripchat_mouflon_keys.json
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - '5000:5000'

The environment variables here are the settings you would otherwise put in parameters.py, and the commented alternatives in the file show the range. The password is unset by default, meaning the admin default applies, and STRMNTR_HOST is set to 0.0.0.0 to unbind the web interface, which the comment says is bound to 127.0.0.1 by default. The confirm delete behaviour is a three state setting, with the empty string disabling it, the string True making it always on, and MOBILE being the value chosen here, which presumably prompts only on a mobile client.

The two frequency settings are about how hard the application polls. The status refresh frequency is 5 seconds for the streamer page and the list refresh frequency is 30 seconds for the list page, so the detail view is checked more often than the overview. That asymmetry makes sense once you understand the cost: each check is a request to a site that may or may not like being checked.

The volumes are the ones to note. The downloads directory is mounted so recordings survive a container rebuild, the config.json and the StripChat keys file are mounted so you can edit them without recreating the container, and the timezone files are mounted read-only so the container picks up the host's timezone, with a commented TZ environment variable as the alternative.

The Dockerfile is a two stage build on python:3.12-alpine3.19, with PYCURL_SSL_LIBRARY set to openssl, ffmpeg and libcurl installed with apk, and a separate build-dependency step that installs build-base and curl-dev, installs pycurl, and then removes the build dependencies so they do not ship in the final image. The application files are copied in afterwards, port 5000 is exposed, and the default command runs the downloader.

The author prefers docker-compose and includes an example file, so starting it is a single docker-compose up in the project directory.

The disclaimer is the most important paragraph in the README

The disclaimer section is longer than most, and it is worth reading before anything technical, because it sets the terms under which any of the above is appropriate.

The program is only a proof of concept and education project, and the author does not encourage anybody to use it. Most, if not every, streamer disallows recording their shows, and the request is to respect their wish. If you do not and you record them despite that request, the instruction is to never publish or share any recordings, because you might be legally punished otherwise. And the last line is that the tool should not be used for monetization in any way.

That is an unusually clear statement of limits from the person who wrote the code, and it aligns with how the technology actually works. The tool is a recorder for a public live stream, and the person on the other end of that stream has a say in whether it is recorded. The author has written code that is genuinely useful for understanding how these platforms work, and has also said plainly that the useful applications are the educational ones.

The technical facts in this article are therefore best read as an account of how a multi-site stream recorder is put together, not as an endorsement of the recording itself.

The project is GPL-3.0 licensed and the last push was on 2026-08-13, with no GitHub releases, so the deployed image or the repository is the artefact to look at. The repository also has a .dockerignore and a .github/ directory, and the docker-compose.yml is the version the author ships, with the local build alternative commented out at the top of the service.

One small thing about the project name, which the description acknowledges with some humour: the tool is called StreaMonitor, and the description says the author could have chosen a better name.

Editorial conclusion

StreaMonitor suits someone who wants a single recording workflow across several cam sites rather than a separate tool per site, because the per-site quirks are isolated in adapters and the site list, the abbreviation table and the quirk column in the README tell you exactly which sites need attention. It does not suit you as a tool for redistribution, and the author's own disclaimer is unambiguous on that point, so the appropriate use is local viewing of streams you are permitted to record. Before you run it, expect to supply your own StripChat decryption keys in stripchat_mouflon_keys.json, and note that the web interface defaults to an admin password of admin on port 5000, which you should change before it is reachable from your network.

Frequently asked questions

Which live stream sites does StreaMonitor support?

Fifteen: Bongacams, Cam4, Cams.com, CamSoda, Chaturbate, DreamCam, DreamCam VR, FanslyLive, Flirt4Free, MyFreeCams, SexChat.hu, StreaMate, StripChat, StripChat VR and XLoveCam. Each has a short abbreviation you can use on the command line, aliases for rebranded variants, a quirks column, and a note on whether a selectable resolution is available.

How do I run the StreaMonitor downloader?

Install the Python 3 packages listed in requirements.txt with pip and have FFmpeg available, then run python3 Downloader.py. It does not fork yet, so it runs in the foreground, and it automatically imports all the streamers from the config file.

What are the StreaMonitor console commands?

add and remove a streamer, start and stop monitoring one or all with the asterisk wildcard, status and status2 for two renderings of the status display, and quit for a clean exit, which is also what pressing CTRL-C does. The username usually has to match the original room URL and some sites are case-sensitive, while the site argument accepts the full or short name and is case-insensitive.

How is the StreaMonitor web interface secured?

It runs on port 5000. If you set a password in parameters.py the username is admin and the password is admin, and an empty password is also allowed. Setting WEBSERVER_HOST makes it reachable from other computers on the network, and the Docker compose file sets STRMNTR_HOST to 0.0.0.0 while leaving the password unset by default.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. lossless1024/StreaMonitor on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lossless1024-streamonitor.svg)](https://hysenlabs.com/projects/lossless1024-streamonitor)

Was this useful?