source: trunk/grabbers/yahoo7widget

Last change on this file was 1527, checked in by mbarry, 2 years ago

Channel updates (incl ABC3 -> ABC ME), some from Wayne

  • Property svn:executable set to *
File size: 25.3 KB
Line 
1#!/usr/bin/env perl
2
3# yahoo7_widget au_tv guide grabber - runs from "Shepherd" master grabber
4#  * written by ltd
5#  * uses yahoo7 widget for ABC/7/9/10/SBS (all they have)
6#  * when used in conjunction with Shepherd, shepherd can collect other channels
7#    using other grabbers
8#  * this does NOT use any config file - all settings are passed in from shepherd
9
10#  changelog:
11#    1.50  22sep06      added support for "shepherd" master grabber script
12#    1.51  02oct06      --ready option
13#    1.52  03oct06      split out yahoo7 grabber into its own grabber
14#    1.54  16oct06      put date/cast/credits/year into correct xmltv fields
15#    1.70  15dec06      sometimes there are holes in data; augment those from yahoo7web
16#    1.78  04feb07      remove augmenting - micrograbbing from other grabbers
17#                       can now fill those in
18#    1.80  22feb07      bugfix: stop throwing away multiple category data
19#    1.81  01mar07      more informative error on no connectivity
20#    2.00  19jun10      moved to JSON data format
21#    2.01  20jun10      add sub-title support in
22#    2.10  22jun10      experimental: drop JSON module for cut-down Shepherd::json_pp
23
24use strict;
25use warnings;
26
27my $progname = "yahoo7widget";
28my $version = "2.44";
29
30use XMLTV;
31use POSIX qw(strftime mktime);
32use Getopt::Long;
33use Data::Dumper;
34use Shepherd::Common;
35use Shepherd::json_pp;  # use JSON;
36
37#
38# some initial cruft
39#
40
41my $script_start_time = time;
42my %stats;
43my $channels, my $opt_channels;
44my $tv_guide;
45my $input_xml;
46my $d;
47$| = 1;
48
49# Map yahoo paytv names to what shepherd knows them as.
50# Format: 'yahoo7widget name' => 'official name'
51my %paytv_fixups = (
52    '111' => '111funny',
53    '1112' => '111funny2',
54#    '13THSTREET' => '13THSTREET',
55    '13THSTREET2' => '13thSTREET2',
56    '13THSTREETHD' => '13thStreetHD',
57#    'ACC' => 'ACC',
58#    'Action' => 'Action',
59#    'Action2' => 'Action2',
60#    'ActionHD' => 'ActionHD',
61#    'AdultsOnly960' => 'AdultsOnly960',
62#    'AE' => 'AE',
63#    'AE2' => 'AE2',
64#    'AEHD' => 'AEHD',
65    'AlJazeeraEnglish' => 'AlJazeera',
66#    'AnimalPlanet' => 'AnimalPlanet',
67    'Antenna' => 'AntennaPacific',
68    'ARENA' => 'Arena',
69    'ARENA2' => 'Arena2',
70    'ARENAHD' => 'ArenaHD',
71#    'Arts' => 'Arts',
72#    'ArtsHD' => 'ArtsHD',
73    'AURORA' => 'Aurora',
74#    'BBCFirst' => 'BBCFirst',
75#    'BBCFirstHD' => 'BBCFirstHD',
76#    'BBCKnowledge' => 'BBCKnowledge',
77#    'BBCKnowledgeHD' => 'BBCKnowledgeHD',
78#    'BBCWorldNews' => 'BBCWorldNews',
79    'beINSports1' => 'beINSPORTS1',
80#    'beINSPORTS1HD' => 'beINSPORTS1HD',
81#    'beINSPORTS2' => 'beINSPORTS2',
82#    'beINSPORTS2HD' => 'beINSPORTS2HD',
83#    'beINSPORTS3' => 'beINSPORTS3',
84#    'beINSPORTS3HD' => 'beINSPORTS3HD',
85#    'Binge' => 'Binge',
86#    'BingeHD' => 'BingeHD',
87#    'Bio' => 'Bio',
88    'Bloomberg' => 'BloombergTelevision',
89    'BOOMERANG' => 'Boomerang',
90    'Boxsets' => 'BoxSets',
91    'BoxsetsHD' => 'BoxSetHD',
92    'CARTOONNETWORK' => 'CartoonNetwork',
93    'BBCCBeebies' => 'Cbeebies',
94#    'CCD' => 'CCD',
95    'CCTV-9Documentary' => 'CCTV9Doco',
96#    'CCTVNews' => 'CCTVNews',
97    'ChelseaFCTV' => 'ChelseaTV',
98    'ChelseaFCTVHD' => 'ChelseaTVHD',
99#    'CMC' => 'CMC',
100#    'CNBC' => 'CNBC',
101#    'CNN' => 'CNN',
102#    'Comedy' => 'Comedy',
103#    'ComedyHD' => 'ComedyHD',
104    'THECOMEDYCHANNEL' => 'TheComedyChannel',
105    'THECOMEDYCHANNEL2' => 'ComedyCh2',
106    'CrimeInvestigation' => 'Crime',
107#    'Daystar' => 'Daystar',
108    'DiscoveryChannel2' => 'Discovery2',
109#    'DiscoveryChannel' => 'DiscoveryChannel',
110#    'DiscoveryHD' => 'DiscoveryHD',
111#    'DiscoveryHealth' => 'DiscoveryHealth',
112#    'DiscoveryKids' => 'DiscoveryKids',
113#    'DiscoveryScience' => 'DiscoveryScience',
114#    'DiscoveryTurbo' => 'DiscoveryTurbo',
115#    'DiscoveryTurbo2' => 'DiscoveryTurbo2',
116    'DisneyMovies2' => 'DisneyMov2',
117#    'DisneyChannel' => 'DisneyChannel',
118#    'DisneyJunior' => 'DisneyJunior',
119#    'DisneyXD' => 'DisneyXD',
120    'E!' => 'E!Entertainment',
121#    'ESPN' => 'ESPN',
122#    'ESPN2' => 'ESPN2',
123#    'ESPNHD' => 'ESPNHD',
124    'ESPN2 HD' => 'ESPN2HD',
125#    'Eurosport' => 'Eurosport',
126#    'EurosportHD' => 'EurosportHD',
127    'EurosportNews' => 'Eurosportnews',
128#    'EXPO' => 'EXPO',
129#    'Family' => 'Family',
130#    'Family2' => 'Family2',
131#    'FamilyHD' => 'FamilyHD',
132#    'FOX8' => 'FOX8',
133#    'FOX82' => 'FOX82',
134#    'FOX8HD' => 'FOX8HD',
135#    'FOXClassics' => 'FOXClassics',
136#    'FOXClassics2' => 'FOXClassics2',
137    'FOXNEWS' => 'FOXNews',
138    'FOXSPORTS1' => 'FoxSports1',
139    'FOXSPORTS1HD' => 'FoxSports1HD',
140    'FOXSPORTS2' => 'FoxSports2',
141    'FOXSPORTS2HD' => 'FoxSports2HD',
142    'FOXSPORTS3' => 'FoxSports3',
143    'FOXSPORTS3HD' => 'FoxSports3HD',
144    'FOXSPORTS4' => 'FoxSports4',
145    'FOXSPORTS4HD' => 'FoxSports4HD',
146    'FOXSPORTS5' => 'FoxSports5',
147    'FOXSPORTS5HD' => 'FoxSports5HD',
148    'FOXFOOTY' => 'FoxFooty',
149    'FOXFOOTYHD' => 'FoxFootyHD',
150    'FOXSPORTSNews' => 'FoxSportsNews',
151    'FOXSPORTSNewsHD' => 'FoxSportsNewsHD',
152    'FoxtelMoviesDisneyHD' => 'DisneyMoviesHD',
153    'FoxtelMoviesDisneySD' => 'DisneyMovies',
154#    'FOXSPORTSPLUS' => 'FOXSPORTSPLUS',
155#    'FUELTV' => 'FUELTV',
156#    'FX' => 'FX',
157#    'FX2' => 'FX2',
158#    'FXHD' => 'FXHD',
159#    'KidsCo' => 'KidsCo',
160    'LifestyleHOME' => 'LifestyleHome',
161    'LifestyleChannel' => 'TheLifestyleChannel',
162    'LifestyleChannel2' => 'Lifestyle2',
163    'LifestyleFOOD' => 'LifestyleFOOD',
164    'LifestyleFOOD2' => 'LifestyleFOOD2',
165    'LifestyleHD' => 'LifestyleHD',
166    'LifestyleYOU' => 'LifestyleYOU',
167    'LifestyleYOU2' => 'LifestyleYOU2',
168    'LiverpoolFCTV' => 'LFCTV',
169    'LiverpoolFCTVHD' => 'LFCTVHD',
170#    'MainEvent' => 'MainEvent',
171    'ManchesterUnitedFCTV' => 'MUTV',
172    'ManchUnitedFCTVHD' => 'MUTVHD',
173#    'Masterpiece' => 'Masterpiece',
174#    'MasterpieceHD' => 'MasterpieceHD',
175#    'MAX' => 'MAX',
176    'MoreMovies' => 'FoxtelMoviesMore',
177    'MoreMoviesHD' => 'FoxtelMoviesMoreHD',
178#    'MTV' => 'MTV',
179#    'MTVMusic' => 'MTVMusic',
180#    'MTVDance' => 'MTVDance',
181#    'NatGeo2' => 'NatGeo2',
182#    'NatGeoAdventure' => 'NatGeoAdventure',
183#    'NatGeoHD' => 'NatGeoHD',
184#    'NatGeoPeople' => 'NatGeoPeople',
185#    'NatGeoWild' => 'NatGeoWild',
186#    'NatGeoWildHD' => 'NatGeoWildHD',
187#    'NationalGeographic' => 'NationalGeographic',
188#    'Nickelodeon' => 'Nickelodeon',
189#    'NickJr' => 'NickJr',
190#    'NITV' => 'NITV',
191    'NHK' => 'NHKWorld',
192#    'Ovation' => 'Ovation',
193#    'Premiere' => 'Premiere',
194#    'Premiere2' => 'Premiere2',
195#    'PremiereHD' => 'PremiereHD',
196    'RAI' => 'RAIITALIA',
197#    'Romance' => 'Romance',
198#    'RomanceHD' => 'RomanceHD',
199#    'RussiaToday' => 'RussiaToday',
200#    'SetantaSports' => 'SetantaSports',
201    'Showcase' => 'showcase',
202    'Showcase2' => 'showcase2',
203    'ShowcaseHD' => 'showcaseHD',
204    'SkyNewsBusiness' => 'SKYNewsBusiness',
205#    'SkyBusinessHD' => 'SkyBusinessHD',
206    'SkyNewsAustralia' => 'SKYNewsLive',
207    'SkyNewsHD' => 'SKYNewsHD',
208    'SkyRacing1' => 'SKYRacing',
209    'SkyNewsElection' => 'SKYNewsElection',
210#    'SkyNewsElectionHD' => 'SKYNewsElectionHD',
211    'SkyRacing2' => 'SKYRacing2',
212#    'SKYRacingWorld' => 'SKYRacingWorld',
213    'SkyThoroughbredCentral' => 'SKYTbredCent',
214    'SkyTbredHD' => 'SKYTbredCentHD',
215#    'SKYWeather' => 'SKYWeather',
216#    'SPEED' => 'SPEED',
217#    'SPEEDHD' => 'SPEEDHD',
218    'style.' => 'Style',
219#    'Syfy' => 'Syfy',
220#    'Syfy2' => 'Syfy2',
221#    'SyfyHD' => 'SyfyHD',
222#    'TCM' => 'TCM',
223#    'TheHistoryChannel' => 'TheHistoryChannel',
224    'TheHistoryChannelHD' => 'HistoryHD',
225#    'Thriller' => 'Thriller',
226#    'ThrillerHD' => 'ThrillerHD',
227#    'TLC' => 'TLC',
228#    'TLC2' => 'TLC2',
229#    'TSN' => 'TSN',
230    'TVH!ts' => 'TVH!TS',
231    'TVH!ts2' => 'TVH!TS2',
232#    'TVN' => 'TVN',
233    'TVSNShopping' => 'TVSN',
234#    'UKTV' => 'UKTV',
235#    'UKTV2' => 'UKTV2',
236#    'UKTVHD' => 'UKTVHD',
237    'UniversalChannel' => 'Universal',
238#    'Universal2' => 'Universal2',
239#    'UniversalHD' => 'UniversalHD',
240    'Smooth' => 'FoxtelSmooth',
241    'VHits' => 'VHITS',
242    'VHits2' => 'VHITS2',
243    'WorldMovies' => 'WORLDMOVIES',
244#    'WorldMoviesHD' => 'WorldMoviesHD',
245);
246
247#
248# parse command line
249#
250
251my $opt;
252$opt->{outputfile} =    "output.xmltv"; # default
253$opt->{days} =          7;              # default
254$opt->{lang} =          "en";
255$opt->{region} =        94;
256
257GetOptions(
258        'region=i'      => \$opt->{region},
259        'days=i'        => \$opt->{days},
260        'offset=i'      => \$opt->{offset},
261        'paytvtimeoffset:s'     => \$opt->{paytvoffset},
262        'channels_file=s' => \$opt->{channels_file},
263        'cachefile=s' => \$opt->{obsolete},
264        'output=s'      => \$opt->{outputfile},
265        'fast'          => \$opt->{fast},
266        'paytv'         => \$opt->{paytv},
267        'warper'        => \$opt->{warper},
268        'lang=s'        => \$opt->{lang},
269        'obfuscate'     => \$opt->{obfuscate},
270        'debug+'        => \$opt->{debug},
271        'help'          => \$opt->{help},
272        'verbose'       => \$opt->{help},
273        'version'       => \$opt->{version},
274        'ready'         => \$opt->{version},
275        'desc'          => \$opt->{desc},
276        'v'             => \$opt->{help});
277
278&help if (defined $opt->{help});
279
280if (defined $opt->{version} || defined $opt->{desc}) {
281        printf "%s %s\n",$progname,$version;
282        printf "%s is a details-aware grabber that collects very high quality data (full title/subtitle/description/genre and year/cast/credits data) using the Yahoo7 website.",$progname if (defined $opt->{desc});
283        exit(0);
284}
285
286# set defaults
287Shepherd::Common::set_default("debug", ($opt->{debug} * 2)) if (defined $opt->{debug});
288Shepherd::Common::set_default("webwarper", 1) if (defined $opt->{warper});
289Shepherd::Common::set_default("squid", 1) if (defined $opt->{obfuscate});
290Shepherd::Common::set_default("referer", "last");
291Shepherd::Common::set_default("retry_delay", 10);
292Shepherd::Common::setup_ua('agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-us)');
293
294die "no channel file specified, see --help for instructions\n", unless (defined $opt->{channels_file});
295
296$opt->{days} = 9 if $opt->{days} > 9;   # no data beyond 9 days
297
298#
299# go go go!
300#
301
302my $starttime = $script_start_time;
303
304# correct $starttime to remove gap between local and Eastern States time
305my $local_time_offset;
306
307if (!defined $opt->{paytvoffset} || !($opt->{paytvoffset} =~ m/(\+|-)\d{4}$/o))  {
308        $local_time_offset = POSIX::strftime("%z",localtime(time)); 
309} else { 
310        $local_time_offset = $opt->{paytvoffset}; 
311}
312
313# yahoo7widget times are always localtime on Eastern States ..
314$ENV{TZ}="Australia/Melbourne";
315my $melbourne_time_offset = POSIX::strftime("%z",localtime(time));
316my $time_offset = ((int(substr($melbourne_time_offset,1,2))-int(substr($local_time_offset,1,2)))*(60*60)) +
317                ((int(substr($melbourne_time_offset,3,2))-int(substr($local_time_offset,3,2)))*(60));
318$starttime -= $time_offset;
319
320my $endtime = $starttime + ($opt->{days} * 86400);
321$starttime += (86400 * $opt->{offset}) if (defined $opt->{offset});
322
323Shepherd::Common::log(sprintf "going to grab %d days%s of data into %s (%s%s) region %s",
324        $opt->{days},
325        ($opt->{offset} ? " (skipping first $opt->{offset} days)" : ""),
326        $opt->{outputfile},
327        (defined $opt->{fast} ? "with haste" : "slowly"),
328        (defined $opt->{warper} ? ", anonymously" : ""),
329        $opt->{region});
330
331if (-r $opt->{channels_file}) {
332        local (@ARGV, $/) = ($opt->{channels_file});
333        no warnings 'all'; eval <>; die "$@" if $@;
334} else {
335        die "WARNING: channels file $opt->{channels_file} could not be read\n";
336}
337
338&check_for_paytv;
339
340$starttime -= ($starttime % $d->{fetch_interval}); # normalize time window to help yahoo's squid cache entries
341for (my $currtime = $starttime; $currtime < $endtime; $currtime += $d->{fetch_interval}) {
342        # pace ourselves
343        if (($currtime != $starttime) && (!defined $opt->{fast})) {
344                my $sleeptimer = int(rand(5)) + 1;  # sleep anywhere from 1 to 5 seconds
345                $stats{slept_for} += $sleeptimer;
346                sleep $sleeptimer;
347        }
348
349        # get data
350        my $tries = 5;
351        my $url = sprintf "http://au.tv.yahoo.com/tv-guide/data/%d/%d/%d/%d/",
352                $opt->{region},
353                ($d->{want_paytv} > 0 ? "168" : "0"),
354                $currtime,
355                ($currtime+$d->{fetch_interval});
356        my ($data, $success, $status_msg, $bytes_fetched, $seconds_slept, $failed_attempts, $response) = 
357          Shepherd::Common::get_url(url => $url, retries => ($tries-1));
358
359        $stats{failed_requests} += $failed_attempts;
360        $stats{slept_for} += $seconds_slept;
361        $stats{bytes_fetched} += $bytes_fetched;
362
363        if ((!$data) || (!$success)) {
364                Shepherd::Common::log("Failed to fetch '$url' after $tries attempts.");
365
366                # if its our first page, abort now
367                if ($currtime == $starttime) {
368                        Shepherd::Common::log("Aborting: likely format change or blocked!");
369                        exit 10;
370                }
371                next;
372        }
373
374        $stats{http_successful_requests}++;
375        &parse_json_data($data);
376}
377
378&write_data;
379Shepherd::Common::print_stats($progname, $version, $script_start_time, %stats);
380exit(0);
381
382######################################################################################################
383# help
384
385sub help
386{
387        print<<EOF
388$progname $version
389
390$0 [options]
391    options are as follows:
392        --region=N                      set region for where to collect data from (default: $opt->{region})
393        --channels_file=file            where to get channel data from (MANDATORY)
394        --days=N                        fetch 'n' days of data (default: $opt->{days})
395        --output=file                   send xml output to file (default: "$opt->{outputfile}")
396
397        --fast                          don't run slow - get data as quick as you can - not recommended
398        --debug                         increase debug level
399        --warper                        fetch data using WebWarper web anonymizer service
400        --obfuscate                     pretend to be a proxy servicing multiple clients
401        --lang=[s]                      set language of xmltv output data (default $opt->{lang})
402
403        --paytvtimeoffset               apply an offset between current timezone and AEST for paytv channels
404        --paytvtimeoffset[="+HHMM"]     apply a difference of +HHMM and AEST for paytv channels ie +1030 (+- is mandatory)
405
406EOF
407;
408
409        exit(0);
410}
411
412######################################################################################################
413# parse it into $tv_guide->{$channel}->{data}->{$event_id}-> structures..
414
415sub parse_json_data
416{
417        my $data = shift;
418
419        unless (($data) && (length($data) > 1)) {
420            print STDERR "ERROR: no data to parse.\n";
421            return;
422        }
423
424        # my $decoded_data = decode_json($data);
425        my $decoded_data = JSON::cut_down_PP::decode_json($data);
426
427        foreach my $item (@{($decoded_data->{'tv'}->[0]->{'item'})}) {
428                my $event_id = $item->{'event_id'};
429
430                # mandatory fields
431                my $event_start = $item->{'event_date'}->[0]->{timestamp};
432                my $event_end =   $item->{'end_date'}->[0]->{timestamp};
433
434                if ($event_start < 10) {
435                        $stats{progs_with_invalid_start}++;
436                        printf "WARNING: programme with event_id '$event_id' had an invalid start time of '$event_start'; skipped\n";
437                        next;
438                }
439                if ($event_end < 10) {
440                        $stats{progs_with_invalid_end}++;
441                        printf "WARNING: programme with event_id '$event_id' had an invalid end time of '$event_end'; skipped\n";
442                        next;
443                }
444
445                my $channel = $item->{'co_v_short'};
446
447                if (ref($channel) eq "ARRAY") { # paytv channels
448
449                        $channel = $channel->[0]->{0};
450                        $channel =~ s/(\s|\[|\]|\+|\&)//g; 
451                        $channel = $paytv_fixups{$channel} if (defined $paytv_fixups{$channel});
452
453                        # Yahoo7 guide is broken in non daylight savings states (QLD at least) returning FTA
454                        # without DLS and Foxtel with DLS. Only apply offset if switch is set and in opt_channels
455                        if (defined $opt_channels->{$channel}) {
456                            $event_start -= $time_offset if (defined $opt->{paytvoffset});
457                            $event_end -= $time_offset if (defined $opt->{paytvoffset});
458                        }
459                }
460
461                # Hack; assuming this is a temporary typo
462                $channel = 'ABC News 24' if ($channel eq 'ABCNews24');
463                $channel = 'WIN GEM' if ($channel eq 'WINGEM');
464                $channel = '31 Digital' if ($channel eq '31Digital'); 
465                $channel = 'ABC2 / KIDS' if ($channel eq 'ABC2/KIDS');
466                $channel = 'SBS 2' if ($channel eq 'SBS2');
467                $channel = 'Food Network' if ($channel eq 'FoodNetwork');
468                $channel = 'TEN HD' if ($channel eq 'TENHD');
469
470# Temp hack Oct 2010 when Seven-related channels gave bad data
471#               if (grep ($channel eq $_, ('Seven', 'Prime', '7mate', '7TWO', 'Prime HD', 'Seven HD')))
472#               {
473#                       &Shepherd::Common::log("ignoring unreliable channel '$channel'");
474#                       $d->{ignored_channels}->{$channel} = 1;
475#                       $stats{skipped_channels}++;
476#                       next;
477#               }
478
479                if ((!defined $channels->{$channel}) && (!defined $opt_channels->{$channel})) {
480                        if (!defined $d->{ignored_channels}->{$channel}) {
481                                $d->{ignored_channels}->{$channel} = 1;
482                                $stats{skipped_channels}++;
483                                Shepherd::Common::log("ignoring unwanted channel '$channel'");
484                        }
485                        next;
486                }
487
488
489                $event_id = $event_start.":".$event_end.":".$event_id; # event_id actually isn't unique - so make it so
490
491                $stats{programmes}++;
492                $stats{duplicate_programmes}++ if ($tv_guide->{$channel}->{data}->{$event_id});
493
494                # store it in the correct XMLTV schema!
495                $tv_guide->{$channel}->{data}->{$event_id}->{'channel'} = $channels->{$channel} if (defined $channels->{$channel});
496                $tv_guide->{$channel}->{data}->{$event_id}->{'channel'} = $opt_channels->{$channel} if (defined $opt_channels->{$channel});
497
498                $tv_guide->{$channel}->{data}->{$event_id}->{'start'} = POSIX::strftime("%Y%m%d%H%M", localtime($event_start));
499                $tv_guide->{$channel}->{data}->{$event_id}->{'stop'} =  POSIX::strftime("%Y%m%d%H%M", localtime($event_end));
500
501                # Hack for what seems to be a bug in the datasource:
502                # i.e. titles/sub-titles of "Law &Order" rather than "Law & Order".
503                $item->{title}->[0]->{0} =~ s/ \&(?=\S)/ \& /g if (defined $item->{title});
504                $item->{subtitle}->[0]->{0} =~ s/ \&(?=\S)/ \& /g if (defined $item->{subtitle});
505
506                $tv_guide->{$channel}->{data}->{$event_id}->{'title'} =         [[ $item->{title}->[0]->{0}, $opt->{lang} ]] if (defined $item->{title});
507                $tv_guide->{$channel}->{data}->{$event_id}->{'desc'} =          [[ $item->{description_1}, $opt->{lang} ]] if (defined $item->{description_1});
508                $tv_guide->{$channel}->{data}->{$event_id}->{'sub-title'} =     [[ $item->{subtitle}->[0]->{0}, $opt->{lang} ]] if (defined $item->{subtitle});
509
510                my %genre, my $category, my $category2;
511                $genre{movie} = 1 if ((defined $item->{show_type}) && ($item->{show_type} eq "Movie"));
512                $genre{live} = 1 if (defined $item->{live});
513                $category = $item->{genre} if (defined $item->{genre});
514                if ((defined $item->{'category'}) && (defined $item->{'category'}->[0]->{'item'}->[0]->{0})) {
515                        my $category2 = $item->{'category'}->[0]->{'item'}->[0]->{0};
516                        $category = $category2 if (!defined $category);
517                        $genre{$category2} = 1;
518                }
519                $tv_guide->{$channel}->{data}->{$event_id}->{'category'} =      [ &Shepherd::Common::generate_category($item->{title}->[0]->{0}, $category, %genre) ];
520                Shepherd::Common::log(sprintf "category: chose '%s' from '%s' and '%s' for '%s'",
521                        $tv_guide->{$channel}->{data}->{$event_id}->{'category'}->[0]->[0], $category,
522                        join(', ',keys %genre), $item->{title}->[0]->{0}) if (defined $opt->{debug});
523
524                $tv_guide->{$channel}->{data}->{$event_id}->{'country'} =       [ map([$_,$opt->{lang}], split(/\//, $item->{country})) ] if (defined $item->{country});
525                $tv_guide->{$channel}->{data}->{$event_id}->{'premiere'} =      [ 'premiere', $opt->{lang} ] if (defined $item->{'premiere'});
526
527                my $rating = "";
528                $rating .= $item->{rating} if (defined $item->{'rating'});
529                $rating .= " ".lc($item->{warnings}) if (defined $item->{'warnings'});
530                $tv_guide->{$channel}->{data}->{$event_id}->{'rating'} =        [[ $rating, 'ABA', undef ]] if $rating ne "";
531
532                $tv_guide->{$channel}->{data}->{$event_id}->{'credits'}{'actor'} = [ split(/, /, $item->{main_cast}) ] if (defined $item->{main_cast});
533                $tv_guide->{$channel}->{data}->{$event_id}->{'credits'}{'director'} = [ split(/, /, $item->{director}) ] if (defined $item->{director});
534                $tv_guide->{$channel}->{data}->{$event_id}->{'credits'}{'writer'} = [ split(/, /, $item->{writer}) ] if (defined $item->{writer}); # unseen
535                $tv_guide->{$channel}->{data}->{$event_id}->{'date'} =  $item->{year_released} if (defined $item->{year_released});
536                $tv_guide->{$channel}->{data}->{$event_id}->{'previously-shown'} = { } if (defined $item->{repeat});
537                $tv_guide->{$channel}->{data}->{$event_id}->{'subtitles'} =     [ { 'type' => 'teletext' } ] if (defined $item->{captions});
538                $tv_guide->{$channel}->{data}->{$event_id}->{'last-chance'} =   [ 'final', $opt->{lang} ] if (defined $item->{final});
539
540                my %video_details;
541                if ((defined $item->{colour}) && ($item->{colour} == 1)) {
542                        $video_details{'colour'} = 1;
543                        $tv_guide->{$channel}->{data}->{$event_id}->{'video'} = \%video_details;
544                }
545
546                $tv_guide->{$channel}->{data}->{$event_id}->{'length'} = ($item->{running_time} * 60) if (defined $item->{running_time});
547                $tv_guide->{$channel}->{data}->{$event_id}->{'language'} = [ $item->{language}, $opt->{lang} ] if (defined $item->{language});
548
549                $d->{seen_progs}->{$channel}++;
550
551                # print out any unused fields
552                foreach my $field (keys %{($item)}) {
553                        next if ($field =~ /(event_id|co_v_short|event_date|end_date|title|subtitle|description_1|show_type|category|country|premiere|rating|warnings|main_cast|director|writer|year_released|repeat|captions|final|colour|running_time|language|genre|live)/); # parsed fields
554                        next if ($field =~ /(program_id|series_id|genre_id|venue_id|y7_url|highlight)/); # ignored fields
555                        next if (defined $d->{ignored_field}->{$field});
556                        $d->{ignored_field}->{$field} = 1;
557                        Shepherd::Common::log("ignoring unknown field '$field'");
558                }
559        }
560}
561
562######################################################################################################
563
564sub write_data
565{
566        my %writer_args = ( encoding => 'ISO-8859-1' );
567        if ($opt->{outputfile}) {
568                my $fh = new IO::File(">$opt->{outputfile}")  or die "can't open $opt->{outputfile}: $!";
569                $writer_args{OUTPUT} = $fh;
570        }
571
572        my $writer = new XMLTV::Writer(%writer_args);
573
574        $writer->start
575          ( { 'source-info-name'   => "$progname $version",
576              'generator-info-name' => "$progname $version"} );
577
578        for my $channel (sort keys %{$channels}) {
579                $writer->write_channel( {'display-name' => [[ $channel, $opt->{lang} ]], 'id' => $channels->{$channel}} )
580                  if (defined $d->{seen_progs}->{$channel});
581        }
582        for my $channel (sort keys %{$opt_channels}) {
583                $writer->write_channel( {'display-name' => [[ $channel, $opt->{lang} ]], 'id' => $opt_channels->{$channel}} )
584                  if (defined $d->{seen_progs}->{$channel});
585        }
586
587        my $abc2_eariest_start = "300000000000";
588
589        for my $channel (sort keys %{($d->{seen_progs})}) {
590                for my $event_id (sort {$a cmp $b} keys %{($tv_guide->{$channel}->{data})}) {
591                        my $show = $tv_guide->{$channel}->{data}->{$event_id};
592                        Shepherd::Common::cleanup($show);
593                        $writer->write_programme($show);
594
595                        $abc2_eariest_start = $show->{'start'}
596                                        if ($channel eq "ABC2" && $abc2_eariest_start > $show->{'start'});
597                }
598        }
599
600        # check if abc2 has a gap on the first day when the station is closed
601        if ($abc2_eariest_start != "300000000000" && (!defined $opt->{offset}) && defined $channels->{ABC2} &&
602                        $abc2_eariest_start > POSIX::strftime("%Y%m%d%H%M", localtime($starttime))) {
603
604                # create 7am today
605                my @timeattr = localtime($script_start_time); # 0=sec,1=min,2=hour,3=day,4=month,5=year,6=wday,7=yday,8=isdst
606                $timeattr[0] = 0; # zero seconds
607                $timeattr[1] = 0; # min
608                $timeattr[2] = 7; # hours 7am
609                my $time7am = mktime(@timeattr);
610                $time7am -= $time_offset;
611                my $xmltime7am = POSIX::strftime("%Y%m%d%H%M", localtime($time7am));
612
613                if (($starttime < $time7am) && ($abc2_eariest_start == $xmltime7am))
614                {
615                        my $show;
616                        $show->{'channel'} =    $channels->{ABC2};
617                        $show->{'title'} =      [[ "Station Close Guess", $opt->{lang} ]];
618                        $show->{'start'} =      POSIX::strftime("%Y%m%d%H%M", localtime($starttime));
619                        $show->{'stop'} =       $abc2_eariest_start;
620
621                        Shepherd::Common::cleanup($show);
622                        $writer->write_programme($show);
623                }
624        }
625
626        $writer->end();
627}
628
629######################################################################################################
630
631sub check_for_paytv
632{
633        $d->{want_paytv} = 0;
634        foreach my $ch ( 
635            qw(
636            111Hits 111HITS2 13THSTREET 13thSTREET2 3DChannel ACC AdultsOnly960 AIR AnimalPlanet AntennaGreek AntennaPacific
637            APAC Arena Arena2 Aurora BBCKnowledge BBCKnowledgeHD BBCWorldNews Bio BloombergTelevision Boomerang CartoonNetwork
638            Cbeebies ChannelV CMC CNBC CNN Comedy2 ComedyChannel Crime Discovery2 DiscoveryChannel DiscoveryHD DiscoveryHealth
639            DiscoveryRealTime DiscoveryScience DiscoveryTravel DiscoveryTurboMAX DiscoveryWorldHD DiscTurboMAX2 DisneyChannel
640            E!Entertainment ERTGreek ESPN ESPNHD Eurosport Eurosportnews EXPO FashionTV FMC FOX8 FOX82 FOX8HD FOXClassics
641            FOXClassics2 FOXNews FOXSPORTS1 FoxSports1HD FOXSPORTS2 FoxSports2HD FOXSPORTS3 FoxSports3HD FOXSPORTSNews
642            FoxtelBoxOffice FUELTV Hallmark HOWTOChannel KidsCo LifeStyle2 LifeStyleFOOD LifestyleFOOD2 LifeStyleYOU LifStyleYOU2
643            MAX MOVIEEXTRA MOVIEGREATS MOVIEONE MOVIEONEHD MOVIETWO MTV MTVClassic MTVHits MTVNLive MTVNLiveHD NatGeo2
644            NatGeoAdventure NatGeoAdventure2 NatGeoHD NATGEOWILD NatGeoWild NatGeoWildHD NationalGeographic Nickelodeon
645            NickJr Ovation PlayhouseDisney RAIITALIA SCIFI SCIFI2 showcase showcaseHD showcasetwo ShowPremiereHD
646            showtimeaction showtimeactionHD showtimecomedy showtimedrama showtimepremiere showtimetwo SkyNewsAustralia SkyNewsBusiness
647            SKYNewsBusiness SKYNewsNational SkyRacing SKYRacing SKYRacing2 SKYRacingWorld SPEED SPEEDHD STARPICS1 STARPICS1HD STARPICS2
648            STARPICS2HD STVDIO TCM TheHistoryChannel TheLifeStyleChannel TheStyleNetwork TheWeatherChannel TLC TLC2 TSN TV1 TV12
649            TVE TVN UKTV UKTV2 UKTVHD Universal VHits W W2 WHD WORLDMOVIES
650            )
651        ) {
652            $d->{want_paytv}++ if ((exists $channels->{$ch} || exists $opt_channels->{$ch}));
653        }
654
655        $d->{want_paytv}++ if (defined $opt->{paytv});
656        if ($d->{want_paytv} > 0) {
657            Shepherd::Common::log("going to gather paytv channels as we have ".$d->{want_paytv}." paytv channels matching.");
658            Shepherd::Common::log("offsetting paytv channels by ".($time_offset/60)." minutes due to --paytvoffset") if (defined $opt->{paytvoffset});
659                $d->{fetch_interval} = (3 * 3600);      # 3 hours (for now)
660        } else {
661                $d->{fetch_interval} = (6 * 3600);      # 6 hours
662        }
663}
Note: See TracBrowser for help on using the repository browser.