{"id":13907676,"url":"https://github.com/jprjr/multistreamer","last_synced_at":"2025-07-18T06:30:45.623Z","repository":{"id":70967049,"uuid":"74601013","full_name":"jprjr/multistreamer","owner":"jprjr","description":"[discontinued] A webapp for publishing video to multiple streaming services at once.","archived":true,"fork":false,"pushed_at":"2021-01-19T15:10:47.000Z","size":1233,"stargazers_count":323,"open_issues_count":0,"forks_count":94,"subscribers_count":31,"default_branch":"master","last_synced_at":"2024-11-25T16:39:02.514Z","etag":null,"topics":["discord","discord-api","facebook","facebook-api","irc","irc-interface","lua-nginx","lua-resty","mixer","openresty","rtmp","stream","streaming","streaming-video","twitch","twitch-api","video","youtube","youtube-api"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jprjr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-11-23T17:51:23.000Z","updated_at":"2024-11-24T03:09:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"7e10e6f3-b58a-4bb2-bb31-a58b823c17e5","html_url":"https://github.com/jprjr/multistreamer","commit_stats":null,"previous_names":[],"tags_count":113,"template":false,"template_full_name":null,"purl":"pkg:github/jprjr/multistreamer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jprjr%2Fmultistreamer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jprjr%2Fmultistreamer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jprjr%2Fmultistreamer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jprjr%2Fmultistreamer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jprjr","download_url":"https://codeload.github.com/jprjr/multistreamer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jprjr%2Fmultistreamer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265710530,"owners_count":23815373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["discord","discord-api","facebook","facebook-api","irc","irc-interface","lua-nginx","lua-resty","mixer","openresty","rtmp","stream","streaming","streaming-video","twitch","twitch-api","video","youtube","youtube-api"],"created_at":"2024-08-06T23:02:05.223Z","updated_at":"2025-07-18T06:30:45.315Z","avatar_url":"https://github.com/jprjr.png","language":"Lua","funding_links":[],"categories":["HarmonyOS","Media Processing"],"sub_categories":["Windows Manager","Rust"],"readme":"# Archived\n\nHi all. I don't enjoy working on this anymore. I'm archiving this repo, you're free to fork it.\n\nStop emailing me directly.\n\n# multistreamer\n\nThis is a tool for simulcasting RTMP streams to multiple services:\n\n* [Mixer](https://github.com/jprjr/multistreamer/wiki/Mixer)\n* [Facebook](https://github.com/jprjr/multistreamer/wiki/Facebook)\n* [Twitch](https://github.com/jprjr/multistreamer/wiki/Twitch)\n* [YouTube](https://github.com/jprjr/multistreamer/wiki/YouTube)\n\nIt allows users to add accounts for their favorite streaming services,\nand gives an endpoint for them to push video to. Their video stream will\nbe relayed to multiple accounts.\n\nIt also allows for updating their stream's metadata (stream title,\ndescription, etc) from a single page, instead of logging into multiple\nservices.\n\nIt supports integration with Discord via webhooks - it can push your\nstream's incoming comments/chat messages to a Discord channel, as well\nas updates when you've started/stopped streaming. There's also a \"raw\"\nwebhook, if you want to develop your own application that responds\nto events. See [the wiki](https://github.com/jprjr/multistreamer/wiki/Webhook)\nfor details.\n\nAdditionally, it provides an IRC interface, where users can read/write\ncomments and messages in a single location. There's also a web interface\nfor viewing and replying to comments, and a chat widget you can embed\ninto OBS (or anything else supporting web-based sources).\n\nNot all services support writing comments/messages from the web or IRC\ninterfaces - please see the [wiki](https://github.com/jprjr/multistreamer/wiki) for\ndetails on which services support which features.\n\nFun, unintentional side effect: you can use this to push video to your\npersonal Facebook profile, instead of using the phone app. This isn't\navailable via the regular Facebook web interface, as far as I know. :)\n\nPlease note: you're responsible for ensuring you're not violating each\nservice's Terms of Service via simulcasting.\n\nHere's some guides on installing/using:\n\n* [My User Guide](https://github.com/jprjr/multistreamer/wiki/User-Guide)\n* [A short intro video](https://youtu.be/NBNLqaUn9mA)\n* [A in-depth tutorial for users](https://youtu.be/Uz2vXppsMIw)\n* [Installing multistreamer with Docker](https://youtu.be/HdDDtBOLme4)\n* [Installing multistreamer without Docker](https://youtu.be/Wr4CD6RU_CU)\n\n## Table of Contents\n\n- [multistreamer](#multistreamer)\n  * [Table of Contents](#table-of-contents)\n  * [Requirements](#requirements)\n  * [Installation](#installation)\n    + [Install with Docker](#install-with-docker)\n    + [Install OpenResty with `setup-openresty`](#install-openresty-with-setup-openresty)\n    + [Alternative: Install OpenResty with RTMP Manually](#alternative-install-openresty-with-rtmp-manually)\n    + [Setup database and user in Postgres](#setup-database-and-user-in-postgres)\n    + [Setup Redis](#setup-redis)\n    + [Setup Sockexec](#setup-sockexec)\n    + [Setup Authentication Server](#setup-authentication-server)\n    + [Clone and setup](#clone-and-setup)\n    + [Install Multistreamer](#install-multistreamer)\n      - [Global install](#global-install)\n      - [Self-contained install](#self-contained-install)\n    + [Initialize the database](#initialize-the-database)\n    + [Customization](#customization)\n  * [Usage](#usage)\n    + [Start the server](#start-the-server)\n    + [Alternative: run as systemd service](#alternative-run-as-systemd-service)\n    + [Web Usage](#web-usage)\n    + [IRC Usage](#irc-usage)\n  * [Reference](#reference)\n    + [`bin/multistreamer` usage:](#binmultistreamer-usage)\n    + [Migrating from Multistreamer 10 -\u003e 11](#migrating-from-multistreamer-10---11)\n  * [Roadmap](#roadmap)\n  * [Versioning](#versioning)\n  * [Licensing](#licensing)\n\n## Requirements\n\n* [OpenResty](https://openresty.org/en/) 1.13.6.1 or greater, with some extra modules:\n  * [nginx-rtmp-module](https://github.com/arut/nginx-rtmp-module)\n* ffmpeg\n* lua 5.1\n* luarocks\n* luajit (included with OpenResty)\n* redis\n* postgresql\n* a POSIX shell (bash, ash, dash, etc)\n\nNote you specifically need OpenResty for this. I no longer support or recommend\ncompiling a custom Nginx with the Lua module, you'll need the OpenResty\ndistribution, which includes Lua modules like `lua-resty-websocket`,\n`lua-resty-redis`, `lua-resty-lock`, and so on.\n\n## Installation\n\n### Install with Docker\n\nI have a Docker image available, along with a docker-compose file for\nquickly getting up and running. Instructions are available here:\nhttps://github.com/jprjr/docker-multistreamer\n\n### Install OpenResty with `setup-openresty`\n\nI've written a script for setting up OpenResty and LuaRocks: https://github.com/jprjr/setup-openresty\n\nThis is now my preferred way for setting up OpenResty. It automatically\ninstalls build pre-requisites for a good number of distros, and installs\nLua 5.1.5 in addition to LuaJIT. This allows LuaRocks to build C modules\nthat no longer build against LuaJIT (like cjson).\n\nTo install, simply:\n\n```bash\ngit clone https://github.com/jprjr/setup-openresty\ncd setup-openresty\nsudo ./setup-openresty\n  --prefix=/opt/openresty-rtmp \\\n  --with-rtmp\n```\n\n### Alternative: Install OpenResty with RTMP Manually\n\nYou'll want to install Lua 5.1.5 as well, so that LuaRocks can build older\nC modules. I have a patch in this repo for building `liblua` as a dynamic\nlibrary, just in case some C module tries to link against `liblua` for\nsome reason.\n\n```bash\nsudo apt-get -y install \\\n  libreadline-dev \\\n  libncurses5-dev \\\n  libpcre3-dev \\\n  libssl-dev \\\n  perl \\\n  make \\\n  build-essential \\\n  unzip \\\n  curl \\\n  git\nmkdir openresty-build \u0026\u0026 cd openresty-build\ncurl -R -L https://openresty.org/download/openresty-1.13.6.1.tar.gz | tar xz\ncurl -R -L https://github.com/arut/nginx-rtmp-module/archive/v1.2.1.tar.gz | tar xz\ncurl -R -L http://luarocks.github.io/luarocks/releases/luarocks-2.4.3.tar.gz | tar xz\ncurl -R -L https://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz\n\ncd openresty-1.13.6.1\n./configure \\\n  --prefix=/opt/openresty-rtmp \\\n  --with-pcre-jit \\\n  --with-ipv6 \\\n  --add-module=../nginx-rtmp-module-1.2.1\nmake\nsudo make install\n\ncd ../lua-5.1.5\npatch -p1 \u003c /path/to/lua-5.1.5.patch # in this repo under misc\nsed -e 's,/usr/local,/opt/openresty-rtmp,g' -i src/luaconf.h\nmake CFLAGS=\"-fPIC -O2 -Wall -DLUA_USE_LINUX\" linux\nsudo make INSTALL_TOP=\"/opt/openresty-rtmp/luajit\" TO_LIB=\"liblua.a liblua.so\" install\n\ncd ../luarocks-2.4.3\n./configure \\\n  --prefix=/opt/openresty-rtmp/luajit \\\n  --with-lua=/opt/openresty-rtmp/luajit\nmake build\nsudo make bootstrap\nsudo ln -s /opt/openresty-rtmp/luajit/bin/luarocks /opt/openresty-rtmp/bin/luarocks\n```\n\n### Setup database and user in Postgres\n\nChange your user/password/database names to whatever you want.\n\nEditing `pg_hba.conf` for network access is outside the scope of\nthis `README` file.\n\n```bash\nsudo su - postgres\npsql\npostgres=# create user multistreamer with password 'multistreamer';\npostgres=# create database multistreamer with owner multistreamer;\npostgres=# \\q\n```\n\n### Setup Redis\n\nI'm not going to write up instructions for setting up Redis - this is more\nof a checklist item.\n\n### Setup Sockexec\n\n`multistreamer` uses the `lua-resty-exec` module for managing ffmpeg processes,\nwhich requires a running instance of [`sockexec`](https://github.com/jprjr/sockexec).\nThe `sockexec` repo has instructions for installation - you can either compile from\nsource, or just download a static binary.\n\nMake sure you change `sockexec`'s default timeout value. The default is pretty\nconservative (60 seconds). I'd recommend making it infinite (ie, `sockexec -t0 /tmp/exec.sock`).\n\n### Setup Authentication Server\n\n`multistreamer` doesn't handle its own authentication - instead, it will\nmake an authenticated HTTP/HTTPS request to some server and allow/deny user\nlogins based on that.\n\nYou can make a really simple htpasswd-based server with nginx:\n\n```nginx\nworker_processes 1;\nerror_log stderr notice;\npid logs/nginx.pid;\ndaemon off;\n\nevents {\n  worker_connections 1024;\n}\n\nhttp {\n  access_log off;\n  server {\n    listen 127.0.0.1:8080;\n    root /dev/null;\n    location / {\n      auth_basic \"default\";\n      auth_basic_user_file \"/path/to/htpasswd/file\";\n      try_files $uri @auth;\n    }\n    location @auth {\n      return 204;\n    }\n  }\n}\n```\n\nI have some some projects for quickly setting up authentication servers:\n\n* htpasswd: https://github.com/jprjr/htpasswd-auth-server\n  * Authenticate users against an htpasswd file\n* postgres: https://github.com/jprjr/postgres-auth-server\n  * Store users in postgres, includes a web interface for adding/managing users\n* LDAP: https://github.com/jprjr/ldap-auth-server\n  * Authenticate users against LDAP\n\n\n### Clone and setup\n\nClone this repo somewhere, copy the example config file, and edit it as-needed\n\n```bash\ngit clone https://github.com/jprjr/multistreamer.git\ncd multistreamer\ncp etc/config.yaml.example /etc/multistreamer/config.yaml\n# edit /etc/multistreamer/config.yaml\n```\n\nI've tried to comment `config.yaml.example` and describe what each setting\ndoes as best as I can.\n\nOne of the more important items in the config file is the `networks` section,\nright now the supported networks are:\n\n* `rtmp` - just push video to an RTMP URL\n* `facebook`\n* `mixer`\n* `twitch`\n* `youtube`\n\nEach module has more details in the [wiki.](https://github.com/jprjr/multistreamer/wiki)\n\n### Install Multistreamer\n\nFor either a global install or self-contained install, you'll need\nlibyaml and its development headers installed. On Ubuntu, this is `libyaml-dev`:\n\n```bash\napt-get install libyaml-dev\n```\n\n#### Global install\n\n```bash\n/opt/openresty/bin/luarocks install multistreamer\n```\n\nIf you used the `setup-openresty` script from above, you'll find\n`multistreamer` at `/opt/openresty/bin/multistreamer`, else it\ndepends on your particular setup.\n\n\n#### Self-contained install\n\nIf you install modules to a folder named `lua_modules`, the  bash script (`./bin/multistreamer`)\nsetup nginx/Lua to only use that folder. So, assuming you're still in\nthe `multistreamer` folder:\n\n```bash\n/opt/openresty-rtmp/bin/luarocks install --tree=lua_modules --only-deps multistreamer\n# or /opt/openresty-rtmp/bin/luarocks install --tree=lua_modules --only-deps rockspecs/multistreamer-dev-1.rockspec\n```\n\nUsing Mac OS? `lapis` will probably fail to install because `luacrypto`\nwill fail to build. If you're using Homebrew, you can install\n`luacrypto` with:\n\n```bash\nluarocks --tree=lua_modules install luacrypto OPENSSL_DIR=/usr/local/opt/openssl\nluarocks --tree=lua_modules install --only-deps multistreamer\n\n```\n\n\n### Initialize the database\n\nMultistreamer will automatically create tables.\n\n### Customization\n\nStarting with Multistreamer 6.0.0, you can override CSS and images.\n\nJust copy the `static` folder to `local`, then edit/replace files as needed.\n\n## Usage\n\n### Start the server\n\nOnce it's been setup, you can start the server with `./bin/multistreamer run`\n\n### Alternative: run as systemd service\n\nFirst, create a local user to run `multistreamer` as:\n\n```bash\nsudo useradd \\\n  -d /var/lib/multistreamer -m \\\n  -r \\\n  -s /usr/sbin/nologin \\\n  multistreamer\n```\n\nThen copy `misc/multistreamer.service` to\n`/etc/systemd/system/multistreamer.service`, and edit it as-needed - you'll\nprobably need to change the `ExecStart` and `ExecStartPre` lines to point\nto wherever you cloned the git repo.\n\n### Web Usage\n\nThe web interface has two fundamental concepts: \"Accounts\" and \"Streams.\"\n\nA user is able to add Accounts to their profile (like a Twitch account or\nFacebook Account). The user is also able to create Streams, which generates a\nstream key for the user.\n\nOnce a stream is created and an account added, the user can start associating\naccounts with streams. An account can be used on as many different streams\nas the user would like.\n\nEach stream has its own set of metadata, like a title for the broadcast, the\ngame being played, and so on. From one page, the user can setup multiple\naccount's metadata. Each account has their own set of fields, so the user\ncan customize the title, description, and so-on for each service.\n\nIt's important to note that updating the web interface does *not* immediately\nchange anything on the user's streaming services - it's saved for later,\nwhen the user starts pushing video.\n\nThe user can setup a stream to either start pushing video to their streaming\nservices as soon as an incoming video stream is detected, or to wait until\nthey've had a chance to preview the stream. Either way, `multistreamer` will\nupdate each account as needed just before it starts pushing video out - things\nlike updating the Twitch's broadcast title and game, or make a new Live Video\nfor Facebook.\n\nOnce the user stops pushing video, `multistreamer` will take any needed\nshutdown/stop actions - like ending the Facebook Live Video.\n\nI highly recommend that users browse the\n[Wiki](https://github.com/jprjr/multistreamer/wiki) - I tried to detail\neach section of the web interface, all the different metadata fields\nof the different network modules, etc.\n\n### IRC Usage\n\nUsers can connect to Multistreamer with an IRC client, and view their\nstream's comments and messages.\n\nThe IRC interface supports logging in with SASL PLAIN authentication, as\nwell as by specifying a server password. Both of these methods transmit\nthe password in plain-text, so you should place some kind\nof SSL terminator in front of Multistreamer, like stunnel or haproxy.\n\nOnce a user has logged into the IRC interface, they'll see a list of rooms\nrepresenting all user's streams on the system. The room names\nuse the format `(username)-(streamname)`\n\nWhenever a stream goes live, an IRC bot will join the room - this bot represents\nan actual account being streamed to. It's username will use the format\n`(network-name)-(account-name)`.\n\nWhenever a new comment/chat/etc comes in, the bot will relay it to the room,\nwith the format `(username)-(network-name) (message)`\n\nI can post messages/comments to my streams by addressing the bots.\n\nWhen the stream ends, the bots will leave the room.\n\nAttached is a screenshot of Adium. I'm the user `john`, and my stream is named\n`Awesome`, so I'm in the room `#john-awesome`\n\n![screenshot](misc/irc-screenshot.png)\n\n## Reference\n\n### `bin/multistreamer` usage:\n\nHere's the full list of options for `multistreamer`:\n\n```\nmultistreamer [-l /path/to/lua] [-c /path/to/config.yaml] [-v] \u003caction\u003e\n```\n\n* `-l /path/to/lua` - explicitly provide a path to the lua/luajit binary\n* `-c /path/to/config.yaml` - specify a config file, defaults to `/etc/multistreamer/config.yaml`\n* `-v` - prints the current version of multistreamer\n* `\u003caction\u003e` - can be one of\n  * `run` - launches nginx\n  * `initdb` - initializes the database\n  * `check` - checks the config file, postgres, redis, etc\n\n### Migrating from Multistreamer 10 -\u003e 11\n\nIn Multistreamer 11, I made changes to (hopefully) make Multistreamer easier\nto deploy.\n\n* You can install Multistreamer using LuaRocks\n  * You can also do a self-contained install with a single luarocks call\n* `config.lua` is removed in favor of a YAML config-file\n  * You can no longer store multiple environments in a single file, use\n    one file per environment.\n  * You can specify a config file with `-c /path/to/config.yaml`\n  * `/etc/multistreamer/config.yaml` is read in by default\n* Database migrations are automatic\n\nVersion 10.2.7 can dump an existing environment's config to YAML, so to migrate:\n\n```bash\ngit checkout 10.2.7\n./bin/multistreamer -e (environment) initdb # prep db for auto-migrations\n./bin/multistreamer -e (environment) dump_yaml \u003e config.yaml\n# checkout config.yaml, make sure everything makes sense\nmkdir /etc/multistreamer\ncp config.yaml /etc/multistreamer/config.yaml\nluarocks --tree=lua_modules install --only-deps rockspecs/multistreamer-dev-1.rockspec\n# or use luarocks --tree=lua_modules install --only-deps multistreamer to pull from luarocks\n```\n\n## Roadmap\n\nNew features I'd like to work on:\n\n* More networks!\n\n## Versioning\n\nThis project uses semantic versioning: `MAJOR.MINOR.PATCH`\n\nA change to the major release number means the user *must* make a\nconfiguration change, running a database migration, etc. Upgrading\nto a new major release without taking action *will* result in a failure.\n\nA change to the minor release number means some new feature is available,\nbut the user doesn't necessarily need to take action (though the new\nfeature might be disabled until they make a config change etc).\n\nA change to the patch number means I've made some small bug fix.\n\nAll releases will include notes with details on migrating databases,\nupdating the config, and so on.\n\n## Licensing\n\nThis project is licensed under the MIT license, see the file `LICENSE`\nfor more details. This license applies to all files, except the\nfollowing exceptions:\n\nThis project includes a copy of Pure.css (`static/css/pure-min.css`),\nwhich is licensed under a BSD-style license. Pure.css license is available\nas LICENSE-purecss.\n\nThis project includes a copy of commonmark.js (`static/js/commonmark.min.js`),\nwhich is licensed under a BSD-style license. The commonmark.js license is\navailable as LICENSE-commonmark-js.\n\nThis project includes a copy of clipboard.js (`static/js/clipboard.min.js`),\nwhich is licensed under an MIT-style license. The clipboard.js license is\navailable as LICENSE-clipboard-js.\n\nThis project includes a copy of Pixabay's \"JavaScript-autoComplete\" library\n(`static/css/auto-complete.css` and `static/js/auto-complete.min.js`), which\nis licensed under an MIT-style license. The license is available\nas LICENSE-autocomplete-js.\n\nThis project includes a copy of balloon.css (`static/css/balloon.css`),\nwhich is licensed under an MIT-style license. The balloon.css licence is\navailable as LICENSE-balloon-css.\n\nThis project includes a copy of zenscroll (`static/js/zenscroll-min.js`), which\nis public-domain code. The license for zenscroll is availble as LICENSE-zenscroll.\n\nThe network modules for Facebook, Twitch, and YouTube include embedded SVG icons from\n[simpleicons.org](https://simpleicons.org/). These icons are in the public domain\nsee [https://github.com/danleech/simple-icons/blob/gh-pages/LICENSE.md](https://github.com/danleech/simple-icons/blob/gh-pages/LICENSE.md).\nI'll be honest, I'm not sure how trademark law applies here (but I'm sure it does),\nso I feel obligated to mention that all trademarked images are property of their\nrespective companies.\n\nThe network module for Mixer uses an embedded SVG icon from [mixer-branding-kit](https://github.com/mixer/branding-kit),\nit is property of [Mixer](https://mixer.com).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjprjr%2Fmultistreamer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjprjr%2Fmultistreamer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjprjr%2Fmultistreamer/lists"}