#!/usr/bin/perl ################################################# # Changelog: # 13/07/2005 # - removed backend lastampa, now using # wfactory.net instead (basically the same) # - removed backend mytv, site doesn't provide # data anymore. Didn't remove the code since # it might come in handy in the future. # 25/08/2005 # - updated after changes in skytv.it site # - first test with simple double language messages and docs # 14/06/2006 # - minor update for changes in skytv.it site (now skylife.it) # 16/08/2006 # - fixes to skytv # - skytv now handles categories when using --slow # 11/01/2007 # - added backend boingtv # - new option --cache-slow # 13/02/2007 # - added backend skylife (soon to replace skytv) # 27/05/2007 # - fixed boingtv.it after site change (thanks Paolo Asioli) # 02/07/2007 # - fixed skylife after site change (thanks Marco Coli) # 20/09/2007 # fixes for warnings when in quiet mode # 06/11/2007 # added backend mtv.it, as skylife strangely doesn't carry it, and wfactory is a stuttering site. # 08/12/2007 # skylife.it has moved to guidatv.sky.it # code cleanup # 15/01/2008 # major optimizations in skylife.it! (thanks Massimo Savazzi) # 30/06/2008 # better handling of season /episodes after site changes # now using also the dtd tags episode-num # 24/09/2008 # aggiunti mediasetpremium e raisat # 25/09/2008 # aggiunto iris # 04/02/2009 # update per sky per sito cambiato completamente # tolto wfactory, il sito non va piu' # sistemato rai4 # nuovi canali per mediasetpremium # 02/03/2009 # piccoli fix per skylife # aggiunto backend rai.it (che include rai4, rai gulp e altri canali 'inediti') # 10/11/2009 # sistemato boingtv (grazie r.ghetta) # 22/02/2010 # sistemato iris (grazie gpancot) # 23/02/2010 # sistemato rai.it (grazie gianni kurgo) # 14/09/2010 # aggiunto nuovo backend dahlia # aggiunto nuovo backend k2 (grazie a r.ghetta!) # fix per skylife di r.ghetta # 18/10/2010 # aggiunto backend la7 e riattivato mtv.it (grazie gpancot) # aggiunto backend mediaset # 25/10/2010 # patch da mennucc per possibili errori di parsing di data # patch da wyrdmeister per aggiungere la7d e un fix per raiit # 30/10/2010 # rimosso k2 (grazie rghetta) # fix per la7 (grazie rghetta) # rimosso searchch # 28/12/2010 # aggiunta opzione --mythweb-categories per utilizzare le categorie usate da mythweb invece di quelle del sito # 25/02/2011 # aggiunto patch per mediaset da charon66 # tolto backend dahlia # 24/07/2011 # nuovi canali # 23/09/2013 # nuovi canali e bugfixes # 23/08/2015 # disabled mtvit backend - site doesn't provide data anymore. ################################################# # TODO # - add more informative errors in xml ################################################# #pod below is handled at install time my $POD_GOES_HERE; #default language for warnings set at install time my $DEF_LANG = 'eng'; ###################################################################### # initializations use warnings; use strict; use XMLTV; use XMLTV::Version "$XMLTV::VERSION"; use XMLTV::Capabilities qw/baseline manualconfig cache/; use XMLTV::Description 'Italy'; use XMLTV::Supplement qw/GetSupplement/; use HTML::Entities; use HTML::Parser; use URI::Escape; use Getopt::Long; use Date::Manip; use Memoize; use XMLTV::Memoize; use XMLTV::Ask; use XMLTV::Config_file; use XMLTV::ProgressBar; use XMLTV::DST; use XMLTV::Get_nice; use XMLTV::Mode; #i hate to do this but it seems that skylife is blocking user agents not containing 'mozilla' #we still advertise ourselves as xmltv so they can block us if they really want to $XMLTV::Get_nice::ua->agent("Mozilla/5.0 xmltv/$XMLTV::VERSION"); use XMLTV::Usage < { domain => 'guidatv.sky.it', base_chan => 'http://guidatv.sky.it/app/guidatv/contenuti/data/grid/', base_icon => 'http://guidatv.sky.it/app/guidatv/images/epgimages/channels/grid/', base_data => 'http://guidatv.sky.it/app/guidatv/contenuti/data/grid/', base_slow => 'http://guidatv.sky.it/guidatv/programma/', rturl => "http://guidatv.sky.it/", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&skylife_fetch_data, channel_list_sub => \&skylife_get_channels_list, }, 'raisat' => { domain => 'raisat.it', base_chan => 'http://www.raisat.it/canaliListForXML.jsp', #base_data => 'http://www.raisat.it/generaxmlpalinsesto.jsp', base_data => 'http://212.162.68.116/generaxmlpalinsesto.jsp', rturl => "http://www.raisat.it/", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&raisat_fetch_data, channel_list_sub => \&raisat_get_channels_list, }, 'boingtv' => { domain => 'boingtv.it', base_chan => 'http://www.boingtv.it/xml/palinsesto.xml', base_data => 'http://www.boingtv.it/xml/palinsesto.xml', rturl => "http://www.boingtv.it/xml/palinsesto.xml", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&boingtv_fetch_data, channel_list_sub => \&boingtv_get_channels_list, }, 'sitcom1' => { domain => 'sitcom1.it', base_chan => 'http://www.sitcom1.it/guidatv.asp', base_data => 'http://www.sitcom1.it/guidatv.asp', rturl => "http://www.sitcom1.it/guidatv.asp", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&sitcom1_fetch_data, channel_list_sub => \&sitcom1_get_channels_list, }, 'iris' => { domain => 'iris.mediaset.it', base_chan => 'http://iris.mediaset.it/palinsesto/palinsesto1.shtml', base_data => 'http://iris.mediaset.it/palinsesto/', rturl => "http://iris.mediaset.it/palinsesto/palinsesto1.shtml", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&iris_fetch_data, channel_list_sub => \&iris_get_channels_list, }, # Disabled 2015-08-23 by knowledgejunkie: site no longer provides listings # 'mtvit' => # { domain => 'www.mtv.it', # base_chan => 'http://www.mtv.it/', # base_data => 'http://www.mtv.it/', # rturl => "http://www.mtv.it/tv/guida-tv/", # needs_login => 0, # needs_cookies => 0, # fetch_data_sub => \&mtvit_fetch_data, # channel_list_sub => \&mtvit_get_channels_list, # }, 'mediasetpremium' => { domain => 'mediasetpremium.mediaset.it', base_chan => 'http://www.mediasetpremium.mediaset.it/export/palinsesto.xml', base_data => 'http://www.mediasetpremium.mediaset.it/export/palinsesto', rturl => "http://www.mediasetpremium.mediaset.it/", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&mediasetpremium_fetch_data, channel_list_sub => \&mediasetpremium_get_channels_list, }, 'raiit' => { domain => 'rai.it', base_chan => 'http://www.rai.it/dl/portale/GuidaProgrammi.html', base_data => 'http://www.rai.it/dl/portale/html/palinsesti/guidatv/static/', rturl => "http://www.rai.it/", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&raiit_fetch_data, channel_list_sub => \&raiit_get_channels_list, }, 'dahlia' => { domain => 'dahliatv.it', base_chan => 'http://www.dahliatv.it/guidatv', base_data => 'http://www.dahliatv.it/html/portlet/ext/epg/epg.jsp', rturl => "http://www.dahliatv.it/", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&dahlia_fetch_data, channel_list_sub => \&dahlia_get_channels_list, }, 'la7' => { domain => 'la7.it', base_chan => 'http://www.la7.it/guidatv/index.html', base_data => 'http://www.la7.it/guidatv/index_', rturl => "http://www.la7.it/guidatv/index", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&la7_fetch_data, channel_list_sub => \&la7_get_channels_list, }, 'mediaset' => { domain => 'mediaset.it', base_chan => 'http://www.tv.mediaset.it/dati/palinsesto/palinsesto-mondotv.xml', base_data => 'http://www.tv.mediaset.it/dati/palinsesto/palinsesto-mondotv.xml', rturl => "http://www.tv.mediaset.it/dati/palinsesto/palinsesto-mondotv.xml", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&mediaset_fetch_data, channel_list_sub => \&mediaset_get_channels_list, }, 'mediaset_guidatv' => { domain => 'mediaset_guidatv.it', base_chan => 'http://www.mediaset.it/guidatv/palinsesto.xml', base_data => 'http://www.mediaset.it/guidatv/palinsesto.xml', rturl => "http://www.mediaset.it/guidatv/palinsesto.xml", needs_login => 0, needs_cookies => 0, fetch_data_sub => \&mediaset_guidatv_fetch_data, channel_list_sub => \&mediaset_guidatv_get_channels_list, }, ); ###################################################################### # Get options, including undocumented --cache option. XMLTV::Memoize::check_argv('XMLTV::Get_nice::get_nice_aux') # cache on disk or memoize('XMLTV::Get_nice::get_nice_aux') # cache in memory or die "cannot memoize 'XMLTV::Get_nice::get_nice_aux': $!"; my ($opt_days, $opt_offset, $opt_help, $opt_output, $opt_slow, $opt_verbose, $opt_configure, $opt_config_file, $opt_gui, $opt_quiet, $opt_errors_in_xml, @opt_backends, $opt_list_channels, $opt_cache_slow, $opt_mythweb_categories, ); # server only holds 7 days, so if there is an offset days must be # opt_days-offset or less. $opt_offset = 0; # default $opt_quiet = 0; # default $opt_slow = 0; # default $opt_verbose = 0; # default GetOptions('days=i' => \$opt_days, 'offset=i' => \$opt_offset, 'help' => \$opt_help, 'configure' => \$opt_configure, 'config-file=s' => \$opt_config_file, 'gui:s' => \$opt_gui, 'output=s' => \$opt_output, 'quiet' => \$opt_quiet, 'slow' => \$opt_slow, 'verbose' => \$opt_verbose, 'errors-in-xml' => \$opt_errors_in_xml, 'backend=s' => \@opt_backends, 'list-channels' => \$opt_list_channels, 'cache-slow' => \$opt_cache_slow, 'mythweb-categories' => \$opt_mythweb_categories, ) or usage(0); die ($DEF_LANG eq 'eng' ? "number of days (--days) must not be negative. You gave: $opt_days\n" : "il numero di giorni (--days) non puo' essere negativo. Hai specificato: $opt_days\n") if (defined $opt_days && $opt_days < 0); die ($DEF_LANG eq 'eng' ? "offset days (--offset) must not be negative. You gave: $opt_offset\n" : "l'intervallo di partenza (--offset) non puo' essere negativo. Hai specificato: $opt_offset\n") if ($opt_offset < 0); usage(1) if $opt_help; if ($opt_quiet) { $opt_verbose = 0; } $opt_days = $opt_days || $MAX_DAYS; $opt_slow = 1 if ($opt_cache_slow); my $mode = XMLTV::Mode::mode('grab', $opt_list_channels => 'list-channels', $opt_configure => 'configure'); # parse the --backend option @opt_backends = split(/,/,join(',',@opt_backends)); #we allow both multiple --backend and --backend=name1,name2 my @backends = (); foreach (@opt_backends) { if (defined $backend_info{$_}) { push @backends, $_; } else { warn ($DEF_LANG eq 'eng' ? "Unknown backend $_!\nProbably you need to update! go to xmltv.org for latest release.\nFor latest version get http://snapshot.xmltv.org or http://alpha-exe.xmltv.org if you are on windows." : "Fonte sconosciuta $_!Probabilmente devi aggiornare il programma! Vai su xmltv.org per l'ultima release.\nPer la versione piu' aggiornata vai su http://snapshot.xmltv.org o http://alpha-exe.xmltv.org per windows.\n" ); } } unless (@backends) { @backends = @default_backends; if (@opt_backends) { #we specified backends but we didn't like them, warn the user warn ($DEF_LANG eq 'eng' ? "No good backend specified, falling back on defaults\n" : "Nessuna fonte corretta specificata, uso i default\n" ); } } XMLTV::Ask::init($opt_gui); # reads the file channel_ids, which contains the tables to convert # between backends' ids and XMLTV ids of channels. # to support multiple backends i add a ini-style [section] header # there are two fields: xmltv_id and site_id. my $str = GetSupplement( "tv_grab_it", "channel_ids" ); my $CHANNEL_NAMES_FILE = "channel_ids"; my (%xmltv_chanid, %seen); my $line_num = 0; my $backend; foreach (split( /\n/, $str )) { ++ $line_num; tr/\r//d; s/#.*//; next if m/^\s*$/; my $where = "$CHANNEL_NAMES_FILE:$line_num"; if (/^\[(.*)\]$/) { if (defined $backend_info{$1}) { #esiste la configurazione $backend = $1; } else { warn ($DEF_LANG eq 'eng' ? "Unknown backend $1 in $where\n" : "Fonte sconosciuta $1 in $where\n"); $backend = undef; } } elsif ($backend) { my @fields = split /;/; die ($DEF_LANG eq 'eng' ? "$where: wrong number of fields" : "$where: numero di campi errato") if @fields != 2;#3; my ($xmltv_id, $site_id) = @fields; warn ($DEF_LANG eq 'eng' ? "$where: backend id $site_id for site '$backend' seen already\n" : "$where: fonte con id $site_id per il sito '$backend' gia' visto!\n" ) if defined $backend_info{$backend}{site_ids}{$xmltv_id}; $backend_info{$backend}{site_ids}{$xmltv_id}{site_id} = $site_id; #$backend_info{$backend}{site_ids}{$xmltv_id}{satellite} = $sat; warn ($DEF_LANG eq 'eng' ? "$where: XMLTV_id $xmltv_id for site '$backend' seen already\n" : "$where: XMLTV_id $xmltv_id per il sito '$backend' gia' visto!\n" ) if $seen{$backend.$xmltv_id}++; } } # File that stores which channels to download. Not needed for # list-channels mode. # my $config_file; unless ($mode eq 'list-channels') { $config_file = XMLTV::Config_file::filename($opt_config_file, 'tv_grab_it', $opt_quiet); } XMLTV::Config_file::check_no_overwrite($config_file) if $mode eq 'configure'; # Arguments for XMLTV::Writer. my %w_args; if (defined $opt_output) { die($DEF_LANG eq 'eng' ? "cannot give --output with --configure" : "non e' possibile specificare --output con --configure") if $mode eq 'configure'; my $fh = new IO::File(">$opt_output"); die ($DEF_LANG eq 'eng' ? "cannot write to $opt_output: $!" : "impossibile scrivere su $opt_output") if not defined $fh; $w_args{OUTPUT} = $fh; } $w_args{encoding} = 'ISO-8859-1'; $line_num = 0; my $foundchannels; my $bar = new XMLTV::ProgressBar(($DEF_LANG eq 'eng' ? 'getting list of channels' : 'prendo la lista dei canali'), scalar @backends) if not $opt_quiet; # find list of available channels foreach $backend (@backends) { %{$backend_info{$backend}{channels}} = &{$backend_info{$backend}{channel_list_sub}}($backend_info{$backend}{base_chan}); $foundchannels+=scalar(keys(%{$backend_info{$backend}{channels}})); if (not $opt_quiet) { update $bar; } } $bar->finish() if (not $opt_quiet); die ($DEF_LANG eq 'eng' ? "no channels could be found" : "nessun canale trovato") unless ($foundchannels); warn ($DEF_LANG eq 'eng' ? "VERBOSE: $foundchannels channels found.\n" : "VERBOSE: $foundchannels canali trovati.\n") if ($opt_verbose); ###################################################################### # write configuration if ($mode eq 'configure') { open(CONF, ">$config_file") or die ($DEF_LANG eq 'eng' ? "cannot write to $config_file: $!" : "impossibile scrivere su $config_file: $!"); my %channels; foreach $backend (@backends) { #faccio un hash con tutti gli id foreach (keys %{$backend_info{$backend}{channels}}) { $channels{$_} = xmltv_chanid($backend, $_); } #not used yet if ($backend_info{$backend}{needs_login}) { say "To get listings on '$backend' you will need a login on the site.\n"; my $username_wanted = ask_boolean('Do you have a login?', 0); if ($username_wanted) { $backend_info{$backend}{username} = ask("Username:"); print CONF "username: $backend:$backend_info{$backend}{username}\n"; } } } #double reverse to get rid of duplicates %channels = reverse %channels; %channels = reverse %channels; # Ask about each channel. my @names = sort keys %channels; my @qs = map { ($DEF_LANG eq 'eng' ? "add channel $_?" : "aggiungo il canale $_?") } @names; my @want = ask_many_boolean(1, @qs); foreach (@names) { die if $_ =~ tr/\r\n//; my $w = shift @want; warn("cannot read input, stopping channel questions"), last if not defined $w; # No need to print to user - XMLTV::Ask is verbose enough. # Print a config line, but comment it out if channel not wanted. print CONF '#' if not $w; print CONF "channel ".$channels{$_}." # $_\n"; } close CONF or warn ($DEF_LANG eq 'eng' ? "cannot close $config_file: $!" : "impossibile chiudere $config_file: $!"); say(($DEF_LANG eq 'eng' ? "Finished configuration." : "Configurazione terminata.")); exit(); } # Not configuring, must be writing some XML. my $w = new XMLTV::Writer(%w_args); my $source_info_str = join ",", map {'http://'.$backend_info{$_}{domain}} @backends; my $source_data_str = join ",", map {$backend_info{$_}{rturl}} @backends; $w->start({ 'source-info-url' => $source_info_str , 'source-data-url' => $source_data_str, 'generator-info-name' => 'XMLTV', 'generator-info-url' => 'http://xmltv.org/', }); my %display_names; my %list_display_names; foreach my $back (@backends) { foreach (keys %{$backend_info{$back}{site_ids}}) { $display_names{$_} = [$backend_info{$back}{site_ids}{$_}{site_id}, $back]; #per controllare altri attributi tipo l'icona devo sapere da che backend viene il canale $list_display_names{$_} = $backend_info{$back}{site_ids}{$_}{site_id}; } } if ($mode eq 'list-channels') { # Write all known channels then finish. foreach my $xmltv_id (sort keys %list_display_names) { next if not defined $display_names{$xmltv_id}; my @display_name= [ [ $display_names{$xmltv_id}->[0] ] ]; my $backend = $display_names{$xmltv_id}->[1]; my @chaninfo; if (defined $backend_info{$backend}{site_ids}{$xmltv_id}{channum}) { #abbiamo il numero di canale, lo mettiamo come display name secondario @chaninfo = ('display-name' => [ [ $display_names{$xmltv_id}->[0] ], [ $backend_info{$backend}{site_ids}{$xmltv_id}{channum}]]); } else { @chaninfo = ('display-name' => [ [ $display_names{$xmltv_id}->[0] ] ]); } #aggiungo l'icona se ce l'ho if (defined $backend_info{$backend}{site_ids}{$xmltv_id}{icon}) { push @chaninfo , (icon => [{src => $backend_info{$backend}{site_ids}{$xmltv_id}{icon}}]); } $w->write_channel({ id => $xmltv_id, @chaninfo }); } $w->end; exit; } ###################################################################### # read configuration my @channels; $line_num = 0; foreach (XMLTV::Config_file::read_lines($config_file)) { ++ $line_num; next if not defined; if (/^channel:?\s*(.*\S+)\s*$/) { push @channels, $1; } elsif (/^username:?\s+(\S+):(\S+)/){ if (defined $backend_info{$1}) { #esiste la configurazione $backend_info{$1}{username} = $2; } else { warn ($DEF_LANG eq 'eng' ? "Found username for unknown backend $1 in $config_file\n" : "Trovato un nome utente per una fonte sconosciuta $1 in $config_file\n"); } } else { warn ($DEF_LANG eq 'eng' ? "$config_file:$line_num: bad line\n" : "$config_file:$line_num: linea errata\n"); } } ###################################################################### # sort out problem in offset options if ($opt_offset >= $MAX_DAYS) { warn ($DEF_LANG eq 'eng' ? "Day offset too big. No program information will be fetched.\n" : "Intervallo specificato troppo grande. Nessun dato verra' scaricato.\n"); $opt_offset = 0; $opt_days = 0; } my $days2get; if (($opt_days+$opt_offset) > $MAX_DAYS) { $days2get=$MAX_DAYS-$opt_offset; warn ($DEF_LANG eq 'eng' ? "The server only has info for ".($MAX_DAYS-1)." days from today.\n" : "Il server ha informazioni solo per ".($MAX_DAYS-1)." giorni da oggi.\n"); if ($days2get > 1) { warn ($DEF_LANG eq 'eng' ? "You'll get listings for only $days2get days.\n" : "Scarico programmi solo per $days2get giorni.\n"); } else { warn ($DEF_LANG eq 'eng' ? "You'll get listings for only 1 day.\n" : "Scarico programmi solo per un giorno.\n"); } } else { $days2get=$opt_days; } t "will get $days2get days from $opt_offset onwards"; ###################################################################### # grabbing listings foreach my $xmltv_id (@channels) { next if not defined $display_names{$xmltv_id}; my @display_name= [ [ $display_names{$xmltv_id}->[0] ] ]; my $backend = $display_names{$xmltv_id}->[1]; my @chaninfo; if (defined $backend_info{$backend}{site_ids}{$xmltv_id}{channum}) { #abbiamo il numero di canale, lo mettiamo come display name secondario @chaninfo = ('display-name' => [ [ $display_names{$xmltv_id}->[0] ], [ $backend_info{$backend}{site_ids}{$xmltv_id}{channum}]]); } else { @chaninfo = ('display-name' => [ [ $display_names{$xmltv_id}->[0] ] ]); } #aggiungo l'icona se ce l'ho if (defined $backend_info{$backend}{site_ids}{$xmltv_id}{icon}) { push @chaninfo , (icon => [{src => $backend_info{$backend}{site_ids}{$xmltv_id}{icon}}]); } $w->write_channel({ id => $xmltv_id, @chaninfo }); } #make a list of channels and days to grab my @to_get; foreach my $day ($opt_offset .. ($days2get + $opt_offset - 1)) { foreach my $channel (@channels) { push @to_get, [$channel, $day]; } } $bar = new XMLTV::ProgressBar(($DEF_LANG eq 'eng' ? 'getting listings' : 'scarico programmi'), scalar @to_get) if not $opt_quiet; ## If we aren't getting any days of program data then clear out the list ## that was created to fetch \. #if ($days2get == 0) {@to_get = ();} foreach (@to_get) { my $day = $_->[1]; my $channel = $_->[0]; #this is where i would handle cookies and logins if needed warn ($DEF_LANG eq 'eng' ? "VERBOSE: Grabbing channel $channel, day $day\n" : "VERBOSE: Prendo dati per il canale $channel, giorno $day\n") if ($opt_verbose); my $error; foreach $backend (@backends) { warn ($DEF_LANG eq 'eng' ? "VERBOSE: Trying with $backend\n" : "VERBOSE: Provo con $backend\n") if ($opt_verbose); my @dati; $error = 0; ($error, @dati) = &{$backend_info{$backend}{fetch_data_sub}}($channel, $day); #TODO different kinds of errors? if ($error) { warn ($DEF_LANG eq 'eng' ? "VERBOSE: Error fetching channel $channel day $day with backend $backend\n" : "VERBOSE: Errore nello scaricare i dati per $channel, giorno $day con $backend\n") if ($opt_verbose); } else { $w->write_programme($_) foreach @dati; last; } } #nessuno ci e' riuscito if ($error) { #this is an easier way to know about errors if all of our scripts are automated if ($opt_errors_in_xml) { $w->write_programme( { title => [[($DEF_LANG eq 'eng' ? 'ERROR FETCHING DATA' : 'ERRORE DI SCARICAMENTO DATI'), $LANG]], start => xmltv_date('00:01', $day), stop => xmltv_date('23:59', $day), channel => $channel, desc => [[($DEF_LANG eq 'eng' ? "XMLTV couldn't grab data for $channel, day $day. Sorry about that." : "XMLTV non e' riuscito a scaricare i dati per $channel, giorno $day. Spiacente."), $LANG]], } ); } else { warn ($DEF_LANG eq 'eng' ? "I couldn't fetch data for channel $channel, day $day from any backend!!\n" : "Non sono riuscito a scaricare i dati per $channel, giorno $day da nessuna fonte!!\n") if (not $opt_quiet); } } update $bar if not $opt_quiet; } $w->end; $bar->finish() if not $opt_quiet; ##################### # general functions # ##################### #################################################### # xmltv_chanid # to handle channels that are not yet in the channel_ids file sub xmltv_chanid { my ($backend, $channel_id) = @_; my %chan_ids; #reverse id hash foreach my $xmltv_id (keys %{$backend_info{$backend}{site_ids}}) { my $site_id = $backend_info{$backend}{site_ids}{$xmltv_id}{site_id}; $chan_ids{$site_id} = $xmltv_id; next if (not defined $site_id); } if (defined $chan_ids{$channel_id}) { return $chan_ids{$channel_id}; } else { warn ($DEF_LANG eq 'eng' ? "***Channel |$channel_id| for '$backend' is not in channel_ids, should be updated.\n" : "***Il canale |$channel_id| su '$backend' non e' in channel_ids, andrebbe aggiornato.\n" ) unless $opt_quiet; my $oldid=$channel_id; $channel_id=~ s/\W//gs; #make up an id my $id = lc($channel_id).".".$backend_info{$backend}{domain}; #warn ("-->update: $id;$oldid\n"); ##update backend info #$backend_info{$backend}{site_ids}{$id}{site_id} = $channel_id; return $id; } } ########################################################## # tidy # decodes entities and removes some illegal chars sub tidy($) { for (my $tmp=shift) { s/[\000-\037]//gm; # remove control characters s/[\222]/\'/gm; # messed up char s/[\224]/\"/gm; # end quote s/[\205]/\.\.\./gm; # ... must be something messed up in my regexps? s/[\223]/\"/gm; #start quote s/[\221]/\'/gm; s/\\\'/\'/gm; #s/Ã/à/gm;# s/è/è/g;# s/â/\'/g;# s/è/è/g;# s/à/à/g;# s/ì/ì/g;# s/â¦/\.\.\./g; #mah... if (s/[\200-\237]//g) { if ($opt_verbose){ warn ($DEF_LANG eq 'eng' ? "VERBOSE: removing illegal char: |\\".ord($&)."|\n" : "VERBOSE: tolgo carattere illegale: |\\".ord($&)."|\n"); } } # Remove leading white space s/^\s*//; # Remove trailing white space s/\s*$//; # FIXME handle a with a grave accent encoded as utf-8 (fallout from LWP::Simple?) s/\xc3\xa0/\xe0/g; return decode_entities($_); } } #################################################### # xmltv_date # this returns a date formatted like 20021229121300 CET # first argument is time (like '14:20') # second is date offset from today sub xmltv_date { my ($time, $offset) = @_; $time =~/([0-9]+?):([0-9]+).*/ or die ($DEF_LANG eq 'eng' ? "bad time $time" : "strano orario $time"); my $hour=$1; my $min=$2; my $data = &DateCalc("today","+ ".$offset." days"); die ($DEF_LANG eq 'eng' ? 'date calculation failed' : 'errore di calcolo data') if not defined $data; return utc_offset(UnixDate($data, '%Y%m%d').$hour.$min.'00', '+0100'); } ######################## # boingtv.it functions # ######################## ######################################################### # boingtv_get_channels_list # since this site only has one channel this is a fake sub sub boingtv_get_channels_list { my %chan_hash = ( 'boingtv' ,'www.boingtv.it'); return %chan_hash; } #################################################### # boingtv_fetch_data # 2 parameters: xmltv_id of channel # day offset # returns an error or an array of data sub boingtv_fetch_data { my ($xmltv_id, $offset) = @_; my $content; my $site_id = $backend_info{boingtv}{site_ids}{$xmltv_id}{site_id}; if (not defined $site_id) { warn ($DEF_LANG eq 'eng' ? "VERBOSE: \tThis site doesn't know about $xmltv_id!\n" : "VERBOSE: \tQuesto sito non sa niente di $xmltv_id!\n" ) if ($opt_verbose); return (1, ()); } # build url to grab # very strange site: only has data till next sunday. if the offset it's too big we return an empty array # but we don't return an error my $day_of_week = UnixDate("today", '%w'); #1 (Monday) to 7 (Sunday) if ($day_of_week + $offset > 7) { return (0, ()); } my $date_grab = &DateCalc("today","+ ".$offset." days"); die ($DEF_LANG eq 'eng' ? 'date calculation failed' : 'errore di calcolo di data') if not defined $date_grab; $date_grab = UnixDate($date_grab, '%Y%m%d'); my $cachestring = "?pippo=".UnixDate("today","%Y%m%d%H") if ($offset == 0); my $url = $backend_info{boingtv}{base_data}.$cachestring; warn ($DEF_LANG eq 'eng' ? "VERBOSE: fetching $url\n" : "VERBOSE: scarico $url\n") if ($opt_verbose); eval { $content=get_nice($url) }; if ($@) { #get_nice has died warn ($DEF_LANG eq 'eng' ? "VERBOSE: Error fetching $url channel $xmltv_id day $offset backend boingtv\n" : "VERBOSE: Errore nello scaricare $url, canale $xmltv_id, giorno $offset, fonte boingtv\n") if ($opt_verbose); # Indicate to the caller that we had problems return (1, ()); } my @programmes = (); warn "VERBOSE: parsing...\n" if ($opt_verbose); my @lines = split /\n/, $content; my $title = ''; my $time_start = ''; my $description = ''; #split the lines foreach my $line (@lines) { next unless $line=~/EVENT/; $line=~/timestamp="(.*?)".*name="(.*?)".*description="(.*?)"/; my %programme = (); eval { ($title, $time_start, $description) = ($2, utc_offset($1.'00', '+0100'), $3) ; } or do { warn 'skipping programme, error: ' . $@ ; next ; }; # Three mandatory fields: title, start, channel. if (not defined $title) { warn 'no title found, skipping programme'; next; } $programme{title}=[[tidy($title), $LANG] ]; if (not defined $time_start) { warn "no start time for title $title, skipping programme"; next; } #dobbiamo buttare via quello che non ci interessa next unless ($time_start=~/^$date_grab/); $programme{desc}=[[tidy($description), $LANG] ] if ($description ne ''); $programme{start}=$time_start;#xmltv_date($time_start, $offset + $past_midnight); $programme{channel}=$xmltv_id; #put info in array push @programmes, {%programme}; } if (scalar @programmes) { return (0, @programmes); } else { # there is a number of reasons why we could get an empty array. # so we return an error return (1, @programmes); } } ######################## # mtv.it functions # ######################## ######################################################### # mtvit_get_channels_list # since this site only has one channel this is a fake sub sub mtvit_get_channels_list { my %chan_hash = ( 'MTV' ,'www.mtv.it'); return %chan_hash; } #################################################### # mtvit_fetch_data # 2 parameters: xmltv_id of channel # day offset # returns an error or an array of data sub mtvit_fetch_data { my ($xmltv_id, $offset) = @_; my $content; my $site_id = $backend_info{mtvit}{site_ids}{$xmltv_id}{site_id}; if (not defined $site_id) { warn ($DEF_LANG eq 'eng' ? "VERBOSE: \tThis site doesn't know about $xmltv_id!\n" : "VERBOSE: \tQuesto sito non sa niente di $xmltv_id!\n" ) if ($opt_verbose); return (1, ()); } # build url to grab # http://tv.mtv.it/guidatv.php?tvguidedate=2014-11-05 my $grabdate = UnixDate(&DateCalc("today","+ ".$offset." days"), '%Y:%m:%d'); my ($anno, $mese, $giorno) = split /:/, $grabdate; #my $url = $backend_info{mtvit}{base_data}.'?canaleSel=MTV&giorno_guid='.$giorno.'%2F'.$mese.'%2F'.$anno; #my $url = $backend_info{mtvit}{base_data}.'guidatv.php?tvguidedate='.$anno.'-'.$mese.'-'.$giorno; # http://tv.mtv.it/guidatv.php?tvguidedate=2015-06-19 my $url = $backend_info{mtvit}{base_data}.'tv/guida-tv/'.$anno.'-'.$mese.'-'.$giorno; # http://www.mtv.it/tv/guida-tv/2015-06-21 warn ($DEF_LANG eq 'eng' ? "VERBOSE: fetching $url\n" : "VERBOSE: scarico $url\n") if ($opt_verbose); eval { $content=get_nice($url) }; if ($@) { #get_nice has died warn ($DEF_LANG eq 'eng' ? "VERBOSE: Error fetching $url channel $xmltv_id day $offset backend mtvit\n" : "VERBOSE: Errore nello scaricare $url, canale $xmltv_id, giorno $offset, fonte mtvit\n") if ($opt_verbose); # Indicate to the caller that we had problems return (1, ()); } #$content=~/colonna centrale(.*)colonna destra/s; $content=$1; #$content=~/
    (.*)?
    /s; $content=$1; #$content=~/