Prime2qam

From MythTV Official Wiki
Jump to: navigation, search

Purpose

This script greatly simplifies the configuration of a HDHR configured for QAM, assuming you also have a HDHR Prime configured for CC connected to the same provider.

This is an alternative to the PrimeUpdateScript, which requires that you have already configured your QAM channels and only want to keep them up to date. This script only requires that you have completed a channel scan on the QAM tuner and added all available channels. You may need to manually remove any channels that this script cannot match to your Prime tuner.

How it works

It simply tunes each available virtual channel # on the prime, then compares the actual channel/multiplex to the channels table to see if any corresponding QAM channels exist. If one does, it will update the channel number, xmltvid, icon, name, and callsign so that the channels appear identical (will only show up once in the guide or when browsing).

Caveats

Currently the script only supports US-Cable frequency table, however adding support for additional tables, or changing the table should not be too difficult if you know python.

Please direct any questions about this script to the mythtv-users mailing list.


PythonIcon.png prime2qam.py

#!/usr/bin/env python
#---------------------------
# Name: prime2qam.py
# Python Script
# Author: Joe Fry
# Purpose:
#   This Python script provides a method to update HDHR QAM channels
#   to match their HDHR Prime counterparts.
#
# How it works:
#   The script tunes each vchannel specified in the channel table for
#   your HDHR Prime.  It then retrieves the frequency (converting it
#   to a channel number) and the program (multiplex), finally it
#   updates any matching QAM channels to reflect the same channel
#   number, icon, xmltvid, and callsign.
#
# Requirements:
#   To function, this script requires that all desired QAM channels
#   have already been added to the channel table by scanning with
#   mythtv-setup.
#
# Limitations:
#   This script currently only supports the US-Cable frequency table.
#
# Use:
#   Update the global variables below and run as any user.
#
#---------------------------

### ---- Update these settings prior to running ---- ###

PRIME = "1234A123"        # Address of the HDHR Prime
PRIME_TUNER = "0"         # Which tuner to use to tune each channel
HDHR = "1234B123"         # Address of your HDHR using QAM
HDHR_TUNER = "0"          # HDHR tuner on same source as Prime
DBHOST = "localhost"      # Address of mythtv database
DBUSER = "mythtv"           # Mysql username
DBPASS = "password"       # Mysql pasword
DBTABLE = "mythconverg"   # Mysql database (mythconverg)
TUNETIME = 1.5            # Time (seconds) to wait after tuning the channel
                          #    before reading the freq/program, lower will
                          #    complete faster, but may miss channels
#PREVIEW = 1              # Uncomment to preview and prevent changes to the DB

### ---- no changes required below this line ---- ####

from subprocess import call, check_output
import MySQLdb as db
import sys
import time

def main():

  # get the source id for the Prime
  prime_sourceid = query(
         "SELECT sourceid FROM cardinput "
         "LEFT JOIN capturecard ON cardinput.cardid=capturecard.cardid "
         "WHERE videodevice='" + PRIME + "-" + PRIME_TUNER + "'"
         )[0][0]

  # get the source id for the HDHR
  hdhr_sourceid = query(
         "SELECT sourceid FROM cardinput "
         "LEFT JOIN capturecard ON cardinput.cardid=capturecard.cardid "
         "WHERE videodevice='" + HDHR + "-" + HDHR_TUNER + "'"
         )[0][0]

  # retrieve the list of defined channels for the prime sourceid
  prime_channels = query("SELECT channum FROM channel "
                         "WHERE sourceid = '" + str(prime_sourceid) + "'")

  # loop through each channel
  for channel in prime_channels:

    # retrieve the channel info
    chaninfo = get_chan_info(channel[0])

    # check the HDHR channels for matching freqid and serviceid
    match_found = query(
         "SELECT chanid FROM channel "
         "WHERE sourceid = " + str(hdhr_sourceid) + " "
         "AND freqid = " + str(chaninfo['freqid']) + " "
         "AND serviceid = " + str(chaninfo['serviceid']))

    # if a channel match is found
    if len(match_found):
      print ('\n*** Channel ' + channel[0] +
             ' matched chanid: ' + str(match_found[0][0]) + " ***")
      print "  Updating HDHR channel info..."

      # if preview mode enabled
      if 'PREVIEW' in globals():
        print ("\n    UPDATE channel SET \n"
               "       channum='%s', callsign='%s', xmltvid='%s' \n"
               "       name='%s', \n"
               "       icon='%s' \n"
               "    WHERE chanid=%s \n"
              ) % (chaninfo['channum'], chaninfo['callsign'],
                     chaninfo['xmltvid'], chaninfo['name'], chaninfo['icon'],
                     str(match_found[0][0]))

      # otherwise update the channel to match the Prime
      else:
        result = query("UPDATE channel SET "
                       "channum='" +chaninfo['channum']+ "', "
                       "callsign='" +chaninfo['callsign']+ "', "
                       "xmltvid='" +chaninfo['xmltvid']+ "', "
                       "name='" +chaninfo['name']+ "', "
                       "icon='" +chaninfo['icon']+ "' "
                       "WHERE chanid=" +str(match_found[0][0]))

    # if no matching channel found
    else:
      print 'Channel ' + channel[0] + ' had no match'


#
# Returns the US Cable channel number for a given frequency in MHz
#
def chan_from_freq(F):
  if F == 75:             #Channel 1
    return 1
  elif 57 <= F <= 69:     #Channel 2-4
    return (F - 67)/6+2
  elif 79 <= F <= 81:     #Channel 5
    return 5
  elif 85 <= F <= 87:     #Channel 6
    return 6
  elif 177 <= F <= 213:   #Channel 7-13
    return (F-177)/6+7
  elif 123 <= F <= 171:   #Channel 14-22
    return (F-123)/6+14
  elif 219 <= F <= 645:   #Channel 23-94
    return (F-219)/6+23
  elif 93 <= F <= 117:    #Channel 95-99
    return (F-93)/6+95
  elif 651 <= F <= 999:   #Channel 100-158
    return (F-651)/6+100
  else:
    return 0

#
# Query the database and return all results
#
def query(q):
  con = None

  try:
    con = db.connect(DBHOST, DBUSER, DBPASS, DBTABLE);
    cur = con.cursor()
    cur.execute(q)
    return cur.fetchall()

  except db.Error, e:
    print "Error %d: %s" % (e.args[0],e.args[1])
    sys.exit(1)

  finally:
    if con:
      con.close()

#
# Returns the channel info for a given HDHR Prime virtual channel
#
def get_chan_info(vchan):

  #Tune the virtual channel
  cmd = ('hdhomerun_config ' + PRIME +
         ' set /tuner' + PRIME_TUNER + '/vchannel ' + vchan)
  call(cmd, shell=True)
  time.sleep(TUNETIME)

  #Get the frequency for the currently tuned channel
  cmd = ('hdhomerun_config ' + PRIME +
         ' get /tuner' + PRIME_TUNER + '/channel')
  freq = check_output(cmd, shell=True)

  #Get the program (multiplex) for the currently tuned channel
  cmd = ('hdhomerun_config ' + PRIME +
         ' get /tuner' + PRIME_TUNER + '/program')
  program = int(check_output(cmd, shell=True))

  #Reformat the frequency
  freq = freq.replace('qam:', '')
  freq = int(freq) / 1000000

  #Convert the frequency to a physical channel
  channel = chan_from_freq(freq)

  #Retrieve the callsign and xmltvid
  result = query("select callsign, xmltvid, name, icon, channum "
                 "from channel where channum = '" + vchan + "'")
  callsign = result[0][0]
  xmltvid = result[0][1]
  name = result[0][2]
  icon = result[0][3]
  channum = result[0][4]

  #Create a dictionary and return it
  dict = {'freqid': channel, 'serviceid': program, 'callsign': callsign,
          'xmltvid': xmltvid, 'name': name, 'icon': icon, 'channum': channum}
  return dict


# Run the main function
main()
print "\n Complete!"