Self-hosted service
m3ue/m3u-editor avatar
m3ue/m3u-editor

m3u-editor turns IPTV playlists into a managed catalog with EPG and post processing

A full-featured IPTV editor, including features similar to xteve or threadfin. With full EPG management, Xtream API output, ability to store and sync .strm files, post processing with ability to call custom scripts, send webhook requests, or send an email, and much more!

879 stars119 forksPHPNOASSERTION

At a glance

What is it?
m3u-editor is a self-hosted PHP application for editing IPTV playlists, with EPG management, Xtream API output, series management that stores .strm files, and post processing that can call scripts, send webhooks or send email. It is a Laravel application deployed with Docker, and its CC BY-NC-SA licence forbids commercial use, which is the first thing to settle.
Who is it for?
m3u-editor fits a home lab operator or a community group that wants one place to merge several IPTV sources, attach EPG, expose the result to Emby, Jellyfin, Plex or an Xtream client, and trigger automation when the catalog changes. Skip it for any commercial or hosted service, because the CC BY-NC-SA licence forbids commercial use, and skip it if you want a single container without the extra proxy.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

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

Editorial analysis

A catalog editor for people who juggle several IPTV sources

The project describes itself as a full-featured IPTV editor, and the description names its reference points as xteve and threadfin. That is a useful signal about the audience, because those are tools for taking a messy collection of playlist sources and turning them into something a media server or a set of clients can consume reliably.

The application is a Laravel one. The top-level tree shows the standard Laravel layout with `app/`, `bootstrap/`, `config/`, `database/`, `resources/`, `routes/`, `storage/`, an `artisan` file and a `composer.json`, plus a Blade and Vite frontend with a `package.json`, a `postcss.config.js` and a `bootstrap.json` style build manifest. There is a `lang/` directory, so the interface is translatable, and a `README-ZH.md` beside the English one.

The input side is broad. The README states the tool works with m3u, m3u8, m3u+ and the Xtream Codes API.

text
Works with m3u, m3u8, m3u+ and Xtream codes api!

The output side is equally broad, with full Xtream API output so that apps which expect to log in with a username and password against a server can connect, series management with the ability to store and sync `.strm` files, and EPG support for XMLTV files whether local or remote, XMLTV URLs, and full Schedules Direct integration.

The media server integrations are visible in the repository topics, which list Emby, Jellyfin and Plex alongside the Xtream and IPTV tags. In practice that means the output is not only for players, it is aimed at libraries that index channels and series themselves.

EPG handling covers both XMLTV and Schedules Direct

The EPG half of the project is what turns a list of channel URLs into something usable, and it supports two distinct sources.

The first is XMLTV, either as a file on disk or as a URL, which is the format most guide data is already published in. The second is Schedules Direct, the guide service, with the README calling it a full integration and the repository topics carrying the schedules-direct tag.

Having both matters because a lot of operators mix them. A local XMLTV file is cheap to maintain and works offline, while a Schedules Direct subscription gives structured metadata for a defined lineup, and the application lets you bring the two together rather than committing to one.

The EPG is not a side feature bolted onto the playlist editor, it is the reason the app keeps state at all. A raw playlist is a list of stream URLs with channel names, and a media server will happily index it while showing the wrong guide data or none. The editor exists to attach guide information and episode metadata to a normalized catalog, and the screenshots in the README show a dedicated series detail and series editor page, which suggests series are first class objects with their own metadata rather than a flat channel list.

The README does not document how guide matching works, how conflicts between two EPG sources are resolved, or how a channel is mapped to a guide identifier. That mapping step is the one that usually needs tuning, and it is where you should expect to spend the time.

Post processing turns the editor into an automation trigger

The feature list includes post processing with the ability to call custom scripts, send webhook requests, or send an email.

That is a different shape of tool from a playlist editor. An editor is something you open, change and save. A post processing hook is something that fires when the catalog changes, and the three mechanisms cover the three common destinations. A custom script is for anything local, such as writing a file for a media server or refreshing a reverse proxy. A webhook is for a chat notification or an external service, and email is for a plain alert.

The repository tree backs this up. There is a `postcss.config.js` for the frontend and a `routes/` directory for the web routes, but the interesting part for automation is the `resources/` directory and the presence of a `phpunit.xml` and a `pint.json` for code style, alongside a `local-test.sh` and a `local-up.sh` for local development.

Combined with the series management that stores and syncs `.strm` files, the result is an application that can own the whole pipeline. A `.strm` file is a text pointer to a media file, so storing them in the editor and syncing them to a media library means the library's series structure can be rebuilt from the catalog rather than maintained by hand.

What the README does not document is the trigger semantics. It does not say which events can start a post processing run, whether runs are serialised, or what happens when a custom script fails. Those are the details to look for in the source or the documentation site before you wire a script into a critical path.

Deploying with Docker and the credentials you must change

The application is deployed with Docker, and the only stated prerequisite is that Docker is installed and set up on the system. There is also a managed hosting option offered through ElfHosted for people who do not want to run a container themselves.

The quick start notes call out three defaults, and they are the first thing to deal with.

The quick start notes give the default username as admin, the default password as admin, and the default port as 36400.

The port comes from the environment file, where the application listens on 36400 and defaults to SQLite for the database.

text
APP_PORT=36400
text
DB_CONNECTION=sqlite
# ENABLE_POSTGRES=true
# DB_CONNECTION=pgsql

Those comments are the start of the database story. SQLite is the default, and PostgreSQL is an opt in that the environment file supports with an `ENABLE_POSTGRES` switch. There is also a one-time migration path, documented in the same file, that copies existing SQLite data into Postgres on the next start, with a flag file so it runs once, and with a backup of `database.sqlite` written to `./data/database/backups/` before the migration. That is a more careful migration story than most self-hosted PHP applications offer, and it is worth reading before you decide which database to run.

The remaining environment entries cover the rest of the stack: `SESSION_DRIVER=database`, `CACHE_STORE=database`, a `REDIS_CLIENT=predis` setting for the modular deployment, and AWS credentials for S3 storage.

The frontend is built with Vite and Tailwind, and the package manifest keeps the build scripts to two.

json
        "build": "vite build",
        "dev": "vite"

For a local run without Docker, the repository ships `local-up.sh` and `local-test.sh`, and the `Dockerfile` is a multi-stage build with a Composer builder stage that installs PHP dependencies, followed by a runtime stage.

The separate proxy container is what enables hardware acceleration

The deployment files are the interesting part of the project structure, because they are not one compose file but a family of them, and the differences carry meaning.

There is a modular deployment, a modular deployment with a VPN using Gluetun, an all-in-one deployment, a fully modular deployment with Nginx, a fully modular deployment with Caddy that includes automatic HTTPS, a development file, and one for an embedded Redis. The README marks the modular proxy setup as the recommended one, with separate containers for m3u-editor, m3u-proxy and Redis, and notes that Postgres and NGINX can be added as separate containers too. The external proxy setup is the requirement for hardware acceleration.

That last clause is the crux. The all-in-one file is described as a simple solution where everything runs in a single container for quick setup, and it states plainly that hardware acceleration is not supported in that setup. So the choice is between one container that is easy to start and a set of containers that can offload transcoding or stream processing to the GPU.

The proxy is a separate project, `m3ue/m3u-proxy`, and the Dockerfile shows how the two are assembled. The build arguments make the source and branch configurable.

text
ARG M3U_PROXY_REPO=https://github.com/m3ue/m3u-proxy.git
ARG M3U_PROXY_BRANCH=master
ARG INSTALL_DEV_DEPENDENCIES=false
ARG INSTALL_CLAMAV=false

The `INSTALL_CLAMAV` argument is worth a note, since it is an optional antivirus component in the image. The comments also explain that a local directory can be used instead of cloning from git, which is what a monorepo layout needs, and that the GitHub Actions workflow overrides the repository and branch values based on the owner.

The screenshots include a proxy stream monitor, which suggests the proxy side is observable rather than a black box, and the front-end dependencies confirm a real player in the browser, with `hls.js`, `mpegts.js` and `video.js`.

Release tagging shows a project shipping from the edge

The release history is unusual in a way that tells you something about the workflow. The three most recent tags are v0.13.5 on 2026-10-19, an Experimental 0.13.5 tag on the same day, and a Dev 0.13.5 tag on the same day, and the last push was on 2026-10-19 as well.

Three tags for one version number means the project publishes a stable build, a development build and an experimental build of the same release. For a self-hosted application that is a sensible arrangement, since a user who wants the newest features can pull the dev or experimental image while someone running a stable setup stays on the release tag, and the compose files pin a version rather than tracking latest.

The project is not archived, and the homepage points at a suite of hosted tools at sparkison.dev, so the repository is part of a broader product rather than an isolated hobby project.

The licence is the item to look at twice, because the repository is classified under a custom licence that GitHub cannot classify, while the README states the terms plainly. The README says m3u editor is licensed under CC BY-NC-SA 4.0, and spells out the three parts. BY means give credit. NC means no commercial use. SA means share alike if you remix.

The no-commercial-use clause is the operative one for an adopter. A self-hosted installation for personal use is what the project is built for, and the contribution section asks contributors to respect the same licence. Any plan to put the application behind a service, to run it for an organisation's internal users as a shared platform, or to base a product on it needs a different licence from the author, and the README does not grant one.

Editorial conclusion

m3u-editor fits a home lab operator or a community group that wants one place to merge several IPTV sources, attach EPG, expose the result to Emby, Jellyfin, Plex or an Xtream client, and trigger automation when the catalog changes. Skip it for any commercial or hosted service, because the CC BY-NC-SA licence forbids commercial use, and skip it if you want a single container without the extra proxy. Verify first that your playlist sources and EPG feed load as expected, change the default admin credentials before exposing the port, and confirm your media server accepts the generated Xtream output.

Frequently asked questions

How do I run m3u-editor on my own machine?

The only stated prerequisite is Docker installed and set up, and the repository ships several compose files for different layouts, including a modular one with m3u-editor, m3u-proxy and Redis as separate containers, and an all-in-one file that runs everything in a single container for quick setup.

What are the default login details and port for m3u-editor?

The quick start notes list the default username as admin, the default password as admin, and the default port as 36400, which is also the value of `APP_PORT` in the example environment file. The credentials should be changed before the port is exposed.

Which playlist formats and guide sources does m3u-editor support?

The README says it works with m3u, m3u8, m3u+ and the Xtream Codes API, and that EPG support covers XMLTV files whether local or remote, XMLTV URLs, and full Schedules Direct integration.

Can I use m3u-editor commercially?

The README states the project is licensed under CC BY-NC-SA 4.0, where NC means no commercial use. Any commercial deployment would need a separate arrangement with the author, since the README grants no such permission.

Does the all-in-one Docker setup support hardware acceleration?

No. The README describes the all-in-one compose file as a simple setup where everything runs in a single container, and notes that hardware acceleration is not supported in that setup. The modular deployment with the separate m3u-proxy container is the one described as required for hardware acceleration.

Can m3u-editor run on PostgreSQL instead of SQLite?

Yes. The example environment file sets `DB_CONNECTION=sqlite` and includes a commented `ENABLE_POSTGRES=true` switch with the PostgreSQL connection settings, plus a documented one-time migration path that copies existing SQLite data into Postgres and keeps a backup of `database.sqlite`.

Official sources

  1. Issues
  2. m3ue/m3u-editor on GitHub
  3. Project website
  4. README
  5. Releases
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/m3ue-m3u-editor.svg)](https://hysenlabs.com/projects/m3ue-m3u-editor)

Was this useful?