Services API with PERL

From MythTV Official Wiki
Jump to: navigation, search


Author Chris Porter
Description Interfacing with the Services API interface of MythTV via SOAP from a Perl script.
Supports Version25.png  Version251.png Version252.png Version26.png Version27.png Version28.png Version29.png 


Introduction

This page describes the new Perl module created to access the Myth Services API. The module itself has been tested on version 0.27.6 of MythTV. During development I looked for the best way to make the module work with all past and hopefully future versions of the Services API. Thus the module has been developed using SOAP and WSDL and is usable on all versions of MythTV which support the Services API.

The design goal of the module was to make Service API calls as if they are methods directly defined within the module. Parameters to these methods are passed just as with any other method call in Perl. All data returned by the module is done with normal Perl data structures.

Features

Most of the features of this module are due in part to the use of SOAP and WSDL (Web Service Description Language)

  1. Easily extensible to support new Service Classes
  2. Service Class methods are treated as native methods
  3. Automatically supports new methods in existing Service Classes
  4. Parameters passed to function as Key-Value pairs
  5. Data is returned as native Perl Data types (thanks to the use of WSDL)
  6. If Myth Version is newer than defined supported version it will support all the Services classes for the highest supported version

Module Documentation

Warning.png Warning: All DateTime formats in the services API are in UTC. Regardless of the timezone of your frontend or backend, the dates produced by the APIs will be UTC. Likewise, all inputs to the API must be in UTC.


Application-x-perl.png test.pl

#!/usr/bin/perl

use MythAPI;
use Data::Dumper;

my $mythAPI = MythAPI->new(server=>'Myth Backend');
my $data = $mythAPI->GetUpcomingList(Count=>2);
print Dumper($data);
$VAR1 = {
          'Count' => '5',
          'Programs' => {
                        'Program' => [
                                     {
                                       'Recording' => {
                                                      'RecGroup' => 'Chris',
                                                      'EndTs' => '2017-04-29T04:00:00Z',
                                                      'Status' => '-1',
                                                      'EncoderId' => '9',
                                                      'RecordId' => '705',
                                                      'DupInType' => '31',
                                                      'PlayGroup' => 'Default',
                                                      'RecType' => '4',
                                                      'Priority' => '0',
                                                      'DupMethod' => '6',
                                                      'StartTs' => '2017-04-29T03:00:00Z',
                                                      'Profile' => 'Default',
                                                      'StorageGroup' => 'Default'
                                                    },
                                       'FileSize' => '0',
                                       'SubTitle' => 'NASA\'s Secret Agenda',
                                       'CatType' => '',
                                       'Artwork' => {
                                                    'ArtworkInfos' => ''
                                                  },
                                       'AudioProps' => '1',
                                       'Inetref' => '',
                                       'FileName' => '',
                                       'SeriesId' => 'EP02633295',
                                       'Stars' => '0',
                                       'Repeat' => 'false',
                                       'Episode' => '0',
                                       'HostName' => 'badboy',
                                       'StartTime' => '2017-04-29T03:00:00Z',
                                       'ProgramId' => 'EP026332950001',
                                       'Channel' => {
                                                    'XMLTVID' => '',
                                                    'NetworkId' => '0',
                                                    'UseEIT' => 'false',
                                                    'ChannelName' => 'History HD (Pacific)',
                                                    'Visible' => 'true',
                                                    'CallSign' => 'HSTRYHP',
                                                    'SourceId' => '1',
                                                    'IconURL' => '',
                                                    'Modulation' => '',
                                                    'FrequencyId' => '',
                                                    'InputId' => '6',
                                                    'FrequencyTable' => '',
                                                    'DefaultAuth' => '',
                                                    'ChanId' => '2055',
                                                    'ChanFilters' => '',
                                                    'FineTune' => '0',
                                                    'ATSCMajorChan' => '0',
                                                    'MplexId' => '0',
                                                    'ATSCMinorChan' => '0',
                                                    'TransportId' => '0',
                                                    'Programs' => '',
                                                    'ChanNum' => '1055',
                                                    'SIStandard' => '',
                                                    'CommFree' => '0',
                                                    'Format' => '',
                                                    'ServiceId' => '0',
                                                    'Frequency' => '0'
                                                  },
                                       'Airdate' => '2017-04-28',
                                       'LastModified' => '2017-04-29T02:04:01Z',
                                       'Category' => 'Documentary',
                                       'Season' => '0',
                                       'Description' => 'Theorists speculate that aerospace engineer Wernher von Braun\'s knowledge of rocketry may have come from his access to advanced technology recovered from the alleged UFO crash in Roswell, N.M.',
                                       'ProgramFlags' => '0',
                                       'VideoProps' => '33',
                                       'SubProps' => '0',
                                       'Title' => 'Ancient Aliens: Declassified',
                                       'EndTime' => '2017-04-29T04:00:00Z'
                                     },
                                     {
                                       'HostName' => 'badboy',
                                       'StartTime' => '2017-04-29T04:00:00Z',
                                       'ProgramId' => 'EP012427480154',
                                       'Channel' => {
                                                    'ChanId' => '2055',
                                                    'ChanFilters' => '',
                                                    'FineTune' => '0',
                                                    'ATSCMajorChan' => '0',
                                                    'ATSCMinorChan' => '0',
                                                    'MplexId' => '0',
                                                    'Programs' => '',
                                                    'TransportId' => '0',
                                                    'ChanNum' => '1055',
                                                    'SIStandard' => '',
                                                    'CommFree' => '0',
                                                    'Format' => '',
                                                    'ServiceId' => '0',
                                                    'Frequency' => '0',
                                                    'XMLTVID' => '',
                                                    'NetworkId' => '0',
                                                    'UseEIT' => 'false',
                                                    'ChannelName' => 'History HD (Pacific)',
                                                    'Visible' => 'true',
                                                    'CallSign' => 'HSTRYHP',
                                                    'SourceId' => '1',
                                                    'IconURL' => '',
                                                    'Modulation' => '',
                                                    'InputId' => '5',
                                                    'FrequencyId' => '',
                                                    'DefaultAuth' => '',
                                                    'FrequencyTable' => ''
                                                  },
                                       'Airdate' => '2017-04-28',
                                       'LastModified' => '2017-04-29T02:04:01Z',
                                       'Category' => 'Documentary',
                                       'Season' => '0',
                                       'Description' => 'Starting in 1947, a series of unexplained events and sightings prompts U.S. government officials to become alien hunters; theorists offer evidence that similar endeavors were made thousands of years ago.',
                                       'ProgramFlags' => '0',
                                       'SubProps' => '0',
                                       'VideoProps' => '33',
                                       'EndTime' => '2017-04-29T05:03:00Z',
                                       'Title' => 'Ancient Aliens',
                                       'Recording' => {
                                                      'RecGroup' => 'Chris',
                                                      'EndTs' => '2017-04-29T05:03:00Z',
                                                      'Status' => '-1',
                                                      'EncoderId' => '7',
                                                      'RecordId' => '312',
                                                      'DupInType' => '15',
                                                      'PlayGroup' => 'Default',
                                                      'RecType' => '4',
                                                      'Priority' => '0',
                                                      'DupMethod' => '6',
                                                      'StartTs' => '2017-04-29T04:00:00Z',
                                                      'Profile' => 'Default',
                                                      'StorageGroup' => 'Default'
                                                    },
                                       'FileSize' => '0',
                                       'SubTitle' => 'The Alien Hunters',
                                       'CatType' => '',
                                       'AudioProps' => '1',
                                       'Artwork' => {
                                                    'ArtworkInfos' => {
                                                                      'ArtworkInfo' => [
                                                                                       {
                                                                                         'URL' => '/Content/GetImageFile?StorageGroup=Coverart&FileName=/Ancient Aliens Season 7_coverart.jpg',
                                                                                         'Type' => 'coverart',
                                                                                         'StorageGroup' => 'Coverart',
                                                                                         'FileName' => 'myth://Coverart@badboy/Ancient Aliens Season 7_coverart.jpg'
                                                                                       },
                                                                                       {
                                                                                         'URL' => '/Content/GetImageFile?StorageGroup=Fanart&FileName=/Ancient Aliens Season 7_fanart.jpg',
                                                                                         'Type' => 'fanart',
                                                                                         'StorageGroup' => 'Fanart',
                                                                                         'FileName' => 'myth://Fanart@badboy/Ancient Aliens Season 7_fanart.jpg'
                                                                                       },
                                                                                       {
                                                                                         'Type' => 'banner',
                                                                                         'URL' => '/Content/GetImageFile?StorageGroup=Banners&FileName=/Ancient Aliens Season 7_banner.jpg',
                                                                                         'FileName' => 'myth://Banners@badboy/Ancient Aliens Season 7_banner.jpg',
                                                                                         'StorageGroup' => 'Banners'
                                                                                       }
                                                                                     ]
                                                                    }
                                                  },
                                       'FileName' => '',
                                       'Inetref' => '101501',
                                       'SeriesId' => 'EP01242748',
                                       'Stars' => '0',
                                       'Repeat' => 'false',
                                       'Episode' => '0'
                                     },
                                     {
                                       'LastModified' => '2017-04-29T02:04:01Z',
                                       'Airdate' => '2009-12-10',
                                       'Channel' => {
                                                    'Modulation' => '',
                                                    'FrequencyId' => '',
                                                    'InputId' => '6',
                                                    'IconURL' => '',
                                                    'DefaultAuth' => '',
                                                    'FrequencyTable' => '',
                                                    'ChannelName' => 'Fox Business HD',
                                                    'NetworkId' => '0',
                                                    'XMLTVID' => '',
                                                    'UseEIT' => 'false',
                                                    'CallSign' => 'FBNHD',
                                                    'SourceId' => '1',
                                                    'Visible' => 'true',
                                                    'ChanNum' => '1079',
                                                    'SIStandard' => '',
                                                    'ServiceId' => '0',
                                                    'Frequency' => '0',
                                                    'CommFree' => '0',
                                                    'Format' => '',
                                                    'ChanId' => '2079',
                                                    'ATSCMinorChan' => '0',
                                                    'MplexId' => '0',
                                                    'ATSCMajorChan' => '0',
                                                    'Programs' => '',
                                                    'TransportId' => '0',
                                                    'ChanFilters' => '',
                                                    'FineTune' => '0'
                                                  },
                                       'ProgramId' => 'SH012184190000',
                                       'StartTime' => '2017-04-29T05:00:00Z',
                                       'HostName' => 'badboy',
                                       'EndTime' => '2017-04-29T06:00:00Z',
                                       'Title' => 'Stossel',
                                       'VideoProps' => '33',
                                       'SubProps' => '0',
                                       'ProgramFlags' => '4096',
                                       'Description' => 'Current consumer issues.',
                                       'Season' => '0',
                                       'Category' => 'News',
                                       'SeriesId' => '',
                                       'Inetref' => '',
                                       'FileName' => '',
                                       'AudioProps' => '0',
                                       'Artwork' => {
                                                    'ArtworkInfos' => ''
                                                  },
                                       'CatType' => '',
                                       'SubTitle' => '',
                                       'FileSize' => '0',
                                       'Recording' => {
                                                      'RecGroup' => 'Default',
                                                      'EndTs' => '2017-04-29T06:00:00Z',
                                                      'Status' => '-1',
                                                      'EncoderId' => '9',
                                                      'RecordId' => '1062',
                                                      'DupInType' => '15',
                                                      'PlayGroup' => 'Default',
                                                      'RecType' => '4',
                                                      'Priority' => '0',
                                                      'DupMethod' => '6',
                                                      'StartTs' => '2017-04-29T05:00:00Z',
                                                      'Profile' => 'Default',
                                                      'StorageGroup' => 'Default'
                                                    },
                                       'Episode' => '0',
                                       'Repeat' => 'true',
                                       'Stars' => '0'
                                     },
                                     {
                                       'Artwork' => {
                                                    'ArtworkInfos' => ''
                                                  },
                                       'AudioProps' => '0',
                                       'CatType' => '',
                                       'Inetref' => '',
                                       'FileName' => '',
                                       'SeriesId' => '',
                                       'FileSize' => '0',
                                       'Recording' => {
                                                      'StartTs' => '2017-04-29T06:00:00Z',
                                                      'Profile' => 'Default',
                                                      'StorageGroup' => 'Default',
                                                      'Priority' => '0',
                                                      'RecType' => '4',
                                                      'DupMethod' => '6',
                                                      'RecordId' => '1062',
                                                      'DupInType' => '15',
                                                      'PlayGroup' => 'Default',
                                                      'RecGroup' => 'Default',
                                                      'EndTs' => '2017-04-29T07:00:00Z',
                                                      'Status' => '-1',
                                                      'EncoderId' => '7'
                                                    },
                                       'SubTitle' => '',
                                       'Repeat' => 'true',
                                       'Episode' => '0',
                                       'Stars' => '0',
                                       'Airdate' => '2009-12-10',
                                       'ProgramId' => 'SH012184190000',
                                       'Channel' => {
                                                    'ChannelName' => 'Fox Business HD',
                                                    'XMLTVID' => '',
                                                    'NetworkId' => '0',
                                                    'UseEIT' => 'false',
                                                    'SourceId' => '1',
                                                    'CallSign' => 'FBNHD',
                                                    'Visible' => 'true',
                                                    'FrequencyId' => '',
                                                    'InputId' => '5',
                                                    'Modulation' => '',
                                                    'IconURL' => '',
                                                    'DefaultAuth' => '',
                                                    'FrequencyTable' => '',
                                                    'ChanId' => '2079',
                                                    'Programs' => '',
                                                    'TransportId' => '0',
                                                    'ATSCMinorChan' => '0',
                                                    'MplexId' => '0',
                                                    'ATSCMajorChan' => '0',
                                                    'FineTune' => '0',
                                                    'ChanFilters' => '',
                                                    'SIStandard' => '',
                                                    'ChanNum' => '1079',
                                                    'Frequency' => '0',
                                                    'ServiceId' => '0',
                                                    'CommFree' => '0',
                                                    'Format' => ''
                                                  },
                                       'LastModified' => '2017-04-29T02:04:01Z',
                                       'HostName' => 'badboy',
                                       'StartTime' => '2017-04-29T06:00:00Z',
                                       'Description' => 'Current consumer issues.',
                                       'ProgramFlags' => '4096',
                                       'Title' => 'Stossel',
                                       'EndTime' => '2017-04-29T07:00:00Z',
                                       'VideoProps' => '33',
                                       'SubProps' => '0',
                                       'Category' => 'News',
                                       'Season' => '0'
                                     },
                                     {
                                       'SubTitle' => '',
                                       'Recording' => {
                                                      'StorageGroup' => 'Default',
                                                      'Profile' => 'Default',
                                                      'StartTs' => '2017-04-29T11:00:00Z',
                                                      'DupMethod' => '6',
                                                      'RecType' => '4',
                                                      'Priority' => '0',
                                                      'PlayGroup' => 'Default',
                                                      'DupInType' => '15',
                                                      'RecordId' => '1062',
                                                      'EncoderId' => '7',
                                                      'Status' => '-1',
                                                      'RecGroup' => 'Default',
                                                      'EndTs' => '2017-04-29T12:00:00Z'
                                                    },
                                       'FileSize' => '0',
                                       'FileName' => '',
                                       'Inetref' => '',
                                       'SeriesId' => '',
                                       'CatType' => '',
                                       'AudioProps' => '0',
                                       'Artwork' => {
                                                    'ArtworkInfos' => ''
                                                  },
                                       'Stars' => '0',
                                       'Episode' => '0',
                                       'Repeat' => 'true',
                                       'StartTime' => '2017-04-29T11:00:00Z',
                                       'HostName' => 'badboy',
                                       'LastModified' => '2017-04-29T02:04:01Z',
                                       'ProgramId' => 'SH012184190000',
                                       'Channel' => {
                                                    'ChanFilters' => '',
                                                    'FineTune' => '0',
                                                    'MplexId' => '0',
                                                    'ATSCMajorChan' => '0',
                                                    'ATSCMinorChan' => '0',
                                                    'TransportId' => '0',
                                                    'Programs' => '',
                                                    'ChanId' => '2079',
                                                    'Format' => '',
                                                    'CommFree' => '0',
                                                    'ServiceId' => '0',
                                                    'Frequency' => '0',
                                                    'ChanNum' => '1079',
                                                    'SIStandard' => '',
                                                    'Visible' => 'true',
                                                    'CallSign' => 'FBNHD',
                                                    'SourceId' => '1',
                                                    'UseEIT' => 'false',
                                                    'XMLTVID' => '',
                                                    'NetworkId' => '0',
                                                    'ChannelName' => 'Fox Business HD',
                                                    'FrequencyTable' => '',
                                                    'DefaultAuth' => '',
                                                    'IconURL' => '',
                                                    'Modulation' => '',
                                                    'InputId' => '5',
                                                    'FrequencyId' => ''
                                                  },
                                       'Airdate' => '2009-12-10',
                                       'Category' => 'News',
                                       'Season' => '0',
                                       'VideoProps' => '33',
                                       'SubProps' => '0',
                                       'EndTime' => '2017-04-29T12:00:00Z',
                                       'Title' => 'Stossel',
                                       'Description' => 'Current consumer issues.',
                                       'ProgramFlags' => '4096'
                                     }
                                   ]
                      },
          'ProtoVer' => '77',
          'AsOf' => '2017-04-29T02:51:03Z',
          'Version' => '0.27.20151025-1',
          'TotalAvailable' => '145',
          'StartIndex' => '0'
        };

The MythAPI module

Application-x-perl.png MythAPI.pm

package MythAPI;

use SOAP::Lite;
use strict;
use warnings;

#Version 1.00    24 April 2017 Initial version using WSDL.


sub new{
    my $class = shift;
    my %options = @_;
   
    #Define MythTV versions and Service classes for the version.
    #Actual supported methods are determined automatically. The list of Services are
    #available via Doxygen output of source code.  https://code.mythtv.org/doxygen/classService.html
    my %mythversion=(
        0.25    =>    ["Capture","Channel","Content","Dvr","Frontend","Guide","Myth","Video"],
        0.26    =>    ["Capture","Channel","Content","Dvr","Frontend","Guide","Myth","Video"],
        0.27    =>    ["Capture","Channel","Content","Dvr","Frontend","Guide","Myth","Video"],
        0.28    =>    ["Capture","Channel","Content","Dvr","Frontend","Guide","Myth","Video","Image","Rtti"],
        0.29    =>    ["Capture","Channel","Content","Dvr","Frontend","Guide","Myth","Video","Image","Rtti"],
    );   
   
    my $self   = {
        '_server'            =>    undef,
        '_backendport'    =>    6544,
        '_frontendport'    =>    6547,
        'MythVersions'    => {},
        'Services'        => {}
    };   

    #Add suported myth versions to the visible class variables.
    $self->{'MythVersions'} = \%mythversion;
   
    if (@_)    {
        foreach my $key (keys %options)    {
            if ( $key eq 'server'){
                $self->{_server}= $options{$key};
            }
            elsif ( $key eq 'backendport'){
                $self->{_backendport}= $options{$key};
            }
            elsif ( $key eq 'frontendport') {
                $self->{_frontendport} = $options{$key};
            }           
        }
        if ( !defined $self->{_server}) {
            die("must at least specify a server to connect to.");
        }
    } else {
        die("must specify a server to connect to.");
    }
   
    bless($self, $class);
    $self->_initAPI();
   
    return $self;
}

sub _run {
    my($self,$method, %args) = @_;
    my $mythService;
   
    FINDMETHOD: foreach my $service ( sort(keys %{$self->{Services}}) ) {
        foreach my $serviceMethod ( @{$self->{Services}->{$service}} ) {
            if ( lc $method eq lc $serviceMethod) {
                $mythService=$service;
                $method=$serviceMethod;
                last FINDMETHOD
            }
        }
    }   
   
    my $soapcall = $self->_buildSOAPConnection ($mythService);
    #SOAP returns results in Perl data structures.
    return $soapcall->$method(%args);
}

sub _buildSOAPConnection {
    my $self = shift;
    my ($mythService) = @_;
    my $URI;
   
    if ( lc $mythService eq lc "frontend" ) {
            $URI = "http://". $self->{_server}.":".$self->{_frontendport}."/".$mythService."/wsdl";
    } else    {
            $URI = "http://". $self->{_server}.":".$self->{_backendport}."/".$mythService."/wsdl";
    }
   
    return SOAP::Lite->service($URI);
}

sub _initAPI{
    my $self = shift;
    my $methodList;
    my @key;
    my $URI;
   
    #Use the one supported service and method on all Myth Versions since 0.25 to determin
    #which mythtv version we are accessing.
    my $useAPI = $self->_matchAPI($self->_getMajorMinorVersion());

    #Build a list of services and methods based on MythTV Version;   
    foreach my $service (@{$self->{'MythVersions'}{$useAPI}}) {
        if ($service eq "Frontend") {
            $URI = "http://". $self->{_server}.":".$self->{_frontendport}."/".$service."/wsdl";
        } else    {
            $URI = "http://". $self->{_server}.":".$self->{_backendport}."/".$service."/wsdl";
        }
   
        my $serviceMethods = SOAP::Schema->new( schema_url => $URI);
        $serviceMethods->parse();
        $methodList = $serviceMethods->services();
        @key = keys %{$methodList};
       
        my @tmp = sort(keys(%{$methodList->{$key[0]}}));
        $self->{Services}->{$service}= [@tmp];
    }
}

# This call should return the same version as passed in to the call.
# If the MythTV system is a higher version we return the closest matching version
sub _matchAPI {
    my $self = shift;
    my ($ver) = @_;
    my @versions = sort (keys (%{$self->{'MythVersions'}}));
    my $index=0;
    my $temp;

    do{
        if ( $ver == $versions[$index]){
            return $ver;
        } else {
            $index++;
            #If ver is larger than higest version we know about make sure we pass
            #back to calling routine the highest version we support.
            if ( $ver > $versions[$index]) {
                $temp = $versions[$index];
            }
        }
       
    }while ($index <= @versions);
    #we did not match any known mythtv versions
    return $temp;
}

#Get the current mythtv version.
sub _getMajorMinorVersion {
    my $self = shift;
   
    my $temp = $self->_buildSOAPConnection("Myth");
    my $data = $temp->GetConnectionInfo();
    my $ret = $data->{Version}->{Version};
   
    #Get only Major and Minor version from returned string.
    $ret = substr($ret, 1,4);
    return $ret;    #Example return 0.27 instead of v0.27.6
}

#Use AUTOLOAD to simulate Service API function calls as part of this object.
#Process method call and access apropriate API call.
sub AUTOLOAD{
    my($self,%args) = @_;
    our $AUTOLOAD;

    #seperate AUTOLOAD into class and method
    my ($class,$method) = $AUTOLOAD =~ m/^(.+)::(.+)$/;
    $self->_run($method,%args);
}

sub DESTROY{
    my($self) = @_;
    $self = undef;
}

1;
]]