Aller au contenu

delianmc

Membres
  • Compteur de contenus

    1
  • Inscription

  • Dernière visite

À propos de delianmc

delianmc's Achievements

Newbie

Newbie (1/14)

0

Réputation sur la communauté

  1. Bonjour, J'utilise https://www.xmltvlistings.com/ pour obtenir mon xmltv et j'habite au Canada. Je ne sais pas pour l'Europe mais ici (ATSC) le sevice ID n'est pas unique ce qui fait que le script ne mappais pas convenablement le contenu du XML aux fichiers epg. J'ai donc du l'adapter pour utiliser un unique id à la place. Cette version devrait fonctionner dans tous les scénario. Désolé si le code n'utilise pas les best practice j'ai du faire un "crash course" sur perl en une soirée... Voici la version modifié: #! /usr/bin/perl # # # $Id: xml2epg.pl,v 2.14 2014/05/12 07:50:57 root Exp $ # $ENV{PATH} = "/usr/syno/bin:/usr/syno/sbin:/bin:/sbin:/usr/bin:/usr/sbin"; use strict; use warnings; use File::Basename; use File::Temp qw/ tempfile /; use Time::Local; use Getopt::Long; use POSIX qw(locale_h); use IO::File; my $progname=basename($0); #+ # use utf8 for terminal output if env specifies utf8 #- if (setlocale(LC_CTYPE) =~ /utf8/) { binmode STDOUT, ":encoding(UTF-8)"; binmode STDERR, ":encoding(UTF-8)"; } #+ # ALL FileIO is utf8 #- use open ':encoding(utf8)'; my $debug=0; my $quiet=0; my $progress=0; my $notafter; my $vsdir_path = "/usr/syno/etc/packages/VideoStation"; # default EPG directory my $epgdir_path; for my $d (qw (EPGs/0EPG EPG)) { $epgdir_path = "$vsdir_path/$d"; last if -d $epgdir_path; } # default channels.conf path my $channels_conf_path; for my $c (qw (channels/0channels.conf channels.conf)) { $channels_conf_path = "$vsdir_path/$c"; last if -r $channels_conf_path; } my $myconf_path = "/usr/local/etc/xml2epg.conf"; my $now = time(); sub info { print STDERR "$progname: @_.\n" unless $quiet; } sub debug { my $level=shift; print STDERR "DEBUG: @_\n" if $debug >= $level; } #+ # format "YYYYMMDDhhmmss[ <utc offset>] string to binary time #- sub str2time { my $string=shift; my ( $year, $mon, $mday, $hour, $min, $sec, $sign_off, $hr_off, $min_off) = ($string =~ /^ (\d{4}) (\d{2}) (\d{2}) (\d{2}) (\d{2}) (\d{2}) \s* (?:([+-])?(\d{2})(\d{2}))?$/x); if (defined $hr_off) { # time is "UTC <offset>" my $offset = ($hr_off * 60 + $min_off) * 60; # seconds $offset = - $offset if $sign_off eq "-"; return timegm($sec, $min, $hour, $mday, $mon-1, $year) - $offset; } else { # time is local return timelocal($sec, $min, $hour, $mday, $mon-1, $year) ; } } #================================================================================ sub usage { my $status=shift; print STDERR <<EOF; Arguments: --debug|-D --quiet|-q --progress|-p --epgdir|-d <epg output directory> --conf|-s <config file path> --chanconf|-C <channels.conf path> EOF exit $status; } #+ # command switches #- my $help; Getopt::Long::Configure ("bundling"); GetOptions ( 'debug|D+' => \$debug, 'quiet|q+' => \$quiet, 'epgdir|d=s' => \$epgdir_path, 'progress|p' => \$progress, 'conf|c=s' => \$myconf_path, 'chanconf|C=s' => \$channels_conf_path, 'maxdays|m=s' => sub {$notafter = $now + ($_[1] * 60 * 60 * 24)}, 'help|?' => \$help, ) or usage(1); usage(0) if $help; my $arg = shift or do { info "missing argument"; usage(1); }; -d $epgdir_path or do { info "invalid dir $epgdir_path ($!)"; exit(1); }; sub quote { my $string = shift; $string =~ s/"/\\"/g; return "\"" . $string . "\""; } my %xml2confchname = (); #+ # parse my conf #- { info ("parsing $myconf_path"); open my $myconf_h, "<", "$myconf_path" or die "$! opening $myconf_path\n"; while (<$myconf_h>) { s/#.*$//; # uncomment; next if /^\s*$/; # skip blank lines; my ($verb, $text) = /^\s*(\S*)\s+(.*\S)\s*$/; defined($verb) or do { info "$myconf_path:$.:syntax error"; exit(1); } ; if ($verb eq "defname") { # trailing spaces have already been suppressed my ($xmlname, $confname) = ($text =~ /^(\S+)\s+(.*)$/); die "syntax error:\n$_" unless defined $xmlname && defined $confname; $xml2confchname{lc $xmlname} = $confname; debug(1,"mapping \"$xmlname\" -> \"^$confname.*\"") } else { die "unknown $verb : $verb\n"; } } info ("done"); } my %chan_conf_name2sid = (); my %sid2suffix = (); my %uniqueid = (); #+ # parse_channel_conf #- { my $chaconf_h = new IO::File; info ("parsing $channels_conf_path"); open $chaconf_h, "<", $channels_conf_path or die "$! opening $channels_conf_path\n"; my $prefix; $chaconf_h->read ($prefix,2) == 2 or die "$! reading prefix\n"; $chaconf_h->seek(0,0); # rewind my $chname; my $sid; my $suffix; if ( $prefix eq '[{') { # hdhomerun format my $chaconf_s = $chaconf_h->getline(); while ($chaconf_s =~ /{(.*?)}/g) { # sample chaconf_s: "frequency":778000000,"service_id":513,"title":"D8" foreach (split /,/, $1) { my ($name, $value) = /^"?(.*?)"?:"?(.*?)"?$/; $chname = $value if $name eq "title"; $suffix = $value if $name eq "frequency"; $sid = $value if $name eq "service_id"; } debug(1, "SID=$sid, NAME=$chname, SUFFIX= $suffix"); $chan_conf_name2sid{$chname} = $sid; $uniqueid{$chname} = $sid . "@" . $suffix; $sid2suffix{$sid} = $suffix; } } else { while (<$chaconf_h>) { next unless /:/; s/\s*$//; # remove trailing cr nl and spacing my @fields = split(/:/); $chname=$fields[0]; $sid=$fields[-1]; $suffix=$fields[1]; $chan_conf_name2sid{$chname} = $sid; $uniqueid{$chname} = $sid . "@" . $suffix; $sid2suffix{$sid} = $suffix; debug(1, "SID=$sid, NAME=$chname, SUFFIX= $suffix"); } } info ("done"); } #+ # arg can be "http://<file>" | "file.zip" | "file.xml" #- my $xmlfile; if ($arg =~ /^http/) { my $zipfile; (undef , $zipfile) = tempfile(DIR => "/tmp", TEMPLATE => "epg-XXXXXX", SUFFIX => ".zip" , UNLINK => 1); info "fetching $arg"; die "wget error\n" if system("wget -nv -O $zipfile $arg") > 0; $arg = $zipfile; info "fetched"; } if ($arg =~ /.zip$/) { (undef , $xmlfile) = tempfile(DIR => "/tmp", TEMPLATE => "epg-XXXXXX", SUFFIX => ".xml", UNLINK => 1); info "unzipping $arg"; die "unzip error\n" if system("unzip -p $arg > $xmlfile") > 0; info "unzipped"; } else { $xmlfile = $arg; } ### Poor man XML parse info ("parsing XMLTV file"); open my $xml_h, "<", $xmlfile or die "$! opening $xmlfile\n"; my $channel_id; my $cur_chaname; # display name my $curprog; # current TV program struct (ref to hash) my %progs = (); # $progs{<channel_id>} : ref to array of "progs" my %id2name = (); while (<$xml_h>) { if (/<channel id="([^"]*?)">/) { # if (/<channel id="(.*)">/) { $channel_id=$1; next; } if (/<display-name>(.*)<\/display-name>/) { $id2name{$channel_id} = $1; next; } if (/^\s+<(title|desc|sub-title).*?>(.*)<\/\1/) { $curprog->{$1} = $2; next; } if (my ($start_s, $stop_s, $chan) = (/^ \s*<programme\s+start="(.*?)".* \s+stop="(.*?)".* \s+channel="(.*?)"/x )) { my $start=str2time($start_s); my $stop=str2time($stop_s); $cur_chaname = $id2name{$chan}; $curprog = { duration => ($stop - $start) , start_time => $start, text_name => "", }; next; } if (/^\s+<\/programme>/) { print STDERR "." if $progress; my $start_time = $curprog->{start_time}; my $duration = $curprog->{duration}; next if ($start_time + $duration < $now); # too late next if (defined($notafter) && ($start_time > $notafter)); push @{$progs{$cur_chaname}}, $curprog ; } } if ($debug) { foreach (keys %id2name) { debug (1,"XMLNAME $_ -> $id2name{$_}"); } } print STDERR "\n" if $progress; info ("parsed"); chdir $epgdir_path or die "chdir $epgdir_path, $!\n"; #+ # in: channel_name (from xml) # out: unique service ids array #- my %ignoring=(); sub cha2uid { my $xml_chaname = shift; my @uids = (); return @uids if ($ignoring{$xml_chaname}); my $squeezed_xml_chaname = $xml_chaname; $squeezed_xml_chaname =~ s/\s//g; # remove spacing #my ($xmlname, $confname) = ($text =~ /^(\S+)\s+(.*)$/); my $vs_chaname_prefix=$xml2confchname{lc($squeezed_xml_chaname)}; if (! defined($vs_chaname_prefix)) { info("mapping for channel $xml_chaname not found!"); info("add \"defname $squeezed_xml_chaname <channel.conf name>\" in config file"); info ("ignoring \"$xml_chaname\""); $ignoring{$xml_chaname}++; return @uids; } else { debug(1, "xml_chaname=$xml_chaname, squeezed_xml_chaname=$squeezed_xml_chaname, vs_chaname_prefix=$vs_chaname_prefix") } foreach my $vs_chaname (keys %chan_conf_name2sid) { if ($vs_chaname =~ /^$vs_chaname_prefix/i) { debug(2, "vs_chaname=$vs_chaname, vs_chaname_prefix=$vs_chaname_prefix, chan_conf_name2sid=$chan_conf_name2sid{$vs_chaname}"); push @uids, $uniqueid{$vs_chaname} } } debug(1,"uids for $xml_chaname: @uids"); return @uids; } foreach my $chaname (keys %progs) { my @sidlist = cha2uid($chaname); foreach my $uid ( @sidlist) { #my $unique_id= $sid . "@" . $sid2suffix{$sid}; my $unique_id=$uid; my $epgfile="epg." . $unique_id; info "creating $epgfile ($chaname)"; unlink $epgfile; open my $epg_h, ">", "$epgfile" or die "$! opening $epgfile\n"; $epg_h->print("{\n"); $epg_h->print(" \"eventdata\" : [\n"); my $eventid=1; my @proglist = sort {$a->{start_time} <=> $b->{start_time}} @{$progs{$chaname}} ; my $lastprog = $proglist[-1]; foreach my $prog (@proglist) { my $event_name = $prog->{title}; $event_name .= " - " . $prog->{"sub-title"} if exists $prog->{"sub-title"}; # remplacer les virgules par des espaces dans le titre $event_name =~ s/,/ /g; my $text_name = exists($prog->{desc}) ? $prog->{desc} : ""; my $islatest = $prog == $lastprog ; debug (2, sprintf ("Chan=%s, id=%s, event=%s",$chaname,$uid, $event_name)); $event_name .= " - " . $prog->{subtitle} if exists $prog->{subtitle}; $epg_h->print(" {\n"); $epg_h->print(" \"duration\" : ", $prog->{duration}, ",\n"); $epg_h->print(" \"event_id\" : ", $eventid++, ",\n"); $epg_h->print(" \"event_name\" : ", quote($event_name), ",\n"); $epg_h->print(" \"finalprogram\" : ", ( $islatest ? "true" : "false") , ",\n"); $epg_h->print(" \"start_time\" : ", $prog->{start_time}, ",\n"); $epg_h->print(" \"text_name\" : ", quote($text_name), "\n"); $epg_h->print(" }", ($islatest ? "" : ",") , "\n"); } $epg_h->print(" ],\n"); $epg_h->print(" \"unique_id\" : \"", $unique_id, "\"\n"); $epg_h->print("}\n"); $epg_h->close(); } } 1; # Local Variables: # mode: cperl # cperl-indent-level: 4 # End: J'espère qu'elle vous sera utile.
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.