Script - fix UK DVB-T channels

From MythTV Official Wiki
Revision as of 08:43, 6 October 2009 by FNX (talk | contribs) (Full scan might break recording rules)

Jump to: navigation, search

This script is something I cobbled together to deal with the most recent (at time of writing) major change in the UK DVB-T line-up.

Your best bet whenever the DVB lineup changes is to let Myth do a re-scan, but this isn't a decent option for me as I have normalised the names of most of the channels (to, e.g., match the names I've set up on Sky, and remove all-caps names, etc.) so that they do not match the broadcast names, and Myth doesn't have nay way to match the channel scan with what I already have.

Plus, I have also set up a number of the channels with xmltvids (so as to fetch listings from the Radio Times instead of using EIT), and I don't want to lose these. Lastly, I've manually deleted a ream of channels I'm not interested in, and don't want to have to bother again. It's also possible that a full rescan will affect chanids of channels I'm interested in, and that could break recording rules.

I readily admit that most of the above may no longer be, or may never have been, actual issues! I just feel safer fixing one or two channels at a time remotely instead of digging out my keyboard, bringing down Myth, and doing a full scan.

You will need to bring Myth down (well, I do, you may not need to) and run scandvb to get a fresh channels listing. I use, for example:

scandvb ~/etc/dvb-t-uk-BluebellHill > /tmp/channels.conf

Then you need to feed this into the following perl script as its only argument. You need to edit this script to give it your PVR's hostname, and SQL username/password. This script will not update your database, it is safe to run to just see “what's what”. It outputs the necessary SQL commands to fix (hopefully) existing channels to new multiplexes. You can feed that output to mysql or cut'n'paste the individual lines manually.

Essentially, it runs through your existing channels, then for each Myth channel, tries to locate that channel in the new channels.conf file. It does this by either the xmltvid (by using the map at the bottom) or the channel (full) name. Also in the map are some alternate names (e.g., for names that are abbreviated when broadcast but you wish to have full length). It only accepts channels on frequencies for which you have Myth settings defined (in the dtv_multiplexes table), and only then only channels that appear to be DVB.

You can pass -D as the first argument to get some extra debug (SQL-comment-safe). If you need to make it work with only one specific input source, you will need to set this in your script. Note that I have not tested this aspect of the script!

This script was coded to work on 0.21-fixes, with a MythTV setup containing a Hauppauge PVR-350 (for Sky video input only, not analogue TV) and a Nova-T with one digital tuner (the DVB-T input). I successfully used it to fix the recent (October 2009) retune, and also identify channels that I have setup that no longer exist.

Please add any xmltvid mappings (my region is South East and so I only have those) and any other alternate names that can be used to match broadcast channel names).

#!/usr/bin/perl -w
# Usage: fixdvb channels.conf
#   Compares given tzap channels.conf output with current mythtv DVB
#   channel settings and outputs necessary SQL to fix existing channels.
#   This will NOT update any database by itself!

use strict;
use DBI;

# Give d/b acces here
my $dbhost = 'pvr';
my $dbuser = 'mythtv';
my $dbpass = 'mythtv';

# If you wish to only affect a specific sourceid, set it here, otherwise make it -1.
my $sourceid = -1;

# The DVB-xmltvid mapping set up routine
my %dvbchannels;
sub setup_dvb_xmltvid();
setup_dvb_xmltvid();

# -D for debug
my $debug = 0;
if (defined($ARGV[0]) and $ARGV[0] eq '-D')
{
    $debug = 1;
    shift(@ARGV);
}


# Command to fetch channels with serviceid (assumed to be DVB
my $getchannels = 'SELECT chanid,channum,name,xmltvid,channel.mplexid,frequency,serviceid,channel.sourceid FROM channel LEFT JOIN dtv_multiplex ON channel.mplexid=dtv_multiplex.mplexid WHERE serviceid IS NOT NULL;';

# Command to get DTV settings
my $getdtv = 'SELECT mplexid,frequency FROM dtv_multiplex WHERE transportid is not NULL;';

if ($sourceid >= 0)
{
    $getchannels =~ s/;$/ and channel.sourceid = $sourceid;/;
    $getdtv =~ s/;$/ and sourceid = $sourceid;/;
}


# Access SQL
my $dsn = "DBI:mysql:mythconverg:$dbhost";
my %dbattr = ( PrintError => 1, RaiseError => 0 );
my $dbh;

$dbh = DBI->connect($dsn, $dbuser, $dbpass, \%dbattr);
$dbh->{RaiseError} = 1  if defined($dbh);


# Get the current Myth DTV settings (look up mplexid by frequency)
print "\n-- Reading DTV multiplexes\n"
    if $debug;
my %dtv;
eval
{
    my $query = $dbh->prepare( $getdtv );
    $query->execute();
    while (my $hashref = $query->fetchrow_hashref())
    {
        print "-- Got $hashref->{frequency} for mplexid $hashref->{mplexid}\n"
            if $debug;
        $dtv{$hashref->{frequency}} = $hashref->{mplexid};
    }
};


# Read the channels.conf file
print "\n-- Reading channels.conf file\n"
    if $debug;
my %channels;
die "No channels.conf file specified\n"  unless defined($ARGV[0]);
open (CHANNELS, "<$ARGV[0]")  or die "Failed to open channels.conf file '$ARGV[0]'\n";
my $line;
while (defined($line = <CHANNELS>))
{
    chomp($line);
    my @parts = split(':',$line);
    my $name = lc($parts[0]);
    my $chaninfo = { name => $name, frequency => $parts[1], serviceid => $parts[12] };
    # Only if the frequency is one we know
    if (defined($dtv{$parts[1]}))
    {
        print "-- Useful channel '$parts[0]' found on freq/serv = $parts[1]/$parts[12]\n"
            if $debug;
        $channels{$name} = $chaninfo;
    }
    else
    {
        print "-- Channel '$parts[0]' found on unrecognised frequency $parts[1]\n"
            if $debug;
    }
}
close (CHANNELS);


# Get the current Myth channel settings, and process them
print "\n-- Processing channels\n"
    if $debug;
my %myth;
#eval
#{
    my $query = $dbh->prepare( $getchannels );
    $query->execute();
    while (my $hashref = $query->fetchrow_hashref())
    {
        # Find the broadcast channel entry
        my $chanentry;
        my $lcname = lc($hashref->{name});
        my $chan_name = $dvbchannels{$lcname};
        my $xmltv = $hashref->{xmltvid};
        my $chan_xml;
        $chan_xml = $dvbchannels{$xmltv}  if defined($xmltv);
        if (defined($channels{$lcname}))  # match by name?
        {
            $chanentry = $channels{$lcname};
        }
        elsif (defined($chan_xml) and defined($channels{$chan_xml}))  # by xmltvid?
        {
            $chanentry = $channels{$chan_xml};
        }
        elsif (defined($chan_name) and defined($channels{$chan_name}))   # by alt-name?
        {
            $chanentry = $channels{$chan_name};
        }
        if (!defined($chanentry))
        {
            print "-- +++ ERROR failed to find channel '$hashref->{name}' (channum $hashref->{channum})\n";
            next;
        }

        # Check it
        if ($hashref->{frequency} != $$chanentry{frequency}  or
            $hashref->{serviceid} != $$chanentry{serviceid})
        {
            # Needs fixing

            # Find the mplex it should be on
            my $mplex = $dtv{$$chanentry{frequency}};
            if (!defined($mplex))
            {
                print "-- +++ ERROR failed to find multiplex for $hashref->{name} (channum $hashref->{channum})";
                print " freq $$chanentry{frequency}\n";
                next;
            }
            print "-- $hashref->{name} ($hashref->{channum})\n";
            print "UPDATE channel SET mplexid=$mplex,serviceid=$$chanentry{serviceid} WHERE chanid=$hashref->{chanid};\n";
        }
        else
        {
            print "-- Channel $hashref->{name} is OK\n"
                if $debug;
        }
    }
#};

exit(0);



# Set up map of xmltvid to broadcast channel name
sub setup_dvb_xmltvid()
{
    %dvbchannels = (
    # xmltvid -> broadcast name
        'filmfour.channel4.com'                  => 'film4',
        'sky-news.sky.com'                       => 'sky news',
        'sky-three.sky.com'                      => 'sky three',
        'yesterday.uktv.co.uk'                   => 'yesterday',
        'tsod.plus-1.e4.channel4.com'            => 'e4+1',
        'parliament.bbc.co.uk'                   => 'bbc parliament',
        'bbcfour.bbc.co.uk'                      => 'bbc four',
        'cbeebies.bbc.co.uk'                     => 'cbeebies',
        'radio-5.bbc.co.uk'                      => 'bbc r5l',
        'bbc_radio5_live_sports_extra'           => 'bbc r5sx',
        'bbc_6music'                             => 'bbc 6 music',
        'bbc7.bbc.co.uk'                         => 'bbc radio 7',
        'bbc_radio1_xtra'                        => 'bbc 1xtra',
        'freeview.communitychannel.org'          => 'community',
        'south-east.bbc1.bbc.co.uk'              => 'bbc one',
        'south-east.bbc2.bbc.co.uk'              => 'bbc two',
        'bbcthree.bbc.co.uk'                     => 'bbc three',
        'news.bbc.co.uk'                         => 'bbc news',
        'cbbc.bbc.co.uk'                         => 'cbbc channel',
        '1.virginmedia.com'                      => 'virgin1',
        'dave.uktv.co.uk'                        => 'dave',
        'radio-4.bbc.co.uk'                      => 'bbc radio 4',
        'radio-3.bbc.co.uk'                      => 'bbc radio 3',
        'radio-2.bbc.co.uk'                      => 'bbc radio 2',
        'radio-1.bbc.co.uk'                      => 'bbc radio 1',
        'channel5.co.uk'                         => 'five',
        'fiveusa.channel5.co.uk'                 => 'five usa',
        'e4.channel4.com'                        => 'e4',
        'more4.channel4.com'                     => 'more 4',
        'channel4.com'                           => 'channel 4',
        'citv.itv.co.uk'                         => 'citv',
        'itv4.itv.co.uk'                         => 'itv4',
        'itv2.itv.co.uk'                         => 'itv2',
        'itv3.itv.co.uk'                         => 'itv3',
        'meridian.itv1.itv.co.uk'                => 'itv1',
        'tsod.plus-1.channel4.com'               => 'channel 4+1',
        'tsod.plus-1.itv2.itv.co.uk'             => 'itv2+1',
        'fiver.channel5.co.uk'                   => 'fiver',
        'tsod.plus-1.freeview.1.virginmedia.com' => 'virgin1+1',

    # Use alternate name
        'sky sports news'   => 'sky spts news',
        'smile tv'          => 'smiletv',
        'bbc asian network' => 'bbc asian net.',
        'bbc world service' => 'bbc world sv.',
        'smooth fm'         => 'smooth radio',
        'the music factory' => 'tmf'
    );
}