Services API with PERL

From MythTV Official Wiki
Revision as of 02:22, 29 April 2017 by Hoodlum7 (talk | contribs)

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.

Features

SOAP and WSDL


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->GetConflictList(Count=>2);
print Dumper($data);



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;
]]