OliveTin for Channels: An Interface for Misc Channels DVR Scripts & Tricks

When I added a Channels DVR ALERNATE server it overrode yours.

1 Like

You should re-pull latest and remove that value from CHANNELS_DVR_ALTERNATES

maybe change the test environment also in the future.

Actually, I generally delete :test once :latest has its features. It'll reappear again once I implement something that I want someone more than just me to take for a spin.

1 Like

Some searching found the attached post elsewhere. Apparently Docker-Desktop sets its own WSL distribution as the default, and that was giving me (an old linux user) a bunch of confusion.

2 Likes

New :latest and :2024.03.02 pushed incorporating 3.1.0 updates to:

More help please. I've got WSL (Ubuntu) running, docker installed (via docker desktop), and a compose.yaml as shown below. I know docker is there because I get the expected response to docker --help and docker-compose --help. My guess was to run docker-compose -f compose.yaml but nothing happened. What do I need to fix? (xxx.xxx.xxx.xxx is the ip of my local Channels server)

version: '3.9'
services:
  olivetin:
    image: bnhf/olivetin:latest 
    container_name: olivetin
    ports:
        - 1337:1337
    environment:
      - CHANNELS_DVR= http://xxx.xxx.xxx.xxx:8089
      - CHANNELS_CLIENTS=”TS4K 1” “TS4K 2”
      - UPDATE_YAMLS=TRUE
      - UPDATE_SCRIPTS=TRUE
      - TZ=US/Eastern
    volumes:
      - /mnt/c/Program Files/Docker/Docker/Data/olivetin:/config
      - /mnt/xxx.xxx.xxx.xxx
    restart: unless-stopped
    
  static-file-server:
    image: halverneus/static-file-server:Latest
    container_name: static-file-server
    ports:
      - 8080:8080
    environment:
      - FOLDER=/Web
    volumes:
      - /mnt/c/Program Files/Docker/Docker/Data/olivetin/data:/Web
    restart: unless-stopped

Though it is possible to do this via the command line, I don't support it that way -- only via Portainer. There are enough variables with this kind of thing without dealing with all of the different ways it can be run. Given the "stack" nature of this project, and the multiple environment variables Portainer makes things easier -- and more cross-platform.

So, you've got Docker Desktop running, and have added the Portainer extension -- if I remember correctly. Now's the time time to fire-up Portainer's excellent WebUI, and paste in the following to Portainer-Stacks:

version: '3.9'
services:
  olivetin:
    image: bnhf/olivetin:${TAG} # Add the tag like latest or test to the environment variables below
    container_name: olivetin
    dns_search: ${DOMAIN} # For Tailscale users using Magic DNS, add your Tailnet (tailxxxxx.ts.net) to use hostnames for remote nodes, otherwise use your local domain name
    ports:
      - 1337:1337
    environment:
      - CHANNELS_DVR=${CHANNELS_DVR} # Add your Channels DVR server in the form hostname:port or ip:port
      - CHANNELS_DVR_ALTERNATES=${CHANNELS_DVR_ALTERNATES} # Space separated list of alternate Channels DVR servers to choose from in the form hostname:port or ip:port
      - CHANNELS_CLIENTS=${CHANNELS_CLIENTS} # Space separated list of Channels DVR clients you'd like notifications sent to in the form hostname or IP
      - UPDATE_YAMLS=${UPDATE_YAMLS} # Set this to true to update config.yaml
      - UPDATE_SCRIPTS=${UPDATE_SCRIPTS} # Set this to true to update all included scripts
      - TZ=${TZ} # Add your local timezone in standard linux format. E.G. US/Eastern, US/Central, US/Mountain, US/Pacific, etc
    volumes:
      - ${HOST_DIR}/olivetin:/config # Add the parent directory on your Docker you'd like to use
      - ${DVR_SHARE}:/mnt/local-server-8089 # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR network share
      - ${DVR2_SHARE}:/mnt/remote-server-8089 # Note that these volume mounts should always be to /mnt/hostname-port or /mnt/ip-port (dash rather than a colon between)
    restart: unless-stopped

  static-file-server:
    image: halverneus/static-file-server:latest
    container_name: static-file-server
    dns_search: ${DOMAIN}
    ports:
      - 8080:8080
    environment:
      - FOLDER=${FOLDER}
    volumes:
      - ${HOST_DIR}/olivetin/data:${FOLDER}
    restart: unless-stopped

#volumes: # use this section if you've setup a docker volume named channels-dvr, with CIFS or NFS, to bind to /mnt/dvr inside the container
  #channels-dvr:
    #external: true

And then, in the environment section of Portainer -- in Advanced mode, paste in the following:

TAG=latest
DOMAIN=tailxxxxx.ts.net
CHANNELS_DVR=local-server:8089
CHANNELS_DVR_ALTERNATES=remote-server:8089
CHANNELS_CLIENTS=appletv4k-den firestick-bedroom
UPDATE_YAMLS=true
UPDATE_SCRIPTS=true
TZ=US/Mountain
HOST_DIR=/data
DVR_SHARE=/mnt/dvr
DVR2_SHARE=/mnt/dvr2
FOLDER=/web

You'll need to modify the environment variables to suit your environment, and tweak the "volumes" section ONLY of the docker-compose to your setup. Use the comments in the docker-compose to help you with the env vars.

Based on what you posted above, your environment variables might look something like this. Note that I'm assuming your LAN domain is localdomain, also hostnames can never have spaces -- so double-check those. And, you need to figure out the full path to your Channels DVR data directory (after the /mnt/c I put in):

TAG=latest
DOMAIN=localdomain
CHANNELS_DVR=http://xxx.xxx.xxx.xxx:8089
CHANNELS_DVR_ALTERNATES=
CHANNELS_CLIENTS=TS4K1 TS4K2
UPDATE_YAMLS=true
UPDATE_SCRIPTS=true
TZ=US/Eastern
HOST_DIR=/mnt/c/'Program Files'/Docker/Docker/Data
DVR_SHARE=/mnt/c/
DVR2_SHARE=
FOLDER=/web

And your Volumes section of the compose, should have this modification. The dash instead of a colon shown below is on-purpose, and required:

    volumes:
      - ${HOST_DIR}/olivetin:/config # Add the parent directory on your Docker you'd like to use
      - ${DVR_SHARE}:/mnt/xxx.xxx.xxx.xxx-8089 # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR network share

Thanks so much, I'll get to work on that.

1 Like

New version of OliveTin-for-Channels pushed as bnhf/olivetin:latest (aka bnhf/olivetin:2024.03.20). This adds a new Healthcheck Action, that should prove useful to diagnose setup issues related to Docker, Portainer, WSL, Tailscale and OliveTin.

screenshot-convertible-pc3-2024.03.20-12_16_39

Here's some background on the motivation for creating this, and samples of the ouput:

I've worked with several people, particularly Windows Docker Desktop users, where their setups haven't been "quite right". Rather than continuing to attempt to address these issues one-by-one, I've created a new OliveTin Action that's intended to root out some common problems with both Windows and Linux docker installations.

This may also work with Mac Docker Desktop installations, but I have no way to test that -- help there would be appreciated.

It also serves as a quick way to confirm that one's OliveTin environment variables are set correctly. :slight_smile: It's intended that this data is safe to post, as anything sensitive is automatically redacted by the script.

Here's what the output looks like when your Docker host is running Windows:

First the basic test, which can be run without using the "helper script" on the host:

Windows basic healthcheck details
Checking your OliveTin installation...

----------------------------------------

Checking that your selected Channels DVR server (media-server6:8089) is reachable by URL:
HTTP Status: 200 indicates success...

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  1276  100  1276    0     0   1696      0 --:--:-- --:--:-- --:--:--  1694
HTTP Status: 200
Effective URL: http://media-server6:8089/

----------------------------------------

Checking that your selected Channels DVR server's data files (/mnt/media-server6-8089) are accessible:
Folders with the names Database, Images, Imports, Logs, Movies, Streaming and TV should be visible...

total 12
drwxr-xr-x 2 root root 8192 Dec 31 01:52 .
drwxr-xr-x 1 root root 4096 Mar 20 11:16 ..
drwxr-xr-x 2 root root    0 Dec 24 11:45 .config
drwxr-xr-x 2 root root    0 Dec 24 03:07 .pki
drwxr-xr-x 2 root root    0 Mar 20 10:18 Database
drwxr-xr-x 2 root root    0 Mar 20 09:42 Images
drwxr-xr-x 2 root root    0 Apr  8  2023 Imports
drwxr-xr-x 2 root root    0 Apr  9  2023 Logs
drwxr-xr-x 2 root root    0 Feb 10 18:55 Movies
drwxr-xr-x 2 root root    0 Dec 15 02:54 PlayOn
drwxr-xr-x 2 root root    0 Mar 19 18:43 Streaming
drwxr-xr-x 2 root root    0 Mar 19 16:35 TV

----------------------------------------

Here's a list of your current OliveTin-related settings:

CHANNELS_DVR=media-server6:8089
CHANNELS_DVR_ALTERNATES=utheater-pc:8089
CHANNELS_CLIENTS=appletv4k firestick-master
UPDATE_YAMLS=false
UPDATE_SCRIPTS=false

----------------------------------------

Here's the contents of /etc/resolv.conf from inside the container:

search tail[Redacted].ts.net
nameserver 127.0.0.11
options ndots:0

----------------------------------------

Here's the contents of /etc/hosts from inside the container:

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.30.0.2	olivetin

And then with the helper script running on the host, which creates a temporary "pipe" between the container and the host. This script can be easily inspected, if desired, to confirm it's safe to run. In particular, you can see that only specific commands can be executed on the host. In addition, the pipe is automatically terminated after the test run:

Here's what that script looks like:

fifopipe_hostside.sh script
#!/bin/bash

parentPath="$1"
  [[ -n $parentPath ]] && export PATH="$parentPath"
fifoPipe="./fifopipe"
  [ ! -p "$fifoPipe" ] && mkfifo "$fifoPipe"

echo -e "\nThis script will be terminated from the container side once the OliveTin healthcheck has finished running..."

finish() {
  rm $fifoPipe
}

trap finish EXIT

while true; do
  if read -r hostCommand < "$fifoPipe"; then
    case "$hostCommand" in
      "tailscale netcheck")
        tailscale netcheck > "$fifoPipe"_latest.log 2>&1
        ;;
      "tailscale status")
        tailscale status > "$fifoPipe"_latest.log 2>&1
        ;;
      "WSL_DISTRO_NAME")
        echo "$WSL_DISTRO_NAME" > "$fifoPipe"_latest.log 2>&1
        ;;
      "LINUX_DISTRO_NAME")
        cat /etc/os-release > "$fifoPipe"_latest.log 2>&1
        ;;      
      "resolv.conf")
        cat /etc/resolv.conf > "$fifoPipe"_latest.log 2>&1
        ;;
      "hosts")
        cat /etc/hosts > "$fifoPipe"_latest.log 2>&1
        ;;
      "wsl.conf")
        cat /etc/wsl.conf > "$fifoPipe"_latest.log 2>&1
        ;;
      ".wslconfig")
        cat /mnt/c/Users/$(whoami)/.wslconfig > "$fifoPipe"_latest.log 2>&1
        ;;
      "windows_hosts")
        cat /mnt/c/Windows/System32/drivers/etc/hosts > "$fifoPipe"_latest.log 2>&1
        ;;
      nslookup*)
        cmd.exe /c $hostCommand > "$fifoPipe"_latest.log 2>&1
        ;;
      "windows_ipconfig")
        cmd.exe /c ipconfig /all > "$fifoPipe"_latest.log 2>&1
        ;;
      "END_OF_RUN")
        exit 0
        ;;
      *)
        echo "Unrecognized command: $hostCommand" > "$fifoPipe"_latest.log
        ;;
    esac
  else
    echo "Error reading from FIFO pipe" > "$fifoPipe"_latest.log
  fi
  sleep 1
done

When that script is executed on your Docker host, from the directory you have bound to /config, it'll look like this while it's waiting for the Action to be executed:

Helper script command line execution example
slayer@Convertible-PC3:/data2/olivetin$ sudo -E ./fifopipe_hostside.sh "$PATH"

This script will be terminated from the container side once the OliveTin healthcheck has finished running...

And the extended output, which includes a few key files on the host, looks like this:

Windows extended healthcheck details
Checking your OliveTin installation...

----------------------------------------

Checking that your selected Channels DVR server (media-server6:8089) is reachable by URL:
HTTP Status: 200 indicates success...

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  1276  100  1276    0     0   1743      0 --:--:-- --:--:-- --:--:--  1743
HTTP Status: 200
Effective URL: http://media-server6:8089/

----------------------------------------

Checking that your selected Channels DVR server's data files (/mnt/media-server6-8089) are accessible:
Folders with the names Database, Images, Imports, Logs, Movies, Streaming and TV should be visible...

total 12
drwxr-xr-x 2 root root 8192 Dec 31 01:52 .
drwxr-xr-x 1 root root 4096 Mar 20 11:16 ..
drwxr-xr-x 2 root root    0 Dec 24 11:45 .config
drwxr-xr-x 2 root root    0 Dec 24 03:07 .pki
drwxr-xr-x 2 root root    0 Mar 20 10:18 Database
drwxr-xr-x 2 root root    0 Mar 20 09:42 Images
drwxr-xr-x 2 root root    0 Apr  8  2023 Imports
drwxr-xr-x 2 root root    0 Apr  9  2023 Logs
drwxr-xr-x 2 root root    0 Feb 10 18:55 Movies
drwxr-xr-x 2 root root    0 Dec 15 02:54 PlayOn
drwxr-xr-x 2 root root    0 Mar 19 18:43 Streaming
drwxr-xr-x 2 root root    0 Mar 19 16:35 TV

----------------------------------------

Here's a list of your current OliveTin-related settings:

CHANNELS_DVR=media-server6:8089
CHANNELS_DVR_ALTERNATES=utheater-pc:8089
CHANNELS_CLIENTS=appletv4k firestick-master
UPDATE_YAMLS=false
UPDATE_SCRIPTS=false

----------------------------------------

Here's the contents of /etc/resolv.conf from inside the container:

search tail[Redacted].ts.net
nameserver 127.0.0.11
options ndots:0

----------------------------------------

Here's the contents of /etc/hosts from inside the container:

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.30.0.2	olivetin

----------------------------------------

Your WSL Docker-host is running:

 Debian

----------------------------------------

Your WSL Docker-host's /etc/resolv.conf file contains:

# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.22.192.1

----------------------------------------

Your WSL Docker-host's /etc/hosts file contains:

# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateHosts = false
127.0.0.1	localhost
127.0.1.1	Convertible-PC3.	Convertible-PC3
192.168.110.130	encoder_48007
192.168.110.49	encoder_23393
192.168.110.224	battery-warmer
192.168.110.66	omr-vps
192.168.110.9	raspberrypi11
192.168.110.167	raspberrypi12
192.168.100.161	host.docker.internal
192.168.100.161	gateway.docker.internal
127.0.0.1	kubernetes.docker.internal

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

----------------------------------------

Your WSL Docker-host's /etc/wsl.conf file contains:

[boot]
systemd=true


----------------------------------------

Your Windows PC's %USERPROFILE%\.wslconfig file contains:

cat: /mnt/c/Users/root/.wslconfig: No such file or directory


----------------------------------------

Your Windows PC's etc/hosts file contains:

## Added by WSU for hostname resolution over Tailscale
192.168.110.130 encoder_48007
192.168.110.49 encoder_23393
192.168.110.224 battery-warmer
192.168.110.66 omr-vps
192.168.110.9 raspberrypi11
192.168.110.167 raspberrypi12
# Added by Docker Desktop
192.168.100.161 host.docker.internal
192.168.100.161 gateway.docker.internal
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

----------------------------------------

Your Windows PC's DNS server resolution:

'\\wsl.localhost\Debian\data2\olivetin'
CMD.EXE was started with the above path as the current directory.
UNC paths are not supported.  Defaulting to Windows directory.
Server:  magicdns.localhost-tailscale-daemon
Address:  100.100.100.100

Name:    media-server6.tail[Redacted].ts.net
Address:  100.[Redacted]


----------------------------------------

Your Windows PC's network interfaces:

'\\wsl.localhost\Debian\data2\olivetin'
CMD.EXE was started with the above path as the current directory.
UNC paths are not supported.  Defaulting to Windows directory.

Windows IP Configuration

   Host Name . . . . . . . . . . . . : Convertible-PC3
   Primary Dns Suffix  . . . . . . . : 
   Node Type . . . . . . . . . . . . : Hybrid
   IP Routing Enabled. . . . . . . . : No
   WINS Proxy Enabled. . . . . . . . : No
   DNS Suffix Search List. . . . . . : tail[Redacted].ts.net
                                       lan

Unknown adapter Tailscale:

   Connection-specific DNS Suffix  . : tail[Redacted].ts.net
   Description . . . . . . . . . . . : Tailscale Tunnel
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   IPv6 Address. . . . . . . . . . . : [Redacted]
   Link-local IPv6 Address . . . . . : [Redacted]
   IPv4 Address. . . . . . . . . . . : 100.[Redacted]
   Subnet Mask . . . . . . . . . . . : 255.255.255.255
   Default Gateway . . . . . . . . . : ::
                                       0.0.0.0
   DNS Servers . . . . . . . . . . . : 100.100.100.100
   NetBIOS over Tcpip. . . . . . . . : Disabled
   Connection-specific DNS Suffix Search List :
                                       tail[Redacted].ts.net

Ethernet adapter Ethernet 2:

   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : VirtualBox Host-Only Ethernet Adapter
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : [Redacted]
   Autoconfiguration IPv4 Address. . : 169.254.73.40(Preferred) 
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Default Gateway . . . . . . . . . : 
   DHCPv6 IAID . . . . . . . . . . . : [Redacted]
   DHCPv6 Client DUID. . . . . . . . : [Redacted]
   NetBIOS over Tcpip. . . . . . . . : Enabled

Unknown adapter Local Area Connection:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : TAP-Windows Adapter V9
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter Local Area Connection* 3:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter #3
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter Local Area Connection* 4:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Microsoft Wi-Fi Direct Virtual Adapter #4
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes

Wireless LAN adapter Wi-Fi:

   Connection-specific DNS Suffix  . : lan
   Description . . . . . . . . . . . : Intel(R) Wi-Fi 6E AX210 160MHz
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : [Redacted]
   IPv4 Address. . . . . . . . . . . : 192.168.8.161(Preferred) 
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Lease Obtained. . . . . . . . . . : Monday, March 18, 2024 7:22:30 AM
   Lease Expires . . . . . . . . . . : Wednesday, March 20, 2024 7:47:03 PM
   Default Gateway . . . . . . . . . : 192.168.8.1
   DHCP Server . . . . . . . . . . . : 192.168.8.1
   DHCPv6 IAID . . . . . . . . . . . : [Redacted]
   DHCPv6 Client DUID. . . . . . . . : [Redacted]
   DNS Servers . . . . . . . . . . . : 192.168.8.1
   NetBIOS over Tcpip. . . . . . . . : Enabled

Ethernet adapter Bluetooth Network Connection:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Bluetooth Device (Personal Area Network)
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes

Ethernet adapter vEthernet (Default Switch):

   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : [Redacted]
   IPv4 Address. . . . . . . . . . . : 172.27.192.1(Preferred) 
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . : 
   DHCPv6 IAID . . . . . . . . . . . : [Redacted]
   DHCPv6 Client DUID. . . . . . . . : [Redacted]
   NetBIOS over Tcpip. . . . . . . . : Enabled

Ethernet adapter vEthernet (WSL (Hyper-V firewall)):

   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter #2
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : [Redacted]
   IPv4 Address. . . . . . . . . . . : 172.22.192.1(Preferred) 
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . : 
   DHCPv6 IAID . . . . . . . . . . . : [Redacted]
   DHCPv6 Client DUID. . . . . . . . : [Redacted]
   NetBIOS over Tcpip. . . . . . . . : Enabled

Ethernet adapter vEthernet (WSLCore):

   Connection-specific DNS Suffix  . : 
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter #3
   Physical Address. . . . . . . . . : [Redacted]
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : [Redacted]
   IPv4 Address. . . . . . . . . . . : 172.30.240.1(Preferred) 
   Subnet Mask . . . . . . . . . . . : 255.255.240.0
   Default Gateway . . . . . . . . . : 
   DHCPv6 IAID . . . . . . . . . . . : [Redacted]
   DHCPv6 Client DUID. . . . . . . . : [Redacted]
   NetBIOS over Tcpip. . . . . . . . : Enabled

Here's what the output looks like when your Docker host is running Linux:

Linux basic healthcheck details
Checking your OliveTin installation...

----------------------------------------

Checking that your selected Channels DVR server (media-server6:8089) is reachable by URL:
HTTP Status: 200 indicates success...

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  1276  100  1276    0     0   249k      0 --:--:-- --:--:-- --:--:--  249k
HTTP Status: 200
Effective URL: http://media-server6:8089/

----------------------------------------

Checking that your selected Channels DVR server's data files (/mnt/media-server6-8089) are accessible:
Folders with the names Database, Images, Imports, Logs, Movies, Streaming and TV should be visible...

total 12
drwxr-xr-x 2 1000 1000 8192 Dec 31 01:52 .
drwxr-xr-x 1 root root 4096 Mar 20 11:36 ..
drwxr-xr-x 2 1000 1000    0 Dec 24 11:45 .config
drwxr-xr-x 2 1000 1000    0 Dec 24 03:07 .pki
drwxr-xr-x 2 1000 1000    0 Mar 20 10:18 Database
drwxr-xr-x 2 1000 1000    0 Mar 20 09:42 Images
drwxr-xr-x 2 1000 1000    0 Apr  8  2023 Imports
drwxr-xr-x 2 1000 1000    0 Apr  9  2023 Logs
drwxr-xr-x 2 1000 1000    0 Feb 10 18:55 Movies
drwxr-xr-x 2 1000 1000    0 Dec 15 02:54 PlayOn
drwxr-xr-x 2 1000 1000    0 Mar 19 18:43 Streaming
drwxr-xr-x 2 1000 1000    0 Mar 19 16:35 TV

----------------------------------------

Here's a list of your current OliveTin-related settings:

CHANNELS_DVR=media-server6:8089
CHANNELS_DVR_ALTERNATES=utheater-pc:8089
CHANNELS_CLIENTS=appletv4k firestick-master
UPDATE_YAMLS=false
UPDATE_SCRIPTS=false

----------------------------------------

Here's the contents of /etc/resolv.conf from inside the container:

search tail[Redacted].ts.net
nameserver 127.0.0.11
options ndots:0

----------------------------------------

Here's the contents of /etc/hosts from inside the container:

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
192.168.16.3	356c775c52a1

And, the extended output when the helper script is running on the host:

Linux extended healthcheck details
Checking your OliveTin installation...

----------------------------------------

Checking that your selected Channels DVR server (media-server6:8089) is reachable by URL:
HTTP Status: 200 indicates success...

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  1276  100  1276    0     0   249k      0 --:--:-- --:--:-- --:--:--  249k
HTTP Status: 200
Effective URL: http://media-server6:8089/

----------------------------------------

Checking that your selected Channels DVR server's data files (/mnt/media-server6-8089) are accessible:
Folders with the names Database, Images, Imports, Logs, Movies, Streaming and TV should be visible...

total 12
drwxr-xr-x 2 1000 1000 8192 Dec 31 01:52 .
drwxr-xr-x 1 root root 4096 Mar 20 11:36 ..
drwxr-xr-x 2 1000 1000    0 Dec 24 11:45 .config
drwxr-xr-x 2 1000 1000    0 Dec 24 03:07 .pki
drwxr-xr-x 2 1000 1000    0 Mar 20 10:18 Database
drwxr-xr-x 2 1000 1000    0 Mar 20 09:42 Images
drwxr-xr-x 2 1000 1000    0 Apr  8  2023 Imports
drwxr-xr-x 2 1000 1000    0 Apr  9  2023 Logs
drwxr-xr-x 2 1000 1000    0 Feb 10 18:55 Movies
drwxr-xr-x 2 1000 1000    0 Dec 15 02:54 PlayOn
drwxr-xr-x 2 1000 1000    0 Mar 19 18:43 Streaming
drwxr-xr-x 2 1000 1000    0 Mar 19 16:35 TV

----------------------------------------

Here's a list of your current OliveTin-related settings:

CHANNELS_DVR=media-server6:8089
CHANNELS_DVR_ALTERNATES=utheater-pc:8089
CHANNELS_CLIENTS=appletv4k firestick-master
UPDATE_YAMLS=false
UPDATE_SCRIPTS=false

----------------------------------------

Here's the contents of /etc/resolv.conf from inside the container:

search tail[Redacted].ts.net
nameserver 127.0.0.11
options ndots:0

----------------------------------------

Here's the contents of /etc/hosts from inside the container:

127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
192.168.16.3	356c775c52a1

----------------------------------------

Your Docker-host is running:

 "Debian GNU/Linux 11 (bullseye)"

----------------------------------------

Your Docker-host's /etc/resolv.conf file contains:

# resolv.conf(5) file generated by tailscale
# For more info, see https://tailscale.com/s/resolvconf-overwrite
# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN

nameserver 100.100.100.100
search tail[Redacted].ts.net

----------------------------------------

Your Docker-host's /etc/hosts file contains:

127.0.0.1	localhost
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters
# --- BEGIN PVE ---
192.168.110.111 htpc6.tail[Redacted].ts.net htpc6
# --- END PVE ---

@bnhf I think there is a bug in the m3u generation for a channels collection. If I have two sources for a channel, say VH1, and I add VH1 to a collection I want to generate a remote m3u for, it dupes the channel in the file.

can you take a look please?

thsnks!

Using the "List Sources for a Single Channel", I found this channel with multiple sources:

-------------------
Matched - Station ID: CNN HEADLINES
Channel name: CNN HEADLINES
Number of sources: 2
Free channels: -
DIRECTV: -
CDVR - Minneapolis: -
Fire TV - DTV: -
Fire TV - Live TV: -
Pluto TV: 2270
Samsung TV Plus: 1009
FrndlyTV: -
FrndlyTV-noEPG: -
Stirr: -
Chrome Capture: -
Virtual Channels: -
VLC-Bridge - PBS: -
-------------------

I then added it to one of my Channels Collections, and created an M3U based on that collection:

M3U for Collection: Up-n-Away
Source M3U used: http://media-server6:8089/devices/ANY/channels.m3u
Copy & Paste M3U from here or use: /config/data/media-server6-8089/Up-n-Away.m3u
Optional access by URL at http://<host:port>/media-server6-8089/Up-n-Away.m3u

#EXTM3U

#EXTINF:-1 channel-id="10008" tvg-id="10008" tvg-chno="10008" tvg-logo="/dvr/uploads/15/content" tvc-guide-stationid="null" tvg-name="One Hit Wonders",One Hit Wonders
http://media-server6:8089/devices/ANY/channels/10008/hls/master.m3u8?

#EXTINF:-1 channel-id="10002" tvg-id="10002" tvg-chno="10002" tvg-logo="/dvr/uploads/9/content" tvc-guide-stationid="null" tvg-name="Political",Political
http://media-server6:8089/devices/ANY/channels/10002/hls/master.m3u8?

#EXTINF:-1 channel-id="10009" tvg-id="10009" tvg-chno="10009" tvg-logo="/dvr/uploads/16/content" tvc-guide-stationid="null" tvg-name="Comedians",Comedians
http://media-server6:8089/devices/ANY/channels/10009/hls/master.m3u8?

#EXTINF:-1 channel-id="10001" tvg-id="10001" tvg-chno="10001" tvg-logo="/dvr/uploads/8/content" tvc-guide-stationid="null" tvg-name="NCIS",NCIS
http://media-server6:8089/devices/ANY/channels/10001/hls/master.m3u8?

#EXTINF:-1 channel-id="10003" tvg-id="10003" tvg-chno="10003" tvg-logo="/dvr/uploads/10/content" tvc-guide-stationid="null" tvg-name="Chicago",Chicago
http://media-server6:8089/devices/ANY/channels/10003/hls/master.m3u8?

#EXTINF:-1 channel-id="10007" tvg-id="10007" tvg-chno="10007" tvg-logo="/dvr/uploads/14/content" tvc-guide-stationid="null" tvg-name="Police - Light",Police - Light
http://media-server6:8089/devices/ANY/channels/10007/hls/master.m3u8?

#EXTINF:-1 channel-id="10010" tvg-id="10010" tvg-chno="10010" tvg-logo="/dvr/uploads/17/content" tvc-guide-stationid="null" tvg-name="Detectives",Detectives
http://media-server6:8089/devices/ANY/channels/10010/hls/master.m3u8?

#EXTINF:-1 channel-id="10005" tvg-id="10005" tvg-chno="10005" tvg-logo="/dvr/uploads/12/content" tvc-guide-stationid="null" tvg-name="Lawyers of Conscience",Lawyers of Conscience
http://media-server6:8089/devices/ANY/channels/10005/hls/master.m3u8?

#EXTINF:-1 channel-id="10006" tvg-id="10006" tvg-chno="10006" tvg-logo="/dvr/uploads/13/content" tvc-guide-stationid="null" tvg-name="Victorian Age",Victorian Age
http://media-server6:8089/devices/ANY/channels/10006/hls/master.m3u8?

#EXTINF:-1 channel-id="10011" tvg-id="10011" tvg-chno="10011" tvg-logo="/dvr/uploads/23/content" tvc-guide-stationid="null" tvg-name="Renaissance",Renaissance
http://media-server6:8089/devices/ANY/channels/10011/hls/master.m3u8?

#EXTINF:-1 channel-id="10012" tvg-id="10012" tvg-chno="10012" tvg-logo="/dvr/uploads/24/content" tvc-guide-stationid="null" tvg-name="Revolutionary War",Revolutionary War
http://media-server6:8089/devices/ANY/channels/10012/hls/master.m3u8?

#EXTINF:-1 channel-id="10004" tvg-id="10004" tvg-chno="10004" tvg-logo="/dvr/uploads/11/content" tvc-guide-stationid="null" tvg-name="Hallmark Christmas",Hallmark Christmas
http://media-server6:8089/devices/ANY/channels/10004/hls/master.m3u8?

#EXTINF:-1 channel-id="9806" tvg-id="9806" tvg-chno="9806" tvg-logo="null" tvc-guide-stationid="21723" tvg-name="KRMA",KRMA
http://media-server6:8089/devices/ANY/channels/9806/hls/master.m3u8?

#EXTINF:-1 channel-id="9521" tvg-id="9521" tvg-chno="9521" tvg-logo="http://media-server6:8089/dvr/uploads/21/content" tvc-guide-stationid="21634" tvg-name="PBS",PBS
http://media-server6:8089/devices/ANY/channels/9521/hls/master.m3u8?

#EXTINF:-1 channel-id="9359" tvg-id="9359" tvg-chno="9359" tvg-logo="null" tvc-guide-stationid="25102" tvg-name="KAET PBS 8",KAET PBS 8
http://media-server6:8089/devices/ANY/channels/9359/hls/master.m3u8?

#EXTINF:-1 channel-id="9549" tvg-id="9549" tvg-chno="9549" tvg-logo="http://media-server6:8089/dvr/uploads/18/content" tvc-guide-stationid="20505" tvg-name="NBC",NBC
http://media-server6:8089/devices/ANY/channels/9549/hls/master.m3u8?

#EXTINF:-1 channel-id="9548" tvg-id="9548" tvg-chno="9548" tvg-logo="https://tmsimg.fancybits.co/assets/s51307_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="128316" tvg-name="MNT",MNT
http://media-server6:8089/devices/ANY/channels/9548/hls/master.m3u8?

#EXTINF:-1 channel-id="9361" tvg-id="9361" tvg-chno="9361" tvg-logo="null" tvc-guide-stationid="20507" tvg-name="KPNX NBC 12",KPNX NBC 12
http://media-server6:8089/devices/ANY/channels/9361/hls/master.m3u8?

#EXTINF:-1 channel-id="9531" tvg-id="9531" tvg-chno="9531" tvg-logo="http://media-server6:8089/dvr/uploads/20/content" tvc-guide-stationid="21236" tvg-name="ABC",ABC
http://media-server6:8089/devices/ANY/channels/9531/hls/master.m3u8?

#EXTINF:-1 channel-id="6001" tvg-id="6001" tvg-chno="6001" tvg-logo="https://tmsimg.fancybits.co/assets/s28708_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="20293" tvg-name="KMGH",KMGH
http://media-server6:8089/devices/ANY/channels/6001/hls/master.m3u8?

#EXTINF:-1 channel-id="9532" tvg-id="9532" tvg-chno="9532" tvg-logo="https://tmsimg.fancybits.co/assets/s32822_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="32822" tvg-name="45TV",45TV
http://media-server6:8089/devices/ANY/channels/9532/hls/master.m3u8?

#EXTINF:-1 channel-id="9533" tvg-id="9533" tvg-chno="9533" tvg-logo="https://tmsimg.fancybits.co/assets/s70436_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="73502" tvg-name="METVN",METVN
http://media-server6:8089/devices/ANY/channels/9533/hls/master.m3u8?

#EXTINF:-1 channel-id="9536" tvg-id="9536" tvg-chno="9536" tvg-logo="https://tmsimg.fancybits.co/assets/s61775_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="75977" tvg-name="THIS",THIS
http://media-server6:8089/devices/ANY/channels/9536/hls/master.m3u8?

#EXTINF:-1 channel-id="9539" tvg-id="9539" tvg-chno="9539" tvg-logo="http://media-server6:8089/dvr/uploads/19/content" tvc-guide-stationid="31247" tvg-name="FOX",FOX
http://media-server6:8089/devices/ANY/channels/9539/hls/master.m3u8?

#EXTINF:-1 channel-id="9360" tvg-id="9360" tvg-chno="9360" tvg-logo="null" tvc-guide-stationid="21209" tvg-name="KSAZ FOX 10",KSAZ FOX 10
http://media-server6:8089/devices/ANY/channels/9360/hls/master.m3u8?

#EXTINF:-1 channel-id="9527" tvg-id="9527" tvg-chno="9527" tvg-logo="http://media-server6:8089/dvr/uploads/22/content" tvc-guide-stationid="21234" tvg-name="CBS",CBS
http://media-server6:8089/devices/ANY/channels/9527/hls/master.m3u8?

#EXTINF:-1 channel-id="6003" tvg-id="6003" tvg-chno="6003" tvg-logo="https://tmsimg.fancybits.co/assets/s28711_h3_ba.png?w=360&h=270" tvc-guide-stationid="35366" tvg-name="KKTV",KKTV
http://media-server6:8089/devices/ANY/channels/6003/hls/master.m3u8?

#EXTINF:-1 channel-id="9528" tvg-id="9528" tvg-chno="9528" tvg-logo="https://tmsimg.fancybits.co/assets/s109454_h3_ba.png?w=360&h=270" tvc-guide-stationid="92038" tvg-name="STARTTV",STARTTV
http://media-server6:8089/devices/ANY/channels/9528/hls/master.m3u8?

#EXTINF:-1 channel-id="11003" tvg-id="11003" tvg-chno="11003" tvg-logo="https://d229kpbsb5jevy.cloudfront.net/frndlytv/400/400/content/common/logos/channel/logos/slaghy.png" tvc-guide-stationid="18633" tvg-name="ION",ION
http://media-server6:8089/devices/ANY/channels/11003/hls/master.m3u8?

#EXTINF:-1 channel-id="6010" tvg-id="6010" tvg-chno="6010" tvg-logo="https://tmsimg.fancybits.co/assets/s62420_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="62420" tvg-name="CC",CC
http://media-server6:8089/devices/ANY/channels/6010/hls/master.m3u8?

#EXTINF:-1 channel-id="6014" tvg-id="6014" tvg-chno="6014" tvg-logo="https://tmsimg.fancybits.co/assets/s60046_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="60046" tvg-name="VH1",VH1
http://media-server6:8089/devices/ANY/channels/6014/hls/master.m3u8?

#EXTINF:-1 channel-id="6016" tvg-id="6016" tvg-chno="6016" tvg-logo="https://tmsimg.fancybits.co/assets/s59440_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="59440" tvg-name="CMT",CMT
http://media-server6:8089/devices/ANY/channels/6016/hls/master.m3u8?

#EXTINF:-1 channel-id="6020" tvg-id="6020" tvg-chno="6020" tvg-logo="https://tmsimg.fancybits.co/assets/s16123_h3_aa.png?w=360&h=270" tvc-guide-stationid="16123" tvg-name="TVLAND",TVLAND
http://media-server6:8089/devices/ANY/channels/6020/hls/master.m3u8?

#EXTINF:-1 channel-id="6022" tvg-id="6022" tvg-chno="6022" tvg-logo="https://tmsimg.fancybits.co/assets/s59186_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="59186" tvg-name="PARAMOUNT",PARAMOUNT
http://media-server6:8089/devices/ANY/channels/6022/hls/master.m3u8?

#EXTINF:-1 channel-id="6030" tvg-id="6030" tvg-chno="6030" tvg-logo="https://tmsimg.fancybits.co/assets/s58646_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="58646" tvg-name="CNN",CNN
http://media-server6:8089/devices/ANY/channels/6030/hls/master.m3u8?

#EXTINF:-1 channel-id="6032" tvg-id="6032" tvg-chno="6032" tvg-logo="https://tmsimg.fancybits.co/assets/s10146_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="10146" tvg-name="CNNI",CNNI
http://media-server6:8089/devices/ANY/channels/6032/hls/master.m3u8?

#EXTINF:-1 channel-id="6033" tvg-id="6033" tvg-chno="6033" tvg-logo="https://tmsimg.fancybits.co/assets/s58515_h3_aa.png?w=360&h=270" tvc-guide-stationid="58515" tvg-name="TBS",TBS
http://media-server6:8089/devices/ANY/channels/6033/hls/master.m3u8?

#EXTINF:-1 channel-id="6034" tvg-id="6034" tvg-chno="6034" tvg-logo="https://tmsimg.fancybits.co/assets/s58515_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="67890" tvg-name="TBSP",TBSP
http://media-server6:8089/devices/ANY/channels/6034/hls/master.m3u8?

#EXTINF:-1 channel-id="6035" tvg-id="6035" tvg-chno="6035" tvg-logo="https://tmsimg.fancybits.co/assets/s42642_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="42642" tvg-name="TNT",TNT
http://media-server6:8089/devices/ANY/channels/6035/hls/master.m3u8?

#EXTINF:-1 channel-id="6036" tvg-id="6036" tvg-chno="6036" tvg-logo="https://tmsimg.fancybits.co/assets/s42642_h3_ba.png?w=360&h=270" tvc-guide-stationid="61340" tvg-name="TNTP",TNTP
http://media-server6:8089/devices/ANY/channels/6036/hls/master.m3u8?

#EXTINF:-1 channel-id="6037" tvg-id="6037" tvg-chno="6037" tvg-logo="https://tmsimg.fancybits.co/assets/s64490_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="64490" tvg-name="TRU",TRU
http://media-server6:8089/devices/ANY/channels/6037/hls/master.m3u8?

#EXTINF:-1 channel-id="6038" tvg-id="6038" tvg-chno="6038" tvg-logo="https://tmsimg.fancybits.co/assets/s64490_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="65717" tvg-name="TRUP",TRUP
http://media-server6:8089/devices/ANY/channels/6038/hls/master.m3u8?

#EXTINF:-1 channel-id="6039" tvg-id="6039" tvg-chno="6039" tvg-logo="https://tmsimg.fancybits.co/assets/s64312_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="64312" tvg-name="TCM",TCM
http://media-server6:8089/devices/ANY/channels/6039/hls/master.m3u8?

#EXTINF:-1 channel-id="6043" tvg-id="6043" tvg-chno="6043" tvg-logo="https://tmsimg.fancybits.co/assets/s51529_h3_ba.png?w=360&h=270" tvc-guide-stationid="51529" tvg-name="AETV",AETV
http://media-server6:8089/devices/ANY/channels/6043/hls/master.m3u8?

#EXTINF:-1 channel-id="6044" tvg-id="6044" tvg-chno="6044" tvg-logo="https://tmsimg.fancybits.co/assets/s14771_ll_h15_af.png?w=360&h=270" tvc-guide-stationid="14771" tvg-name="HISTORY",HISTORY
http://media-server6:8089/devices/ANY/channels/6044/hls/master.m3u8?

#EXTINF:-1 channel-id="6046" tvg-id="6046" tvg-chno="6046" tvg-logo="https://tmsimg.fancybits.co/assets/s60150_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="60150" tvg-name="LIFETIME",LIFETIME
http://media-server6:8089/devices/ANY/channels/6046/hls/master.m3u8?

#EXTINF:-1 channel-id="9346" tvg-id="9346" tvg-chno="9346" tvg-logo="null" tvc-guide-stationid="58452" tvg-name="USA Network HD",USA Network HD
http://media-server6:8089/devices/ANY/channels/9346/hls/master.m3u8?

#EXTINF:-1 channel-id="6080" tvg-id="6080" tvg-chno="6080" tvg-logo="https://tmsimg.fancybits.co/assets/s58574_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="58574" tvg-name="FX",FX
http://media-server6:8089/devices/ANY/channels/6080/hls/master.m3u8?

#EXTINF:-1 channel-id="6081" tvg-id="6081" tvg-chno="6081" tvg-logo="https://tmsimg.fancybits.co/assets/s58574_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="59814" tvg-name="FXP",FXP
http://media-server6:8089/devices/ANY/channels/6081/hls/master.m3u8?

#EXTINF:-1 channel-id="6082" tvg-id="6082" tvg-chno="6082" tvg-logo="https://tmsimg.fancybits.co/assets/s66379_ll_h9_aa.png?w=360&h=270" tvc-guide-stationid="66379" tvg-name="FXX",FXX
http://media-server6:8089/devices/ANY/channels/6082/hls/master.m3u8?

#EXTINF:-1 channel-id="6083" tvg-id="6083" tvg-chno="6083" tvg-logo="https://tmsimg.fancybits.co/assets/s66379_ll_h9_aa.png?w=360&h=270" tvc-guide-stationid="82571" tvg-name="FXXP",FXXP
http://media-server6:8089/devices/ANY/channels/6083/hls/master.m3u8?

#EXTINF:-1 channel-id="6084" tvg-id="6084" tvg-chno="6084" tvg-logo="https://tmsimg.fancybits.co/assets/s14988_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="14988" tvg-name="FXM",FXM
http://media-server6:8089/devices/ANY/channels/6084/hls/master.m3u8?

#EXTINF:-1 channel-id="6085" tvg-id="6085" tvg-chno="6085" tvg-logo="https://tmsimg.fancybits.co/assets/s92041_ll_h9_aa.png?w=360&h=270" tvc-guide-stationid="92041" tvg-name="SUNDANCE",SUNDANCE
http://media-server6:8089/devices/ANY/channels/6085/hls/master.m3u8?

#EXTINF:-1 channel-id="6086" tvg-id="6086" tvg-chno="6086" tvg-logo="https://tmsimg.fancybits.co/assets/s59337_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="59337" tvg-name="AMC",AMC
http://media-server6:8089/devices/ANY/channels/6086/hls/master.m3u8?

#EXTINF:-1 channel-id="6087" tvg-id="6087" tvg-chno="6087" tvg-logo="https://tmsimg.fancybits.co/assets/s64492_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="64492" tvg-name="BBCA",BBCA
http://media-server6:8089/devices/ANY/channels/6087/hls/master.m3u8?

#EXTINF:-1 channel-id="6088" tvg-id="6088" tvg-chno="6088" tvg-logo="https://tmsimg.fancybits.co/assets/s92008_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="92008" tvg-name="IFC",IFC
http://media-server6:8089/devices/ANY/channels/6088/hls/master.m3u8?

#EXTINF:-1 channel-id="6090" tvg-id="6090" tvg-chno="6090" tvg-logo="https://tmsimg.fancybits.co/assets/s66268_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="66268" tvg-name="HALLMARK",HALLMARK
http://media-server6:8089/devices/ANY/channels/6090/hls/master.m3u8?

#EXTINF:-1 channel-id="6091" tvg-id="6091" tvg-chno="6091" tvg-logo="https://tmsimg.fancybits.co/assets/s46710_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="46710" tvg-name="HALLMARKMM",HALLMARKMM
http://media-server6:8089/devices/ANY/channels/6091/hls/master.m3u8?

#EXTINF:-1 channel-id="11017" tvg-id="11017" tvg-chno="11017" tvg-logo="https://d229kpbsb5jevy.cloudfront.net/frndlytv/400/400/content/common/logos/channel/logos/obdlam.png" tvc-guide-stationid="105723" tvg-name="Hallmark Family",Hallmark Family
http://media-server6:8089/devices/ANY/channels/11017/hls/master.m3u8?

#EXTINF:-1 channel-id="6101" tvg-id="6101" tvg-chno="6101" tvg-logo="https://tmsimg.fancybits.co/assets/s56905_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="56905" tvg-name="DISCOVERY",DISCOVERY
http://media-server6:8089/devices/ANY/channels/6101/hls/master.m3u8?

#EXTINF:-1 channel-id="6104" tvg-id="6104" tvg-chno="6104" tvg-logo="https://tmsimg.fancybits.co/assets/s49788_ll_h15_ab.png?w=360&h=270" tvc-guide-stationid="49788" tvg-name="HGTV",HGTV
http://media-server6:8089/devices/ANY/channels/6104/hls/master.m3u8?

#EXTINF:-1 channel-id="6105" tvg-id="6105" tvg-chno="6105" tvg-logo="https://tmsimg.fancybits.co/assets/s57391_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="57391" tvg-name="TLC",TLC
http://media-server6:8089/devices/ANY/channels/6105/hls/master.m3u8?

#EXTINF:-1 channel-id="6106" tvg-id="6106" tvg-chno="6106" tvg-logo="https://tmsimg.fancybits.co/assets/s59303_h3_aa.png?w=360&h=270" tvc-guide-stationid="59303" tvg-name="TRAVEL",TRAVEL
http://media-server6:8089/devices/ANY/channels/6106/hls/master.m3u8?

#EXTINF:-1 channel-id="6108" tvg-id="6108" tvg-chno="6108" tvg-logo="https://tmsimg.fancybits.co/assets/s67375_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="67375" tvg-name="DIY",DIY
http://media-server6:8089/devices/ANY/channels/6108/hls/master.m3u8?

#EXTINF:-1 channel-id="6111" tvg-id="6111" tvg-chno="6111" tvg-logo="https://tmsimg.fancybits.co/assets/s78808_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="78808" tvg-name="AHC",AHC
http://media-server6:8089/devices/ANY/channels/6111/hls/master.m3u8?

#EXTINF:-1 channel-id="6120" tvg-id="6120" tvg-chno="6120" tvg-logo="https://tmsimg.fancybits.co/assets/s59684_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="59684" tvg-name="DISNEY",DISNEY
http://media-server6:8089/devices/ANY/channels/6120/hls/master.m3u8?

#EXTINF:-1 channel-id="6121" tvg-id="6121" tvg-chno="6121" tvg-logo="https://tmsimg.fancybits.co/assets/s59684_ll_h15_ad.png?w=360&h=270" tvc-guide-stationid="63320" tvg-name="DISNEYP",DISNEYP
http://media-server6:8089/devices/ANY/channels/6121/hls/master.m3u8?

#EXTINF:-1 channel-id="6126" tvg-id="6126" tvg-chno="6126" tvg-logo="https://tmsimg.fancybits.co/assets/s59615_ll_h15_ae.png?w=360&h=270" tvc-guide-stationid="59615" tvg-name="FREEFORM",FREEFORM
http://media-server6:8089/devices/ANY/channels/6126/hls/master.m3u8?

#EXTINF:-1 channel-id="6127" tvg-id="6127" tvg-chno="6127" tvg-logo="https://tmsimg.fancybits.co/assets/s59615_h3_aa.png?w=360&h=270" tvc-guide-stationid="63324" tvg-name="FREEFORMP",FREEFORMP
http://media-server6:8089/devices/ANY/channels/6127/hls/master.m3u8?

#EXTINF:-1 channel-id="6140" tvg-id="6140" tvg-chno="6140" tvg-logo="https://tmsimg.fancybits.co/assets/s32645_h3_aa.png?w=360&h=270" tvc-guide-stationid="32645" tvg-name="ESPN1",ESPN1
http://media-server6:8089/devices/ANY/channels/6140/hls/master.m3u8?

#EXTINF:-1 channel-id="6141" tvg-id="6141" tvg-chno="6141" tvg-logo="https://tmsimg.fancybits.co/assets/s45507_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="45507" tvg-name="ESPN2",ESPN2
http://media-server6:8089/devices/ANY/channels/6141/hls/master.m3u8?

#EXTINF:-1 channel-id="6142" tvg-id="6142" tvg-chno="6142" tvg-logo="https://tmsimg.fancybits.co/assets/s60696_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="60696" tvg-name="ESPNU",ESPNU
http://media-server6:8089/devices/ANY/channels/6142/hls/master.m3u8?

#EXTINF:-1 channel-id="6143" tvg-id="6143" tvg-chno="6143" tvg-logo="https://tmsimg.fancybits.co/assets/s59976_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="59976" tvg-name="ESPNEWS",ESPNEWS
http://media-server6:8089/devices/ANY/channels/6143/hls/master.m3u8?

#EXTINF:-1 channel-id="6144" tvg-id="6144" tvg-chno="6144" tvg-logo="https://tmsimg.fancybits.co/assets/s89714_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="89714" tvg-name="SEC",SEC
http://media-server6:8089/devices/ANY/channels/6144/hls/master.m3u8?

#EXTINF:-1 channel-id="6147" tvg-id="6147" tvg-chno="6147" tvg-logo="https://tmsimg.fancybits.co/assets/s111871_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="111871" tvg-name="ACC",ACC
http://media-server6:8089/devices/ANY/channels/6147/hls/master.m3u8?

#EXTINF:-1 channel-id="9347" tvg-id="9347" tvg-chno="9347" tvg-logo="null" tvc-guide-stationid="45399" tvg-name="NFL Network HD",NFL Network HD
http://media-server6:8089/devices/ANY/channels/9347/hls/master.m3u8?

#EXTINF:-1 channel-id="9712" tvg-id="9712" tvg-chno="9712" tvg-logo="null" tvc-guide-stationid="62081" tvg-name="MLB Network HD",MLB Network HD
http://media-server6:8089/devices/ANY/channels/9712/hls/master.m3u8?

#EXTINF:-1 channel-id="9724" tvg-id="9724" tvg-chno="9724" tvg-logo="null" tvc-guide-stationid="58690" tvg-name="NHL Network HD",NHL Network HD
http://media-server6:8089/devices/ANY/channels/9724/hls/master.m3u8?

#EXTINF:-1 channel-id="9348" tvg-id="9348" tvg-chno="9348" tvg-logo="null" tvc-guide-stationid="45526" tvg-name="NBA TV HD",NBA TV HD
http://media-server6:8089/devices/ANY/channels/9348/hls/master.m3u8?

#EXTINF:-1 channel-id="9345" tvg-id="9345" tvg-chno="9345" tvg-logo="null" tvc-guide-stationid="60316" tvg-name="Tennis Channel HD",Tennis Channel HD
http://media-server6:8089/devices/ANY/channels/9345/hls/master.m3u8?

#EXTINF:-1 channel-id="9725" tvg-id="9725" tvg-chno="9725" tvg-logo="null" tvc-guide-stationid="61854" tvg-name="Golf Channel HD",Golf Channel HD
http://media-server6:8089/devices/ANY/channels/9725/hls/master.m3u8?

#EXTINF:-1 channel-id="6197" tvg-id="6197" tvg-chno="6197" tvg-logo="https://tmsimg.fancybits.co/assets/s82547_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="82547" tvg-name="FS1",FS1
http://media-server6:8089/devices/ANY/channels/6197/hls/master.m3u8?

#EXTINF:-1 channel-id="6198" tvg-id="6198" tvg-chno="6198" tvg-logo="https://tmsimg.fancybits.co/assets/s59305_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="59305" tvg-name="FS2",FS2
http://media-server6:8089/devices/ANY/channels/6198/hls/master.m3u8?

#EXTINF:-1 channel-id="6196" tvg-id="6196" tvg-chno="6196" tvg-logo="https://tmsimg.fancybits.co/assets/s59250_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="59250" tvg-name="CBSSPORTS",CBSSPORTS
http://media-server6:8089/devices/ANY/channels/6196/hls/master.m3u8?

#EXTINF:-1 channel-id="6199" tvg-id="6199" tvg-chno="6199" tvg-logo="https://tmsimg.fancybits.co/assets/s58321_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="58321" tvg-name="BTN",BTN
http://media-server6:8089/devices/ANY/channels/6199/hls/master.m3u8?

#EXTINF:-1 channel-id="9351" tvg-id="9351" tvg-chno="9351" tvg-logo="null" tvc-guide-stationid="19548" tvg-name="HBO HD East",HBO HD East
http://media-server6:8089/devices/ANY/channels/9351/hls/master.m3u8?

#EXTINF:-1 channel-id="9352" tvg-id="9352" tvg-chno="9352" tvg-logo="null" tvc-guide-stationid="59368" tvg-name="HBO2 HD East",HBO2 HD East
http://media-server6:8089/devices/ANY/channels/9352/hls/master.m3u8?

#EXTINF:-1 channel-id="9340" tvg-id="9340" tvg-chno="9340" tvg-logo="null" tvc-guide-stationid="19566" tvg-name="HBO West HD",HBO West HD
http://media-server6:8089/devices/ANY/channels/9340/hls/master.m3u8?

#EXTINF:-1 channel-id="9354" tvg-id="9354" tvg-chno="9354" tvg-logo="null" tvc-guide-stationid="59355" tvg-name="HBO2 West HD",HBO2 West HD
http://media-server6:8089/devices/ANY/channels/9354/hls/master.m3u8?

#EXTINF:-1 channel-id="9353" tvg-id="9353" tvg-chno="9353" tvg-logo="null" tvc-guide-stationid="59363" tvg-name="HBO Signature HD East",HBO Signature HD East
http://media-server6:8089/devices/ANY/channels/9353/hls/master.m3u8?

#EXTINF:-1 channel-id="9355" tvg-id="9355" tvg-chno="9355" tvg-logo="null" tvc-guide-stationid="59839" tvg-name="HBO Comedy HD",HBO Comedy HD
http://media-server6:8089/devices/ANY/channels/9355/hls/master.m3u8?

#EXTINF:-1 channel-id="9356" tvg-id="9356" tvg-chno="9356" tvg-logo="null" tvc-guide-stationid="59357" tvg-name="HBO Family East HD",HBO Family East HD
http://media-server6:8089/devices/ANY/channels/9356/hls/master.m3u8?

#EXTINF:-1 channel-id="9357" tvg-id="9357" tvg-chno="9357" tvg-logo="null" tvc-guide-stationid="59845" tvg-name="HBO Zone HD",HBO Zone HD
http://media-server6:8089/devices/ANY/channels/9357/hls/master.m3u8?

#EXTINF:-1 channel-id="9362" tvg-id="9362" tvg-chno="9362" tvg-logo="http://htpc6:7654/static/logos/reboot.png" tvc-guide-stationid="null" tvg-name="Reboot FireTV",Reboot FireTV
http://media-server6:8089/devices/ANY/channels/9362/hls/master.m3u8?

#EXTINF:-1 channel-id="9363" tvg-id="9363" tvg-chno="9363" tvg-logo="http://htpc6:7654/static/logos/exit.png" tvc-guide-stationid="null" tvg-name="Exit DirecTV",Exit DirecTV
http://media-server6:8089/devices/ANY/channels/9363/hls/master.m3u8?

#EXTINF:-1 channel-id="9790" tvg-id="9790" tvg-chno="9790" tvg-logo="null" tvc-guide-stationid="121815" tvg-name="24/7 Laughs",24/7 Laughs
http://media-server6:8089/devices/ANY/channels/9790/hls/master.m3u8?

#EXTINF:-1 channel-id="9769" tvg-id="9769" tvg-chno="9769" tvg-logo="null" tvc-guide-stationid="59961" tvg-name="5StarMAX East",5StarMAX East
http://media-server6:8089/devices/ANY/channels/9769/hls/master.m3u8?

#EXTINF:-1 channel-id="9770" tvg-id="9770" tvg-chno="9770" tvg-logo="null" tvc-guide-stationid="59948" tvg-name="ActionMAX HD East",ActionMAX HD East
http://media-server6:8089/devices/ANY/channels/9770/hls/master.m3u8?

#EXTINF:-1 channel-id="9771" tvg-id="9771" tvg-chno="9771" tvg-logo="null" tvc-guide-stationid="34933" tvg-name="Cinemax HD East",Cinemax HD East
http://media-server6:8089/devices/ANY/channels/9771/hls/master.m3u8?

#EXTINF:-1 channel-id="9772" tvg-id="9772" tvg-chno="9772" tvg-logo="null" tvc-guide-stationid="35975" tvg-name="Cinemax HD West",Cinemax HD West
http://media-server6:8089/devices/ANY/channels/9772/hls/master.m3u8?

#EXTINF:-1 channel-id="9722" tvg-id="9722" tvg-chno="9722" tvg-logo="null" tvc-guide-stationid="72015" tvg-name="Encore Action HD East",Encore Action HD East
http://media-server6:8089/devices/ANY/channels/9722/hls/master.m3u8?

#EXTINF:-1 channel-id="9721" tvg-id="9721" tvg-chno="9721" tvg-logo="null" tvc-guide-stationid="36225" tvg-name="Encore HD East",Encore HD East
http://media-server6:8089/devices/ANY/channels/9721/hls/master.m3u8?

#EXTINF:-1 channel-id="9773" tvg-id="9773" tvg-chno="9773" tvg-logo="null" tvc-guide-stationid="65669" tvg-name="MGM+",MGM+
http://media-server6:8089/devices/ANY/channels/9773/hls/master.m3u8?

#EXTINF:-1 channel-id="9774" tvg-id="9774" tvg-chno="9774" tvg-logo="null" tvc-guide-stationid="103828" tvg-name="MGM+ DRIVE-IN",MGM+ DRIVE-IN
http://media-server6:8089/devices/ANY/channels/9774/hls/master.m3u8?

#EXTINF:-1 channel-id="9775" tvg-id="9775" tvg-chno="9775" tvg-logo="null" tvc-guide-stationid="67929" tvg-name="MGM+ HITS",MGM+ HITS
http://media-server6:8089/devices/ANY/channels/9775/hls/master.m3u8?

#EXTINF:-1 channel-id="9776" tvg-id="9776" tvg-chno="9776" tvg-logo="null" tvc-guide-stationid="74073" tvg-name="MGM+ MARQUEE",MGM+ MARQUEE
http://media-server6:8089/devices/ANY/channels/9776/hls/master.m3u8?

#EXTINF:-1 channel-id="9777" tvg-id="9777" tvg-chno="9777" tvg-logo="null" tvc-guide-stationid="59373" tvg-name="MoreMAX HD East",MoreMAX HD East
http://media-server6:8089/devices/ANY/channels/9777/hls/master.m3u8?

#EXTINF:-1 channel-id="9778" tvg-id="9778" tvg-chno="9778" tvg-logo="null" tvc-guide-stationid="59963" tvg-name="MovieMAX HD East",MovieMAX HD East
http://media-server6:8089/devices/ANY/channels/9778/hls/master.m3u8?

#EXTINF:-1 channel-id="9779" tvg-id="9779" tvg-chno="9779" tvg-logo="null" tvc-guide-stationid="59952" tvg-name="OuterMAX HD East",OuterMAX HD East
http://media-server6:8089/devices/ANY/channels/9779/hls/master.m3u8?

#EXTINF:-1 channel-id="9720" tvg-id="9720" tvg-chno="9720" tvg-logo="null" tvc-guide-stationid="67236" tvg-name="Starz Cinema HD East",Starz Cinema HD East
http://media-server6:8089/devices/ANY/channels/9720/hls/master.m3u8?

#EXTINF:-1 channel-id="9717" tvg-id="9717" tvg-chno="9717" tvg-logo="null" tvc-guide-stationid="57569" tvg-name="Starz Comedy HD East",Starz Comedy HD East
http://media-server6:8089/devices/ANY/channels/9717/hls/master.m3u8?

#EXTINF:-1 channel-id="9718" tvg-id="9718" tvg-chno="9718" tvg-logo="null" tvc-guide-stationid="57573" tvg-name="Starz Edge HD East",Starz Edge HD East
http://media-server6:8089/devices/ANY/channels/9718/hls/master.m3u8?

#EXTINF:-1 channel-id="9714" tvg-id="9714" tvg-chno="9714" tvg-logo="null" tvc-guide-stationid="34941" tvg-name="Starz HD East",Starz HD East
http://media-server6:8089/devices/ANY/channels/9714/hls/master.m3u8?

#EXTINF:-1 channel-id="9715" tvg-id="9715" tvg-chno="9715" tvg-logo="null" tvc-guide-stationid="34949" tvg-name="Starz HD West",Starz HD West
http://media-server6:8089/devices/ANY/channels/9715/hls/master.m3u8?

#EXTINF:-1 channel-id="9719" tvg-id="9719" tvg-chno="9719" tvg-logo="null" tvc-guide-stationid="67235" tvg-name="Starz inBlack HD East",Starz inBlack HD East
http://media-server6:8089/devices/ANY/channels/9719/hls/master.m3u8?

#EXTINF:-1 channel-id="9716" tvg-id="9716" tvg-chno="9716" tvg-logo="null" tvc-guide-stationid="57581" tvg-name="Starz Kids & Family HD East",Starz Kids & Family HD East
http://media-server6:8089/devices/ANY/channels/9716/hls/master.m3u8?

#EXTINF:-1 channel-id="9780" tvg-id="9780" tvg-chno="9780" tvg-logo="null" tvc-guide-stationid="59954" tvg-name="ThrillerMAX East",ThrillerMAX East
http://media-server6:8089/devices/ANY/channels/9780/hls/master.m3u8?

#EXTINF:-1 channel-id="9788" tvg-id="9788" tvg-chno="9788" tvg-logo="null" tvc-guide-stationid="21868" tvg-name="Showtime",Showtime
http://media-server6:8089/devices/ANY/channels/9788/hls/master.m3u8?

#EXTINF:-1 channel-id="9789" tvg-id="9789" tvg-chno="9789" tvg-logo="null" tvc-guide-stationid="22532" tvg-name="Showtime West",Showtime West
http://media-server6:8089/devices/ANY/channels/9789/hls/master.m3u8?

#EXTINF:-1 channel-id="13206" tvg-id="13206" tvg-chno="13206" tvg-logo="https://images.pluto.tv/channels/5421f71da6af422839419cb3/colorLogoPNG.png" tvc-guide-stationid="5421f71da6af422839419cb3" tvg-name="CNN HEADLINES",CNN HEADLINES
http://media-server6:8089/devices/ANY/channels/13206/hls/master.m3u8?

But it was only listed once (at the very end of the file).

Maybe you could give me some specific data on where you're seeing this behavior, as so far, I haven't been able to duplicate what you're describing?

Might be an issue if the channel-id used in the source is not unique between sources.
A Channel Collection just contains the channel-id's. No source devices or channel numbers.

Sure, going back to my VH1 example, I have a couple of TVE sources Philo and Hulu. When I run the find sources for single channels I get:

Matched - Station ID: VH1
Channel name: VH1
Number of sources: 2
Free channels: -
HDFX-4K: -
Hulu Live: 6014
Philo: 6014
Frndly: -
PlutoTV: -
PlutoTV UK: -
PlutoTV Canada: -
Samsung: -
Channel Feed: -
ADB Tuner: -
Tubi: -
Plex: -
EPlusTV: -
Virtual Channels: -

The using the following settings:

The M3U results in:

#EXTM3U

#EXTINF:-1 channel-id="8000" tvg-id="8000" tvg-chno="8000" tvg-logo="https://tmsimg.fancybits.co/assets/s51529_h3_ba.png?w=360&h=270" tvc-guide-stationid="51529" tvg-name="A&E",A&E
http://192.168.50.103:8089/devices/ANY/channels/8000/hls/master.m3u8?

#EXTINF:-1 channel-id="6767" tvg-id="6767" tvg-chno="6767" tvg-logo="https://tmsimg.fancybits.co/assets/s113380_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="113380" tvg-name="ABCNEWS",ABCNEWS
http://192.168.50.103:8089/devices/ANY/channels/6767/hls/master.m3u8?
#EXTINF:-1 channel-id="6767" tvg-id="6767" tvg-chno="6767" tvg-logo="https://tmsimg.fancybits.co/assets/s113380_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="113380" tvg-name="ABCNEWS",ABCNEWS
http://192.168.50.103:8089/devices/ANY/channels/6767/hls/master.m3u8?

#EXTINF:-1 channel-id="8006" tvg-id="8006" tvg-chno="8006" tvg-logo="https://tmsimg.fancybits.co/assets/s66143_ll_h15_ac.png?w=360&h=270" tvc-guide-stationid="66143" tvg-name="UPtv",UPtv
http://192.168.50.103:8089/devices/ANY/channels/8006/hls/master.m3u8?

#EXTINF:-1 channel-id="6014" tvg-id="6014" tvg-chno="6014" tvg-logo="https://tmsimg.fancybits.co/assets/s60046_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="60046" tvg-name="VH1",VH1
http://192.168.50.103:8089/devices/ANY/channels/6014/hls/master.m3u8?
#EXTINF:-1 channel-id="6014" tvg-id="6014" tvg-chno="6014" tvg-logo="https://tmsimg.fancybits.co/assets/s60046_ll_h15_aa.png?w=360&h=270" tvc-guide-stationid="60046" tvg-name="VH1",VH1
http://192.168.50.103:8089/devices/ANY/channels/6014/hls/master.m3u8?

#EXTINF:-1 channel-id="6015" tvg-id="6015" tvg-chno="6015" tvg-logo="https://tmsimg.fancybits.co/assets/s60046_h3_aa.png?w=360&h=270" tvc-guide-stationid="64634" tvg-name="VH1P",VH1P
http://192.168.50.103:8089/devices/ANY/channels/6015/hls/master.m3u8?
#EXTINF:-1 channel-id="6015" tvg-id="6015" tvg-chno="6015" tvg-logo="https://tmsimg.fancybits.co/assets/s60046_h3_aa.png?w=360&h=270" tvc-guide-stationid="64634" tvg-name="VH1P",VH1P
http://192.168.50.103:8089/devices/ANY/channels/6015/hls/master.m3u8?

I think it might be related to the two sources sharing the same channel number.

Yeah an since it is a TVE source I can't control the channel id.

That is definitely why you see dups.
Would be the same if you had multiple HDHR tuners getting overlapping lineup channels.

But if it is just a list of channel ids in the collection, should be able to get a unique list right? Would there ever be a situation where you would want two different channels tied up to the same channel number?

@bnhf I think I see the spot in Olivetin that could be updated. Potentially a checkbox to remove duplicate channel ids before generating the m3u file?

It shouldn't be difficult to scan the M3U and remove duplicates -- and I guess we'd just keep the first one found and discard the rest?

That'd be my preference. Probably just a sort -u on the id collection before generating the m3u?

In the outputCollectionM3U() function, try replacing this line:

[[ -n $collectionChannelM3U ]] && echo -e "$collectionChannelM3U\n" >> $m3uFile

With this line -- and see if it does the job for you:

[[ -n $collectionChannelM3U ]] && echo -e "$collectionChannelM3U\n" | awk '!seen[$0]++' | tr -s '\n' | sed 's/#EXTINF/\n#EXTINF/g' >> $m3uFile

If that works, I'll add it to the next build.