4/18/21 Update - For the moment, I no longer use this as it can be done with the client I’ve switched to using (Tivimate). Also worth mentioning, m3ufilter looks to no longer be actively developed… on his github page he recommends using tvheadend. I really like m3ufilter and there may be a time when I need to use it again. For slow hardware running Kodi clients it was the perfect fit.

So on my home server I have a cron job that runs hourly and uses wget to download m3u files from various hosts. I then run m3ufilter against all of those m3u files to filter them and assemble them in one nice organized m3u file on a Samba share. All of the TV’s which run Kodi in one way or another look toward this m3u file.

Here is an example config but I’ll be explaining it below so just scroll down past it:

core:
  output: m3u
  group_order:
    - "Entertainment + Premiums - Rad"
    - "Entertainment + Premiums - Helix"
    - "Entertainment + Premiums - Dark"
    - "NFL Sunday Ticket - Rad"
    - "NFL Sunday Ticket - Helix"
    - "NFL Sunday Ticket - Dark"
    - "Sports - Helix"
    - "Sports - Dark"
    - "Locals - Rad"
    - "Locals - Helix"
    - "Locals - Dark"
    - "Radio/Music"
providers:
  - uri: file:///path/to/m3ufile
    filters:
      - match(Group, "USA ENTERTAINMENT") && !match(Group, "VIP")
      - match(Group, "USA MOVIE NETWORKS") && !match(Group, "VIP")
      - match(Group, "NFL PACKAGE")
      - match(Group, "USA \\& CANADA SPORTS")
      - match(Group, "ABC LOCAL NETWORKS")
      - match(Group, "CBS LOCAL NETWORKS")
      - match(Group, "NBC LOCAL NETWORKS")
      - match(Group, "FOX LOCAL NETWORKS")
    setters:
      - name: replace(Name, "USA ", "")
      - group: replace(Group, "USA ENTERTAINMENT", "Entertainment + Premiums - Helix")
      - group: replace(Group, "USA MOVIE NETWORKS", "Entertainment + Premiums - Helix")
      - group: replace(Group, "NFL PACKAGE", "NFL Sunday Ticket - Helix")
      - group: replace(Group, "USA \\& CANADA SPORTS", "Sports - Helix")
      - group: replace(Group, "ABC LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "CBS LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "NBC LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "FOX LOCAL NETWORKS", "Locals - Helix")

Okay so let’s go over this.

      - match(Group, "USA ENTERTAINMENT") && !match(Group, "VIP")
      - match(Group, "USA MOVIE NETWORKS") && !match(Group, "VIP")
      - match(Group, "NFL PACKAGE")
      - match(Group, "USA \\& CANADA SPORTS")
      - match(Group, "ABC LOCAL NETWORKS")
      - match(Group, "CBS LOCAL NETWORKS")
      - match(Group, "NBC LOCAL NETWORKS")
      - match(Group, "FOX LOCAL NETWORKS")

This is where you are matching your channels. You can see here that I am doing it by group name but you can also match to channel names. You can also see that I have some operators where I’m telling it not to match VIP in the first two lines. And also take notice that I needed to escape the & with two backslashes in the fourth line. Something I figured out with trial and error.

If you want an easy way to get the group names in a nice list you can run these commands against the m3u file from your host:

grep -Eo 'group-title="(?:\\.|[^"\\])*"' your_m3ufile | grep -Eo '"(?:\\.|[^"\\])*"' | sort | uniq > output.txt

Now you have a text file with all the group names you can use to match against in your m3u file. Moving on, let’s organize a bit and rename some categories. We do that in the setters section:

      - name: replace(Name, "USA ", "")
      - group: replace(Group, "USA ENTERTAINMENT", "Entertainment + Premiums - Helix")
      - group: replace(Group, "USA MOVIE NETWORKS", "Entertainment + Premiums - Helix")
      - group: replace(Group, "NFL PACKAGE", "NFL Sunday Ticket - Helix")
      - group: replace(Group, "USA \\& CANADA SPORTS", "Sports - Helix")
      - group: replace(Group, "ABC LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "CBS LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "NBC LOCAL NETWORKS", "Locals - Helix")
      - group: replace(Group, "FOX LOCAL NETWORKS", "Locals - Helix")

You can see from the above example that I am renaming both USA ENTERTAINMENT and USA MOVIE NETWORKS to Entertainment + Premiums - Helix. That is putting both those groups in the same category. You can see that I renamed some other categories as well as put all the local channels into the same category. What’s next? group_order:

    - "Entertainment + Premiums - Rad"
    - "Entertainment + Premiums - Helix"
    - "Entertainment + Premiums - Dark"
    - "NFL Sunday Ticket - Rad"
    - "NFL Sunday Ticket - Helix"
    - "NFL Sunday Ticket - Dark"
    - "Sports - Helix"
    - "Sports - Dark"
    - "Locals - Rad"
    - "Locals - Helix"
    - "Locals - Dark"
    - "Radio/Music"

This takes all the channel categories we have and puts them in the order that we want them to appear.