File Coverage

blib/lib/Net/TiVo.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # $Id: TiVo.pm 63 2007-03-29 14:09:37Z boumenot $
2             # Author: Christopher Boumenot
3             ######################################################################
4             #
5             # Copyright 2006-2007 by Christopher Boumenot. This program is free
6             # software; you can redistribute it and/or modify it under the same
7             # terms as Perl itself.
8             #
9             ######################################################################
10              
11             package Net::TiVo;
12              
13 3     3   73595 use strict;
  3         7  
  3         124  
14 3     3   17 use warnings;
  3         6  
  3         135  
15              
16             our $VERSION = '0.11';
17              
18 3     3   14211 use LWP::UserAgent;
  3         283385  
  3         154  
19 3     3   38 use HTTP::Request;
  3         6  
  3         157  
20 3     3   5155 use XML::Simple;
  0            
  0            
21             use Data::Dumper;
22             use Log::Log4perl qw(:easy get_logger);
23             use Net::TiVo::Folder;
24             use Net::TiVo::Show;
25              
26             use constant TIVO_URL => '/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying';
27              
28             sub new {
29             my $class = shift;
30             my $self = {username => 'tivo',
31             realm => 'TiVo DVR',
32             @_};
33              
34             $self->{host} || die "%Error: no host was defined!\n";
35             $self->{mac} || die "%Error: no mac was defined!\n";
36             $self->{username} || die "%Error: no username was defined!\n";
37              
38             $self->{ua} = LWP::UserAgent->new() or
39             die "%Error: failed to create a LWP::UserAgent!";
40              
41             $self->{ua}->credentials($self->{host}.':443',
42             $self->{realm},
43             $self->{username} => $self->{mac});
44              
45             $self->{url} = 'https://'.$self->{host}.TIVO_URL;
46              
47             bless $self, $class;
48             return $self;
49             }
50              
51              
52             sub folders {
53             my $self = shift;
54              
55             my $resp = $self->_fetch($self->{url});
56              
57             if ($resp->is_success()) {
58             my @folders;
59             $self->_parse_content($resp->content(), \@folders);
60              
61             return unless @folders;
62             return (wantarray) ? @folders : \@folders;
63             }
64              
65             print "%Error: $resp->status_line()!\n";
66             return;
67             }
68              
69              
70             sub _fetch {
71             my ($self, $url) = @_;
72             my $resp;
73              
74             INFO("fetching $url");
75              
76             if (exists $self->{cache}) {
77             $resp = $self->{cache}->get($url, $resp);
78             if (defined $resp) {
79             INFO("cache hit");
80             return $resp;
81             }
82             INFO("cache miss");
83             }
84              
85             $resp = $self->{ua}->request(HTTP::Request->new(GET => $url));
86             die "%Error: fetch failed, " . $resp->status_line() . "!\n" unless $resp->is_success();
87              
88             if (exists $self->{cache}) {
89             $self->{cache}->set($url, $resp);
90             }
91              
92             return $resp;
93             }
94              
95             sub _parse_content {
96             my ($self, $cont, $folder_aref) = @_;
97              
98             DEBUG(sub { "Received [" . $cont . "]"});
99              
100             my $xmlref = XMLin($cont, ForceArray => ['Item']);
101             unless (defined $xmlref->{Item}) {
102             INFO("No content to parse, skipping ...");
103             return;
104             }
105            
106             DEBUG(sub { Dumper($xmlref) });
107              
108             # TiVo only allows you to create one folder to hold shows, but the
109             # top most folder, Now Playing, as to be accounted for too. If we
110             # haven't created any folders yet, then this is the Now Playing
111             # folder, and needs to be treated specially.
112             push @$folder_aref, Net::TiVo::Folder->new(xmlref => $xmlref);
113              
114             # 2006/12/29 - RHARMAN: TiVo Suggestions can exist but contain zero videos
115             if ($folder_aref->[-1]->total_items() > 0) {
116             INFO("added the folder " . $folder_aref->[-1]->name());
117             } else {
118             INFO("skipped the folder " , $folder_aref->[-1]->name(), " because it was empty.");
119             pop @$folder_aref;
120             }
121              
122             for my $i (@{$xmlref->{Item}}) {
123             my $ct = $i->{Links}->{Content}->{ContentType};
124              
125              
126             if ($ct eq 'x-tivo-container/folder') {
127             my $resp = $self->_fetch($i->{Links}->{Content}->{Url});
128             $self->_parse_content($resp->content(), $folder_aref);
129             } else {
130             INFO("skipping the content for $ct");
131             }
132             }
133             }
134              
135              
136             1;
137             __END__