I recently did this. In my case, EPlusTV creates virtual channels for sporting events. But many channels will be empty if there aren't many overlapping events.
For scripting, I chose Python because it could make the API calls with its "requests" module, as well as easily manipulate the data returned from those API calls.
First, assign a certain tag in TVHeadend to all of the channels you want to check, if they don't have one already (I used an internal tag named "EPlusTV").
Next, fill in your TVHeadend connection information in the code below, save it to a file like "disable-inactive-channels.py", and run the script like python3 disable-inactive-channels.py "EPlusTV" disable
I actually first run this script without the word "disable" at the end (so python3 disable-inactive-channels.py "EPlusTV"
) before running my TVHeadend XML guide import command. This just enables all of the channels to avoid any potential errors with importing guide data to disabled channels. Then I run this script again, with "disable" at the end of the command, to disable those channels that don't have any events in the new EPG.
Finally, schedule that Python command to run daily using cron.
import sys
import requests
import json
# your TVHeadend connection information
tvh_user="user" # optional
tvh_pass="pass" # optional
server_prefix="http://" # REQUIRED
server_ip="localhost" # REQUIRED
server_port="9981" # REQUIRED
http_root="/tvheadend" # optional
# TVHeadend API base URL creation
api_url_base = server_prefix
if tvh_user != "":
api_url_base += tvh_user
if tvh_user != "":
api_url_base += ":" + tvh_pass
api_url_base += "@"
api_url_base += server_ip + ":" + server_port + http_root + "/api/"
# get the required tag (case-sensitive) passed to this script
try:
tag_name = sys.argv[1]
except:
print("no tag specified")
sys.exit(1)
# find the UUID for that tag
tag_uuid = ""
r = requests.get(api_url_base + "channeltag/list?all=1")
for entry in r.json()['entries']:
if entry['val'] == tag_name:
tag_uuid = entry['key']
if tag_uuid == "":
print("specified tag not found")
sys.exit(1)
# get all channels with that tag
tagged_channels = []
r = requests.get(api_url_base + "channel/grid?all=1&limit=10000")
for entry in r.json()['entries']:
if tag_uuid in entry['tags']:
tagged_channels.append(entry['uuid'])
# enable all channels with that tag (before looking for EPG events, or before updating EPG)
headers = {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'}
data = 'node={"enabled": true, "uuid": ' + json.dumps(tagged_channels) + '}'
requests.post(api_url_base + "idnode/save", data=data, headers=headers)
# if second "disable" parameter was passed to this script, proceed with disabling inactive channels
try:
if sys.argv[2] == 'disable':
# get only active channels with that tag (those channels that have upcoming EPG events)
active_tagged_channels = []
data = {"dir": "ASC", "sort": "start", "start": "0", "limit": "100000", "channelTag": tag_uuid}
r = requests.post(api_url_base + "epg/events/grid", data=data)
for entry in r.json()['entries']:
if entry['title'] != 'Off Air' and entry['channelUuid'] not in active_tagged_channels:
active_tagged_channels.append(entry['channelUuid'])
# disable all channels with that tag
data = 'node={"enabled": false, "uuid": ' + json.dumps(tagged_channels) + '}'
requests.post(api_url_base + "idnode/save", data=data, headers=headers)
# re-enable only active channels with that tag
data = 'node={"enabled": true, "uuid": ' + json.dumps(active_tagged_channels) + '}'
requests.post(api_url_base + "idnode/save", data=data, headers=headers)
except:
pass